diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 4a019a693..f42143b27 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -17,6 +17,7 @@ - Hid empty HTML comment separators in Markdown-rendered TUI output instead of displaying them literally ([#4911](https://github.com/can1357/oh-my-pi/issues/4911)). - Fixed automatic file completion treating punctuation, trailing spaces, and ambiguous slash-command text as paths, immediately dismissing slash autocomplete on Backspace and requiring selection before applying a sole forced file match ([#5376](https://github.com/can1357/oh-my-pi/issues/5376)). - Fixed Kitty graphics under tmux by wrapping every graphics command in DCS passthrough, preserving quiet mode across continuation chunks, and using Unicode placeholder cells for explicitly forced Kitty rendering so images follow pane scrolling and reflow. ([#5381](https://github.com/can1357/oh-my-pi/issues/5381)) +- Fixed tmux sessions becoming unresponsive after terminal capability replies by keeping keyboard input in legacy mode when the Kitty protocol is unavailable ([#5378](https://github.com/can1357/oh-my-pi/issues/5378)). ## [16.5.0] - 2026-07-13 diff --git a/packages/tui/src/terminal.ts b/packages/tui/src/terminal.ts index 4c622c620..2ad11d612 100644 --- a/packages/tui/src/terminal.ts +++ b/packages/tui/src/terminal.ts @@ -45,6 +45,7 @@ export function resolveHangulCompatibilityJamoWidthFromTerminalIdentity( } function shouldEnableModifyOtherKeysFallback(env: NodeJS.ProcessEnv = Bun.env): boolean { + if (isInsideTmux(env)) return false; if (!env.SSH_CONNECTION && !env.SSH_TTY && !env.SSH_CLIENT) return true; return TERMINAL.id !== "base" && TERMINAL.id !== "trueColor"; } diff --git a/packages/tui/test/kitty-keyboard-da1-ordering.test.ts b/packages/tui/test/kitty-keyboard-da1-ordering.test.ts index f38a158c5..300e16d1c 100644 --- a/packages/tui/test/kitty-keyboard-da1-ordering.test.ts +++ b/packages/tui/test/kitty-keyboard-da1-ordering.test.ts @@ -22,9 +22,10 @@ class ModalProbe implements Component { const originalSshConnection = Bun.env.SSH_CONNECTION; const originalSshTty = Bun.env.SSH_TTY; const originalSshClient = Bun.env.SSH_CLIENT; +const originalTmux = Bun.env.TMUX; const originalTerminalId = TERMINAL.id; -function restoreEnv(name: "SSH_CONNECTION" | "SSH_TTY" | "SSH_CLIENT", value: string | undefined): void { +function restoreEnv(name: "SSH_CONNECTION" | "SSH_TTY" | "SSH_CLIENT" | "TMUX", value: string | undefined): void { if (value === undefined) { delete Bun.env[name]; return; @@ -41,6 +42,7 @@ describe("ProcessTerminal kitty keyboard progressive-enhancement ordering", () = restoreEnv("SSH_CONNECTION", originalSshConnection); restoreEnv("SSH_TTY", originalSshTty); restoreEnv("SSH_CLIENT", originalSshClient); + restoreEnv("TMUX", originalTmux); Object.defineProperty(TERMINAL, "id", { value: originalTerminalId, configurable: true }); }); @@ -110,6 +112,23 @@ describe("ProcessTerminal kitty keyboard progressive-enhancement ordering", () = expect(harness.terminal.keyboardEnhancementEnterSequence).toBeNull(); }); + it("keeps legacy keyboard input under tmux when kitty is unavailable", async () => { + Bun.env.TMUX = "/tmp/tmux-501/default,1234,0"; + delete Bun.env.SSH_CONNECTION; + delete Bun.env.SSH_TTY; + delete Bun.env.SSH_CLIENT; + harness = createProcessTerminalRenderHarness(100, 30); + await harness.settle(); + harness.writes.length = 0; + + await harness.feed("\x1b[?1;2c"); + + const out = harness.writes.join(""); + expect(harness.terminal.kittyProtocolActive).toBe(false); + expect(out).not.toContain("\x1b[>4;2m"); + expect(harness.terminal.keyboardEnhancementEnterSequence).toBeNull(); + }); + it("reasserts modifyOtherKeys fallback when fullscreen overlays enter the alternate screen", async () => { harness = createProcessTerminalRenderHarness(100, 30); await harness.settle();