Repository navigation
Conversation
With stdin closed (`< /dev/null`, a CI runner, an agent shell) or a pipe that runs out before the last prompt, `prompt()` never settled: nothing resolved on the input ending, so `await confirm()` left an unsettled top-level await, Node exited 13 and the cursor stayed hidden. The input is now watched for `end`/`close`, and an input that already ended before the prompt started settles at once. Like the abort signal, it cancels: there is nothing left to read. A prompt that already submitted is untouched, and a validator that resolves after the prompt closed no longer emits a submit.
🦋 Changeset detectedLatest commit: a467781 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Author
|
Note on the red |
The first version of this test destroyed the stream, which reaches the cancel through the `close` event and therefore passed with the `readableEnded` check removed. A stream that ended before the prompt attached does not emit `end` again, which is the case the check exists for: the test now builds it with a finished `Readable` and asserts `readableEnded` first.
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.
What does this PR do?
Closes #615
When stdin ends while a prompt is waiting, or before it starts, nothing settles the prompt:
prompt()resolves only onsubmitandcancel, soawait confirm()leaves an unsettled top-level await, Node exits 13, and the cursor stays hidden. It happens with closed stdin (< /dev/null, some CI runners and agent shells) and with piped input that runs out before the last prompt.The input is now watched for
endandclose, and a prompt whose input already ended before it started settles immediately (readableEnded/destroyed) because no event is left to fire. Like the abort signal, ending input cancels — there is nothing left to read. A prompt that already submitted is untouched, the listeners are removed inclose(), and a validator that resolves after the prompt closed no longer emits asubmitfor a value nobody read.I reproduced the failure and the fix on real streams:
node repro.mjs < /dev/null— before:Warning: Detected unsettled top-level await ..., exit code 13; after:SETTLED {"cancel":true}, exit code 0.printf 'y\n' | cli— the answered prompt still submits (answer: true) and only the prompt whose input ran out cancels, so this is not a blanket "EOF cancels".master(noendleft to fire) and cancels here.Type of change
Checklist
pnpm testpasses (or targeted tests for my change)pnpm formathas been runpnpm test:@clack/core174 passed (13 files),@clack/prompts618 passed (20 files), 0 failed.pnpm run typesandpnpm run lintare clean. Three tests inpackages/core/test/prompts/prompt.test.ts: input ending while waiting, input that already ended before the prompt started, and the submitted value surviving anendafterwards. Both halves are pinned: with theendlistener removed the first test times out, and with thereadableEndedcheck removed the second one does.AI-generated code disclosure