refactor(cli): extract common command options into reusable helpers

This commit is contained in:
Mohamed Boudra
2026-03-11 21:08:08 +07:00
parent b60d253926
commit e2cb67462d
9 changed files with 323 additions and 312 deletions
+34 -33
View File
@@ -21,6 +21,12 @@ import { runWaitCommand } from './commands/agent/wait.js'
import { runAttachCommand } from './commands/agent/attach.js' import { runAttachCommand } from './commands/agent/attach.js'
import { withOutput } from './output/index.js' import { withOutput } from './output/index.js'
import { onboardCommand } from './commands/onboard.js' import { onboardCommand } from './commands/onboard.js'
import {
addDaemonHostOption,
addJsonAndDaemonHostOptions,
addJsonOption,
collectMultiple,
} from './utils/command-options.js'
const require = createRequire(import.meta.url) const require = createRequire(import.meta.url)
@@ -38,11 +44,6 @@ function resolveCliVersion(): string {
const VERSION = resolveCliVersion() 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 { export function createCli(): Command {
const program = new Command() const program = new Command()
@@ -58,6 +59,7 @@ export function createCli(): Command {
.option('--no-color', 'disable colored output') .option('--no-color', 'disable colored output')
// Primary agent commands (top-level) // Primary agent commands (top-level)
addJsonAndDaemonHostOptions(
program program
.command('ls') .command('ls')
.description('List agents. By default excludes archived agents.') .description('List agents. By default excludes archived agents.')
@@ -65,10 +67,9 @@ export function createCli(): Command {
.option('-g, --global', 'Legacy no-op (kept for compatibility)') .option('-g, --global', 'Legacy no-op (kept for compatibility)')
.option('--label <key=value>', 'Filter by label (can be used multiple times)', collectMultiple, []) .option('--label <key=value>', 'Filter by label (can be used multiple times)', collectMultiple, [])
.option('--thinking <id>', 'Filter by thinking option ID') .option('--thinking <id>', 'Filter by thinking option ID')
.option('--json', 'Output in JSON format') ).action(withOutput(runLsCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runLsCommand))
addJsonAndDaemonHostOptions(
program program
.command('run') .command('run')
.description('Create and start an agent with a task') .description('Create and start an agent with a task')
@@ -81,21 +82,25 @@ export function createCli(): Command {
.option('--mode <mode>', 'Provider-specific mode (e.g., plan, default, bypass)') .option('--mode <mode>', 'Provider-specific mode (e.g., plan, default, bypass)')
.option('--worktree <name>', 'Create agent in a new git worktree') .option('--worktree <name>', 'Create agent in a new git worktree')
.option('--base <branch>', 'Base branch for worktree (default: current branch)') .option('--base <branch>', 'Base branch for worktree (default: current branch)')
.option('--image <path>', 'Attach image(s) to the initial prompt (can be used multiple times)', collectMultiple, []) .option(
'--image <path>',
'Attach image(s) to the initial prompt (can be used multiple times)',
collectMultiple,
[]
)
.option('--cwd <path>', 'Working directory (default: current)') .option('--cwd <path>', 'Working directory (default: current)')
.option('--label <key=value>', 'Add label(s) to the agent (can be used multiple times)', collectMultiple, []) .option('--label <key=value>', 'Add label(s) to the agent (can be used multiple times)', collectMultiple, [])
.option('--output-schema <schema>', 'Output JSON matching the provided schema file path or inline JSON schema') .option('--output-schema <schema>', 'Output JSON matching the provided schema file path or inline JSON schema')
.option('--json', 'Output in JSON format') ).action(withOutput(runRunCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runRunCommand))
addDaemonHostOption(
program program
.command('attach') .command('attach')
.description("Attach to a running agent's output stream") .description("Attach to a running agent's output stream")
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)') ).action(runAttachCommand)
.action(runAttachCommand)
addDaemonHostOption(
program program
.command('logs') .command('logs')
.description('View agent activity/timeline') .description('View agent activity/timeline')
@@ -104,29 +109,27 @@ export function createCli(): Command {
.option('--tail <n>', 'Show last n entries') .option('--tail <n>', 'Show last n entries')
.option('--filter <type>', 'Filter by event type (tools, text, errors, permissions)') .option('--filter <type>', 'Filter by event type (tools, text, errors, permissions)')
.option('--since <time>', 'Show logs since timestamp') .option('--since <time>', 'Show logs since timestamp')
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)') ).action(runLogsCommand)
.action(runLogsCommand)
addJsonAndDaemonHostOptions(
program program
.command('stop') .command('stop')
.description('Interrupt an agent if it is running (no-op for idle agents)') .description('Interrupt an agent if it is running (no-op for idle agents)')
.argument('[id]', 'Agent ID (or prefix) - optional if --all or --cwd specified') .argument('[id]', 'Agent ID (or prefix) - optional if --all or --cwd specified')
.option('--all', 'Stop all agents') .option('--all', 'Stop all agents')
.option('--cwd <path>', 'Stop all agents in directory') .option('--cwd <path>', 'Stop all agents in directory')
.option('--json', 'Output in JSON format') ).action(withOutput(runStopCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runStopCommand))
addJsonAndDaemonHostOptions(
program program
.command('delete') .command('delete')
.description('Delete an agent (interrupt if running, then hard-delete)') .description('Delete an agent (interrupt if running, then hard-delete)')
.argument('[id]', 'Agent ID (or prefix) - optional if --all or --cwd specified') .argument('[id]', 'Agent ID (or prefix) - optional if --all or --cwd specified')
.option('--all', 'Delete all agents') .option('--all', 'Delete all agents')
.option('--cwd <path>', 'Delete all agents in directory') .option('--cwd <path>', 'Delete all agents in directory')
.option('--json', 'Output in JSON format') ).action(withOutput(runDeleteCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runDeleteCommand))
addJsonAndDaemonHostOptions(
program program
.command('send') .command('send')
.description('Send a message/task to an existing agent') .description('Send a message/task to an existing agent')
@@ -134,26 +137,22 @@ export function createCli(): Command {
.argument('<prompt>', 'The message to send') .argument('<prompt>', 'The message to send')
.option('--no-wait', 'Return immediately without waiting for completion') .option('--no-wait', 'Return immediately without waiting for completion')
.option('--image <path>', 'Attach image(s) to the message', collectMultiple, []) .option('--image <path>', 'Attach image(s) to the message', collectMultiple, [])
.option('--json', 'Output in JSON format') ).action(withOutput(runSendCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runSendCommand))
addJsonAndDaemonHostOptions(
program program
.command('inspect') .command('inspect')
.description('Show detailed information about an agent') .description('Show detailed information about an agent')
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.option('--json', 'Output in JSON format') ).action(withOutput(runInspectCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runInspectCommand))
addJsonAndDaemonHostOptions(
program program
.command('wait') .command('wait')
.description('Wait for an agent to become idle') .description('Wait for an agent to become idle')
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.option('--timeout <seconds>', 'Maximum wait time (default: no limit)') .option('--timeout <seconds>', 'Maximum wait time (default: no limit)')
.option('--json', 'Output in JSON format') ).action(withOutput(runWaitCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runWaitCommand))
// Top-level local daemon shortcuts // Top-level local daemon shortcuts
program.addCommand(onboardCommand()) program.addCommand(onboardCommand())
@@ -168,17 +167,19 @@ export function createCli(): Command {
await runDaemonUpdateCommandOrExit(options) await runDaemonUpdateCommandOrExit(options)
}) })
addJsonOption(
program program
.command('status') .command('status')
.description('Show local daemon status (alias for "paseo daemon status")') .description('Show local daemon status (alias for "paseo daemon status")')
.option('--json', 'Output in JSON format') )
.option('--home <path>', 'Paseo home directory (default: ~/.paseo)') .option('--home <path>', 'Paseo home directory (default: ~/.paseo)')
.action(withOutput(runDaemonStatusCommand)) .action(withOutput(runDaemonStatusCommand))
addJsonOption(
program program
.command('restart') .command('restart')
.description('Restart local daemon (alias for "paseo daemon restart")') .description('Restart local daemon (alias for "paseo daemon restart")')
.option('--json', 'Output in JSON format') )
.option('--home <path>', 'Paseo home directory (default: ~/.paseo)') .option('--home <path>', 'Paseo home directory (default: ~/.paseo)')
.option('--timeout <seconds>', 'Wait timeout before force step (default: 15)') .option('--timeout <seconds>', 'Wait timeout before force step (default: 15)')
.option('--force', 'Send SIGKILL if graceful stop times out') .option('--force', 'Send SIGKILL if graceful stop times out')
+29 -39
View File
@@ -12,16 +12,17 @@ import { runWaitCommand } from './wait.js'
import { runAttachCommand } from './attach.js' import { runAttachCommand } from './attach.js'
import { runUpdateCommand } from './update.js' import { runUpdateCommand } from './update.js'
import { withOutput } from '../../output/index.js' import { withOutput } from '../../output/index.js'
import {
addDaemonHostOption,
addJsonAndDaemonHostOptions,
collectMultiple,
} from '../../utils/command-options.js'
export function createAgentCommand(): Command { export function createAgentCommand(): Command {
const agent = new Command('agent').description('Manage agents (advanced operations)') const agent = new Command('agent').description('Manage agents (advanced operations)')
// Helper function to collect multiple option values into an array
const collectMultiple = (value: string, previous: string[]): string[] => {
return previous.concat([value])
}
// Primary agent commands (same as top-level) // Primary agent commands (same as top-level)
addJsonAndDaemonHostOptions(
agent agent
.command('ls') .command('ls')
.description('List agents. By default excludes archived agents.') .description('List agents. By default excludes archived agents.')
@@ -29,10 +30,9 @@ export function createAgentCommand(): Command {
.option('-g, --global', 'Legacy no-op (kept for compatibility)') .option('-g, --global', 'Legacy no-op (kept for compatibility)')
.option('--label <key=value>', 'Filter by label (can be used multiple times)', collectMultiple, []) .option('--label <key=value>', 'Filter by label (can be used multiple times)', collectMultiple, [])
.option('--thinking <id>', 'Filter by thinking option ID') .option('--thinking <id>', 'Filter by thinking option ID')
.option('--json', 'Output in JSON format') ).action(withOutput(runLsCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runLsCommand))
addJsonAndDaemonHostOptions(
agent agent
.command('run') .command('run')
.description('Create and start an agent with a task') .description('Create and start an agent with a task')
@@ -46,17 +46,16 @@ export function createAgentCommand(): Command {
.option('--cwd <path>', 'Working directory (default: current)') .option('--cwd <path>', 'Working directory (default: current)')
.option('--label <key=value>', 'Add label(s) to the agent (can be used multiple times)', collectMultiple, []) .option('--label <key=value>', 'Add label(s) to the agent (can be used multiple times)', collectMultiple, [])
.option('--output-schema <schema>', 'Output JSON matching the provided schema file path or inline JSON schema') .option('--output-schema <schema>', 'Output JSON matching the provided schema file path or inline JSON schema')
.option('--json', 'Output in JSON format') ).action(withOutput(runRunCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runRunCommand))
addDaemonHostOption(
agent agent
.command('attach') .command('attach')
.description("Attach to a running agent's output stream") .description("Attach to a running agent's output stream")
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)') ).action(runAttachCommand)
.action(runAttachCommand)
addDaemonHostOption(
agent agent
.command('logs') .command('logs')
.description('View agent activity/timeline') .description('View agent activity/timeline')
@@ -64,76 +63,69 @@ export function createAgentCommand(): Command {
.option('-f, --follow', 'Follow log output (streaming)') .option('-f, --follow', 'Follow log output (streaming)')
.option('--tail <n>', 'Show last n entries') .option('--tail <n>', 'Show last n entries')
.option('--filter <type>', 'Filter by event type (tools, text, errors, permissions)') .option('--filter <type>', 'Filter by event type (tools, text, errors, permissions)')
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)') ).action(runLogsCommand)
.action(runLogsCommand)
addJsonAndDaemonHostOptions(
agent agent
.command('stop') .command('stop')
.description('Interrupt an agent if it is running (no-op for idle agents)') .description('Interrupt an agent if it is running (no-op for idle agents)')
.argument('[id]', 'Agent ID (or prefix) - optional if --all or --cwd specified') .argument('[id]', 'Agent ID (or prefix) - optional if --all or --cwd specified')
.option('--all', 'Stop all agents') .option('--all', 'Stop all agents')
.option('--cwd <path>', 'Stop all agents in directory') .option('--cwd <path>', 'Stop all agents in directory')
.option('--json', 'Output in JSON format') ).action(withOutput(runStopCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runStopCommand))
addJsonAndDaemonHostOptions(
agent agent
.command('delete') .command('delete')
.description('Delete an agent (interrupt if running, then hard-delete)') .description('Delete an agent (interrupt if running, then hard-delete)')
.argument('[id]', 'Agent ID (or prefix) - optional if --all or --cwd specified') .argument('[id]', 'Agent ID (or prefix) - optional if --all or --cwd specified')
.option('--all', 'Delete all agents') .option('--all', 'Delete all agents')
.option('--cwd <path>', 'Delete all agents in directory') .option('--cwd <path>', 'Delete all agents in directory')
.option('--json', 'Output in JSON format') ).action(withOutput(runDeleteCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runDeleteCommand))
addJsonAndDaemonHostOptions(
agent agent
.command('send') .command('send')
.description('Send a message/task to an existing agent') .description('Send a message/task to an existing agent')
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.argument('<prompt>', 'The message to send') .argument('<prompt>', 'The message to send')
.option('--no-wait', 'Return immediately without waiting for completion') .option('--no-wait', 'Return immediately without waiting for completion')
.option('--json', 'Output in JSON format') ).action(withOutput(runSendCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runSendCommand))
addJsonAndDaemonHostOptions(
agent agent
.command('inspect') .command('inspect')
.description('Show detailed information about an agent') .description('Show detailed information about an agent')
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.option('--json', 'Output in JSON format') ).action(withOutput(runInspectCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runInspectCommand))
addJsonAndDaemonHostOptions(
agent agent
.command('wait') .command('wait')
.description('Wait for an agent to become idle') .description('Wait for an agent to become idle')
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.option('--timeout <seconds>', 'Maximum wait time (default: no limit)') .option('--timeout <seconds>', 'Maximum wait time (default: no limit)')
.option('--json', 'Output in JSON format') ).action(withOutput(runWaitCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runWaitCommand))
// Advanced agent commands (less common operations) // Advanced agent commands (less common operations)
addJsonAndDaemonHostOptions(
agent agent
.command('mode') .command('mode')
.description("Change an agent's operational mode") .description("Change an agent's operational mode")
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.argument('[mode]', 'Mode to set (required unless --list)') .argument('[mode]', 'Mode to set (required unless --list)')
.option('--list', 'List available modes for this agent') .option('--list', 'List available modes for this agent')
.option('--json', 'Output in JSON format') ).action(withOutput(runModeCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runModeCommand))
addJsonAndDaemonHostOptions(
agent agent
.command('archive') .command('archive')
.description('Archive an agent (soft-delete)') .description('Archive an agent (soft-delete)')
.argument('<id>', 'Agent ID (or prefix)') .argument('<id>', 'Agent ID (or prefix)')
.option('--force', 'Force archive running agent (interrupts active run first)') .option('--force', 'Force archive running agent (interrupts active run first)')
.option('--json', 'Output in JSON format') ).action(withOutput(runArchiveCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runArchiveCommand))
addJsonAndDaemonHostOptions(
agent agent
.command('update') .command('update')
.description("Update an agent's metadata") .description("Update an agent's metadata")
@@ -145,9 +137,7 @@ export function createAgentCommand(): Command {
collectMultiple, collectMultiple,
[] []
) )
.option('--json', 'Output in JSON format') ).action(withOutput(runUpdateCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runUpdateCommand))
return agent return agent
} }
+7 -3
View File
@@ -6,6 +6,7 @@ import { runRestartCommand } from './restart.js'
import { pairCommand } from './pair.js' import { pairCommand } from './pair.js'
import { updateCommand } from './update.js' import { updateCommand } from './update.js'
import { withOutput } from '../../output/index.js' import { withOutput } from '../../output/index.js'
import { addJsonOption } from '../../utils/command-options.js'
export function createDaemonCommand(): Command { export function createDaemonCommand(): Command {
const daemon = new Command('daemon').description('Manage the Paseo daemon') const daemon = new Command('daemon').description('Manage the Paseo daemon')
@@ -14,26 +15,29 @@ export function createDaemonCommand(): Command {
daemon.addCommand(pairCommand()) daemon.addCommand(pairCommand())
daemon.addCommand(updateCommand()) daemon.addCommand(updateCommand())
addJsonOption(
daemon daemon
.command('status') .command('status')
.description('Show local daemon status') .description('Show local daemon status')
.option('--json', 'Output in JSON format') )
.option('--home <path>', 'Paseo home directory (default: ~/.paseo)') .option('--home <path>', 'Paseo home directory (default: ~/.paseo)')
.action(withOutput(runStatusCommand)) .action(withOutput(runStatusCommand))
addJsonOption(
daemon daemon
.command('stop') .command('stop')
.description('Stop the local daemon') .description('Stop the local daemon')
.option('--json', 'Output in JSON format') )
.option('--home <path>', 'Paseo home directory (default: ~/.paseo)') .option('--home <path>', 'Paseo home directory (default: ~/.paseo)')
.option('--timeout <seconds>', 'Wait timeout before failing (default: 15)') .option('--timeout <seconds>', 'Wait timeout before failing (default: 15)')
.option('--force', 'Send SIGKILL if graceful stop times out') .option('--force', 'Send SIGKILL if graceful stop times out')
.action(withOutput(runStopCommand)) .action(withOutput(runStopCommand))
addJsonOption(
daemon daemon
.command('restart') .command('restart')
.description('Restart the local daemon') .description('Restart the local daemon')
.option('--json', 'Output in JSON format') )
.option('--home <path>', 'Paseo home directory (default: ~/.paseo)') .option('--home <path>', 'Paseo home directory (default: ~/.paseo)')
.option('--timeout <seconds>', 'Wait timeout before force step (default: 15)') .option('--timeout <seconds>', 'Wait timeout before force step (default: 15)')
.option('--force', 'Send SIGKILL if graceful stop times out') .option('--force', 'Send SIGKILL if graceful stop times out')
+4 -2
View File
@@ -1,6 +1,7 @@
import { Command } from 'commander' import { Command } from 'commander'
import chalk from 'chalk' import chalk from 'chalk'
import { generateLocalPairingOffer, loadConfig, resolvePaseoHome } from '@getpaseo/server' import { generateLocalPairingOffer, loadConfig, resolvePaseoHome } from '@getpaseo/server'
import { addJsonOption } from '../../utils/command-options.js'
interface PairOptions { interface PairOptions {
home?: string home?: string
@@ -8,9 +9,10 @@ interface PairOptions {
} }
export function pairCommand(): Command { export function pairCommand(): Command {
return new Command('pair') return addJsonOption(
new Command('pair')
.description('Print the daemon pairing QR code and link') .description('Print the daemon pairing QR code and link')
.option('--json', 'Output in JSON format') )
.option('--home <path>', 'Paseo home directory (default: ~/.paseo)') .option('--home <path>', 'Paseo home directory (default: ~/.paseo)')
.action(async (_options: PairOptions, command: Command) => { .action(async (_options: PairOptions, command: Command) => {
await runPairCommand(command.optsWithGlobals() as PairOptions) await runPairCommand(command.optsWithGlobals() as PairOptions)
+7 -9
View File
@@ -3,17 +3,18 @@ import { runLsCommand } from './ls.js'
import { runAllowCommand } from './allow.js' import { runAllowCommand } from './allow.js'
import { runDenyCommand } from './deny.js' import { runDenyCommand } from './deny.js'
import { withOutput } from '../../output/index.js' import { withOutput } from '../../output/index.js'
import { addJsonAndDaemonHostOptions } from '../../utils/command-options.js'
export function createPermitCommand(): Command { export function createPermitCommand(): Command {
const permit = new Command('permit').description('Manage permission requests') const permit = new Command('permit').description('Manage permission requests')
addJsonAndDaemonHostOptions(
permit permit
.command('ls') .command('ls')
.description('List all pending permissions') .description('List all pending permissions')
.option('--json', 'Output in JSON format') ).action(withOutput(runLsCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runLsCommand))
addJsonAndDaemonHostOptions(
permit permit
.command('allow') .command('allow')
.description('Allow a permission request') .description('Allow a permission request')
@@ -21,10 +22,9 @@ export function createPermitCommand(): Command {
.argument('[req_id]', 'Permission request ID (optional if --all)') .argument('[req_id]', 'Permission request ID (optional if --all)')
.option('--all', 'Allow all pending permissions for this agent') .option('--all', 'Allow all pending permissions for this agent')
.option('--input <json>', 'Modified input parameters (JSON)') .option('--input <json>', 'Modified input parameters (JSON)')
.option('--json', 'Output in JSON format') ).action(withOutput(runAllowCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runAllowCommand))
addJsonAndDaemonHostOptions(
permit permit
.command('deny') .command('deny')
.description('Deny a permission request') .description('Deny a permission request')
@@ -33,9 +33,7 @@ export function createPermitCommand(): Command {
.option('--all', 'Deny all pending permissions for this agent') .option('--all', 'Deny all pending permissions for this agent')
.option('--message <msg>', 'Denial reason message') .option('--message <msg>', 'Denial reason message')
.option('--interrupt', 'Stop agent after denial') .option('--interrupt', 'Stop agent after denial')
.option('--json', 'Output in JSON format') ).action(withOutput(runDenyCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runDenyCommand))
return permit return permit
} }
+5 -6
View File
@@ -2,25 +2,24 @@ import { Command } from 'commander'
import { runLsCommand } from './ls.js' import { runLsCommand } from './ls.js'
import { runModelsCommand } from './models.js' import { runModelsCommand } from './models.js'
import { withOutput } from '../../output/index.js' import { withOutput } from '../../output/index.js'
import { addJsonAndDaemonHostOptions } from '../../utils/command-options.js'
export function createProviderCommand(): Command { export function createProviderCommand(): Command {
const provider = new Command('provider').description('Manage agent providers') const provider = new Command('provider').description('Manage agent providers')
addJsonAndDaemonHostOptions(
provider provider
.command('ls') .command('ls')
.description('List available providers and status') .description('List available providers and status')
.option('--json', 'Output in JSON format') ).action(withOutput(runLsCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runLsCommand))
addJsonAndDaemonHostOptions(
provider provider
.command('models') .command('models')
.description('List models for a provider') .description('List models for a provider')
.argument('<provider>', 'Provider name (claude, codex, opencode)') .argument('<provider>', 'Provider name (claude, codex, opencode)')
.option('--thinking', 'Include thinking option IDs for each model') .option('--thinking', 'Include thinking option IDs for each model')
.option('--json', 'Output in JSON format') ).action(withOutput(runModelsCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runModelsCommand))
return provider return provider
} }
+16 -21
View File
@@ -1,29 +1,24 @@
import { Command } from "commander"; import { Command } from 'commander'
import { withOutput } from "../../output/index.js"; import { withOutput } from '../../output/index.js'
import { runSpeechModelsCommand } from "./models.js"; import { runSpeechModelsCommand } from './models.js'
import { runSpeechDownloadCommand } from "./download.js"; import { runSpeechDownloadCommand } from './download.js'
import { addJsonAndDaemonHostOptions, collectMultiple } from '../../utils/command-options.js'
function collectMultiple(value: string, previous: string[]): string[] {
return previous.concat([value]);
}
export function createSpeechCommand(): Command { export function createSpeechCommand(): Command {
const speech = new Command("speech").description("Manage local speech models"); const speech = new Command('speech').description('Manage local speech models')
addJsonAndDaemonHostOptions(
speech speech
.command("models") .command('models')
.description("List local speech model download status") .description('List local speech model download status')
.option("--json", "Output in JSON format") ).action(withOutput(runSpeechModelsCommand))
.option("--host <host>", "Daemon host target (default: local socket/pipe, then localhost:6767)")
.action(withOutput(runSpeechModelsCommand));
addJsonAndDaemonHostOptions(
speech speech
.command("download") .command('download')
.description("Download local speech models") .description('Download local speech models')
.option("--model <id>", "Model ID to download (repeatable)", collectMultiple, []) .option('--model <id>', 'Model ID to download (repeatable)', collectMultiple, [])
.option("--json", "Output in JSON format") ).action(withOutput(runSpeechDownloadCommand))
.option("--host <host>", "Daemon host target (default: local socket/pipe, then localhost:6767)")
.action(withOutput(runSpeechDownloadCommand));
return speech; return speech
} }
+5 -6
View File
@@ -2,24 +2,23 @@ import { Command } from 'commander'
import { runLsCommand } from './ls.js' import { runLsCommand } from './ls.js'
import { runArchiveCommand } from './archive.js' import { runArchiveCommand } from './archive.js'
import { withOutput } from '../../output/index.js' import { withOutput } from '../../output/index.js'
import { addJsonAndDaemonHostOptions } from '../../utils/command-options.js'
export function createWorktreeCommand(): Command { export function createWorktreeCommand(): Command {
const worktree = new Command('worktree').description('Manage Paseo-managed git worktrees') const worktree = new Command('worktree').description('Manage Paseo-managed git worktrees')
addJsonAndDaemonHostOptions(
worktree worktree
.command('ls') .command('ls')
.description('List Paseo-managed git worktrees') .description('List Paseo-managed git worktrees')
.option('--json', 'Output in JSON format') ).action(withOutput(runLsCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runLsCommand))
addJsonAndDaemonHostOptions(
worktree worktree
.command('archive') .command('archive')
.description('Archive a worktree (removes worktree and associated branch)') .description('Archive a worktree (removes worktree and associated branch)')
.argument('<name>', 'Worktree name or branch name') .argument('<name>', 'Worktree name or branch name')
.option('--json', 'Output in JSON format') ).action(withOutput(runArchiveCommand))
.option('--host <host>', 'Daemon host target (default: local socket/pipe, then localhost:6767)')
.action(withOutput(runArchiveCommand))
return worktree return worktree
} }
+23
View File
@@ -0,0 +1,23 @@
import type { Command } from 'commander'
const JSON_OPTION_DESCRIPTION = 'Output in JSON format'
const DAEMON_HOST_OPTION_DESCRIPTION =
'Daemon host target (default: local socket/pipe, then localhost:6767)'
export function collectMultiple(value: string, previous: string[]): string[] {
return previous.concat([value])
}
export function addJsonOption<T extends Command>(command: T): T {
command.option('--json', JSON_OPTION_DESCRIPTION)
return command
}
export function addDaemonHostOption<T extends Command>(command: T): T {
command.option('--host <host>', DAEMON_HOST_OPTION_DESCRIPTION)
return command
}
export function addJsonAndDaemonHostOptions<T extends Command>(command: T): T {
return addDaemonHostOption(addJsonOption(command))
}