From 40ff9cecf03127e548320a5a111be4b4345f1349 Mon Sep 17 00:00:00 2001 From: andywendt Date: Sat, 17 Jan 2026 13:28:39 -0700 Subject: [PATCH] fix: set permissionMode when --yolo flag is used The --yolo flag only passed --dangerously-skip-permissions to Claude CLI but did not set options.permissionMode internally. This caused the PermissionHandler to stay in "default" mode for remote/mobile sessions, resulting in permission prompts even when yolo mode was selected. Additionally, when the CLI is started with --yolo, messages from the mobile app with permissionMode: "default" would override the CLI's setting. Now the CLI's explicit mode is preserved unless the mobile explicitly chooses a different mode. Fixes slopus/happy#206 Co-Authored-By: Claude --- src/claude/runClaude.ts | 16 +++++++++++++--- src/index.ts | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/claude/runClaude.ts b/src/claude/runClaude.ts index bcdd74fd..73625371 100644 --- a/src/claude/runClaude.ts +++ b/src/claude/runClaude.ts @@ -241,6 +241,7 @@ export async function runClaude(credentials: Credentials, options: StartOptions // Forward messages to the queue // Permission modes: Use the unified 7-mode type, mapping happens at SDK boundary in claudeRemote.ts let currentPermissionMode: PermissionMode | undefined = options.permissionMode; + const cliPermissionMode = options.permissionMode; // Remember CLI's explicit permission mode (e.g., --yolo) let currentModel = options.model; // Track current model state let currentFallbackModel: string | undefined = undefined; // Track current fallback model let currentCustomSystemPrompt: string | undefined = undefined; // Track current custom system prompt @@ -250,11 +251,20 @@ export async function runClaude(credentials: Credentials, options: StartOptions session.onUserMessage((message) => { // Resolve permission mode from meta - pass through as-is, mapping happens at SDK boundary + // If CLI was started with explicit mode (e.g., --yolo), don't let "default" messages override it let messagePermissionMode: PermissionMode | undefined = currentPermissionMode; if (message.meta?.permissionMode) { - messagePermissionMode = message.meta.permissionMode; - currentPermissionMode = messagePermissionMode; - logger.debug(`[loop] Permission mode updated from user message to: ${currentPermissionMode}`); + const incomingMode = message.meta.permissionMode as PermissionMode; + // Only override CLI's explicit mode if message has a non-default mode + // This ensures --yolo persists unless mobile explicitly changes to a different mode + if (cliPermissionMode && incomingMode === 'default') { + messagePermissionMode = cliPermissionMode; + logger.debug(`[loop] Keeping CLI permission mode (${cliPermissionMode}) instead of message's "default"`); + } else { + messagePermissionMode = incomingMode; + currentPermissionMode = messagePermissionMode; + logger.debug(`[loop] Permission mode updated from user message to: ${currentPermissionMode}`); + } } else { logger.debug(`[loop] User message received with no permission mode override, using current: ${currentPermissionMode}`); } diff --git a/src/index.ts b/src/index.ts index c7ec6b15..3f98dee4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -491,6 +491,8 @@ ${chalk.bold('To clean up runaway processes:')} Use ${chalk.cyan('happy doctor c } else if (arg === '--yolo') { // Shortcut for --dangerously-skip-permissions unknownArgs.push('--dangerously-skip-permissions') + // Also set internal permissionMode for PermissionHandler (fixes #206) + options.permissionMode = 'bypassPermissions' } else if (arg === '--started-by') { options.startedBy = args[++i] as 'daemon' | 'terminal' } else if (arg === '--js-runtime') {