@oh-my-pi/pi-tui 18.8.8 → 18.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +25 -23
  2. package/dist/types/charts/chart-plan.d.ts +11 -5
  3. package/dist/types/charts/chart-svg.d.ts +11 -7
  4. package/dist/types/charts/table-data.d.ts +6 -1
  5. package/dist/types/kitty-graphics.d.ts +2 -2
  6. package/dist/types/multiplexers/cmux.d.ts +16 -0
  7. package/dist/types/multiplexers/herdr.d.ts +26 -0
  8. package/dist/types/multiplexers/notify.d.ts +13 -0
  9. package/dist/types/multiplexers/orca.d.ts +12 -0
  10. package/dist/types/multiplexers/screen.d.ts +9 -0
  11. package/dist/types/multiplexers/tmux.d.ts +29 -0
  12. package/dist/types/multiplexers/types.d.ts +100 -0
  13. package/dist/types/multiplexers/wmux.d.ts +12 -0
  14. package/dist/types/multiplexers/zellij.d.ts +12 -0
  15. package/dist/types/status-line/types.d.ts +2 -2
  16. package/dist/types/terminal-capabilities.d.ts +24 -32
  17. package/dist/types/terminal-multiplexer.d.ts +127 -14
  18. package/dist/types/terminal.d.ts +5 -4
  19. package/dist/types/tmux.d.ts +1 -4
  20. package/package.json +9 -9
  21. package/src/charts/chart-plan.ts +152 -12
  22. package/src/charts/chart-svg.ts +479 -126
  23. package/src/charts/table-data.ts +43 -8
  24. package/src/chat/svg-figure.ts +45 -8
  25. package/src/kitty-graphics.ts +4 -4
  26. package/src/multiplexers/cmux.ts +29 -0
  27. package/src/multiplexers/herdr.ts +64 -0
  28. package/src/multiplexers/notify.ts +24 -0
  29. package/src/multiplexers/orca.ts +16 -0
  30. package/src/multiplexers/screen.ts +15 -0
  31. package/src/multiplexers/tmux.ts +40 -0
  32. package/src/multiplexers/types.ts +110 -0
  33. package/src/multiplexers/wmux.ts +16 -0
  34. package/src/multiplexers/zellij.ts +24 -0
  35. package/src/status-line/component.ts +12 -8
  36. package/src/status-line/segments.ts +7 -11
  37. package/src/status-line/types.ts +2 -2
  38. package/src/terminal-capabilities.ts +65 -181
  39. package/src/terminal-multiplexer.ts +112 -33
  40. package/src/terminal.ts +34 -28
  41. package/src/theme/session-color.ts +1 -7
  42. package/src/theme/theme.ts +7 -4
  43. package/src/tmux.ts +4 -11
  44. package/src/tui.ts +18 -12
package/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.8.9] - 2026-10-10
6
+
7
+ ### Breaking Changes
8
+
9
+ - Removed the `isInsideTmux()`, `isInsideZellij()`, and `isInsideHerdr()` exports; use `hasTerminalMultiplexerSession("tmux" | "zellij" | "herdr", env)` instead ([#13620](https://github.com/can1357/oh-my-pi/pull/13620) by [@anatoli-tsinovoy](https://github.com/anatoli-tsinovoy))
10
+
11
+ ### Added
12
+
13
+ - `classifyTerminalMultiplexer()` reports `"orca"` inside Orca terminals while `isInsideTerminalMultiplexer()` stays false there, so Orca keeps the direct-terminal render path; `TERMINAL_MULTIPLEXER_ENV_KEYS` lists every environment variable multiplexer detection reads ([#13620](https://github.com/can1357/oh-my-pi/pull/13620) by [@anatoli-tsinovoy](https://github.com/anatoli-tsinovoy))
14
+ - Added `terminalMultiplexerSessions()`, `terminalMultiplexerForTerm()`, `classifyTerminalMultiplexerModule()`, and `routeTerminalMultiplexerNotification()`, driven by one multiplexer registry that now owns notification routing and per-multiplexer capability overrides ([#13620](https://github.com/can1357/oh-my-pi/pull/13620) by [@anatoli-tsinovoy](https://github.com/anatoli-tsinovoy))
15
+ - Added `change` and `progress` table-chart kinds with `ChartSpec.baseline` and `TableColumn.scores`: a before/after table whose rows have their own units charts each metric as a factor of the baseline column (rows without two numbers are named in the caption), and `analyzeTable` reads whole-number scores (`12/12`, `154/160`) as the percent of their total, keeping `a / b` pairs and lists as written
16
+
17
+ ### Changed
18
+
19
+ - `StatusLineComponent.describeComposerFacts()` includes the configured `git` segment among the composer's facts (branch and status, the `status.git` click action, pinned so it outlasts the other facts) instead of leaving the branch to Tern's pane header ([#15220](https://github.com/can1357/oh-my-pi/pull/15220) by [@H4vC](https://github.com/H4vC))
20
+ - Small-multiple table charts with more than three panels and at most six categories draw as bands of per-metric panels with a color legend, and `worthCharting` counts their panels like categories
21
+ - Table charts take the look of Apple's charts and Tern: a UI sans, hairline gridlines, rounded bars and cells, smooth lines over a soft area fill, dot legends, left-aligned category labels that never run off the edge, and axes labeled in one unit (`0, 5k, 10k`)
22
+ - Line charts whose series differ 8× or more in size stack panels on their own axes instead of flattening the smaller lines, and their end labels no longer overlap
23
+ - SVG figure series colors `--c1`…`--c6` are an even-weight palette led by the theme accent's hue instead of syntax colors
24
+
25
+ ### Fixed
26
+
27
+ - Fixed `parseCell` throwing on table cells such as `3 constructor` or `2 valueOf calls`, and reading a `constructor` cell as a missing value
28
+
5
29
  ## [18.8.8] - 2026-10-10
6
30
 
7
31
  ### Breaking Changes
@@ -2982,26 +3006,4 @@ Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mon
2982
3006
  - Added undo support to Editor with Ctrl+- hotkey. Undo coalesces consecutive word characters into one unit (fish-style). ([#831](https://github.com/badlogic/pi-mono/pull/831) by [@Perlence](https://github.com/Perlence))
2983
3007
  - Added legacy terminal support for Ctrl+symbol keys (Ctrl+\, Ctrl+], Ctrl+-) and their Ctrl+Alt variants. ([#831](https://github.com/badlogic/pi-mono/pull/831) by [@Perlence](https://github.com/Perlence))
2984
3008
 
2985
- ## [0.49.0] - 2026-01-17
2986
-
2987
- ### Added
2988
-
2989
- - Added `showHardwareCursor` getter and setter to control cursor visibility while keeping IME positioning active. ([#800](https://github.com/badlogic/pi-mono/pull/800) by [@ghoulr](https://github.com/ghoulr))
2990
- - Added Emacs-style kill ring editing with yank and yank-pop keybindings. ([#810](https://github.com/badlogic/pi-mono/pull/810) by [@Perlence](https://github.com/Perlence))
2991
- - Added legacy Alt+letter handling and Alt+D delete word forward support in the editor keymap. ([#810](https://github.com/badlogic/pi-mono/pull/810) by [@Perlence](https://github.com/Perlence))
2992
-
2993
- ## [0.48.0] - 2026-01-16
2994
-
2995
- ### Added
2996
-
2997
- - `EditorOptions` with optional `paddingX` for horizontal content padding, plus `getPaddingX()`/`setPaddingX()` methods ([#791](https://github.com/badlogic/pi-mono/pull/791) by [@ferologics](https://github.com/ferologics))
2998
-
2999
- ### Changed
3000
-
3001
- - Hardware cursor is now disabled by default for better terminal compatibility. Set `PI_HARDWARE_CURSOR=1` to enable (replaces `PI_NO_HARDWARE_CURSOR=1` which disabled it).
3002
-
3003
- ### Fixed
3004
-
3005
- - Decode Kitty CSI-u printable sequences in the editor so shifted symbol keys (e.g., `@`, `?`) work in terminals that enable Kitty keyboard protocol ([#779](https://github.com/badlogic/pi-mono/pull/779) by [@iamd3vil](https://github.com/iamd3vil))
3006
-
3007
- Older entries are archived in [packages/tui/CHANGELOG.md@01e0b5c26e26](https://github.com/can1357/oh-my-pi/blob/01e0b5c26e267dff08c305f51d1ab56ec5a2f05d/packages/tui/CHANGELOG.md).
3009
+ Older entries are archived in [packages/tui/CHANGELOG.md@110bcbdfe908](https://github.com/can1357/oh-my-pi/blob/110bcbdfe908cbe2978e7607d4f2fe64a0c13de0/packages/tui/CHANGELOG.md).
@@ -24,14 +24,16 @@ import { type Dimension, type TableAnalysis } from "./table-data.js";
24
24
  * - `share`: parts of a whole (percentages summing to 100).
25
25
  * - `diverging`: signed changes around zero.
26
26
  * - `scatter`: two continuous measures per item.
27
+ * - `change`: metrics in different units against a baseline column (before/after), as factors.
28
+ * - `progress`: scores out of a total (`12/12`), as filled tracks.
27
29
  */
28
- export type ChartKind = "bar" | "paired" | "grouped" | "line" | "heatmap" | "multiples" | "share" | "diverging" | "scatter";
30
+ export type ChartKind = "bar" | "paired" | "grouped" | "line" | "heatmap" | "multiples" | "share" | "diverging" | "scatter" | "change" | "progress";
29
31
  /** What to draw from a table: the kind, the column naming each category, and the columns plotted. */
30
32
  export interface ChartPlan {
31
33
  readonly kind: ChartKind;
32
34
  /** Column naming each category (or holding the x values of a line); rows are numbered without one. */
33
35
  readonly label: number | undefined;
34
- /** Plotted columns, in order. */
36
+ /** Plotted columns, in order; a `change` measures the rest against the first (or its `a → b` cells). */
35
37
  readonly series: readonly number[];
36
38
  /** Each data row is its own series (a metric with its own unit) and the plotted columns are the categories. */
37
39
  readonly transpose: boolean;
@@ -73,6 +75,8 @@ export interface ChartSpec {
73
75
  readonly caption?: string;
74
76
  /** Name of the category axis (the label column's header). */
75
77
  readonly axis: string;
78
+ /** What a `change` measures against (its baseline column); its points are factors of it. */
79
+ readonly baseline?: string;
76
80
  }
77
81
  /** The local best guess at a chart for `table`, or `undefined` when no chart fits. */
78
82
  export declare function planChart(table: TableAnalysis): ChartPlan | undefined;
@@ -85,8 +89,10 @@ export declare function planChart(table: TableAnalysis): ChartPlan | undefined;
85
89
  export declare function buildChart(table: TableAnalysis, plan: ChartPlan): ChartSpec | undefined;
86
90
  /**
87
91
  * Whether a chart of `spec` reads faster than its table: at least four
88
- * categories, and either nine plotted values or a 3× spread within a series.
89
- * On a model-judged sample of assistant tables this gate kept 85% of the
90
- * tables a chart clearly helped while rejecting most two- and three-row ones.
92
+ * categories (or small-multiple panels), and either nine plotted values or a
93
+ * 3× spread within a series. On a model-judged sample of assistant tables this
94
+ * gate kept 85% of the tables a chart clearly helped while rejecting most two-
95
+ * and three-row ones. A `change` needs three metrics and one moving by
96
+ * {@link NOTABLE_FACTOR} either way: its factors are what the table lacks.
91
97
  */
92
98
  export declare function worthCharting(spec: ChartSpec): boolean;
@@ -6,10 +6,12 @@
6
6
  * so the host resolves them against the live theme (`prepareSvg`) for both
7
7
  * the rasterized terminal image and the native TSP blob.
8
8
  *
9
- * Geometry follows the terminal: 16 user units per row and a monospace face,
10
- * so 13-unit labels land near the terminal's own glyph size. Marks are flat
11
- * and square (no rounding, gradients or shadows); bolded table cells draw at
12
- * full strength while their neighbours recede.
9
+ * Styled after Apple's charts and Tern's UI: a UI sans (Geist where Tern
10
+ * provides it), muted labels, hairline gridlines that recede behind the
11
+ * marks, bars and cells with rounded corners, smooth lines over a soft area
12
+ * fill, dot legends. 13-unit labels land near the terminal's own glyph size
13
+ * at 16 user units per row; bolded table cells draw at full strength while
14
+ * their neighbours recede.
13
15
  */
14
16
  import type { ChartSpec } from "./chart-plan.js";
15
17
  import type { Dimension } from "./table-data.js";
@@ -24,7 +26,9 @@ export declare function renderChartSvg(spec: ChartSpec): ChartSvg;
24
26
  /** One-line description of the chart, for screen readers and terminals that show the alt text. */
25
27
  export declare function chartAlt(spec: ChartSpec): string;
26
28
  /**
27
- * A value in base units as an axis label: durations and sizes in the unit
28
- * their magnitude reads best in, counts compacted (`12k`, `3.4M`).
29
+ * A value in base units as an axis label: durations and sizes in the unit,
30
+ * counts compacted under the suffix (`12k`, `3.4M`), that `magnitude` reads
31
+ * best in — the value's own size by default, an axis' largest tick to keep
32
+ * its labels in one unit.
29
33
  */
30
- export declare function formatValue(value: number, dim: Dimension, unit: string): string;
34
+ export declare function formatValue(value: number, dim: Dimension, unit: string, magnitude?: number): string;
@@ -42,7 +42,10 @@ export interface NumberCell {
42
42
  readonly toFigure?: string;
43
43
  /** `a–b`: `b`, in the same base units. */
44
44
  readonly upper?: number;
45
- /** `a/b`: `b`. */
45
+ /**
46
+ * `a/b`: `b`. {@link analyzeTable} reads a score (`12/12`, `154/160`) as the
47
+ * percent of `b` reached; a pair (`85 / 147` under `Edit / read calls`) keeps `a`.
48
+ */
46
49
  readonly denominator?: number;
47
50
  }
48
51
  /** A cell that is not a quantity. */
@@ -70,6 +73,8 @@ export interface TableColumn {
70
73
  readonly unit: string;
71
74
  /** Numeric cells disagree on dimension (a metric-per-row table). */
72
75
  readonly mixed: boolean;
76
+ /** Numeric cells are mostly scores out of a total (`12/12`), read as percent of it. */
77
+ readonly scores: boolean;
73
78
  /** Every numeric data cell holds the same value: an echoed setting, not a measure. */
74
79
  readonly constant: boolean;
75
80
  /** Share of numeric cells written with an explicit sign. */
@@ -30,8 +30,8 @@ export interface KittyGraphicsFeatures {
30
30
  * cannot use cursor-positioned placements because the outer terminal does not
31
31
  * know pane scroll/reflow state. An explicit `PI_FORCE_IMAGE_PROTOCOL=kitty`
32
32
  * opts into placeholders under any multiplexer — matching `timg -pk`.
33
- * Automatic Herdr fallback stays off because its pane marker does not prove
34
- * that the experimental Kitty renderer is enabled.
33
+ * Automatic fallback stays off inside multiplexers whose pane marker does not
34
+ * prove that a Kitty renderer is enabled (Herdr's is experimental).
35
35
  *
36
36
  * `PI_NO_KITTY_PLACEHOLDERS=1` and `PI_KITTY_PLACEHOLDERS=0` remain hard
37
37
  * opt-outs; `PI_KITTY_PLACEHOLDERS=1` explicitly opts in anywhere else.
@@ -0,0 +1,16 @@
1
+ export declare const cmuxMultiplexer: {
2
+ readonly id: "cmux";
3
+ readonly precedence: "session";
4
+ readonly sessionEnvKeys: readonly ["CMUX_WORKSPACE_ID", "CMUX_SURFACE_ID", "CMUX_REMOTE_TRANSPORT"];
5
+ readonly ownsScreenGrid: true;
6
+ readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
7
+ /**
8
+ * Workspace/socket state alone is not enough: only the injected surface UUID
9
+ * identifies the pane that should receive the notification. Without a valid
10
+ * surface, or without the binary, delivery falls through unchanged.
11
+ */
12
+ readonly notifier: {
13
+ readonly tier: "surface";
14
+ readonly send: ({ message, env }: import("./types.js").TerminalMultiplexerNotificationRequest) => boolean;
15
+ };
16
+ };
@@ -0,0 +1,26 @@
1
+ export declare const herdrMultiplexer: {
2
+ readonly id: "herdr";
3
+ readonly precedence: "session";
4
+ readonly sessionEnvKeys: readonly ["HERDR_ENV", "HERDR_PANE_ID", "HERDR_TAB_ID", "HERDR_WORKSPACE_ID"];
5
+ readonly ownsScreenGrid: true;
6
+ readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
7
+ /**
8
+ * Herdr multiplexes panes like tmux but swallows bare OSC 9 / OSC 99 and has
9
+ * no DCS passthrough envelope, and its bell relay does not flag a
10
+ * backgrounded tab — so without its CLI a backgrounded pane gets no signal
11
+ * at all that the agent finished or is waiting for input.
12
+ *
13
+ * `sound` maps the notification kind onto what Herdr offers: a question
14
+ * waiting on the user and a turn that stopped with an error both need the
15
+ * human and ring `request`, a settled turn rings `done`, anything else stays
16
+ * silent. The exact pane ID addresses the CLI call; without a valid one, or
17
+ * without the binary, delivery falls through.
18
+ */
19
+ readonly notifier: {
20
+ readonly tier: "pane";
21
+ readonly send: ({ message, env }: import("./types.js").TerminalMultiplexerNotificationRequest) => boolean;
22
+ };
23
+ readonly hyperlinks: "render";
24
+ readonly honorsSynchronizedOutput: true;
25
+ readonly imagesRequireOverride: true;
26
+ };
@@ -0,0 +1,13 @@
1
+ import type { TerminalNotification } from "../terminal-capabilities.js";
2
+ /** Title for out-of-band multiplexer notifications that carry none of their own. */
3
+ export declare const DEFAULT_NOTIFICATION_TITLE = "omp";
4
+ /** Title and body for an out-of-band multiplexer notification (cmux, Herdr). */
5
+ export declare function notificationTitleAndBody(message: string | TerminalNotification): {
6
+ title: string;
7
+ body: string;
8
+ };
9
+ /**
10
+ * Start a notifier CLI without waiting for or pinning it. Returns false when
11
+ * the binary cannot be spawned, which leaves delivery to the terminal fallback.
12
+ */
13
+ export declare function spawnNotifier(cmd: string[]): boolean;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Orca is an xterm.js-based IDE whose terminals expose paired pane/worktree IDs.
3
+ * It is recognized for launches, but it ranks below nested multiplexers and keeps
4
+ * the direct-terminal render path it used before it was recognized.
5
+ */
6
+ export declare const orcaMultiplexer: {
7
+ readonly id: "orca";
8
+ readonly precedence: "outerApp";
9
+ readonly sessionEnvKeys: readonly ["ORCA_PANE_KEY", "ORCA_WORKTREE_ID"];
10
+ readonly ownsScreenGrid: false;
11
+ readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
12
+ };
@@ -0,0 +1,9 @@
1
+ export declare const screenMultiplexer: {
2
+ readonly id: "screen";
3
+ readonly precedence: "session";
4
+ readonly sessionEnvKeys: readonly ["STY"];
5
+ readonly termPrefix: "screen";
6
+ readonly ownsScreenGrid: true;
7
+ readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
8
+ readonly hyperlinks: "drop";
9
+ };
@@ -0,0 +1,29 @@
1
+ /** Wrap a control sequence in tmux's DCS passthrough envelope. */
2
+ export declare function wrapTmuxPassthrough(payload: string): string;
3
+ export declare const tmuxMultiplexer: {
4
+ readonly id: "tmux";
5
+ readonly precedence: "session";
6
+ readonly sessionEnvKeys: readonly ["TMUX"];
7
+ readonly termPrefix: "tmux";
8
+ readonly ownsScreenGrid: true;
9
+ readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
10
+ readonly notifier: {
11
+ readonly tier: "inBand";
12
+ readonly send: ({ sequence, write }: import("./types.js").TerminalMultiplexerNotificationRequest) => boolean;
13
+ };
14
+ readonly hyperlinks: {
15
+ readonly forward: {
16
+ readonly termProgram: "tmux";
17
+ readonly major: 3;
18
+ readonly minor: 4;
19
+ };
20
+ };
21
+ readonly backgroundColorCache: {
22
+ readonly passthrough: typeof wrapTmuxPassthrough;
23
+ readonly settleMs: 100;
24
+ };
25
+ readonly expandsRepPadding: true;
26
+ readonly expiresSynchronizedOutput: true;
27
+ readonly altRestoreEndsSynchronizedOutput: true;
28
+ readonly growsBeforeSigwinch: true;
29
+ };
@@ -0,0 +1,100 @@
1
+ import type { TerminalNotification } from "../terminal-capabilities.js";
2
+ /**
3
+ * Classification tier. `session` markers outrank the TERM fallback; `outerApp`
4
+ * hosts rank below it so a multiplexer nested inside them still wins.
5
+ */
6
+ export type TerminalMultiplexerPrecedence = "session" | "outerApp";
7
+ /**
8
+ * Notification delivery tier, tried in this order so the innermost target wins:
9
+ * a `pane` notifier addresses the exact pane through the multiplexer's CLI, a
10
+ * `surface` notifier addresses the containing app surface, and an `inBand`
11
+ * notifier rewrites the terminal's own notification sequence.
12
+ */
13
+ export type TerminalMultiplexerNotificationTier = "pane" | "surface" | "inBand";
14
+ /** One notification offered to a multiplexer notifier. */
15
+ export interface TerminalMultiplexerNotificationRequest {
16
+ readonly message: string | TerminalNotification;
17
+ readonly env: NodeJS.ProcessEnv;
18
+ /** The host terminal's formatted OSC notification, or `null` when it notifies with a bare BEL. */
19
+ readonly sequence: string | null;
20
+ /** Write a sequence through the active terminal. */
21
+ write(data: string): void;
22
+ }
23
+ export interface TerminalMultiplexerNotifier {
24
+ readonly tier: TerminalMultiplexerNotificationTier;
25
+ /** Deliver the notification. `false` leaves it to the next notifier and then the terminal fallback. */
26
+ send(request: TerminalMultiplexerNotificationRequest): boolean;
27
+ }
28
+ /**
29
+ * OSC 8 handling inside a multiplexer session:
30
+ * - `render`: the multiplexer draws and opens links itself, so links work
31
+ * whatever the outer terminal supports, unless another session with a
32
+ * hyperlink policy sits in the path.
33
+ * - `drop`: never forwards OSC 8; its session anywhere in the path disables links.
34
+ * - `forward`: forwards OSC 8 once it self-reports (`TERM_PROGRAM`/`TERM_PROGRAM_VERSION`)
35
+ * at least `major.minor`; older or unreported versions stay off.
36
+ */
37
+ export type TerminalMultiplexerHyperlinks = "render" | "drop" | {
38
+ readonly forward: {
39
+ /** Lowercase `TERM_PROGRAM` the multiplexer sets inside its panes. */
40
+ readonly termProgram: string;
41
+ readonly major: number;
42
+ readonly minor: number;
43
+ };
44
+ };
45
+ /** A multiplexer that answers OSC 11 from a cached copy of the outer terminal's background color. */
46
+ export interface TerminalMultiplexerBackgroundColorCache {
47
+ /** Wrap a query so it reaches the outer terminal and refreshes the cache. */
48
+ passthrough(query: string): string;
49
+ /** How long the multiplexer needs to store the outer reply before the cache is re-read. */
50
+ readonly settleMs: number;
51
+ }
52
+ /** Everything omp needs to recognize one terminal multiplexer and adapt to it. */
53
+ export interface TerminalMultiplexerModule<Id extends string = string> {
54
+ readonly id: Id;
55
+ readonly precedence: TerminalMultiplexerPrecedence;
56
+ /** Every environment variable `isInside()` reads. */
57
+ readonly sessionEnvKeys: readonly string[];
58
+ /** Lowercase TERM prefix that identifies the multiplexer when its session markers were stripped. */
59
+ readonly termPrefix?: string;
60
+ /**
61
+ * Whether the multiplexer owns the screen grid. When true, rendering takes the
62
+ * multiplexer path (no scrollback rebuild, anchored resize, skipped probes).
63
+ */
64
+ readonly ownsScreenGrid: boolean;
65
+ isInside(env?: NodeJS.ProcessEnv): boolean;
66
+ /** Routes notifications the multiplexer would otherwise swallow. */
67
+ readonly notifier?: TerminalMultiplexerNotifier;
68
+ /** OSC 8 policy inside a session; unset defers to the outer terminal. */
69
+ readonly hyperlinks?: TerminalMultiplexerHyperlinks;
70
+ /**
71
+ * The pane's VTE honors DEC 2026 even when DECRQM is unanswered or reports
72
+ * the mode unrecognized (status 0): synchronized output starts on inside a
73
+ * session, and an unrecognized report does not turn it off.
74
+ */
75
+ readonly honorsSynchronizedOutput?: boolean;
76
+ /**
77
+ * The session does not reveal whether its client renders graphics while
78
+ * outer-terminal identity variables leak in, so images and Kitty
79
+ * placeholders stay off unless the user forces them.
80
+ */
81
+ readonly imagesRequireOverride?: boolean;
82
+ /** Platforms where the multiplexer breaks OSC 11 passthrough, so host appearance is used instead. */
83
+ readonly backgroundQueryBrokenOn?: readonly NodeJS.Platform[];
84
+ /** Present when OSC 11 replies come from a cache an explicit refresh must update first. */
85
+ readonly backgroundColorCache?: TerminalMultiplexerBackgroundColorCache;
86
+ /** Expands REP into identical styled cells, so destructive replays REP-encode their padding. */
87
+ readonly expandsRepPadding?: boolean;
88
+ /** Expires a synchronized update after a deadline, so large rebuild replays renew DEC 2026 as they stream. */
89
+ readonly expiresSynchronizedOutput?: boolean;
90
+ /**
91
+ * Restoring the alternate buffer schedules a redraw that ends a synchronized
92
+ * update early, so a synchronized resize rebuild stays on the main buffer.
93
+ */
94
+ readonly altRestoreEndsSynchronizedOutput?: boolean;
95
+ /**
96
+ * May grow its grid before SIGWINCH reaches the app, so a rebuild-mode grow
97
+ * whose full viewport no longer reaches the bottom replays history.
98
+ */
99
+ readonly growsBeforeSigwinch?: boolean;
100
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * wmux is a Windows multiplexer (Electron + xterm.js) modeled on cmux/herdr that
3
+ * repaints its pane in place. WMUX_CLI / WMUX_PIPE are CLI path overrides and can
4
+ * be set outside a wmux terminal.
5
+ */
6
+ export declare const wmuxMultiplexer: {
7
+ readonly id: "wmux";
8
+ readonly precedence: "session";
9
+ readonly sessionEnvKeys: readonly ["WMUX", "WMUX_SURFACE_ID"];
10
+ readonly ownsScreenGrid: true;
11
+ readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
12
+ };
@@ -0,0 +1,12 @@
1
+ export declare const zellijMultiplexer: {
2
+ readonly id: "zellij";
3
+ readonly precedence: "session";
4
+ readonly sessionEnvKeys: readonly ["ZELLIJ"];
5
+ readonly ownsScreenGrid: true;
6
+ readonly isInside: (env?: NodeJS.ProcessEnv) => boolean;
7
+ readonly notifier: {
8
+ readonly tier: "inBand";
9
+ readonly send: ({ sequence, write }: import("./types.js").TerminalMultiplexerNotificationRequest) => boolean;
10
+ };
11
+ readonly backgroundQueryBrokenOn: readonly ["darwin"];
12
+ };
@@ -245,8 +245,8 @@ export interface SegmentView {
245
245
  }
246
246
  /**
247
247
  * The status line's facts for the native composer. A TSP terminal shows no
248
- * status strip: the tab title carries the session, the pane header the path
249
- * and branch, and the composer the rest.
248
+ * status strip: the tab title carries the session, the pane header the path,
249
+ * and the composer the rest (the git branch among its facts).
250
250
  */
251
251
  export interface ComposerFacts {
252
252
  /**
@@ -1,6 +1,6 @@
1
1
  import type { HangulCompatibilityJamoWidth } from "./utils.js";
2
2
  export * from "./terminal-multiplexer.js";
3
- export { isInsideTmux, wrapTmuxPassthrough } from "./tmux.js";
3
+ export { wrapTmuxPassthrough } from "./tmux.js";
4
4
  export declare enum ImageProtocol {
5
5
  Kitty = "\u001B_G",
6
6
  Iterm2 = "\u001B]1337;File=",
@@ -55,12 +55,6 @@ export declare class TerminalInfo {
55
55
  formatNotification(message: string | TerminalNotification): string;
56
56
  sendNotification(message: string | TerminalNotification): void;
57
57
  }
58
- /**
59
- * Whether the agent process is running inside a Zellij session. Read fresh on
60
- * each call (like {@link isInsideTmux}) so a session attached/detached mid-run
61
- * is observed and tests can toggle `Bun.env.ZELLIJ` per case.
62
- */
63
- export declare function isInsideZellij(env?: NodeJS.ProcessEnv): boolean;
64
58
  /**
65
59
  * Whether the agent process runs in an SSH session, so the terminal emulator
66
60
  * is remote and host-local input/keyboard modes cannot be assumed.
@@ -96,12 +90,12 @@ export declare function synchronizedOutputUserOverride(env?: NodeJS.ProcessEnv):
96
90
  * 2. Positive `TERM_FEATURES` advertisement (`Sy`) — survives SSH/mux wrapping.
97
91
  * 3. Windows Terminal (1.24+) via `WT_SESSION`, on native win32 and the
98
92
  * WSL/SSH-fronted host alike.
99
- * 4. Herdr panes. Herdr is otherwise treated as a multiplexer so leaked
100
- * kitty/ghostty identities cannot enable placeholder graphics, but its
101
- * pane VTE is libghostty and already suppresses compositing while DEC 2026
102
- * is set. Leaving sync off lets CUP-diff paints and split write(2) chunks
103
- * composite as dirty-row patches — the live viewport tears, with the top
104
- * frozen while only the bottom refreshes.
93
+ * 4. A multiplexer session whose pane VTE honors DEC 2026 regardless of its
94
+ * DECRQM reply (Herdr's libghostty pane). Such a multiplexer still owns
95
+ * the grid, so leaked kitty/ghostty identities cannot enable placeholder
96
+ * graphics, but leaving sync off lets CUP-diff paints and split write(2)
97
+ * chunks composite as dirty-row patches — the live viewport tears, with
98
+ * the top frozen while only the bottom refreshes.
105
99
  * 5. Known direct terminals with confirmed support. SSH does *not* disable —
106
100
  * DEC 2026 passes through SSH when the outer terminal honors it.
107
101
  * 6. Everything else starts off, including risky multiplexers; the runtime
@@ -159,27 +153,25 @@ export declare function hyperlinksUserOverride(env?: NodeJS.ProcessEnv): boolean
159
153
  * Policy (highest precedence first):
160
154
  * 1. Explicit user override (`PI_NO_HYPERLINKS=1` off, `PI_FORCE_HYPERLINKS=1`
161
155
  * on). Opt-out wins ties.
162
- * 2. Herdr pane with no nested screen/tmux: on. Herdr hides the outer
163
- * terminal (`TERM=xterm-256color`, no `TERM_PROGRAM`), but it renders
164
- * OSC 8 in its own grid and opens links itself on Ctrl+click, so the
165
- * outer terminal's support does not matter.
156
+ * 2. Every multiplexer session with a hyperlink policy renders OSC 8 itself
157
+ * (`render`, e.g. Herdr): on. Herdr hides the outer terminal
158
+ * (`TERM=xterm-256color`, no `TERM_PROGRAM`), so the outer terminal's
159
+ * support does not matter.
166
160
  * 3. Static terminal capability — terminals whose {@link TerminalInfo} marks
167
161
  * `hyperlinks: false` (e.g. `base`) stay off unless the user forced on.
168
- * 4. GNU screen's explicit session marker (`STY`) always off, even if tmux is
169
- * also present: a screen layer anywhere in the path cannot forward OSC 8.
170
- * 5. tmux session (`TMUX` set): enabled when tmux self-reports >= 3.4 via
171
- * `TERM_PROGRAM_VERSION` (tmux 3.4 stores OSC 8 as a cell attribute and
172
- * forwards it to outer terminals whose `terminal-features` include
173
- * `hyperlinks`). Older or unknown versions stay off; on outer terminals
174
- * without the feature configured, tmux silently drops the sequence —
175
- * identical to today. Checked before the screen-family TERM heuristic
176
- * because tmux's historical `default-terminal` is `screen-256color`, so
177
- * `TERM=screen*` inside a tmux session must NOT short-circuit to off.
178
- * 6. screen-family TERM without `TMUX` always off: screen never gained OSC 8
179
- * support.
180
- * 7. tmux-family TERM without `TMUX` env — unusual (e.g. inspection scripts);
181
- * no version available, so off.
182
- * 8. Otherwise honor the static terminal capability.
162
+ * 4. A session that never forwards OSC 8 (`drop`, e.g. GNU screen's `STY`)
163
+ * always off, even when a forwarding multiplexer is also present.
164
+ * 5. Forwarding sessions (`forward`, e.g. `TMUX`): enabled when every one
165
+ * self-reports at least its forwarding version via `TERM_PROGRAM` /
166
+ * `TERM_PROGRAM_VERSION` (tmux 3.4). Older or unknown versions stay off;
167
+ * on outer terminals without the feature configured, tmux silently drops
168
+ * the sequence. Checked before the TERM heuristic because tmux's
169
+ * historical `default-terminal` is `screen-256color`, so `TERM=screen*`
170
+ * inside a tmux session must NOT short-circuit to off.
171
+ * 6. TERM naming a multiplexer whose session markers were stripped: off,
172
+ * since no session proves the multiplexer forwards OSC 8 (screen never
173
+ * does; tmux has no version to check).
174
+ * 7. Otherwise honor the static terminal capability.
183
175
  */
184
176
  export declare function shouldEnableHyperlinksByDefault(env?: NodeJS.ProcessEnv, terminalId?: TerminalId): boolean;
185
177
  /**