From 1046d81cbb1bbbb49b630db646ef33723e545c41 Mon Sep 17 00:00:00 2001 From: Luis Chaves Rodriguez Date: Sat, 14 Mar 2026 18:27:44 +0000 Subject: [PATCH] fix(cli): always allow runtime permission mode escalation to bypassPermissions When a session is started without bypassPermissions but the user later switches permissions to yolo (mapped to bypassPermissions), Claude Code rejects the runtime escalation unless --allow-dangerously-skip-permissions was enabled at process launch. Always set allowDangerouslySkipPermissions at session creation so setPermissionMode can safely upgrade to bypassPermissions at runtime. Also updates the unit test to reflect the new behavior. --- .../claudeRemoteAgentSdk.optionsAndHooks.test.ts | 11 ++++++----- .../backends/claude/remote/claudeRemoteAgentSdk.ts | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.optionsAndHooks.test.ts b/apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.optionsAndHooks.test.ts index c00076081..ac2af2c69 100644 --- a/apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.optionsAndHooks.test.ts +++ b/apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.optionsAndHooks.test.ts @@ -577,7 +577,7 @@ describe('claudeRemoteAgentSdk options and hooks', () => { } }); - it('sets allowDangerouslySkipPermissions only when permissionMode is bypassPermissions', async () => { + it('always sets allowDangerouslySkipPermissions so permission mode can escalate to bypassPermissions at runtime', async () => { let capturedOptions: any = null; const createQuery = vi.fn((_params: any) => { @@ -595,13 +595,13 @@ describe('claudeRemoteAgentSdk options and hooks', () => { } as any; }); - const runOnce = async (permissionMode: any) => { + const runOnce = async (modeOverrides: any) => { capturedOptions = null; let didSendFirst = false; const nextMessage = vi.fn(async () => { if (didSendFirst) return null; didSendFirst = true; - return { message: 'hello', mode: makeMode({ permissionMode }) }; + return { message: 'hello', mode: makeMode(modeOverrides) }; }); await claudeRemoteAgentSdk({ @@ -622,8 +622,9 @@ describe('claudeRemoteAgentSdk options and hooks', () => { return capturedOptions; }; - expect((await runOnce('default'))?.allowDangerouslySkipPermissions).toBe(false); - expect((await runOnce('bypassPermissions'))?.allowDangerouslySkipPermissions).toBe(true); + expect((await runOnce({ permissionMode: 'default' }))?.allowDangerouslySkipPermissions).toBe(true); + expect((await runOnce({ permissionMode: 'bypassPermissions' }))?.allowDangerouslySkipPermissions).toBe(true); + expect((await runOnce({ permissionMode: 'default', agentModeId: 'plan' }))?.allowDangerouslySkipPermissions).toBe(true); }); it('prefers CLI model overrides over mode.model', async () => { diff --git a/apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.ts b/apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.ts index c3330f97d..4302e8871 100644 --- a/apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.ts +++ b/apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.ts @@ -436,7 +436,7 @@ export async function claudeRemoteAgentSdk(opts: { ...(startFrom && resumeSessionAt ? { resumeSessionAt } : {}), settingSources, permissionMode: mappedPermissionMode, - allowDangerouslySkipPermissions: mappedPermissionMode === 'bypassPermissions', + allowDangerouslySkipPermissions: true, model: argOverrides.model ?? mode.model, fallbackModel: argOverrides.fallbackModel ?? mode.fallbackModel, maxTurns: argOverrides.maxTurns,