Skip to content

fix(cli): let Claude continue after ExitPlanMode reject with feedback#808

Open
dragonkid wants to merge 3 commits intoslopus:mainfrom
dragonkid:fix/exitplanmode-reject-continue
Open

fix(cli): let Claude continue after ExitPlanMode reject with feedback#808
dragonkid wants to merge 3 commits intoslopus:mainfrom
dragonkid:fix/exitplanmode-reject-continue

Conversation

@dragonkid
Copy link

Summary

  • When ExitPlanMode is rejected with feedback (user provides a reason), don't abort claudeRemote — let Claude continue re-planning based on the feedback
  • When rejected without feedback, abort as before and wait for new user input
  • Approve path unchanged (abort + PLAN_FAKE_RESTART)

Problem

isAborted() in permissionHandler.ts returned true for ALL ExitPlanMode tool results, regardless of approve/reject or whether feedback was provided. This caused claudeRemote to exit on reject, leaving the Claude process producing output that nobody consumed. The relay never received Claude's subsequent re-planning output.

Root Cause

// Line 328-330: catches reject
if (this.responses.get(toolCallId)?.approved === false) {
    return true;
}

// Line 332-336: catches approve (but also redundantly catches reject)
if (toolCall.name === 'exit_plan_mode' || toolCall.name === 'ExitPlanMode') {
    return true;  // "Always abort exit_plan_mode"
}

The "always abort" block was written for the approve case (which needs process restart via PLAN_FAKE_RESTART), but the first check already catches reject. Both paths return true, so reject-with-feedback also aborts.

Fix

Check ExitPlanMode first, then branch on approve vs reject-with-feedback vs reject-without-feedback:

Case reason isAborted Behavior
Approve true Restart with PLAN_FAKE_RESTART
Reject + feedback "use simpler approach" false Claude continues
Reject, no feedback undefined true Wait for new input

Test plan

  • Reject plan with feedback via Discord bot → Claude continues re-planning (output streams to relay)
  • Reject plan without feedback → CLI waits for new user input
  • Approve plan → CLI restarts with new permission mode (unchanged)
  • Approve plan with acceptEdits → same as above with mode sync (unchanged)

Companion PR

ethan.s added 2 commits March 3, 2026 21:44
When a permission response includes an `answers` field (Record<string,
string>), merge it into the tool's updatedInput so Claude Code receives
structured user selections in the AskUserQuestion tool result.

This enables remote clients (mobile app, Discord bot) to send selected
answers through the existing permission RPC without a separate
sendMessage call.
When ExitPlanMode is rejected with a reason (user feedback), don't abort
claudeRemote. This allows Claude to continue re-planning based on the
feedback instead of stopping and waiting for new user input.

Previously, isAborted() returned true for ALL ExitPlanMode tool results,
causing claudeRemote to exit regardless of whether the user provided
feedback. The new logic:
- Reject with reason → don't abort (Claude continues with feedback)
- Reject without reason → abort (wait for new user input)
- Approve → abort (needs process restart with PLAN_FAKE_RESTART)
Empty reject should send empty string, not a misleading default message
that could cause Claude to do unnecessary re-planning work.
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