Map Ctrl-C to exit code 130 (cancel) instead of 0#202
Merged
Conversation
The CLI's documented exit-code contract (REFERENCE.md / errors.py) already promised "130 — cancelled with Ctrl-C", but the interactive commands swallowed KeyboardInterrupt and returned 0. That made `assembly stream && next` run `next` after a Ctrl-C, and broke composition with make/just/CI, which read exit 0 as success. Map a cancel to its conventional Unix code (128 + SIGINT) in one place: run_command now catches KeyboardInterrupt and exits 130, and each interactive handler (stream/agent/agent-cascade/dictate/llm --follow/share/webhooks listen and the init/dev server runner) raises typer.Exit(130) after its clean "Stopped." flush rather than returning 0. SIGTERM, which core.signals already routes through the same clean-stop path, rides along to 130. The transcript is still saved and "Stopped." still prints — only the misleading exit 0 goes away; `q` in dictate still finishes with 0. Telemetry records the cancel as a new "cancelled" outcome (exit 130) so a Ctrl-C of a long-running stream/agent session doesn't inflate the crash rate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRiB7KpAgb833DkxHh5ntc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This change establishes a consistent exit code convention for user interrupts (Ctrl-C / SIGTERM) across all interactive and streaming commands. Previously, Ctrl-C was treated as a clean success (exit 0), which made it impossible for callers to distinguish between a normal completion and an interrupt. Now all Ctrl-C paths exit with code 130 (the conventional Unix "cancelled by SIGINT" code), while maintaining clean shutdown behavior.
Key Changes
Core interrupt handling: Added
CANCELLED_EXIT_CODE = 130constant inaai_cli/core/errors.pyas the single source of truth for cancel exit codes.Telemetry tracking: Updated
aai_cli/core/telemetry.pyto:KeyboardInterruptexceptions as "cancelled" rather than "internal_error"Command execution: Refactored
aai_cli/app/context.pyto:_run_body()helperKeyboardInterruptinrun_command()and map it totyper.Exit(code=130)Interactive commands: Updated all interactive/streaming commands to raise
typer.Exit(code=130)on Ctrl-C instead of returning cleanly:aai_cli/commands/llm/_exec.py(follow mode)aai_cli/commands/dictate/_exec.pyaai_cli/commands/agent/_exec.pyaai_cli/commands/agent_cascade/_exec.pyaai_cli/commands/share/_exec.pyaai_cli/commands/webhooks/_listen.pyaai_cli/streaming/session.py(batch streaming)aai_cli/init/runner.py(dev server)Tests: Updated all test expectations to verify exit code 130 on Ctrl-C, with clarified comments explaining the cancel semantics.
Implementation Details
KeyboardInterruptreachingrun_command) now exit 130 instead of Click's default exit 1.config pathcommand (which tolerates unreadable config) continues to skip telemetry/update-check wrappers as before.assembly stream && next_commandwill not runnext_commandif the user pressed Ctrl-C.https://claude.ai/code/session_01BRiB7KpAgb833DkxHh5ntc