fix(cx-gakp): persist Claude permission suggestions
Summary
acpmux's Claude stdio adapter now answers Claude Code's can_use_tool asks the way Claude Code itself does.
- Allow always. The adapter keeps Claude's
permission_suggestionswith the control request id. When the person picksallow_always, it returns them unchanged asupdatedPermissions, which is the only way Claude installs the rule.allow_oncenever sends them. "Allow for this session" is offered only when Claude sent at least one suggestion; an empty or missing list hides it, so there is no "always" option that does nothing. - Reject. The pane labels the reject "No, tell Claude what to do differently" and moves focus to the composer. acpmux used to send a plain deny, so Claude carried on with the turn by itself. The person's
reject_oncenow sends{"behavior":"deny","message":…,"interrupt":true}, which is Claude Code's own "No, and tell Claude what to do differently". The shape comes from the Claude CLI 2.1.299 bundle: its SDKcan_use_toolresponse schema is{behavior:"deny", message, interrupt?: boolean}, and the handler logsSDK permission prompt deny+interruptand aborts the turn. Cancels, errors and unknown options still send the plain deny.
Verification
The behavior test runs at the product boundary: fork_through::claude_permission_answers::claude_gets_the_persons_permission_answer_as_claude_code_defines_it. The person answers three scripted can_use_tool asks from fake_claude.py, each carrying permission_suggestions, and the test checks the control response Claude Code receives for each.
Both runs used the same fleet command: scripts/ci/cmux-tui-rust-check.sh test claude_gets_the_persons_permission_answer.
- Red, on test commit 2df7fae16ec5 (before the fix):
panicked at claude_permission_answers.rs:94:5 left: Null right: true. That is the interrupt assertion; the allow_once and allow_always assertions passed. - Green, on merged head 7851c01fc38b (fix 5bbddb8a6c87 + base merge 705b5d752d18):
test fork_through::claude_permission_answers::claude_gets_the_persons_permission_answer_as_claude_code_defines_it ... ok(1 passed).
Local checks: cargo fmt --check -p acpmux and scripts/cmux-next/crash_ratchet.py both pass. No unit tests were added.
Changelog
Fixed: Claude's "Yes, and don't ask again" now saves Claude's suggested permission rule, and "No, tell Claude what to do differently" stops Claude's turn so it waits for your message.
🤖 Generated with Claude Code