fix: wrap clack notes for cleaner boxes
This commit is contained in:
@@ -4,7 +4,6 @@ import {
|
|||||||
confirm as clackConfirm,
|
confirm as clackConfirm,
|
||||||
intro as clackIntro,
|
intro as clackIntro,
|
||||||
multiselect as clackMultiselect,
|
multiselect as clackMultiselect,
|
||||||
note as clackNote,
|
|
||||||
outro as clackOutro,
|
outro as clackOutro,
|
||||||
select as clackSelect,
|
select as clackSelect,
|
||||||
text as clackText,
|
text as clackText,
|
||||||
@@ -26,6 +25,7 @@ import { ensureControlUiAssetsBuilt } from "../infra/control-ui-assets.js";
|
|||||||
import { listChatProviders } from "../providers/registry.js";
|
import { listChatProviders } from "../providers/registry.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime } from "../runtime.js";
|
||||||
|
import { note } from "../terminal/note.js";
|
||||||
import {
|
import {
|
||||||
stylePromptHint,
|
stylePromptHint,
|
||||||
stylePromptMessage,
|
stylePromptMessage,
|
||||||
@@ -90,8 +90,6 @@ const intro = (message: string) =>
|
|||||||
clackIntro(stylePromptTitle(message) ?? message);
|
clackIntro(stylePromptTitle(message) ?? message);
|
||||||
const outro = (message: string) =>
|
const outro = (message: string) =>
|
||||||
clackOutro(stylePromptTitle(message) ?? message);
|
clackOutro(stylePromptTitle(message) ?? message);
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
const text = (params: Parameters<typeof clackText>[0]) =>
|
const text = (params: Parameters<typeof clackText>[0]) =>
|
||||||
clackText({
|
clackText({
|
||||||
...params,
|
...params,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { note as clackNote } from "@clack/prompts";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
buildAuthHealthSummary,
|
buildAuthHealthSummary,
|
||||||
DEFAULT_OAUTH_WARN_MS,
|
DEFAULT_OAUTH_WARN_MS,
|
||||||
@@ -14,12 +12,9 @@ import {
|
|||||||
resolveProfileUnusableUntilForDisplay,
|
resolveProfileUnusableUntilForDisplay,
|
||||||
} from "../agents/auth-profiles.js";
|
} from "../agents/auth-profiles.js";
|
||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
import { note } from "../terminal/note.js";
|
||||||
import type { DoctorPrompter } from "./doctor-prompter.js";
|
import type { DoctorPrompter } from "./doctor-prompter.js";
|
||||||
|
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
|
|
||||||
export async function maybeRepairAnthropicOAuthProfileId(
|
export async function maybeRepairAnthropicOAuthProfileId(
|
||||||
cfg: ClawdbotConfig,
|
cfg: ClawdbotConfig,
|
||||||
prompter: DoctorPrompter,
|
prompter: DoctorPrompter,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import { note as clackNote } from "@clack/prompts";
|
|
||||||
|
|
||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
import { resolveGatewayPort, resolveIsNixMode } from "../config/paths.js";
|
import { resolveGatewayPort, resolveIsNixMode } from "../config/paths.js";
|
||||||
import { resolveGatewayLaunchAgentLabel } from "../daemon/constants.js";
|
import { resolveGatewayLaunchAgentLabel } from "../daemon/constants.js";
|
||||||
@@ -26,7 +24,7 @@ import {
|
|||||||
} from "../daemon/service-audit.js";
|
} from "../daemon/service-audit.js";
|
||||||
import { buildServiceEnvironment } from "../daemon/service-env.js";
|
import { buildServiceEnvironment } from "../daemon/service-env.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
import { note } from "../terminal/note.js";
|
||||||
import {
|
import {
|
||||||
DEFAULT_GATEWAY_DAEMON_RUNTIME,
|
DEFAULT_GATEWAY_DAEMON_RUNTIME,
|
||||||
GATEWAY_DAEMON_RUNTIME_OPTIONS,
|
GATEWAY_DAEMON_RUNTIME_OPTIONS,
|
||||||
@@ -34,9 +32,6 @@ import {
|
|||||||
} from "./daemon-runtime.js";
|
} from "./daemon-runtime.js";
|
||||||
import type { DoctorOptions, DoctorPrompter } from "./doctor-prompter.js";
|
import type { DoctorOptions, DoctorPrompter } from "./doctor-prompter.js";
|
||||||
|
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
|
|
||||||
function detectGatewayRuntime(
|
function detectGatewayRuntime(
|
||||||
programArguments: string[] | undefined,
|
programArguments: string[] | undefined,
|
||||||
): GatewayDaemonRuntime {
|
): GatewayDaemonRuntime {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import { note as clackNote } from "@clack/prompts";
|
|
||||||
|
|
||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
import {
|
import {
|
||||||
CONFIG_PATH_CLAWDBOT,
|
CONFIG_PATH_CLAWDBOT,
|
||||||
@@ -12,12 +10,9 @@ import {
|
|||||||
writeConfigFile,
|
writeConfigFile,
|
||||||
} from "../config/config.js";
|
} from "../config/config.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
import { note } from "../terminal/note.js";
|
||||||
import { resolveUserPath } from "../utils.js";
|
import { resolveUserPath } from "../utils.js";
|
||||||
|
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
|
|
||||||
function resolveLegacyConfigPath(env: NodeJS.ProcessEnv): string {
|
function resolveLegacyConfigPath(env: NodeJS.ProcessEnv): string {
|
||||||
const override = env.CLAWDIS_CONFIG_PATH?.trim();
|
const override = env.CLAWDIS_CONFIG_PATH?.trim();
|
||||||
if (override) return override;
|
if (override) return override;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import { note as clackNote } from "@clack/prompts";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_SANDBOX_BROWSER_IMAGE,
|
DEFAULT_SANDBOX_BROWSER_IMAGE,
|
||||||
DEFAULT_SANDBOX_COMMON_IMAGE,
|
DEFAULT_SANDBOX_COMMON_IMAGE,
|
||||||
@@ -12,13 +10,10 @@ import {
|
|||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
import { runCommandWithTimeout, runExec } from "../process/exec.js";
|
import { runCommandWithTimeout, runExec } from "../process/exec.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
import { note } from "../terminal/note.js";
|
||||||
import { replaceModernName } from "./doctor-legacy-config.js";
|
import { replaceModernName } from "./doctor-legacy-config.js";
|
||||||
import type { DoctorPrompter } from "./doctor-prompter.js";
|
import type { DoctorPrompter } from "./doctor-prompter.js";
|
||||||
|
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
|
|
||||||
type SandboxScriptInfo = {
|
type SandboxScriptInfo = {
|
||||||
scriptPath: string;
|
scriptPath: string;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import { note as clackNote } from "@clack/prompts";
|
|
||||||
|
|
||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
import { readProviderAllowFromStore } from "../pairing/pairing-store.js";
|
import { readProviderAllowFromStore } from "../pairing/pairing-store.js";
|
||||||
import { readTelegramAllowFromStore } from "../telegram/pairing-store.js";
|
import { readTelegramAllowFromStore } from "../telegram/pairing-store.js";
|
||||||
import { resolveTelegramToken } from "../telegram/token.js";
|
import { resolveTelegramToken } from "../telegram/token.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
import { note } from "../terminal/note.js";
|
||||||
import { normalizeE164 } from "../utils.js";
|
import { normalizeE164 } from "../utils.js";
|
||||||
|
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
|
|
||||||
export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
||||||
const warnings: string[] = [];
|
const warnings: string[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import fs from "node:fs";
|
|||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import { note as clackNote } from "@clack/prompts";
|
|
||||||
|
|
||||||
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
|
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
import { resolveOAuthDir, resolveStateDir } from "../config/paths.js";
|
import { resolveOAuthDir, resolveStateDir } from "../config/paths.js";
|
||||||
@@ -14,10 +12,7 @@ import {
|
|||||||
resolveSessionTranscriptsDirForAgent,
|
resolveSessionTranscriptsDirForAgent,
|
||||||
resolveStorePath,
|
resolveStorePath,
|
||||||
} from "../config/sessions.js";
|
} from "../config/sessions.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
import { note } from "../terminal/note.js";
|
||||||
|
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
|
|
||||||
type DoctorPrompterLike = {
|
type DoctorPrompterLike = {
|
||||||
confirmSkipInNonInteractive: (params: {
|
confirmSkipInNonInteractive: (params: {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import os from "node:os";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import {
|
import {
|
||||||
intro as clackIntro,
|
intro as clackIntro,
|
||||||
note as clackNote,
|
|
||||||
outro as clackOutro,
|
outro as clackOutro,
|
||||||
} from "@clack/prompts";
|
} from "@clack/prompts";
|
||||||
import {
|
import {
|
||||||
@@ -41,6 +40,7 @@ import { runCommandWithTimeout } from "../process/exec.js";
|
|||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime } from "../runtime.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
||||||
|
import { note } from "../terminal/note.js";
|
||||||
import { sleep } from "../utils.js";
|
import { sleep } from "../utils.js";
|
||||||
import {
|
import {
|
||||||
DEFAULT_GATEWAY_DAEMON_RUNTIME,
|
DEFAULT_GATEWAY_DAEMON_RUNTIME,
|
||||||
@@ -97,8 +97,6 @@ const intro = (message: string) =>
|
|||||||
clackIntro(stylePromptTitle(message) ?? message);
|
clackIntro(stylePromptTitle(message) ?? message);
|
||||||
const outro = (message: string) =>
|
const outro = (message: string) =>
|
||||||
clackOutro(stylePromptTitle(message) ?? message);
|
clackOutro(stylePromptTitle(message) ?? message);
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
|
|
||||||
function resolveMode(cfg: ClawdbotConfig): "local" | "remote" {
|
function resolveMode(cfg: ClawdbotConfig): "local" | "remote" {
|
||||||
return cfg.gateway?.mode === "remote" ? "remote" : "local";
|
return cfg.gateway?.mode === "remote" ? "remote" : "local";
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import { note as clackNote } from "@clack/prompts";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
enableSystemdUserLinger,
|
enableSystemdUserLinger,
|
||||||
isSystemdUserServiceAvailable,
|
isSystemdUserServiceAvailable,
|
||||||
readSystemdUserLingerStatus,
|
readSystemdUserLingerStatus,
|
||||||
} from "../daemon/systemd.js";
|
} from "../daemon/systemd.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
import { note } from "../terminal/note.js";
|
||||||
|
|
||||||
const note = (message: string, title?: string) =>
|
|
||||||
clackNote(message, stylePromptTitle(title));
|
|
||||||
|
|
||||||
export type LingerPrompter = {
|
export type LingerPrompter = {
|
||||||
confirm?: (params: {
|
confirm?: (params: {
|
||||||
|
|||||||
94
src/terminal/note.ts
Normal file
94
src/terminal/note.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import { note as clackNote } from "@clack/prompts";
|
||||||
|
import { stylePromptTitle } from "./prompt-style.js";
|
||||||
|
|
||||||
|
const ANSI_ESCAPE = /\u001b\[[0-9;]*m/g;
|
||||||
|
|
||||||
|
function visibleLength(value: string): number {
|
||||||
|
return Array.from(value.replace(ANSI_ESCAPE, "")).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitLongWord(word: string, maxLen: number): string[] {
|
||||||
|
if (maxLen <= 0) return [word];
|
||||||
|
const chars = Array.from(word);
|
||||||
|
const parts: string[] = [];
|
||||||
|
for (let i = 0; i < chars.length; i += maxLen) {
|
||||||
|
parts.push(chars.slice(i, i + maxLen).join(""));
|
||||||
|
}
|
||||||
|
return parts.length > 0 ? parts : [word];
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapLine(line: string, maxWidth: number): string[] {
|
||||||
|
if (line.trim().length === 0) return [line];
|
||||||
|
const match = line.match(/^(\s*)([-*\u2022]\s+)?(.*)$/);
|
||||||
|
const indent = match?.[1] ?? "";
|
||||||
|
const bullet = match?.[2] ?? "";
|
||||||
|
const content = match?.[3] ?? "";
|
||||||
|
const firstPrefix = `${indent}${bullet}`;
|
||||||
|
const nextPrefix = `${indent}${bullet ? " ".repeat(bullet.length) : ""}`;
|
||||||
|
const firstWidth = Math.max(10, maxWidth - visibleLength(firstPrefix));
|
||||||
|
const nextWidth = Math.max(10, maxWidth - visibleLength(nextPrefix));
|
||||||
|
|
||||||
|
const words = content.split(/\s+/).filter(Boolean);
|
||||||
|
const lines: string[] = [];
|
||||||
|
let current = "";
|
||||||
|
let prefix = firstPrefix;
|
||||||
|
let available = firstWidth;
|
||||||
|
|
||||||
|
for (const word of words) {
|
||||||
|
if (!current) {
|
||||||
|
if (visibleLength(word) > available) {
|
||||||
|
const parts = splitLongWord(word, available);
|
||||||
|
const first = parts.shift() ?? "";
|
||||||
|
lines.push(prefix + first);
|
||||||
|
prefix = nextPrefix;
|
||||||
|
available = nextWidth;
|
||||||
|
for (const part of parts) lines.push(prefix + part);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current = word;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const candidate = `${current} ${word}`;
|
||||||
|
if (visibleLength(candidate) <= available) {
|
||||||
|
current = candidate;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push(prefix + current);
|
||||||
|
prefix = nextPrefix;
|
||||||
|
available = nextWidth;
|
||||||
|
|
||||||
|
if (visibleLength(word) > available) {
|
||||||
|
const parts = splitLongWord(word, available);
|
||||||
|
const first = parts.shift() ?? "";
|
||||||
|
lines.push(prefix + first);
|
||||||
|
for (const part of parts) lines.push(prefix + part);
|
||||||
|
current = "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current = word;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current || words.length === 0) {
|
||||||
|
lines.push(prefix + current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function wrapNoteMessage(
|
||||||
|
message: string,
|
||||||
|
options: { maxWidth?: number; columns?: number } = {},
|
||||||
|
): string {
|
||||||
|
const columns = options.columns ?? process.stdout.columns ?? 80;
|
||||||
|
const maxWidth = options.maxWidth ?? Math.max(40, Math.min(88, columns - 10));
|
||||||
|
return message
|
||||||
|
.split("\n")
|
||||||
|
.flatMap((line) => wrapLine(line, maxWidth))
|
||||||
|
.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function note(message: string, title?: string) {
|
||||||
|
clackNote(wrapNoteMessage(message), stylePromptTitle(title));
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
intro,
|
intro,
|
||||||
isCancel,
|
isCancel,
|
||||||
multiselect,
|
multiselect,
|
||||||
note,
|
|
||||||
type Option,
|
type Option,
|
||||||
outro,
|
outro,
|
||||||
select,
|
select,
|
||||||
@@ -18,6 +17,7 @@ import {
|
|||||||
stylePromptTitle,
|
stylePromptTitle,
|
||||||
} from "../terminal/prompt-style.js";
|
} from "../terminal/prompt-style.js";
|
||||||
import { theme } from "../terminal/theme.js";
|
import { theme } from "../terminal/theme.js";
|
||||||
|
import { note as emitNote } from "../terminal/note.js";
|
||||||
import type { WizardProgress, WizardPrompter } from "./prompts.js";
|
import type { WizardProgress, WizardPrompter } from "./prompts.js";
|
||||||
import { WizardCancelledError } from "./prompts.js";
|
import { WizardCancelledError } from "./prompts.js";
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ export function createClackPrompter(): WizardPrompter {
|
|||||||
outro(stylePromptTitle(message) ?? message);
|
outro(stylePromptTitle(message) ?? message);
|
||||||
},
|
},
|
||||||
note: async (message, title) => {
|
note: async (message, title) => {
|
||||||
note(message, stylePromptTitle(title));
|
emitNote(message, title);
|
||||||
},
|
},
|
||||||
select: async (params) =>
|
select: async (params) =>
|
||||||
guardCancel(
|
guardCancel(
|
||||||
|
|||||||
Reference in New Issue
Block a user