diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 0507c6f0240..8362d3bdd9c 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -63,6 +63,7 @@ import { TuiConfigProvider, useTuiConfig } from "./context/tui-config" import { TuiConfig } from "@/config/tui" import { createTuiApi, TuiPluginRuntime, type RouteMap } from "./plugin" import { FormatError, FormatUnknownError } from "@/cli/error" +import { resetTerminalState } from "@tui/util/terminal" // kilocode_change async function getTerminalBackgroundColor(): Promise<"dark" | "light"> { // can't set raw mode if not a TTY @@ -197,6 +198,9 @@ export function tui(input: { await TuiPluginRuntime.dispose() } + // kilocode_change - safety net: ensure mouse tracking is disabled regardless of exit path + process.on("exit", resetTerminalState) // kilocode_change + const renderer = await createCliRenderer(rendererConfig(input.config)) await render(() => { @@ -1010,6 +1014,8 @@ function ErrorComponent(props: { renderer?.setTerminalTitle("") renderer?.destroy() win32FlushInputBuffer() + // kilocode_change - reset terminal state to disable mouse tracking on exit + resetTerminalState() 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 205025f867d..4f0c5eae0b2 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 { resetTerminalState } from "@tui/util/terminal" // kilocode_change type Exit = ((reason?: unknown) => Promise) & { message: { set: (value?: string) => () => void @@ -38,6 +39,7 @@ export const { use: useExit, provider: ExitProvider } = createSimpleContext({ renderer.setTerminalTitle("") renderer.destroy() win32FlushInputBuffer() + resetTerminalState() // kilocode_change if (reason) { const formatted = FormatError(reason) ?? FormatUnknownError(reason) if (formatted) { diff --git a/packages/opencode/src/cli/cmd/tui/util/terminal.ts b/packages/opencode/src/cli/cmd/tui/util/terminal.ts index 2b81068b3f9..a2e289b3e64 100644 --- a/packages/opencode/src/cli/cmd/tui/util/terminal.ts +++ b/packages/opencode/src/cli/cmd/tui/util/terminal.ts @@ -1,5 +1,29 @@ import { RGBA } from "@opentui/core" +// kilocode_change start +/** + * Write escape sequences to disable all mouse tracking modes and reset terminal state. + * This is a safety net to ensure the terminal is clean after exit, even if the renderer's + * cleanup didn't flush properly (e.g. on Windows). + */ +export function resetTerminalState() { + const sequences = [ + "\x1b[?1000l", // disable normal mouse tracking + "\x1b[?1002l", // disable button-event mouse tracking + "\x1b[?1003l", // disable any-event mouse tracking (all movement) + "\x1b[?1006l", // disable SGR extended mouse mode + "\x1b[?1015l", // disable RXVT mouse mode + "\x1b[> /**