feat(tui): added Zellij and WezTerm pane fallbacks for terminal session continuity
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the session-continuation tip to mention Zellij and WezTerm panes.
|
||||
|
||||
## [15.12.3] - 2026-06-12
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}`;
|
||||
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user