refactor: normalize cli command hints

This commit is contained in:
Peter Steinberger
2026-01-20 07:42:21 +00:00
parent 11b9b6dba5
commit 6d5195c890
106 changed files with 521 additions and 220 deletions

View File

@@ -7,6 +7,7 @@ import { callGateway, randomIdempotencyKey } from "../gateway/call.js";
import { listAgentIds } from "../agents/agent-scope.js";
import { normalizeAgentId } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { formatCliCommand } from "../cli/command-format.js";
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
@@ -92,7 +93,7 @@ export async function agentViaGatewayCommand(opts: AgentCliOpts, runtime: Runtim
const knownAgents = listAgentIds(cfg);
if (!knownAgents.includes(agentId)) {
throw new Error(
`Unknown agent id "${agentIdRaw}". Use "clawdbot agents list" to see configured agents.`,
`Unknown agent id "${agentIdRaw}". Use "${formatCliCommand("clawdbot agents list")}" to see configured agents.`,
);
}
}

View File

@@ -47,6 +47,7 @@ import {
} from "../infra/agent-events.js";
import { getRemoteSkillEligibility } from "../infra/skills-remote.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import { formatCliCommand } from "../cli/command-format.js";
import { applyVerboseOverride } from "../sessions/level-overrides.js";
import { resolveSendPolicy } from "../sessions/send-policy.js";
import { resolveMessageChannel } from "../utils/message-channel.js";
@@ -75,7 +76,7 @@ export async function agentCommand(
const knownAgents = listAgentIds(cfg);
if (!knownAgents.includes(agentIdOverride)) {
throw new Error(
`Unknown agent id "${agentIdOverrideRaw}". Use "clawdbot agents list" to see configured agents.`,
`Unknown agent id "${agentIdOverrideRaw}". Use "${formatCliCommand("clawdbot agents list")}" to see configured agents.`,
);
}
}

View File

@@ -1,3 +1,4 @@
import { formatCliCommand } from "../cli/command-format.js";
import type { ClawdbotConfig } from "../config/config.js";
import { readConfigFileSnapshot } from "../config/config.js";
import type { RuntimeEnv } from "../runtime.js";
@@ -14,7 +15,7 @@ export async function requireValidConfig(runtime: RuntimeEnv): Promise<ClawdbotC
? snapshot.issues.map((issue) => `- ${issue.path}: ${issue.message}`).join("\n")
: "Unknown validation issue.";
runtime.error(`Config invalid:\n${issues}`);
runtime.error("Fix the config or run clawdbot doctor.");
runtime.error(`Fix the config or run ${formatCliCommand("clawdbot doctor")}.`);
runtime.exit(1);
return null;
}

View File

@@ -2,6 +2,7 @@ import type { AgentBinding } from "../config/types.js";
import { normalizeAgentId } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { formatCliCommand } from "../cli/command-format.js";
import { describeBinding } from "./agents.bindings.js";
import { requireValidConfig } from "./agents.command-shared.js";
import type { AgentSummary } from "./agents.config.js";
@@ -116,7 +117,7 @@ export async function agentsListCommand(
const lines = ["Agents:", ...summaries.map(formatSummary)];
lines.push("Routing rules map channel/account/peer to an agent. Use --bindings for full rules.");
lines.push(
"Channel status reflects local config/creds. For live health: clawdbot channels status --probe.",
`Channel status reflects local config/creds. For live health: ${formatCliCommand("clawdbot channels status --probe")}.`,
);
runtime.log(lines.join("\n"));
}

View File

@@ -1,4 +1,5 @@
import { type ChannelId, getChannelPlugin } from "../../channels/plugins/index.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { type ClawdbotConfig, readConfigFileSnapshot } from "../../config/config.js";
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
import { defaultRuntime, type RuntimeEnv } from "../../runtime.js";
@@ -15,7 +16,7 @@ export async function requireValidConfig(
? snapshot.issues.map((issue) => `- ${issue.path}: ${issue.message}`).join("\n")
: "Unknown validation issue.";
runtime.error(`Config invalid:\n${issues}`);
runtime.error("Fix the config or run clawdbot doctor.");
runtime.error(`Fix the config or run ${formatCliCommand("clawdbot doctor")}.`);
runtime.exit(1);
return null;
}

View File

@@ -8,6 +8,7 @@ import { formatAge } from "../../infra/channel-summary.js";
import { collectChannelStatusIssues } from "../../infra/channels-status-issues.js";
import { defaultRuntime, type RuntimeEnv } from "../../runtime.js";
import { formatDocsLink } from "../../terminal/links.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { theme } from "../../terminal/theme.js";
import { type ChatChannel, formatChannelAccountLabel, requireValidConfig } from "./shared.js";
@@ -142,7 +143,7 @@ export function formatGatewayChannelsStatusLines(payload: Record<string, unknown
`- ${issue.channel} ${issue.accountId}: ${issue.message}${issue.fix ? ` (${issue.fix})` : ""}`,
);
}
lines.push(`- Run: clawdbot doctor`);
lines.push(`- Run: ${formatCliCommand("clawdbot doctor")}`);
lines.push("");
}
lines.push(

View File

@@ -1,4 +1,5 @@
import { getChannelPlugin, listChannelPlugins } from "../channels/plugins/index.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { ClawdbotConfig } from "../config/config.js";
import { CONFIG_PATH_CLAWDBOT } from "../config/config.js";
import type { RuntimeEnv } from "../runtime.js";
@@ -23,7 +24,7 @@ export async function removeChannelConfigWizard(
note(
[
"No channel config found in clawdbot.json.",
"Tip: `clawdbot channels status` shows what is configured and enabled.",
`Tip: \`${formatCliCommand("clawdbot channels status")}\` shows what is configured and enabled.`,
].join("\n"),
"Remove channel",
);

View File

@@ -1,3 +1,4 @@
import { formatCliCommand } from "../cli/command-format.js";
import type { ClawdbotConfig } from "../config/config.js";
import {
CONFIG_PATH_CLAWDBOT,
@@ -198,7 +199,9 @@ export async function runConfigureWizard(
);
}
if (!snapshot.valid) {
outro("Config invalid. Run `clawdbot doctor` to repair it, then re-run configure.");
outro(
`Config invalid. Run \`${formatCliCommand("clawdbot doctor")}\` to repair it, then re-run configure.`,
);
runtime.exit(1);
return;
}

View File

@@ -6,6 +6,7 @@ import {
resolveSystemNodeInfo,
} from "../daemon/runtime-paths.js";
import { buildServiceEnvironment } from "../daemon/service-env.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { GatewayDaemonRuntime } from "./daemon-runtime.js";
type WarnFn = (message: string, title?: string) => void;
@@ -65,5 +66,5 @@ export async function buildGatewayInstallPlan(params: {
export function gatewayInstallErrorHint(platform = process.platform): string {
return platform === "win32"
? "Tip: rerun from an elevated PowerShell (Start → type PowerShell → right-click → Run as administrator) or skip daemon install."
: "Tip: rerun `clawdbot daemon install` after fixing the error.";
: `Tip: rerun \`${formatCliCommand("clawdbot daemon install")}\` after fixing the error.`;
}

View File

@@ -3,6 +3,7 @@ import { runCommandWithTimeout } from "../process/exec.js";
import type { RuntimeEnv } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { isRich, theme } from "../terminal/theme.js";
import { formatCliCommand } from "../cli/command-format.js";
const SEARCH_TOOL = "https://docs.clawd.bot/mcp.SearchClawdbot";
const SEARCH_TIMEOUT_MS = 30_000;
@@ -150,10 +151,10 @@ export async function docsSearchCommand(queryParts: string[], runtime: RuntimeEn
const docs = formatDocsLink("/", "docs.clawd.bot");
if (isRich()) {
runtime.log(`${theme.muted("Docs:")} ${docs}`);
runtime.log(`${theme.muted("Search:")} clawdbot docs "your query"`);
runtime.log(`${theme.muted("Search:")} ${formatCliCommand('clawdbot docs "your query"')}`);
} else {
runtime.log("Docs: https://docs.clawd.bot/");
runtime.log('Search: clawdbot docs "your query"');
runtime.log(`Search: ${formatCliCommand('clawdbot docs "your query"')}`);
}
return;
}

View File

@@ -13,6 +13,7 @@ import {
} from "../agents/auth-profiles.js";
import type { ClawdbotConfig } from "../config/config.js";
import { note } from "../terminal/note.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { DoctorPrompter } from "./doctor-prompter.js";
export async function maybeRepairAnthropicOAuthProfileId(
@@ -49,9 +50,9 @@ function formatAuthIssueHint(issue: AuthIssue): string | null {
return "Run `claude setup-token` on the gateway host.";
}
if (issue.provider === "openai-codex" && issue.profileId === CODEX_CLI_PROFILE_ID) {
return "Run `codex login` (or `clawdbot configure` → OpenAI Codex OAuth).";
return `Run \`codex login\` (or \`${formatCliCommand("clawdbot configure")}\` → OpenAI Codex OAuth).`;
}
return "Re-auth via `clawdbot configure` or `clawdbot onboard`.";
return `Re-auth via \`${formatCliCommand("clawdbot configure")}\` or \`${formatCliCommand("clawdbot onboard")}\`.`;
}
function formatAuthIssueLine(issue: AuthIssue): string {

View File

@@ -8,6 +8,7 @@ import {
readConfigFileSnapshot,
} from "../config/config.js";
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
import { formatCliCommand } from "../cli/command-format.js";
import { note } from "../terminal/note.js";
import { normalizeLegacyConfigValues } from "./doctor-legacy-config.js";
import type { DoctorOptions } from "./doctor-prompter.js";
@@ -139,7 +140,10 @@ export async function loadAndMaybeMigrateDoctorConfig(params: {
if (changes.length > 0) note(changes.join("\n"), "Doctor changes");
if (migrated) cfg = migrated;
} else {
note('Run "clawdbot doctor --fix" to apply legacy migrations.', "Doctor");
note(
`Run "${formatCliCommand("clawdbot doctor --fix")}" to apply legacy migrations.`,
"Doctor",
);
}
}
@@ -149,7 +153,7 @@ export async function loadAndMaybeMigrateDoctorConfig(params: {
if (shouldRepair) {
cfg = normalized.config;
} else {
note('Run "clawdbot doctor --fix" to apply these changes.', "Doctor");
note(`Run "${formatCliCommand("clawdbot doctor --fix")}" to apply these changes.`, "Doctor");
}
}
@@ -159,7 +163,7 @@ export async function loadAndMaybeMigrateDoctorConfig(params: {
if (shouldRepair) {
cfg = autoEnable.config;
} else {
note('Run "clawdbot doctor --fix" to apply these changes.', "Doctor");
note(`Run "${formatCliCommand("clawdbot doctor --fix")}" to apply these changes.`, "Doctor");
}
}

View File

@@ -8,6 +8,7 @@ import {
isSystemdUnavailableDetail,
renderSystemdUnavailableHints,
} from "../daemon/systemd-hints.js";
import { formatCliCommand } from "../cli/command-format.js";
import { isWSLEnv } from "../infra/wsl.js";
import type { GatewayServiceRuntime } from "../daemon/service-runtime.js";
import { getResolvedLoggerSettings } from "../logging.js";
@@ -69,10 +70,10 @@ export function buildGatewayRuntimeHints(
hints.push(
`LaunchAgent label cached but plist missing. Clear with: launchctl bootout gui/$UID/${label}`,
);
hints.push("Then reinstall: clawdbot daemon install");
hints.push(`Then reinstall: ${formatCliCommand("clawdbot daemon install", env)}`);
}
if (runtime.missingUnit) {
hints.push("Service not installed. Run: clawdbot daemon install");
hints.push(`Service not installed. Run: ${formatCliCommand("clawdbot daemon install", env)}`);
if (fileLog) hints.push(`File logs: ${fileLog}`);
return hints;
}

View File

@@ -17,6 +17,7 @@ import { renderSystemdUnavailableHints } from "../daemon/systemd-hints.js";
import { formatPortDiagnostics, inspectPortUsage } from "../infra/ports.js";
import { isWSL } from "../infra/wsl.js";
import type { RuntimeEnv } from "../runtime.js";
import { formatCliCommand } from "../cli/command-format.js";
import { note } from "../terminal/note.js";
import { sleep } from "../utils.js";
import {
@@ -201,7 +202,7 @@ export async function maybeRepairGatewayDaemon(params: {
if (process.platform === "darwin") {
const label = resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE);
note(
`LaunchAgent loaded; stopping requires "clawdbot daemon stop" or launchctl bootout gui/$UID/${label}.`,
`LaunchAgent loaded; stopping requires "${formatCliCommand("clawdbot daemon stop")}" or launchctl bootout gui/$UID/${label}.`,
"Gateway",
);
}

View File

@@ -4,10 +4,11 @@ import type { ChannelId } from "../channels/plugins/types.js";
import type { ClawdbotConfig } from "../config/config.js";
import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
import { note } from "../terminal/note.js";
import { formatCliCommand } from "../cli/command-format.js";
export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
const warnings: string[] = [];
const auditHint = `- Run: clawdbot security audit --deep`;
const auditHint = `- Run: ${formatCliCommand("clawdbot security audit --deep")}`;
const warnDmPolicy = async (params: {
label: string;

View File

@@ -3,6 +3,7 @@ import { isTruthyEnvValue } from "../infra/env.js";
import { runCommandWithTimeout } from "../process/exec.js";
import type { RuntimeEnv } from "../runtime.js";
import { note } from "../terminal/note.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { DoctorOptions } from "./doctor-prompter.js";
async function detectClawdbotGitCheckout(root: string): Promise<"git" | "not-git" | "unknown"> {
@@ -71,7 +72,7 @@ export async function maybeOfferUpdateBeforeDoctor(params: {
note(
[
"This install is not a git checkout.",
"Run `clawdbot update` to update via your package manager (npm/pnpm), then rerun doctor.",
`Run \`${formatCliCommand("clawdbot update")}\` to update via your package manager (npm/pnpm), then rerun doctor.`,
].join("\n"),
"Update",
);

View File

@@ -9,6 +9,7 @@ import {
resolveConfiguredModelRef,
resolveHooksGmailModel,
} from "../agents/model-selection.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { ClawdbotConfig } from "../config/config.js";
import { CONFIG_PATH_CLAWDBOT, readConfigFileSnapshot, writeConfigFile } from "../config/config.js";
import { resolveGatewayService } from "../daemon/service.js";
@@ -258,7 +259,7 @@ export async function doctorCommand(
runtime.log(`Backup: ${backupPath}`);
}
} else {
runtime.log('Run "clawdbot doctor --fix" to apply changes.');
runtime.log(`Run "${formatCliCommand("clawdbot doctor --fix")}" to apply changes.`);
}
if (options.workspaceSuggestions !== false) {

View File

@@ -15,6 +15,7 @@ import {
} from "../../agents/agent-scope.js";
import { resolveDefaultAgentWorkspaceDir } from "../../agents/workspace.js";
import { parseDurationMs } from "../../cli/parse-duration.js";
import { formatCliCommand } from "../../cli/command-format.js";
import {
CONFIG_PATH_CLAWDBOT,
readConfigFileSnapshot,
@@ -340,7 +341,9 @@ export async function modelsAuthLoginCommand(opts: LoginOptions, runtime: Runtim
const providers = resolvePluginProviders({ config, workspaceDir });
if (providers.length === 0) {
throw new Error("No provider plugins found. Install one via `clawdbot plugins install`.");
throw new Error(
`No provider plugins found. Install one via \`${formatCliCommand("clawdbot plugins install")}\`.`,
);
}
const prompter = createClackPrompter();

View File

@@ -22,6 +22,7 @@ import {
} from "../../infra/provider-usage.js";
import type { RuntimeEnv } from "../../runtime.js";
import { colorize, theme } from "../../terminal/theme.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { shortenHomePath } from "../../utils.js";
import { resolveProviderAuthOverview } from "./list.auth-overview.js";
import { isRich } from "./list.format.js";
@@ -395,8 +396,8 @@ export async function modelsStatusCommand(
for (const provider of missingProvidersInUse) {
const hint =
provider === "anthropic"
? "Run `claude setup-token` or `clawdbot configure`."
: "Run `clawdbot configure` or set an API key env var.";
? `Run \`claude setup-token\` or \`${formatCliCommand("clawdbot configure")}\`.`
: `Run \`${formatCliCommand("clawdbot configure")}\` or set an API key env var.`;
runtime.log(`- ${theme.heading(provider)} ${hint}`);
}
}

View File

@@ -14,6 +14,7 @@ import { resolveChannelDefaultAccountId } from "../channels/plugins/helpers.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { formatCliCommand } from "../cli/command-format.js";
import { enablePluginInConfig } from "../plugins/enable.js";
import type { WizardPrompter, WizardSelectOption } from "../wizard/prompts.js";
import type { ChannelChoice } from "./onboard-types.js";
@@ -186,7 +187,7 @@ async function noteChannelPrimer(
await prompter.note(
[
"DM security: default is pairing; unknown DMs get a pairing code.",
"Approve with: clawdbot pairing approve <channel> <code>",
`Approve with: ${formatCliCommand("clawdbot pairing approve <channel> <code>")}`,
'Public DMs require dmPolicy="open" + allowFrom=["*"].',
'Multi-user DMs: set session.dmScope="per-channel-peer" to isolate sessions.',
`Docs: ${formatDocsLink("/start/pairing", "start/pairing")}`,
@@ -233,7 +234,7 @@ async function maybeConfigureDmPolicies(params: {
await prompter.note(
[
"Default: pairing (unknown DMs get a pairing code).",
`Approve: clawdbot pairing approve ${policy.channel} <code>`,
`Approve: ${formatCliCommand(`clawdbot pairing approve ${policy.channel} <code>`)}`,
`Allowlist DMs: ${policy.policyKey}="allowlist" + ${policy.allowFromKey} entries.`,
`Public DMs: ${policy.policyKey}="open" + ${policy.allowFromKey} includes "*".`,
'Multi-user DMs: set session.dmScope="per-channel-peer" to isolate sessions.',
@@ -581,7 +582,7 @@ export async function setupChannels(
{
value: "__skip__",
label: "Skip for now",
hint: "You can add channels later via `clawdbot channels add`",
hint: `You can add channels later via \`${formatCliCommand("clawdbot channels add")}\``,
},
],
initialValue: quickstartDefault,

View File

@@ -3,6 +3,7 @@ import type { RuntimeEnv } from "../runtime.js";
import type { WizardPrompter } from "../wizard/prompts.js";
import { buildWorkspaceHookStatus } from "../hooks/hooks-status.js";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { formatCliCommand } from "../cli/command-format.js";
export async function setupInternalHooks(
cfg: ClawdbotConfig,
@@ -73,9 +74,9 @@ export async function setupInternalHooks(
`Enabled ${selected.length} hook${selected.length > 1 ? "s" : ""}: ${selected.join(", ")}`,
"",
"You can manage hooks later with:",
" clawdbot hooks list",
" clawdbot hooks enable <name>",
" clawdbot hooks disable <name>",
` ${formatCliCommand("clawdbot hooks list")}`,
` ${formatCliCommand("clawdbot hooks enable <name>")}`,
` ${formatCliCommand("clawdbot hooks disable <name>")}`,
].join("\n"),
"Hooks Configured",
);

View File

@@ -1,3 +1,4 @@
import { formatCliCommand } from "../cli/command-format.js";
import type { ClawdbotConfig } from "../config/config.js";
import { readConfigFileSnapshot } from "../config/config.js";
import type { RuntimeEnv } from "../runtime.js";
@@ -12,7 +13,9 @@ export async function runNonInteractiveOnboarding(
) {
const snapshot = await readConfigFileSnapshot();
if (snapshot.exists && !snapshot.valid) {
runtime.error("Config invalid. Run `clawdbot doctor` to repair it, then re-run onboarding.");
runtime.error(
`Config invalid. Run \`${formatCliCommand("clawdbot doctor")}\` to repair it, then re-run onboarding.`,
);
runtime.exit(1);
return;
}

View File

@@ -1,6 +1,7 @@
import type { ClawdbotConfig } from "../../config/config.js";
import { CONFIG_PATH_CLAWDBOT, resolveGatewayPort, writeConfigFile } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { DEFAULT_GATEWAY_DAEMON_RUNTIME } from "../daemon-runtime.js";
import { healthCommand } from "../health.js";
import {
@@ -123,7 +124,7 @@ export async function runNonInteractiveOnboardingLocal(params: {
if (!opts.json) {
runtime.log(
"Tip: run `clawdbot configure --section web` to store your Brave API key for web_search. Docs: https://docs.clawd.bot/tools/web",
`Tip: run \`${formatCliCommand("clawdbot configure --section web")}\` to store your Brave API key for web_search. Docs: https://docs.clawd.bot/tools/web`,
);
}
}

View File

@@ -1,6 +1,7 @@
import type { ClawdbotConfig } from "../../config/config.js";
import { CONFIG_PATH_CLAWDBOT, writeConfigFile } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { applyWizardMetadata } from "../onboard-helpers.js";
import type { OnboardOptions } from "../onboard-types.js";
@@ -45,7 +46,7 @@ export async function runNonInteractiveOnboardingRemote(params: {
runtime.log(`Remote gateway: ${remoteUrl}`);
runtime.log(`Auth: ${payload.auth}`);
runtime.log(
"Tip: run `clawdbot configure --section web` to store your Brave API key for web_search. Docs: https://docs.clawd.bot/tools/web",
`Tip: run \`${formatCliCommand("clawdbot configure --section web")}\` to store your Brave API key for web_search. Docs: https://docs.clawd.bot/tools/web`,
);
}
}

View File

@@ -1,5 +1,6 @@
import { installSkill } from "../agents/skills-install.js";
import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { ClawdbotConfig } from "../config/config.js";
import type { RuntimeEnv } from "../runtime.js";
import type { WizardPrompter } from "../wizard/prompts.js";
@@ -152,7 +153,9 @@ export async function setupSkills(
spin.stop(`Install failed: ${name}${code}${detail ? `${detail}` : ""}`);
if (result.stderr) runtime.log(result.stderr.trim());
else if (result.stdout) runtime.log(result.stdout.trim());
runtime.log("Tip: run `clawdbot doctor` to review skills + requirements.");
runtime.log(
`Tip: run \`${formatCliCommand("clawdbot doctor")}\` to review skills + requirements.`,
);
runtime.log("Docs: https://docs.clawd.bot/skills");
}
}

View File

@@ -6,6 +6,7 @@ import { resolveUserPath } from "../utils.js";
import { DEFAULT_WORKSPACE, handleReset } from "./onboard-helpers.js";
import { runInteractiveOnboarding } from "./onboard-interactive.js";
import { runNonInteractiveOnboarding } from "./onboard-non-interactive.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { OnboardOptions } from "./onboard-types.js";
export async function onboardCommand(opts: OnboardOptions, runtime: RuntimeEnv = defaultRuntime) {
@@ -18,7 +19,7 @@ export async function onboardCommand(opts: OnboardOptions, runtime: RuntimeEnv =
[
"Non-interactive onboarding requires explicit risk acknowledgement.",
"Read: https://docs.clawd.bot/security",
"Re-run with: clawdbot onboard --non-interactive --accept-risk ...",
`Re-run with: ${formatCliCommand("clawdbot onboard --non-interactive --accept-risk ...")}`,
].join("\n"),
);
runtime.exit(1);

View File

@@ -10,6 +10,7 @@ import {
import { resolveGatewayService } from "../daemon/service.js";
import type { RuntimeEnv } from "../runtime.js";
import { stylePromptHint, stylePromptMessage, stylePromptTitle } from "../terminal/prompt-style.js";
import { formatCliCommand } from "../cli/command-format.js";
import {
collectWorkspaceDirs,
isPathWithin,
@@ -143,7 +144,7 @@ export async function resetCommand(runtime: RuntimeEnv, opts: ResetOptions) {
for (const dir of sessionDirs) {
await removePath(dir, runtime, { dryRun, label: dir });
}
runtime.log("Next: clawdbot onboard --install-daemon");
runtime.log(`Next: ${formatCliCommand("clawdbot onboard --install-daemon")}`);
return;
}
@@ -158,7 +159,7 @@ export async function resetCommand(runtime: RuntimeEnv, opts: ResetOptions) {
for (const workspace of workspaceDirs) {
await removePath(workspace, runtime, { dryRun, label: workspace });
}
runtime.log("Next: clawdbot onboard --install-daemon");
runtime.log(`Next: ${formatCliCommand("clawdbot onboard --install-daemon")}`);
return;
}
}

View File

@@ -3,6 +3,7 @@
*/
import type { SandboxBrowserInfo, SandboxContainerInfo } from "../agents/sandbox.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { RuntimeEnv } from "../runtime.js";
import {
formatAge,
@@ -88,7 +89,9 @@ export function displaySummary(
if (mismatchCount > 0) {
runtime.log(`\n⚠ ${mismatchCount} container(s) with image mismatch detected.`);
runtime.log(` Run 'clawdbot sandbox recreate --all' to update all containers.`);
runtime.log(
` Run '${formatCliCommand("clawdbot sandbox recreate --all")}' to update all containers.`,
);
}
}

View File

@@ -1,5 +1,6 @@
import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
import { withProgress } from "../cli/progress.js";
import { formatCliCommand } from "../cli/command-format.js";
import { loadConfig, readConfigFileSnapshot, resolveGatewayPort } from "../config/config.js";
import { readLastGatewayErrorLine } from "../daemon/diagnostics.js";
import type { GatewayService } from "../daemon/service.js";
@@ -337,7 +338,7 @@ export async function statusAllCommand(
Item: "Gateway",
Value: `${gatewayMode}${remoteUrlMissing ? " (remote.url missing)" : ""} · ${gatewayTarget} (${connection.urlSource}) · ${gatewayStatus}${gatewayAuth}`,
},
{ Item: "Security", Value: "Run: clawdbot security audit --deep" },
{ Item: "Security", Value: `Run: ${formatCliCommand("clawdbot security audit --deep")}` },
gatewaySelfLine
? { Item: "Gateway self", Value: gatewaySelfLine }
: { Item: "Gateway self", Value: "unknown" },

View File

@@ -7,6 +7,7 @@ import type { RuntimeEnv } from "../runtime.js";
import { runSecurityAudit } from "../security/audit.js";
import { renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { formatCliCommand } from "../cli/command-format.js";
import {
resolveMemoryCacheSummary,
resolveMemoryFtsState,
@@ -374,8 +375,8 @@ export async function statusCommand(
runtime.log(theme.muted(`… +${sorted.length - shown.length} more`));
}
}
runtime.log(theme.muted("Full report: clawdbot security audit"));
runtime.log(theme.muted("Deep probe: clawdbot security audit --deep"));
runtime.log(theme.muted(`Full report: ${formatCliCommand("clawdbot security audit")}`));
runtime.log(theme.muted(`Deep probe: ${formatCliCommand("clawdbot security audit --deep")}`));
runtime.log("");
runtime.log(theme.heading("Channels"));
@@ -531,11 +532,11 @@ export async function statusCommand(
runtime.log("");
}
runtime.log("Next steps:");
runtime.log(" Need to share? clawdbot status --all");
runtime.log(" Need to debug live? clawdbot logs --follow");
runtime.log(` Need to share? ${formatCliCommand("clawdbot status --all")}`);
runtime.log(` Need to debug live? ${formatCliCommand("clawdbot logs --follow")}`);
if (gatewayReachable) {
runtime.log(" Need to test channels? clawdbot status --deep");
runtime.log(` Need to test channels? ${formatCliCommand("clawdbot status --deep")}`);
} else {
runtime.log(" Fix reachability first: clawdbot gateway status");
runtime.log(` Fix reachability first: ${formatCliCommand("clawdbot gateway status")}`);
}
}

View File

@@ -4,6 +4,7 @@ import {
compareSemverStrings,
type UpdateCheckResult,
} from "../infra/update-check.js";
import { formatCliCommand } from "../cli/command-format.js";
import { VERSION } from "../version.js";
export async function getUpdateCheckResult(params: {
@@ -63,7 +64,7 @@ export function formatUpdateAvailableHint(update: UpdateCheckResult): string | n
details.push(`npm ${availability.latestVersion}`);
}
const suffix = details.length > 0 ? ` (${details.join(" · ")})` : "";
return `Update available${suffix}. Run: clawdbot update`;
return `Update available${suffix}. Run: ${formatCliCommand("clawdbot update")}`;
}
export function formatUpdateOneLiner(update: UpdateCheckResult): string {