Conversation
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
Please edit this PR description to address the above within 2 hours, or it will be automatically closed. If you believe this was flagged incorrectly, please let a maintainer know. |
|
The following comment was made by an LLM, it may be inaccurate: Found one potentially related PR: PR #48878: fix(tui): force terminal reset on exit for Windows ConPTY This PR is related because it also addresses terminal reset issues on exit, though it's Windows ConPTY-specific while PR #49089 provides a general cross-platform terminal reset mechanism. These PRs may complement each other or could be consolidated depending on their implementation approaches. |
|
This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window. Feel free to open a new pull request that follows our guidelines. |
fix(tui): reset terminal modes and position epilogue cleanly on exit
Fixes #48776 · Refs #38860
Problem
When the TUI exits, the terminal can be left in a corrupted state and the
session epilogue can overprint restored shell content:
@opentui/core's teardown does not disable every mode the rendererenabled (mouse reporting, application cursor keys, kitty keyboard
protocol, bracketed paste). Mouse movement and key presses then emit raw
escape sequences into the shell. Previously reported in TUI leaves terminal in raw/corrupted state on /exit under Alacritty + zellij-windows (Windows ConPTY) #48776, Mouse tracking state not reset on exit (/exit) #38860,
TUI: incomplete terminal teardown on exit — mouse tracking, alt-screen, bracketed paste left enabled #32336, Terminal left in raw mode on exit (Alacritty, Ubuntu 24.04, zsh, v1.17.9) #34397.
terminal emulator. Apple Terminal restores it to the top-left corner, so
the epilogue (logo + Session/Continue lines) written on exit overprints
restored shell content and the shell prompt ends up on the wrong line.
Change
packages/tui/src/util/renderer.tsterminalReset(): synchronously writes a minimal ANSI reset sequence(application cursor keys off, show cursor, default cursor shape, kitty
keyboard off, mouse reporting off, bracketed paste off, SGR reset). No-op
when stdout is not a TTY.
destroyRenderer()now emitsterminalReset()right afterrenderer.destroy().packages/tui/src/app.tsxprocess.on("exit", terminalReset)so modes are restored evenwhen the process exits without going through the scoped renderer teardown
(e.g. an uncaught error).
\x1b[2J\x1b[H(clear screen + home) sothe epilogue renders at the top of a clean screen regardless of where the
terminal restored the cursor.
How did you verify your code works?
bun typecheckinpackages/tui— passes, no new errors.bun ./packages/opencode/script/build.ts --singleand smoke-testedopencode --version.opened a session, and exited via
/exit:\x1b[?1000l(mouse off),\x1b[?1l,\x1b[>1u,\x1b[?2004lare allemitted after the last enable.
\x1b[2J\x1b[His emitted immediately before the epilogue.Checklist