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 |
|
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.
|
Hi — a quick check on this one: is settling the prompt when its input stream ends something you would like to take? The branch is green apart from the If there is no interest I will go ahead and close it in ten days or so, no worries at all — I would just rather keep the queue here tidy than leave it sitting. |
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