Merge pull request #1702 from basedcorp99/feat/cmux-terminal-id
Add cmux terminal surface detection to getTerminalId
This commit is contained in:
@@ -372,7 +372,7 @@ These are read as runtime signals; they are usually set by the terminal/OS rathe
|
||||
| `COLORFGBG` | Terminal background light/dark auto-detection |
|
||||
| `TERM_PROGRAM`, `TERM_PROGRAM_VERSION`, `TERMINAL_EMULATOR` | Terminal identity in system prompt/context |
|
||||
| `KDE_FULL_SESSION`, `XDG_CURRENT_DESKTOP`, `DESKTOP_SESSION`, `XDG_SESSION_DESKTOP`, `GDMSESSION`, `WINDOWMANAGER` | Desktop/window-manager detection in system prompt/context |
|
||||
| `KITTY_WINDOW_ID`, `TMUX_PANE`, `TERM_SESSION_ID`, `WT_SESSION` | Stable per-terminal session breadcrumb IDs |
|
||||
| `TMUX_PANE`, `CMUX_SURFACE_ID`, `KITTY_WINDOW_ID`, `TERM_SESSION_ID`, `WT_SESSION` | Stable per-terminal session breadcrumb IDs |
|
||||
| `SHELL`, `ComSpec`, `TERM_PROGRAM`, `TERM` | System info diagnostics |
|
||||
| `APPDATA`, `XDG_CONFIG_HOME` | lspmux config path resolution |
|
||||
| `HOME` | Path shortening in MCP command UI |
|
||||
|
||||
@@ -67,7 +67,7 @@ For `SessionInfo` list entries:
|
||||
3. If breadcrumb is invalid/missing, fall back to newest file by mtime in the session dir (`findMostRecentSession`)
|
||||
4. If none found, create a new session
|
||||
|
||||
Terminal ID derivation prefers TTY path and falls back to env-based identifiers (`KITTY_WINDOW_ID`, `TMUX_PANE`, `TERM_SESSION_ID`, `WT_SESSION`).
|
||||
Terminal ID derivation prefers TTY path and falls back to env-based identifiers (`TMUX_PANE`, `CMUX_SURFACE_ID`, `KITTY_WINDOW_ID`, `TERM_SESSION_ID`, `WT_SESSION`).
|
||||
|
||||
Breadcrumb writes are best-effort and non-fatal.
|
||||
|
||||
|
||||
@@ -73,6 +73,10 @@
|
||||
- Fixed startup model resolution ignoring cached discovery rows for special built-in providers (`google-antigravity`, `google-gemini-cli`, `openai-codex`) until the background refresh completed ([#1721](https://github.com/can1357/oh-my-pi/issues/1721)).
|
||||
- Fixed Windows clipboard-image paste keeping `Ctrl+V` unregistered by default. The TUI now registers `Ctrl+V` plus the Windows Terminal-safe `Alt+V` fallback, and the keybinding docs call out when to use the fallback ([#1708](https://github.com/can1357/oh-my-pi/issues/1708)).
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the "each kitty/tmux split" tip to include cmux.
|
||||
|
||||
## [15.8.0] - 2026-06-02
|
||||
|
||||
### Added
|
||||
|
||||
@@ -5,7 +5,7 @@ Find out which model you emotionally abuse the most with `omp stats`
|
||||
Try task isolation to create CoW worktrees
|
||||
Your LLM can call an LLM using `llm(x...)`. Have a big batch of tasks? Ask clanker to use it!
|
||||
Spaghetti code? Try complaining with /omfg
|
||||
Did you know? Each kitty/tmux split keeps its own session — `omp -c` resumes the right one
|
||||
Did you know? Each kitty/tmux/cmux 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 `workflow` in your message to drive the task with parallel subagents in eval — watch it glow as you type
|
||||
|
||||
@@ -62,6 +62,10 @@
|
||||
|
||||
- Deferred eager live scrollback rebuilds on VTE terminals so GNOME-style Linux terminals do not flash or erase readable scrollback during streaming ([#1719](https://github.com/can1357/oh-my-pi/issues/1719)).
|
||||
|
||||
### Added
|
||||
|
||||
- Added `CMUX_SURFACE_ID` environment variable support to `getTerminalId()`, so cmux terminal surfaces get a stable identifier alongside kitty, tmux, macOS Terminal.app, and Windows Terminal — enabling per-surface session breadcrumbs for `omp -c` in cmux.
|
||||
|
||||
## [15.8.0] - 2026-06-02
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -50,12 +50,16 @@ export function getTerminalId(): string | null {
|
||||
}
|
||||
|
||||
// Fallback to terminal-specific env vars
|
||||
const kittyId = process.env.KITTY_WINDOW_ID;
|
||||
if (kittyId) return `kitty-${kittyId}`;
|
||||
|
||||
// Prefer inner multiplexers over host terminal emulators when stdin has no TTY path.
|
||||
const tmuxPane = process.env.TMUX_PANE;
|
||||
if (tmuxPane) return `tmux-${tmuxPane}`;
|
||||
|
||||
const cmuxSurface = process.env.CMUX_SURFACE_ID;
|
||||
if (cmuxSurface) return `cmux-${cmuxSurface}`;
|
||||
|
||||
const kittyId = process.env.KITTY_WINDOW_ID;
|
||||
if (kittyId) return `kitty-${kittyId}`;
|
||||
|
||||
const terminalSessionId = process.env.TERM_SESSION_ID; // macOS Terminal.app
|
||||
if (terminalSessionId) return `apple-${terminalSessionId}`;
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
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 originalTerminalEnv = Object.fromEntries(terminalEnvKeys.map(key => [key, process.env[key]]));
|
||||
|
||||
function restoreProperty(target: object, key: string, descriptor: PropertyDescriptor | undefined): void {
|
||||
if (descriptor) {
|
||||
Object.defineProperty(target, key, descriptor);
|
||||
return;
|
||||
}
|
||||
delete (target as Record<string, unknown>)[key];
|
||||
}
|
||||
|
||||
function setTerminalEnv(overrides: Partial<Record<(typeof terminalEnvKeys)[number], string>>): void {
|
||||
for (const key of terminalEnvKeys) {
|
||||
const value = overrides[key];
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
continue;
|
||||
}
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
describe("getTerminalId", () => {
|
||||
afterEach(() => {
|
||||
restoreProperty(process.stdin, "isTTY", stdinIsTtyDescriptor);
|
||||
for (const key of terminalEnvKeys) {
|
||||
const value = originalTerminalEnv[key];
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
continue;
|
||||
}
|
||||
process.env[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
it("uses CMUX_SURFACE_ID as the terminal identity when stdin is piped", () => {
|
||||
Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true });
|
||||
setTerminalEnv({ CMUX_SURFACE_ID: "surface-1234" });
|
||||
|
||||
expect(getTerminalId()).toBe("cmux-surface-1234");
|
||||
});
|
||||
|
||||
it("prefers TMUX_PANE over CMUX_SURFACE_ID when both are present", () => {
|
||||
Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true });
|
||||
setTerminalEnv({ TMUX_PANE: "%7", CMUX_SURFACE_ID: "surface-1234" });
|
||||
|
||||
expect(getTerminalId()).toBe("tmux-%7");
|
||||
});
|
||||
|
||||
it("prefers CMUX_SURFACE_ID over KITTY_WINDOW_ID when both are present", () => {
|
||||
Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true });
|
||||
setTerminalEnv({ KITTY_WINDOW_ID: "window-42", CMUX_SURFACE_ID: "surface-1234" });
|
||||
|
||||
expect(getTerminalId()).toBe("cmux-surface-1234");
|
||||
});
|
||||
|
||||
it("ignores an empty CMUX_SURFACE_ID and falls through to the outer terminal", () => {
|
||||
Object.defineProperty(process.stdin, "isTTY", { value: false, configurable: true });
|
||||
setTerminalEnv({ KITTY_WINDOW_ID: "window-42", CMUX_SURFACE_ID: "" });
|
||||
|
||||
expect(getTerminalId()).toBe("kitty-window-42");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user