Repository navigation
fix(interactive): keep the shell alive on Ctrl+C at a y/n prompt - #475
Merged
Merged
Conversation
Pressing Ctrl+C at a promptForConfirmation prompt inside `ably interactive` exited the whole shell with code 0 instead of cancelling the command. With no SIGINT listener, readline handles Ctrl+C by silently closing the confirm's interface, so its promise never settles. The shell's readline is paused while a command runs, so nothing keeps the event loop alive and Node drains it and exits. It was not the shell's readline 'close' handler: that would exit 42 in wrapper mode, and --trace-exit shows no process.exit call. The prompt now closes and rejects with an InterruptError on Ctrl+C. Callers already route rejections through fail(), and the shell's catch returns to the prompt. It rejects rather than answering "no" because several callers (login, invalid-key removal, init) carry on when the answer is no. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThis PR fixes a bug in Changes
Review Notes
|
splindsay-92
approved these changes
Oct 21, 2026
This branch was successfully deployed
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.
Why
Inside
ably interactive, pressing Ctrl+C at a[y/n]confirmation (for examplepush devices remove dev1) exited the whole shell with code 0. It should cancel that one command and return toably>, the way Ctrl+C at a running command already does.Root cause
The original suspicion was the shell's readline
closehandler. It isn't that:--trace-exitshows noprocess.exitcall.What actually happens:
promptForConfirmationcreates its own readline on stdin with noSIGINTlistener.rl.questionpromise never settles.handleCommandis fire-and-forget. Nothing keeps the event loop alive, so Node drains it and exits with code 0.Fix
On Ctrl+C,
promptForConfirmationnow closes its interface and rejects with anInterruptError("Interrupted by user"). Callers already send rejections throughfail(), and the interactive shell's catch block prints the message and redraws the prompt.interactive.tsneeded no change.Rejected alternative: resolving
false(treating Ctrl+C as "no"). Several callers carry on when the answer is no: login's "create your first app?", "running the control plane locally?" and "use a different alias?", base-command's "remove invalid key?", and init's global install. For those, Ctrl+C would have meant "no, keep going".Outside interactive mode, Ctrl+C at a confirm now exits 1 with "Interrupted by user". Before this change it exited 0 silently, for the same drain reason.
Interaction with #474 (DX-1967)
#474 adds
forwardSigintToProcess(rl)to this prompt: on Ctrl+C it closes the prompt and re-raises the signal as a process SIGINT. That alone doesn't settle the promise, which is why this bug reproduced with it applied. Whichever PR merges second needs to combine the two:ably accounts loginreliably #474).ably accounts loginreliably #474'sInterruptErrorfromsigint-cancellation.tsrather than the class added here.If two separate classes survive the merge, the prompt's rejection reaches
withSigintCancellation's race before the re-raised signal does. Login'sinstanceof InterruptErrorcheck would then miss it, and login would exit 1 instead of 130.Tests
test/tty/commands/interactive-confirm-sigint.test.ts:push devices removeconfirm;ably>;versionand exits 42 onexit.InterruptErrorand closes its interface on SIGINT.Not fixed here
Answering
n+ Enter at the same prompt in interactive mode echoesnn, and the shell then runsnas a command ("Command n not found"). The paused shell readline still has itslinelistener attached. That is a separate bug, to be fixed in its own PR.🤖 Generated with Claude Code