Summary
outcome_from_exit_code() treats any exit code equal to 130 as an interruption, even when no KeyboardInterrupt/signal actually occurred.
Details
lib/python/base_cli/_lifecycle.py:114-121 (outcome_from_exit_code) special-cases exit_code == ExitCode.INTERRUPTED (130) and unconditionally returns InvocationOutcome("interrupted", "error", exit_code).
- Reached from
outcome_from_exception's click.exceptions.Exit branch (:137) and called from app.py:1016 and app.py:2855.
- Any command that
return 130 (e.g. forwarding a subprocess's exit status) or calls ctx.exit(130) for an unrelated reason gets recorded with outcome: "interrupted" in run.json, in history, and — for JSON mode — as "code": "interrupted" in the error envelope, even though nothing was interrupted.
Impact
Contradicts the README's own outcome table ("another returned nonzero integer → nonzero_return") and ExitCode.INTERRUPTED's documented meaning ("the user interrupted the command with Ctrl+C"). Only KeyboardInterrupt/click.Abort(cause=KeyboardInterrupt) should map to "interrupted".
Suggested fix
Have outcome_from_exit_code() always return "nonzero_return" for non-{0,2} codes; keep the "interrupted" kind exclusive to the exception-based paths in outcome_from_exception.
Summary
outcome_from_exit_code()treats any exit code equal to 130 as an interruption, even when noKeyboardInterrupt/signal actually occurred.Details
lib/python/base_cli/_lifecycle.py:114-121(outcome_from_exit_code) special-casesexit_code == ExitCode.INTERRUPTED(130) and unconditionally returnsInvocationOutcome("interrupted", "error", exit_code).outcome_from_exception'sclick.exceptions.Exitbranch (:137) and called fromapp.py:1016andapp.py:2855.return 130(e.g. forwarding a subprocess's exit status) or callsctx.exit(130)for an unrelated reason gets recorded withoutcome: "interrupted"inrun.json, in history, and — for JSON mode — as"code": "interrupted"in the error envelope, even though nothing was interrupted.Impact
Contradicts the README's own outcome table ("another returned nonzero integer →
nonzero_return") andExitCode.INTERRUPTED's documented meaning ("the user interrupted the command with Ctrl+C"). OnlyKeyboardInterrupt/click.Abort(cause=KeyboardInterrupt)should map to"interrupted".Suggested fix
Have
outcome_from_exit_code()always return"nonzero_return"for non-{0,2} codes; keep the"interrupted"kind exclusive to the exception-based paths inoutcome_from_exception.