fix(cli): only exit alternate screen buffer on SIGINT if it was entered#245
fix(cli): only exit alternate screen buffer on SIGINT if it was entered#245jrvb-rl wants to merge 2 commits into
Conversation
The global SIGINT handler unconditionally sent \x1b[?1049l even when no TUI was active (e.g. `rli d ssh` waiting for a provisioning devbox). Terminals restore their saved cursor position on that sequence, so Ctrl+C during a plain-text wait loop jumped the cursor to the top of the screen and left output garbled. Track whether the alternate screen buffer is actually active in screen.ts and guard the SIGINT handler so it only exits the buffer when needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| let _inAlternateScreenBuffer = false; | ||
|
|
||
| /** Returns true if the alternate screen buffer is currently active. */ | ||
| export function isInAlternateScreenBuffer(): boolean { |
There was a problem hiding this comment.
maybe worth adding a small test to verify isInAlternateScreenBuffer() starts as false, is true after enterAlternateScreenBuffer(), and false after exitAlternateScreenBuffer()
There was a problem hiding this comment.
Added tests/__tests__/utils/screen.test.ts covering false → true → false around enter/exit. (ac87f8b)
There was a problem hiding this comment.
we should also move, or document a follow-up to move, benchmark-job watch to use these helpers (right now it does its own handling of the raw escape sequences, but that also means isInAlternateScreenBuffer() is false when we're in the benchmark-job watch alternate screen buffer -- potential footgun)
There was a problem hiding this comment.
Migrated benchmark-job watch to the shared helpers (replaced its raw enterAltScreen/exitAltScreen/cursor/clear sequences). isInAlternateScreenBuffer() now reports true while in the watch alt-screen, so the global SIGINT handler restores it correctly. (ac87f8b)
…job watch to shared helpers Add a test verifying isInAlternateScreenBuffer() transitions false -> true -> false around enter/exit. Migrate benchmark-job watch off its own raw escape sequences to the shared screen helpers so isInAlternateScreenBuffer() correctly reports the alt-screen state, letting the global SIGINT handler restore the screen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
cli.tsunconditionally sent\x1b[?1049l(exit alternate screen buffer) on every Ctrl+C, even when no TUI was active.rli d sshprovisioning wait loop) rendered below the restored cursor.enterAlternateScreenBuffer()was actually called in a boolean inscreen.ts, and guard the SIGINT handler so it only exits the buffer when needed.Root cause
rli d ssh dbx_<id>goes through the plain Commander path — it never callsenterAlternateScreenBuffer(). Pressing Ctrl+C while waiting for a provisioning devbox fired the SIGINT handler which always wrote\x1b[?1049l. If the terminal had a stale saved-cursor position from a prior TUI session, that escape sequence restored it, jumping the cursor and garbling the output.Test plan
rli d ssh <id>against a provisioning devbox: confirm Ctrl+C exits cleanly with the cursor at the bottom of the output, no jumping.rli(interactive TUI): confirm Ctrl+C still exits the alternate screen buffer and restores the normal terminal view.rli d pty <id>: same check as TUI.🤖 Generated with Claude Code