Skip to content

fix(prompts): end an interrupted spinner with the signal status - #3432

Draft
jong-kyung wants to merge 6 commits into
voidzero-dev:mainfrom
jong-kyung:fix/prompts-spinner-signal-exit
Draft

jong-kyung wants to merge 6 commits into
voidzero-dev:mainfrom
jong-kyung:fix/prompts-spinner-signal-exit

Conversation

@jong-kyung

Copy link
Copy Markdown
Collaborator

Closes #3429. Supersedes #3345.

Summary

The TypeScript spinner reported an interrupt as success. This PR makes it end by the signal, as the Rust progress row does, so the shell reports 130 or 143.

Changes

  • Ctrl+C: a local input block replaces clack's block(), which calls process.exit(0). It stops the spinner
    and sends SIGINT to the foreground process group.
  • Escape: it no longer ends the process while a spinner is active.
  • SIGINT and SIGTERM: the spinner raises the signal again after it stops, but only when no other listener
    owns the signal.

clack's block() calls process.exit(0) on Ctrl+C and Escape, so an
interrupted command reported success. Replace it with a local input
block that stops the spinner and sends SIGINT to the foreground process
group, as the terminal does outside raw mode. Windows has no signals, so
the process exits with 130 there.

Escape and other keys are ignored, as the Rust progress row does. A key
pressed just before the spinner stops no longer leaves a listener on
stdin.

Refs voidzero-dev#3429
An active spinner listened for SIGINT and SIGTERM, stopped itself, and
returned, so the command kept running after a termination request.

Raise the signal again after stopping, but only when no other listener
owns it: none was registered before the spinner started and none was
added while it spun. An emit without the signal name only stops the
spinner. Windows exits with the matching status instead.

Closes voidzero-dev#3429
@jong-kyung jong-kyung self-assigned this Nov 11, 2026
@jong-kyung

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-11T08:13:19.527421Z e506d16 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19eee2b1a4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/prompts/src/spinner.ts Resolved
The Ctrl+C and Escape tests expected process.kill, which only the POSIX
branch calls. On Windows the spinner exits with 130 instead, so the
tests failed there. Pin a POSIX platform unless a test asks for Windows.
Each active spinner blocked input, so two spinners both received a
single Ctrl+C and each sent SIGINT to the process group. A shutdown
handler then saw two interrupts for one key press.

Let only one spinner block input at a time, as the Rust progress row
does. The others receive the forwarded signal through their signal
listeners.
The Ctrl+C test waited for the worker's PID to disappear. Where nothing
reaps orphans, as in some Linux containers, the worker stays a zombie
after the group is interrupted, so the test timed out although the
worker had ended. Read the process state on Linux and accept a zombie.
@jong-kyung

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 0be6ecfefe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

A spinner remembered that another listener had been registered for a
signal and never forgot it. After that listener was removed, a signal
only stopped the spinner and the command kept running.

Check the registered listeners when the signal arrives instead. Node
removes a one-shot listener just before calling it, so a removal during
the current delivery still counts as another owner, and its cleanup is
not cut short.
@jong-kyung

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: e506d16db5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@jong-kyung jong-kyung added test: e2e Auto run e2e tests test: install-e2e run vite install e2e test test: create-e2e Run `vp create` e2e tests labels Nov 11, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test: create-e2e Run `vp create` e2e tests test: e2e Auto run e2e tests test: install-e2e run vite install e2e test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spinner interrupt exit code differs between the Rust and TypeScript implementations

1 participant