From a74c19feed6636767ec6de95c0ddfcb734bb8927 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 21 Jan 2026 04:46:15 +0000 Subject: [PATCH] docs: unify cli help examples --- src/cli/browser-cli.ts | 6 +- src/cli/help-format.ts | 21 +++ src/cli/program/register.agent.ts | 39 ++++-- src/cli/program/register.message.ts | 22 +++- .../register.status-health-sessions.ts | 39 +++--- src/cli/sandbox-cli.ts | 123 ++++++++++-------- src/cli/service-cli.ts | 17 +-- src/cli/update-cli.ts | 21 ++- 8 files changed, 177 insertions(+), 111 deletions(-) create mode 100644 src/cli/help-format.ts diff --git a/src/cli/browser-cli.ts b/src/cli/browser-cli.ts index 1193b2f80..b3b456dea 100644 --- a/src/cli/browser-cli.ts +++ b/src/cli/browser-cli.ts @@ -5,6 +5,7 @@ import { defaultRuntime } from "../runtime.js"; import { formatDocsLink } from "../terminal/links.js"; import { theme } from "../terminal/theme.js"; import { formatCliCommand } from "./command-format.js"; +import { formatHelpExamples } from "./help-format.js"; import { registerBrowserActionInputCommands } from "./browser-cli-actions-input.js"; import { registerBrowserActionObserveCommands } from "./browser-cli-actions-observe.js"; import { registerBrowserDebugCommands } from "./browser-cli-debug.js"; @@ -26,7 +27,10 @@ export function registerBrowserCli(program: Command) { .addHelpText( "after", () => - `\nExamples:\n ${[...browserCoreExamples, ...browserActionExamples].join("\n ")}\n\n${theme.muted("Docs:")} ${formatDocsLink( + `\n${theme.heading("Examples:")}\n${formatHelpExamples( + [...browserCoreExamples, ...browserActionExamples].map((cmd) => [cmd, ""]), + true, + )}\n\n${theme.muted("Docs:")} ${formatDocsLink( "/cli/browser", "docs.clawd.bot/cli/browser", )}\n`, diff --git a/src/cli/help-format.ts b/src/cli/help-format.ts new file mode 100644 index 000000000..a57ae8d29 --- /dev/null +++ b/src/cli/help-format.ts @@ -0,0 +1,21 @@ +import { theme } from "../terminal/theme.js"; + +export type HelpExample = [command: string, description: string]; + +export function formatHelpExample(command: string, description: string): string { + return ` ${theme.command(command)}\n ${theme.muted(description)}`; +} + +export function formatHelpExampleLine(command: string, description: string): string { + if (!description) return ` ${theme.command(command)}`; + return ` ${theme.command(command)} ${theme.muted(`# ${description}`)}`; +} + +export function formatHelpExamples(examples: HelpExample[], inline = false): string { + const formatter = inline ? formatHelpExampleLine : formatHelpExample; + return examples.map(([command, description]) => formatter(command, description)).join("\n"); +} + +export function formatHelpExampleGroup(label: string, examples: HelpExample[], inline = false) { + return `${theme.muted(label)}\n${formatHelpExamples(examples, inline)}`; +} diff --git a/src/cli/program/register.agent.ts b/src/cli/program/register.agent.ts index 7cbb63e2f..048a91de0 100644 --- a/src/cli/program/register.agent.ts +++ b/src/cli/program/register.agent.ts @@ -12,6 +12,7 @@ import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; import { hasExplicitOptions } from "../command-options.js"; +import { formatHelpExamples } from "../help-format.js"; import { createDefaultDeps } from "../deps.js"; import { runCommandWithRuntime } from "../cli-utils.js"; import { collectOption } from "./helpers.js"; @@ -48,13 +49,24 @@ export function registerAgentCommands(program: Command, args: { agentChannelOpti "after", () => ` -Examples: - clawdbot agent --to +15555550123 --message "status update" - clawdbot agent --agent ops --message "Summarize logs" - clawdbot agent --session-id 1234 --message "Summarize inbox" --thinking medium - clawdbot agent --to +15555550123 --message "Trace logs" --verbose on --json - clawdbot agent --to +15555550123 --message "Summon reply" --deliver - clawdbot agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports" +${theme.heading("Examples:")} +${formatHelpExamples([ + ['clawdbot agent --to +15555550123 --message "status update"', "Start a new session."], + ['clawdbot agent --agent ops --message "Summarize logs"', "Use a specific agent."], + [ + 'clawdbot agent --session-id 1234 --message "Summarize inbox" --thinking medium', + "Target a session with explicit thinking level.", + ], + [ + 'clawdbot agent --to +15555550123 --message "Trace logs" --verbose on --json', + "Enable verbose logging and JSON output.", + ], + ['clawdbot agent --to +15555550123 --message "Summon reply" --deliver', "Deliver reply."], + [ + 'clawdbot agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports"', + "Send reply to a different channel/target.", + ], +])} ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.clawd.bot/cli/agent")}`, ) @@ -140,10 +152,15 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.clawd.bot/cli/agent "after", () => ` -Examples: - clawdbot agents set-identity --agent main --name "Clawd" --emoji "🦞" - clawdbot agents set-identity --workspace ~/clawd --from-identity - clawdbot agents set-identity --identity-file ~/clawd/IDENTITY.md --agent main +${theme.heading("Examples:")} +${formatHelpExamples([ + ['clawdbot agents set-identity --agent main --name "Clawd" --emoji "🦞"', "Set name + emoji."], + ["clawdbot agents set-identity --workspace ~/clawd --from-identity", "Load from IDENTITY.md."], + [ + "clawdbot agents set-identity --identity-file ~/clawd/IDENTITY.md --agent main", + "Use a specific IDENTITY.md.", + ], +])} `, ) .action(async (opts) => { diff --git a/src/cli/program/register.message.ts b/src/cli/program/register.message.ts index bcff92a98..24af5f37f 100644 --- a/src/cli/program/register.message.ts +++ b/src/cli/program/register.message.ts @@ -1,6 +1,7 @@ import type { Command } from "commander"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; +import { formatHelpExamples } from "../help-format.js"; import type { ProgramContext } from "./context.js"; import { createMessageCliHelpers } from "./message/helpers.js"; import { registerMessageDiscordAdminCommands } from "./message/register.discord-admin.js"; @@ -28,11 +29,22 @@ export function registerMessageCommands(program: Command, ctx: ProgramContext) { "after", () => ` -Examples: - clawdbot message send --target +15555550123 --message "Hi" - clawdbot message send --target +15555550123 --message "Hi" --media photo.jpg - clawdbot message poll --channel discord --target channel:123 --poll-question "Snack?" --poll-option Pizza --poll-option Sushi - clawdbot message react --channel discord --target 123 --message-id 456 --emoji "✅" +${theme.heading("Examples:")} +${formatHelpExamples([ + ['clawdbot message send --target +15555550123 --message "Hi"', "Send a text message."], + [ + 'clawdbot message send --target +15555550123 --message "Hi" --media photo.jpg', + "Send a message with media.", + ], + [ + 'clawdbot message poll --channel discord --target channel:123 --poll-question "Snack?" --poll-option Pizza --poll-option Sushi', + "Create a Discord poll.", + ], + [ + 'clawdbot message react --channel discord --target 123 --message-id 456 --emoji "✅"', + "React to a message.", + ], +])} ${theme.muted("Docs:")} ${formatDocsLink("/cli/message", "docs.clawd.bot/cli/message")}`, ) diff --git a/src/cli/program/register.status-health-sessions.ts b/src/cli/program/register.status-health-sessions.ts index cb34e7cea..66d0c4abb 100644 --- a/src/cli/program/register.status-health-sessions.ts +++ b/src/cli/program/register.status-health-sessions.ts @@ -7,6 +7,7 @@ import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; import { runCommandWithRuntime } from "../cli-utils.js"; +import { formatHelpExamples } from "../help-format.js"; import { parsePositiveIntOrUndefined } from "./helpers.js"; function resolveVerbose(opts: { verbose?: boolean; debug?: boolean }): boolean { @@ -36,15 +37,18 @@ export function registerStatusHealthSessionsCommands(program: Command) { .option("--debug", "Alias for --verbose", false) .addHelpText( "after", - ` -Examples: - clawdbot status # show linked account + session store summary - clawdbot status --all # full diagnosis (read-only) - clawdbot status --json # machine-readable output - clawdbot status --usage # show model provider usage/quota snapshots - clawdbot status --deep # run channel probes (WA + Telegram + Discord + Slack + Signal) - clawdbot status --deep --timeout 5000 # tighten probe timeout - clawdbot channels status # gateway channel runtime + probes`, + () => + `\n${theme.heading("Examples:")}\n${formatHelpExamples([ + ["clawdbot status", "Show channel health + session summary."], + ["clawdbot status --all", "Full diagnosis (read-only)."], + ["clawdbot status --json", "Machine-readable output."], + ["clawdbot status --usage", "Show model provider usage/quota snapshots."], + [ + "clawdbot status --deep", + "Run channel probes (WA + Telegram + Discord + Slack + Signal).", + ], + ["clawdbot status --deep --timeout 5000", "Tighten probe timeout."], + ])}`, ) .addHelpText( "after", @@ -113,14 +117,15 @@ Examples: .option("--active ", "Only show sessions updated within the past N minutes") .addHelpText( "after", - ` -Examples: - clawdbot sessions # list all sessions - clawdbot sessions --active 120 # only last 2 hours - clawdbot sessions --json # machine-readable output - clawdbot sessions --store ./tmp/sessions.json - -Shows token usage per session when the agent reports it; set agents.defaults.contextTokens to see % of your model window.`, + () => + `\n${theme.heading("Examples:")}\n${formatHelpExamples([ + ["clawdbot sessions", "List all sessions."], + ["clawdbot sessions --active 120", "Only last 2 hours."], + ["clawdbot sessions --json", "Machine-readable output."], + ["clawdbot sessions --store ./tmp/sessions.json", "Use a specific session store."], + ])}\n\n${theme.muted( + "Shows token usage per session when the agent reports it; set agents.defaults.contextTokens to see % of your model window.", + )}`, ) .addHelpText( "after", diff --git a/src/cli/sandbox-cli.ts b/src/cli/sandbox-cli.ts index 4766c0ec4..746566f82 100644 --- a/src/cli/sandbox-cli.ts +++ b/src/cli/sandbox-cli.ts @@ -5,6 +5,7 @@ import { sandboxExplainCommand } from "../commands/sandbox-explain.js"; import { defaultRuntime } from "../runtime.js"; import { formatDocsLink } from "../terminal/links.js"; import { theme } from "../terminal/theme.js"; +import { formatHelpExamples } from "./help-format.js"; // --- Types --- @@ -12,58 +13,34 @@ type CommandOptions = Record; // --- Helpers --- -const EXAMPLES = { - main: ` -Examples: - clawdbot sandbox list # List all sandbox containers - clawdbot sandbox list --browser # List only browser containers - clawdbot sandbox recreate --all # Recreate all containers - clawdbot sandbox recreate --session main # Recreate specific session - clawdbot sandbox recreate --agent mybot # Recreate agent containers - clawdbot sandbox explain # Explain effective sandbox config`, - - list: ` -Examples: - clawdbot sandbox list # List all sandbox containers - clawdbot sandbox list --browser # List only browser containers - clawdbot sandbox list --json # JSON output - -Output includes: - • Container name and status (running/stopped) - • Docker image and whether it matches current config - • Age (time since creation) - • Idle time (time since last use) - • Associated session/agent ID`, - - recreate: ` -Examples: - clawdbot sandbox recreate --all # Recreate all containers - clawdbot sandbox recreate --session main # Specific session - clawdbot sandbox recreate --agent mybot # Specific agent (includes sub-agents) - clawdbot sandbox recreate --browser --all # All browser containers only - clawdbot sandbox recreate --all --force # Skip confirmation - -Why use this? - After updating Docker images or sandbox configuration, existing containers - continue running with old settings. This command removes them so they'll be - recreated automatically with current config when next needed. - -Filter options: - --all Remove all sandbox containers - --session Remove container for specific session key - --agent Remove containers for agent (includes agent:id:* variants) - -Modifiers: - --browser Only affect browser containers (not regular sandbox) - --force Skip confirmation prompt`, - - explain: ` -Examples: - clawdbot sandbox explain - clawdbot sandbox explain --session agent:main:main - clawdbot sandbox explain --agent work - clawdbot sandbox explain --json`, -}; +const SANDBOX_EXAMPLES = { + main: [ + ["clawdbot sandbox list", "List all sandbox containers."], + ["clawdbot sandbox list --browser", "List only browser containers."], + ["clawdbot sandbox recreate --all", "Recreate all containers."], + ["clawdbot sandbox recreate --session main", "Recreate a specific session."], + ["clawdbot sandbox recreate --agent mybot", "Recreate agent containers."], + ["clawdbot sandbox explain", "Explain effective sandbox config."], + ], + list: [ + ["clawdbot sandbox list", "List all sandbox containers."], + ["clawdbot sandbox list --browser", "List only browser containers."], + ["clawdbot sandbox list --json", "JSON output."], + ], + recreate: [ + ["clawdbot sandbox recreate --all", "Recreate all containers."], + ["clawdbot sandbox recreate --session main", "Recreate a specific session."], + ["clawdbot sandbox recreate --agent mybot", "Recreate a specific agent (includes sub-agents)."], + ["clawdbot sandbox recreate --browser --all", "Recreate only browser containers."], + ["clawdbot sandbox recreate --all --force", "Skip confirmation."], + ], + explain: [ + ["clawdbot sandbox explain", "Show effective sandbox config."], + ["clawdbot sandbox explain --session agent:main:main", "Explain a specific session."], + ["clawdbot sandbox explain --agent work", "Explain an agent sandbox."], + ["clawdbot sandbox explain --json", "JSON output."], + ], +} as const; function createRunner( commandFn: (opts: CommandOptions, runtime: typeof defaultRuntime) => Promise, @@ -84,7 +61,10 @@ export function registerSandboxCli(program: Command) { const sandbox = program .command("sandbox") .description("Manage sandbox containers (Docker-based agent isolation)") - .addHelpText("after", EXAMPLES.main) + .addHelpText( + "after", + () => `\n${theme.heading("Examples:")}\n${formatHelpExamples(SANDBOX_EXAMPLES.main)}\n`, + ) .addHelpText( "after", () => @@ -101,7 +81,17 @@ export function registerSandboxCli(program: Command) { .description("List sandbox containers and their status") .option("--json", "Output result as JSON", false) .option("--browser", "List browser containers only", false) - .addHelpText("after", EXAMPLES.list) + .addHelpText( + "after", + () => + `\n${theme.heading("Examples:")}\n${formatHelpExamples(SANDBOX_EXAMPLES.list)}\n\n${theme.heading( + "Output includes:", + )}\n${theme.muted("- Container name and status (running/stopped)")}\n${theme.muted( + "- Docker image and whether it matches current config", + )}\n${theme.muted("- Age (time since creation)")}\n${theme.muted( + "- Idle time (time since last use)", + )}\n${theme.muted("- Associated session/agent ID")}`, + ) .action( createRunner((opts) => sandboxListCommand( @@ -124,7 +114,25 @@ export function registerSandboxCli(program: Command) { .option("--agent ", "Recreate containers for specific agent") .option("--browser", "Only recreate browser containers", false) .option("--force", "Skip confirmation prompt", false) - .addHelpText("after", EXAMPLES.recreate) + .addHelpText( + "after", + () => + `\n${theme.heading("Examples:")}\n${formatHelpExamples(SANDBOX_EXAMPLES.recreate)}\n\n${theme.heading( + "Why use this?", + )}\n${theme.muted( + "After updating Docker images or sandbox configuration, existing containers continue running with old settings.", + )}\n${theme.muted( + "This command removes them so they'll be recreated automatically with current config when next needed.", + )}\n\n${theme.heading("Filter options:")}\n${theme.muted( + " --all Remove all sandbox containers", + )}\n${theme.muted( + " --session Remove container for specific session key", + )}\n${theme.muted( + " --agent Remove containers for agent (includes agent:id:* variants)", + )}\n\n${theme.heading("Modifiers:")}\n${theme.muted( + " --browser Only affect browser containers (not regular sandbox)", + )}\n${theme.muted(" --force Skip confirmation prompt")}`, + ) .action( createRunner((opts) => sandboxRecreateCommand( @@ -148,7 +156,10 @@ export function registerSandboxCli(program: Command) { .option("--session ", "Session key to inspect (defaults to agent main)") .option("--agent ", "Agent id to inspect (defaults to derived agent)") .option("--json", "Output result as JSON", false) - .addHelpText("after", EXAMPLES.explain) + .addHelpText( + "after", + () => `\n${theme.heading("Examples:")}\n${formatHelpExamples(SANDBOX_EXAMPLES.explain)}\n`, + ) .action( createRunner((opts) => sandboxExplainCommand( diff --git a/src/cli/service-cli.ts b/src/cli/service-cli.ts index d2dcc376d..fa2ac3ffb 100644 --- a/src/cli/service-cli.ts +++ b/src/cli/service-cli.ts @@ -1,6 +1,7 @@ import type { Command } from "commander"; import { formatDocsLink } from "../terminal/links.js"; import { theme } from "../terminal/theme.js"; +import { formatHelpExampleGroup } from "./help-format.js"; import { createDefaultDeps } from "./deps.js"; import { runDaemonInstall, @@ -20,12 +21,6 @@ import { } from "./node-cli/daemon.js"; export function registerServiceCli(program: Command) { - const formatExample = (cmd: string, desc: string) => - ` ${theme.command(cmd)}\n ${theme.muted(desc)}`; - - const formatGroup = (label: string, examples: Array<[string, string]>) => - `${theme.muted(label)}\n${examples.map(([cmd, desc]) => formatExample(cmd, desc)).join("\n")}`; - const gatewayExamples: Array<[string, string]> = [ ["clawdbot service gateway status", "Show gateway service status + probe."], [ @@ -50,10 +45,12 @@ export function registerServiceCli(program: Command) { .addHelpText( "after", () => - `\n${theme.heading("Examples:")}\n${formatGroup("Gateway:", gatewayExamples)}\n\n${formatGroup( - "Node:", - nodeExamples, - )}\n\n${theme.muted("Docs:")} ${formatDocsLink("/cli/service", "docs.clawd.bot/cli/service")}\n`, + `\n${theme.heading("Examples:")}\n${formatHelpExampleGroup( + "Gateway:", + gatewayExamples, + )}\n\n${formatHelpExampleGroup("Node:", nodeExamples)}\n\n${theme.muted( + "Docs:", + )} ${formatDocsLink("/cli/service", "docs.clawd.bot/cli/service")}\n`, ); const gateway = service.command("gateway").description("Manage the Gateway service"); diff --git a/src/cli/update-cli.ts b/src/cli/update-cli.ts index ff33f9e9a..4e269cee7 100644 --- a/src/cli/update-cli.ts +++ b/src/cli/update-cli.ts @@ -32,6 +32,7 @@ import { formatCliCommand } from "./command-format.js"; import { stylePromptMessage } from "../terminal/prompt-style.js"; import { theme } from "../terminal/theme.js"; import { renderTable } from "../terminal/table.js"; +import { formatHelpExamples } from "./help-format.js"; import { formatUpdateAvailableHint, formatUpdateOneLiner, @@ -734,17 +735,15 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.clawd.bot/cli/upda .addHelpText( "after", () => - ` -Examples: - clawdbot update status - clawdbot update status --json - clawdbot update status --timeout 10 - -Notes: - - Shows current update channel (stable/beta/dev) and source - - Includes git tag/branch/SHA for source checkouts - -${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.clawd.bot/cli/update")}`, + `\n${theme.heading("Examples:")}\n${formatHelpExamples([ + ["clawdbot update status", "Show channel + version status."], + ["clawdbot update status --json", "JSON output."], + ["clawdbot update status --timeout 10", "Custom timeout."], + ])}\n\n${theme.heading("Notes:")}\n${theme.muted( + "- Shows current update channel (stable/beta/dev) and source", + )}\n${theme.muted("- Includes git tag/branch/SHA for source checkouts")}\n\n${theme.muted( + "Docs:", + )} ${formatDocsLink("/cli/update", "docs.clawd.bot/cli/update")}`, ) .action(async (opts) => { try {