From e2cb67462d2006663e89cd5221d0f33b18ff6b32 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Wed, 11 Mar 2026 21:08:08 +0700 Subject: [PATCH] refactor(cli): extract common command options into reusable helpers --- packages/cli/src/cli.ts | 203 ++++++++--------- packages/cli/src/commands/agent/index.ts | 228 ++++++++++---------- packages/cli/src/commands/daemon/index.ts | 28 +-- packages/cli/src/commands/daemon/pair.ts | 8 +- packages/cli/src/commands/permit/index.ts | 52 +++-- packages/cli/src/commands/provider/index.ts | 27 ++- packages/cli/src/commands/speech/index.ts | 41 ++-- packages/cli/src/commands/worktree/index.ts | 25 ++- packages/cli/src/utils/command-options.ts | 23 ++ 9 files changed, 323 insertions(+), 312 deletions(-) create mode 100644 packages/cli/src/utils/command-options.ts diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index 2bb8e2095..d89703b3c 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -21,6 +21,12 @@ import { runWaitCommand } from './commands/agent/wait.js' import { runAttachCommand } from './commands/agent/attach.js' import { withOutput } from './output/index.js' import { onboardCommand } from './commands/onboard.js' +import { + addDaemonHostOption, + addJsonAndDaemonHostOptions, + addJsonOption, + collectMultiple, +} from './utils/command-options.js' const require = createRequire(import.meta.url) @@ -38,11 +44,6 @@ function resolveCliVersion(): string { const VERSION = resolveCliVersion() -// Helper function to collect multiple option values into an array -function collectMultiple(value: string, previous: string[]): string[] { - return previous.concat([value]) -} - export function createCli(): Command { const program = new Command() @@ -58,102 +59,100 @@ export function createCli(): Command { .option('--no-color', 'disable colored output') // Primary agent commands (top-level) - program - .command('ls') - .description('List agents. By default excludes archived agents.') - .option('-a, --all', 'Include archived agents') - .option('-g, --global', 'Legacy no-op (kept for compatibility)') - .option('--label ', 'Filter by label (can be used multiple times)', collectMultiple, []) - .option('--thinking ', 'Filter by thinking option ID') - .option('--json', 'Output in JSON format') - .option('--host ', 'Daemon host target (default: local socket/pipe, then localhost:6767)') - .action(withOutput(runLsCommand)) + addJsonAndDaemonHostOptions( + program + .command('ls') + .description('List agents. By default excludes archived agents.') + .option('-a, --all', 'Include archived agents') + .option('-g, --global', 'Legacy no-op (kept for compatibility)') + .option('--label ', 'Filter by label (can be used multiple times)', collectMultiple, []) + .option('--thinking ', 'Filter by thinking option ID') + ).action(withOutput(runLsCommand)) - program - .command('run') - .description('Create and start an agent with a task') - .argument('', 'The task/prompt for the agent') - .option('-d, --detach', 'Run in background (detached)') - .option('--name ', 'Assign a name/title to the agent') - .option('--provider ', 'Agent provider: claude | codex | opencode', 'claude') - .option('--model ', 'Model to use (e.g., claude-sonnet-4-20250514, claude-3-5-haiku-20241022)') - .option('--thinking ', 'Thinking option ID to use for this run') - .option('--mode ', 'Provider-specific mode (e.g., plan, default, bypass)') - .option('--worktree ', 'Create agent in a new git worktree') - .option('--base ', 'Base branch for worktree (default: current branch)') - .option('--image ', 'Attach image(s) to the initial prompt (can be used multiple times)', collectMultiple, []) - .option('--cwd ', 'Working directory (default: current)') - .option('--label ', 'Add label(s) to the agent (can be used multiple times)', collectMultiple, []) - .option('--output-schema ', 'Output JSON matching the provided schema file path or inline JSON schema') - .option('--json', 'Output in JSON format') - .option('--host ', 'Daemon host target (default: local socket/pipe, then localhost:6767)') - .action(withOutput(runRunCommand)) + addJsonAndDaemonHostOptions( + program + .command('run') + .description('Create and start an agent with a task') + .argument('', 'The task/prompt for the agent') + .option('-d, --detach', 'Run in background (detached)') + .option('--name ', 'Assign a name/title to the agent') + .option('--provider ', 'Agent provider: claude | codex | opencode', 'claude') + .option('--model ', 'Model to use (e.g., claude-sonnet-4-20250514, claude-3-5-haiku-20241022)') + .option('--thinking ', 'Thinking option ID to use for this run') + .option('--mode ', 'Provider-specific mode (e.g., plan, default, bypass)') + .option('--worktree ', 'Create agent in a new git worktree') + .option('--base ', 'Base branch for worktree (default: current branch)') + .option( + '--image ', + 'Attach image(s) to the initial prompt (can be used multiple times)', + collectMultiple, + [] + ) + .option('--cwd ', 'Working directory (default: current)') + .option('--label ', 'Add label(s) to the agent (can be used multiple times)', collectMultiple, []) + .option('--output-schema ', 'Output JSON matching the provided schema file path or inline JSON schema') + ).action(withOutput(runRunCommand)) - program - .command('attach') - .description("Attach to a running agent's output stream") - .argument('', 'Agent ID (or prefix)') - .option('--host ', 'Daemon host target (default: local socket/pipe, then localhost:6767)') - .action(runAttachCommand) + addDaemonHostOption( + program + .command('attach') + .description("Attach to a running agent's output stream") + .argument('', 'Agent ID (or prefix)') + ).action(runAttachCommand) - program - .command('logs') - .description('View agent activity/timeline') - .argument('', 'Agent ID (or prefix)') - .option('-f, --follow', 'Follow log output (streaming)') - .option('--tail ', 'Show last n entries') - .option('--filter ', 'Filter by event type (tools, text, errors, permissions)') - .option('--since