Skip to content

fix: permission mode switching not detected by remote session#1402

Open
zz327455573 wants to merge 1 commit into
slopus:mainfrom
zz327455573:fix/permission-mode-switching
Open

fix: permission mode switching not detected by remote session#1402
zz327455573 wants to merge 1 commit into
slopus:mainfrom
zz327455573:fix/permission-mode-switching

Conversation

@zz327455573

@zz327455573 zz327455573 commented Jun 15, 2026

Copy link
Copy Markdown

Problem

Switching permission modes (default → bypassPermissions/yolo) in the mobile app has no effect on the active Claude remote session. The session continues using the old permission mode, making mode switching appear "stuck".

Root Cause

Two bugs in the permission mode change detection pipeline:

Bug 1: Hash function doesn't capture permission mode changes

In runClaude.ts, the MessageQueue2 hash function uses:

isPlan: mode.permissionMode === 'plan',

This reduces all non-plan modes to isPlan: false, producing identical hashes. When nextMessage compares the incoming message's hash with the current mode hash, it never detects a change between default, acceptEdits, bypassPermissions, etc.

Bug 2: handleModeChange doesn't propagate to SDK

PermissionHandler.handleModeChange() only updates its internal permissionMode field but never calls the setPermissionModeCallback that propagates the change to the active Claude SDK query via q.setPermissionMode().

Fix

  1. Replace isPlan: mode.permissionMode === 'plan' with permissionMode: mode.permissionMode in the hash function — mode changes now produce different hashes, triggering the nextMessage mode-change detection path.

  2. Call setPermissionModeCallback in handleModeChange() — the active SDK query immediately picks up the new permission mode.

Testing

Verified on a live server: after applying these fixes, switching to YOLO mode in the mobile app correctly changes the Claude session's permission mode (confirmed by --permission-mode plan in the spawned process args and successful auto-approval of tool calls).

When switching permission modes (e.g. default → bypassPermissions) in the
mobile app, the Claude remote session failed to detect the change because:

1. The MessageQueue2 hash function used `isPlan: mode.permissionMode === 'plan'`
   instead of `permissionMode: mode.permissionMode`. This made all non-plan
   modes produce identical hashes, so the nextMessage callback never detected
   a mode change.

2. PermissionHandler.handleModeChange() only updated internal state but never
   called the SDK's setPermissionMode() callback, so the running Claude query
   kept the old permission mode.

Fix by:
- Including the full permissionMode string in the hash object
- Calling setPermissionModeCallback in handleModeChange to propagate mode
  changes to the active SDK query

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
DanielBiondi pushed a commit to DanielBiondi/happy that referenced this pull request Jun 18, 2026
…s; eliminate silent message loss

Cherry-picks slopus#1402, slopus#1157, slopus#1299 plus a broader ambient-default guard. With v1
we made 'auto' / 'dontAsk' acceptable; this makes them actually take effect.

- runClaude.ts (slopus#1402): hash on full permissionMode, not just isPlan -- the
  old hash collapsed every non-plan mode to the same value, so default->auto
  was invisible to nextMessage.
- permissionHandler.ts (slopus#1402 + slopus#1157): handleModeChange normalizes via
  mapToClaudeMode and propagates to the active SDK query via the
  setPermissionModeCallback. Without this, switching modes mid-session
  updated local state but the SDK never knew.
- permissionMode.ts (broader slopus#1235): protect ANY explicit non-default mode
  from the ambient 'default' the mobile app sends with every message.
- reducer.ts (slopus#1299): crypto.randomUUID instead of ~67-bit Math.random IDs
  to prevent birthday-paradox collisions silently overwriting messages.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant