From 74a02b67c9737428c0f8c656f2041458c54dd6f8 Mon Sep 17 00:00:00 2001 From: t Date: Thu, 4 Jun 2026 16:41:41 +0800 Subject: [PATCH] fix(cli): wire --permission-mode as a true alias for --mode Previously --permission-mode was parsed and validated but stored into a separate ParsedArgs.permissionMode field that cli.ts never read (only args.mode is forwarded to the agent), so "deepcode --permission-mode plan" silently ran in the default mode with no feedback. It now sets out.mode directly, matching the documented "alias for --mode" semantics, and the dead permissionMode field is removed. Last flag wins when both --mode and --permission-mode are given. Adds parse-args tests for the alias and the last-wins precedence. docs/BEHAVIOR_PARITY.md already marks the combined --mode / --permission-mode row as supported; this fix makes that accurate. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/cli/src/parse-args.test.ts | 17 +++++++++++++++++ apps/cli/src/parse-args.ts | 6 ++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/cli/src/parse-args.test.ts b/apps/cli/src/parse-args.test.ts index 749474c..a115b65 100644 --- a/apps/cli/src/parse-args.test.ts +++ b/apps/cli/src/parse-args.test.ts @@ -63,6 +63,23 @@ describe('parseArgs', () => { expect(p.unknownFlags).toContain('--mode invalid'); }); + it('--permission-mode is a true alias for --mode (sets mode, is wired)', () => { + // Regression: previously parsed into a separate field that cli.ts never read, + // so --permission-mode was silently ignored. It must set `mode` like --mode. + expect(parseArgs(['--permission-mode', 'plan']).mode).toBe('plan'); + expect(parseArgs(['--permission-mode', 'bypassPermissions']).mode).toBe('bypassPermissions'); + const p = parseArgs(['--permission-mode', 'invalid']); + expect(p.mode).toBeUndefined(); + expect(p.unknownFlags).toContain('--permission-mode invalid'); + }); + + it('--mode and --permission-mode: last flag wins', () => { + expect(parseArgs(['--mode', 'plan', '--permission-mode', 'acceptEdits']).mode).toBe( + 'acceptEdits', + ); + expect(parseArgs(['--permission-mode', 'acceptEdits', '--mode', 'plan']).mode).toBe('plan'); + }); + it('--effort validation', () => { expect(parseArgs(['--effort', 'high']).effort).toBe('high'); expect(parseArgs(['--effort', 'wrong']).unknownFlags).toContain('--effort wrong'); diff --git a/apps/cli/src/parse-args.ts b/apps/cli/src/parse-args.ts index 23d4323..f2fc27f 100644 --- a/apps/cli/src/parse-args.ts +++ b/apps/cli/src/parse-args.ts @@ -21,7 +21,6 @@ export interface ParsedArgs { // Session shaping mode?: Mode; - permissionMode?: Mode; model?: string; effort?: Effort; maxTurns?: number; @@ -159,9 +158,12 @@ export function parseArgs(argv: string[]): ParsedArgs { else out.unknownFlags.push(`--mode ${v ?? ''}`); break; } + // Claude Code alias for --mode: set out.mode directly so it's actually + // wired through cli.ts (which only forwards args.mode). Last flag wins if + // both --mode and --permission-mode are given. case a === '--permission-mode': { const v = next(); - if (v && (VALID_MODES as string[]).includes(v)) out.permissionMode = v as Mode; + if (v && (VALID_MODES as string[]).includes(v)) out.mode = v as Mode; else out.unknownFlags.push(`--permission-mode ${v ?? ''}`); break; }