Skip to content

TUI leaves terminal in raw/corrupted state on /exit under Alacritty + zellij-windows (Windows ConPTY) #48776

Description

@kraso

Description

OpenCode CLI's TUI intermittently leaves the terminal in a corrupted state when exiting via /exit while running inside Alacritty + Zellij on Windows. No response/confirmation is needed from the maintainers below — this is a bug report.

Environment

  • OS: Windows 11 (10.0.26200)
  • Terminal: Alacritty 0.17.0
  • Multiplexer: arndawg.zellij-windows 0.43.1-win32.5 (community fork; zellij has no official Windows support)
  • OpenCode version: 1.18.30
  • Shell in pane: PowerShell / pwsh

Expected behavior

Exiting via /exit closes OpenCode cleanly and returns to the pane's shell, leaving the Zellij pane usable (and showing the session-reminder message so the session can be resumed). This occasionally happens — the correct behavior — but the result is unpredictable across runs.

Actual (erratic) behavior

Three different outcomes occur non-deterministically:

  1. Pane closes too: exiting via /exit sometimes also drops the whole Zellij pane.
  2. Clean exit: only OpenCode closes; the pane stays alive and usable (expected).
  3. Corrupted terminal state: before any exit, the app freezes and a series of strange characters appears at the bottom of the pane "as if the terminal were available when it is not". Pressing keys or moving the mouse then emits further gibberish — a mix of special characters, numbers and closing brackets (typical of leaked raw-mode sequences, e.g. raw mouse-report sequences like ESC[<...M).

Root-cause hypothesis

The TUI renderer is acquired with Effect.acquireRelease(...) and calls destroyRenderer() on release, which exits the alternate screen buffer and restores cooked terminal mode (see packages/tui/src/app.tsx). If that cleanup is bypassed — process.exit(), SIGKILL, or the renderer release being interrupted when the multiplexer tears down the PTY — the terminal remains in raw mode on the alternate screen. Under Windows ConPTY with a second Pty layer (the zellij-windows fork), the mode reset is not propagated to the outer terminal when the process dies uncleanly, so subsequent input/output prints uninterpreted escape sequences.

Mouse reporting is enabled by default (useMouse), which accounts for the numeric/bracket garbage once the terminal state has leaked.

Steps to reproduce

  1. Launch Alacritty.
  2. Start zellij (0.43.1-win32.5).
  3. In a pane, run opencode.
  4. Use the TUI normally, then exit via /exit.
  5. Repeat several times (also try closing the pane while OpenCode is running).

Observe the three outcomes above. Once in the corrupted state, any keypress/mouse move prints additional raw escape sequences until the pane is force-closed.

Suggested areas to investigate

  • Guarantee destroyRenderer() runs on every exit path (clean /exit, Ctrl+C, process exit, and external PTY close).
  • Consider a fallback (e.g. atexit/signal handler) that force-resets the terminal (\x1b[0m, leave alternate screen, disable mouse reporting, restore cooked mode) even on abnormal termination.
  • Test under a single ConPTY layer (plain Alacritty tab, no zellij) to confirm the multi-Pty ConPTY interaction.

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions