diff --git a/src/commands/help-command.ts b/src/commands/help-command.ts index f3c8334b..70ea294d 100644 --- a/src/commands/help-command.ts +++ b/src/commands/help-command.ts @@ -214,6 +214,16 @@ Run ${color('ccs config', 'command')} for web dashboard`.trim(); ['/ccs:continue "follow-up"', 'Continue last delegation session'], ]); + // Delegation CLI Flags (Claude Code passthrough) + printSubSection('Delegation Flags (Claude Code passthrough)', [ + ['--max-turns ', 'Limit agentic turns (prevents loops)'], + ['--fallback-model ', 'Auto-fallback on overload (sonnet)'], + ['--agents ', 'Inject dynamic subagents'], + ['--betas ', 'Enable experimental features'], + ['--allowedTools ', 'Restrict available tools'], + ['--disallowedTools ', 'Block specific tools'], + ]); + // Diagnostics printSubSection('Diagnostics', [ ['ccs setup', 'First-time setup wizard'], diff --git a/src/delegation/delegation-handler.ts b/src/delegation/delegation-handler.ts index bfe4aa61..5526fcb6 100644 --- a/src/delegation/delegation-handler.ts +++ b/src/delegation/delegation-handler.ts @@ -17,7 +17,12 @@ interface ParsedArgs { timeout?: number; resumeSession?: boolean; sessionId?: string; - extraArgs?: string[]; // Passthrough args for Claude CLI + // Claude Code CLI passthrough flags (explicit) + maxTurns?: number; + fallbackModel?: string; + agents?: string; + betas?: string; + extraArgs?: string[]; // Catch-all for new/unknown flags }; } @@ -187,9 +192,45 @@ export class DelegationHandler { options.timeout = parseInt(args[timeoutIndex + 1], 10); } + // Parse --max-turns (limit agentic turns) + const maxTurnsIndex = args.indexOf('--max-turns'); + if (maxTurnsIndex !== -1 && maxTurnsIndex < args.length - 1) { + const val = parseInt(args[maxTurnsIndex + 1], 10); + if (!isNaN(val) && val > 0) { + options.maxTurns = val; + } + } + + // Parse --fallback-model (auto-fallback on overload) + const fallbackIndex = args.indexOf('--fallback-model'); + if (fallbackIndex !== -1 && fallbackIndex < args.length - 1) { + options.fallbackModel = args[fallbackIndex + 1]; + } + + // Parse --agents (dynamic subagent JSON) + const agentsIndex = args.indexOf('--agents'); + if (agentsIndex !== -1 && agentsIndex < args.length - 1) { + options.agents = args[agentsIndex + 1]; + } + + // Parse --betas (experimental features) + const betasIndex = args.indexOf('--betas'); + if (betasIndex !== -1 && betasIndex < args.length - 1) { + options.betas = args[betasIndex + 1]; + } + // Collect extra args to pass through to Claude CLI // CCS-handled flags with values (skip these and their values): - const ccsFlagsWithValue = new Set(['-p', '--prompt', '--timeout', '--permission-mode']); + const ccsFlagsWithValue = new Set([ + '-p', + '--prompt', + '--timeout', + '--permission-mode', + '--max-turns', + '--fallback-model', + '--agents', + '--betas', + ]); const extraArgs: string[] = []; const profile = this._extractProfile(args); diff --git a/src/delegation/executor/types.ts b/src/delegation/executor/types.ts index 4efd61c6..0bb0b922 100644 --- a/src/delegation/executor/types.ts +++ b/src/delegation/executor/types.ts @@ -55,7 +55,12 @@ export interface ExecutionOptions { resumeSession?: boolean; sessionId?: string; maxRetries?: number; - extraArgs?: string[]; // Passthrough args for Claude CLI + // Claude Code CLI passthrough flags (explicit) + maxTurns?: number; // --max-turns: Limit agentic turns (prevents infinite loops) + fallbackModel?: string; // --fallback-model: Auto-fallback when model overloaded + agents?: string; // --agents: Dynamic subagent JSON injection + betas?: string; // --betas: Enable experimental features + extraArgs?: string[]; // Catch-all for new/unknown flags (future-proof) } /** diff --git a/src/delegation/headless-executor.ts b/src/delegation/headless-executor.ts index 815c73a2..c837798b 100644 --- a/src/delegation/headless-executor.ts +++ b/src/delegation/headless-executor.ts @@ -41,6 +41,10 @@ export class HeadlessExecutor { permissionMode = 'acceptEdits', resumeSession = false, sessionId = null, + maxTurns, + fallbackModel, + agents, + betas, extraArgs = [], } = options; @@ -116,7 +120,21 @@ export class HeadlessExecutor { args.push('--disallowedTools', ...toolRestrictions.disallowedTools); } - // Passthrough extra args + // Claude Code CLI passthrough flags (explicit, validated) + if (maxTurns !== undefined && maxTurns > 0) { + args.push('--max-turns', String(maxTurns)); + } + if (fallbackModel) { + args.push('--fallback-model', fallbackModel); + } + if (agents) { + args.push('--agents', agents); + } + if (betas) { + args.push('--betas', betas); + } + + // Passthrough extra args (catch-all for new/unknown flags) if (extraArgs.length > 0) { args.push(...extraArgs); }