diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index ff17b6142..85a986bff 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Changed + +- Updated the session-continuation tip to mention Zellij and WezTerm panes. + ## [15.12.3] - 2026-06-12 ### Fixed diff --git a/packages/coding-agent/src/modes/components/tips.txt b/packages/coding-agent/src/modes/components/tips.txt index cf86a5ff3..8c06cf92b 100644 --- a/packages/coding-agent/src/modes/components/tips.txt +++ b/packages/coding-agent/src/modes/components/tips.txt @@ -6,7 +6,7 @@ Find out which model you emotionally abuse the most with `omp stats` Try task isolation to create CoW worktrees Need a cheap nested model call? Use `completion(x...)`. Have a big batch of tasks? Ask clanker to use it! Spaghetti code? Try complaining with /omfg -Did you know? Each kitty/tmux/cmux split keeps its own session — `omp -c` resumes the right one +Did you know? Each kitty/tmux/cmux/zellij/wezterm split keeps its own session — `omp -c` resumes the right one Drop the word `ultrathink` in your message for harder multi-step reasoning — watch it glow rainbow as you type Say `orchestrate` in your message to drive a multi-phase task with parallel subagents — watch it glow as you type Say `workflowz` in your message to drive the task with parallel subagents in eval — watch it glow as you type diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 09f2d355a..00a746a7b 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added Zellij and WezTerm pane environment fallbacks for terminal-specific session continuation when no TTY path is available. + ## [15.11.8] - 2026-06-12 ### Changed diff --git a/packages/tui/src/ttyid.ts b/packages/tui/src/ttyid.ts index 5933a7cdc..7d0db608c 100644 --- a/packages/tui/src/ttyid.ts +++ b/packages/tui/src/ttyid.ts @@ -51,15 +51,29 @@ export function getTerminalId(): string | null { // Fallback to terminal-specific env vars // Prefer inner multiplexers over host terminal emulators when stdin has no TTY path. + const zellijPane = process.env.ZELLIJ_PANE_ID; + if (zellijPane) { + // Session names are user-chosen (`zellij -s …`) and the id is used as a + // breadcrumb filename — normalize path separators like the TTY branch does. + const zellijSession = process.env.ZELLIJ_SESSION_NAME?.replace(/[\\/]/g, "-"); + return zellijSession ? `zellij-${zellijSession}-${zellijPane}` : `zellij-${zellijPane}`; + } + const tmuxPane = process.env.TMUX_PANE; if (tmuxPane) return `tmux-${tmuxPane}`; const cmuxSurface = process.env.CMUX_SURFACE_ID; if (cmuxSurface) return `cmux-${cmuxSurface}`; + // Kitty before WezTerm/others, matching terminal-capabilities.ts detection + // order. Inherited env makes either order wrong for some nesting; staying + // consistent with the capability detector keeps the two answers aligned. const kittyId = process.env.KITTY_WINDOW_ID; if (kittyId) return `kitty-${kittyId}`; + const weztermPane = process.env.WEZTERM_PANE; + if (weztermPane) return `wezterm-${weztermPane}`; + const terminalSessionId = process.env.TERM_SESSION_ID; // macOS Terminal.app if (terminalSessionId) return `apple-${terminalSessionId}`; diff --git a/packages/tui/test/ttyid.test.ts b/packages/tui/test/ttyid.test.ts index fdc6877e3..6a30cb233 100644 --- a/packages/tui/test/ttyid.test.ts +++ b/packages/tui/test/ttyid.test.ts @@ -2,7 +2,16 @@ import { afterEach, describe, expect, it } from "bun:test"; import { getTerminalId } from "@oh-my-pi/pi-tui/ttyid"; const stdinIsTtyDescriptor = Object.getOwnPropertyDescriptor(process.stdin, "isTTY"); -const terminalEnvKeys = ["TMUX_PANE", "CMUX_SURFACE_ID", "KITTY_WINDOW_ID", "TERM_SESSION_ID", "WT_SESSION"] as const; +const terminalEnvKeys = [ + "ZELLIJ_PANE_ID", + "ZELLIJ_SESSION_NAME", + "TMUX_PANE", + "CMUX_SURFACE_ID", + "WEZTERM_PANE", + "KITTY_WINDOW_ID", + "TERM_SESSION_ID", + "WT_SESSION", +] as const; const originalTerminalEnv = Object.fromEntries(terminalEnvKeys.map(key => [key, process.env[key]])); function restoreProperty(target: object, key: string, descriptor: PropertyDescriptor | undefined): void { @@ -64,4 +73,39 @@ describe("getTerminalId", () => { expect(getTerminalId()).toBe("kitty-window-42"); }); + + it("prefers ZELLIJ_PANE_ID over TMUX_PANE", () => { + Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true }); + setTerminalEnv({ ZELLIJ_PANE_ID: "123", TMUX_PANE: "%7" }); + + expect(getTerminalId()).toBe("zellij-123"); + }); + + it("scopes ZELLIJ_PANE_ID by ZELLIJ_SESSION_NAME when present", () => { + Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true }); + setTerminalEnv({ ZELLIJ_PANE_ID: "123", ZELLIJ_SESSION_NAME: "work" }); + + expect(getTerminalId()).toBe("zellij-work-123"); + }); + + it("normalizes path separators in ZELLIJ_SESSION_NAME so the id stays filename-safe", () => { + Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true }); + setTerminalEnv({ ZELLIJ_PANE_ID: "123", ZELLIJ_SESSION_NAME: "foo/bar" }); + + expect(getTerminalId()).toBe("zellij-foo-bar-123"); + }); + + it("prefers KITTY_WINDOW_ID over an inherited WEZTERM_PANE", () => { + Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true }); + setTerminalEnv({ KITTY_WINDOW_ID: "window-42", WEZTERM_PANE: "pane-456" }); + + expect(getTerminalId()).toBe("kitty-window-42"); + }); + + it("uses WEZTERM_PANE when no multiplexer or kitty markers are present", () => { + Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true }); + setTerminalEnv({ WEZTERM_PANE: "pane-456", TERM_SESSION_ID: "abc" }); + + expect(getTerminalId()).toBe("wezterm-pane-456"); + }); });