fix(login): allow ctrl-c to cancel browser login#1126
Conversation
The spinner during `sanity login` was started with ora's default `discardStdin: true`, which puts stdin in raw mode. In our particular setup this could leave Ctrl+C unhandled and hang the command despite the spinner text inviting the user to cancel. Passing `discardStdin: false` keeps stdin in cooked mode so the terminal delivers SIGINT and the process exits as expected.
|
Claude finished @runeb's task in 56s —— View job Review
Missing changeset. This is a user-facing bug fix in ---
"@sanity/cli": patch
---
Allow Ctrl+C to cancel `sanity login` while the browser callback is pending.Nit (optional). No other issues. The change is minimal and scoped to the one call site that prompts the user to press Ctrl+C, which is the right place to opt out of |
📦 Bundle Stats —
|
| Metric | Value | vs main (cd110e7) |
|---|---|---|
| Internal (raw) | 2.1 KB | - |
| Internal (gzip) | 799 B | - |
| Bundled (raw) | 10.97 MB | - |
| Bundled (gzip) | 2.06 MB | - |
| Import time | 810ms | -2ms, -0.2% |
bin:sanity
| Metric | Value | vs main (cd110e7) |
|---|---|---|
| Internal (raw) | 1023 B | - |
| Internal (gzip) | 486 B | - |
| Bundled (raw) | 9.84 MB | - |
| Bundled (gzip) | 1.77 MB | - |
| Import time | 1.90s | +2ms, +0.1% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — @sanity/cli-core
Compared against main (cd110e7c)
| Metric | Value | vs main (cd110e7) |
|---|---|---|
| Internal (raw) | 97.0 KB | - |
| Internal (gzip) | 22.7 KB | - |
| Bundled (raw) | 21.61 MB | - |
| Bundled (gzip) | 3.42 MB | - |
| Import time | 772ms | -2ms, -0.3% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — create-sanity
Compared against main (cd110e7c)
| Metric | Value | vs main (cd110e7) |
|---|---|---|
| Internal (raw) | 908 B | - |
| Internal (gzip) | 483 B | - |
| Bundled (raw) | 931 B | - |
| Bundled (gzip) | 491 B | - |
| Import time | ❌ ChildProcess denied: node | - |
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
Coverage Delta
Comparing 1 changed file against main @ Overall Coverage
|
Description
sanity login(browser-callback flow) used a spinner with ora's defaultdiscardStdin: true. The spinner text invites the user to cancel ("Press Ctrl + C to cancel"), but Ctrl+C did nothing.This is a documented ora gotcha. From the ora README:
discardStdin: falseis one of the two officially recommended workarounds. See also ora#156 — ctrl + c not working (closed with no clean fix; the README note above is effectively the resolution).In our specific case the re-emit path also breaks for a more interesting reason:
getProvider()runs its own spinner immediately before this one (packages/@sanity/cli/src/actions/auth/login/getProvider.ts:44). Both spinners drive the samestdin-discardersingleton, and the back-to-backstart → stop → startcycle leaves stdin in a state where the second spinner's data listener never sees the0x03byte. Adding anyprocess.stdin.on('data', …)listener after the second spinner starts unsticks it — which is consistent with the TTY-state-corruption family of bugs around raw-mode toggling. Untangling that is out of scope here;discardStdin: falsesidesteps the whole thing for this call site.The same pattern (sequential spinners) likely affects other commands; we should sweep them in a follow-up.
What to review
packages/@sanity/cli/src/actions/auth/login/login.ts— one option added to the spinner.Testing
Manual:
pnpm build:cli./packages/@sanity/cli/bin/run.js login --provider google(with or without--no-open— both reproduce)Reverting the change reproduces the hang.
No new automated test — the bug depends on TTY/stdin raw-mode interaction that's awkward to simulate in unit tests.