From c43ec24a82836e6b8dd9d86607a55f9540f3e5fd Mon Sep 17 00:00:00 2001 From: Tim Richardson Date: Tue, 31 Mar 2026 17:31:08 +1100 Subject: [PATCH] fix(tui): restore terminal modes on exit --- .../src/cli/cmd/tui/component/error-component.tsx | 3 +++ packages/opencode/src/cli/cmd/tui/context/exit.tsx | 3 +++ packages/opencode/src/cli/cmd/tui/util/terminal.ts | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/packages/opencode/src/cli/cmd/tui/component/error-component.tsx b/packages/opencode/src/cli/cmd/tui/component/error-component.tsx index c568e54e4262..602d5974510c 100644 --- a/packages/opencode/src/cli/cmd/tui/component/error-component.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/error-component.tsx @@ -4,6 +4,7 @@ import { Clipboard } from "@tui/util/clipboard" import { createSignal } from "solid-js" import { Installation } from "@/installation" import { win32FlushInputBuffer } from "../win32" +import { Terminal } from "../util/terminal" export function ErrorComponent(props: { error: Error @@ -18,7 +19,9 @@ export function ErrorComponent(props: { const handleExit = async () => { await props.onBeforeExit?.() renderer.setTerminalTitle("") + Terminal.restore() renderer.destroy() + Terminal.restore() win32FlushInputBuffer() await props.onExit() } diff --git a/packages/opencode/src/cli/cmd/tui/context/exit.tsx b/packages/opencode/src/cli/cmd/tui/context/exit.tsx index 205025f867de..c39efdc0af23 100644 --- a/packages/opencode/src/cli/cmd/tui/context/exit.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/exit.tsx @@ -2,6 +2,7 @@ import { useRenderer } from "@opentui/solid" import { createSimpleContext } from "./helper" import { FormatError, FormatUnknownError } from "@/cli/error" import { win32FlushInputBuffer } from "../win32" +import { Terminal } from "../util/terminal" type Exit = ((reason?: unknown) => Promise) & { message: { set: (value?: string) => () => void @@ -36,7 +37,9 @@ export const { use: useExit, provider: ExitProvider } = createSimpleContext({ await input.onBeforeExit?.() // Reset window title before destroying renderer renderer.setTerminalTitle("") + Terminal.restore() renderer.destroy() + Terminal.restore() win32FlushInputBuffer() if (reason) { const formatted = FormatError(reason) ?? FormatUnknownError(reason) diff --git a/packages/opencode/src/cli/cmd/tui/util/terminal.ts b/packages/opencode/src/cli/cmd/tui/util/terminal.ts index 2b81068b3f94..44f7895bb884 100644 --- a/packages/opencode/src/cli/cmd/tui/util/terminal.ts +++ b/packages/opencode/src/cli/cmd/tui/util/terminal.ts @@ -1,7 +1,16 @@ import { RGBA } from "@opentui/core" export namespace Terminal { + const RESET = + "\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1004l\x1b[?1005l\x1b[?1006l\x1b[?1015l\x1b[?1016l\x1b[?2004l\x1b[?25h" + export type Colors = Awaited> + + export function restore() { + if (!process.stdout.isTTY) return + process.stdout.write(RESET) + } + /** * Query terminal colors including background, foreground, and palette (0-15). * Uses OSC escape sequences to retrieve actual terminal color values.