@oh-my-pi/pi-tui 18.12.2 → 18.12.4

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 (76) hide show
  1. package/CHANGELOG.md +44 -48
  2. package/dist/types/autocomplete.d.ts +6 -0
  3. package/dist/types/chat/skill-message.d.ts +3 -4
  4. package/dist/types/components/sparkline.d.ts +34 -0
  5. package/dist/types/index.d.ts +1 -0
  6. package/dist/types/native/describe.d.ts +7 -1
  7. package/dist/types/native/tone.d.ts +2 -0
  8. package/dist/types/overlays/agent-hub.d.ts +3 -3
  9. package/dist/types/overlays/approval-dialog.d.ts +15 -1
  10. package/dist/types/overlays/jobs-panel.d.ts +3 -0
  11. package/dist/types/overlays/model-browser.d.ts +1 -1
  12. package/dist/types/render/output-block.d.ts +2 -0
  13. package/dist/types/render/tool-card.d.ts +2 -0
  14. package/dist/types/sixel.d.ts +28 -0
  15. package/dist/types/status-line/host.d.ts +3 -0
  16. package/dist/types/terminal-capabilities.d.ts +5 -0
  17. package/dist/types/tools/bash.d.ts +2 -0
  18. package/dist/types/tools/default-renderer.d.ts +3 -0
  19. package/dist/types/tools/eval.d.ts +9 -8
  20. package/dist/types/tools/irc.d.ts +6 -0
  21. package/dist/types/tools/job-widget.d.ts +226 -0
  22. package/dist/types/tools/json-tree.d.ts +2 -0
  23. package/dist/types/tools/line-ranges.d.ts +8 -1
  24. package/dist/types/tools/mcp.d.ts +23 -0
  25. package/dist/types/tools/output-meta.d.ts +1 -1
  26. package/dist/types/tools/read.d.ts +8 -2
  27. package/dist/types/tools/renderer.d.ts +8 -2
  28. package/dist/types/tools/result-card.d.ts +1 -1
  29. package/dist/types/tools/streaming-output.d.ts +1 -0
  30. package/dist/types/tools/task.d.ts +12 -0
  31. package/dist/types/tools/wait.d.ts +5 -0
  32. package/package.json +9 -9
  33. package/src/autocomplete.ts +12 -1
  34. package/src/chat/skill-message.ts +19 -21
  35. package/src/chat/tool-execution.ts +35 -0
  36. package/src/chrome/transcript-container.ts +85 -12
  37. package/src/components/editor.ts +17 -7
  38. package/src/components/image.ts +5 -4
  39. package/src/components/markdown.ts +11 -3
  40. package/src/components/sparkline.ts +89 -0
  41. package/src/index.ts +1 -0
  42. package/src/native/backend.ts +25 -5
  43. package/src/native/describe.ts +18 -1
  44. package/src/native/tone.ts +22 -0
  45. package/src/overlays/agent-hub.ts +14 -10
  46. package/src/overlays/agent-transcript-viewer.ts +2 -2
  47. package/src/overlays/approval-dialog.ts +59 -13
  48. package/src/overlays/jobs-panel.ts +24 -2
  49. package/src/overlays/model-browser.ts +3 -0
  50. package/src/prompt/attachment-chips.ts +1 -1
  51. package/src/render/output-block.ts +25 -12
  52. package/src/render/tool-card.ts +6 -0
  53. package/src/sixel.ts +185 -0
  54. package/src/status-line/component.ts +19 -2
  55. package/src/status-line/host.ts +3 -0
  56. package/src/terminal-capabilities.ts +43 -3
  57. package/src/theme/symbols.ts +5 -3
  58. package/src/tools/bash.ts +25 -9
  59. package/src/tools/default-renderer.ts +54 -17
  60. package/src/tools/eval.ts +32 -14
  61. package/src/tools/find.ts +4 -5
  62. package/src/tools/glob.ts +4 -6
  63. package/src/tools/grep.ts +4 -6
  64. package/src/tools/irc.ts +6 -0
  65. package/src/tools/job-widget.ts +1036 -0
  66. package/src/tools/json-tree.ts +8 -0
  67. package/src/tools/line-ranges.ts +23 -13
  68. package/src/tools/mcp.ts +44 -1
  69. package/src/tools/output-meta.ts +1 -1
  70. package/src/tools/read.ts +64 -21
  71. package/src/tools/renderer.ts +8 -2
  72. package/src/tools/result-card.ts +1 -2
  73. package/src/tools/streaming-output.ts +11 -9
  74. package/src/tools/task.ts +25 -1
  75. package/src/tools/wait.ts +288 -147
  76. package/src/tui.ts +45 -5
package/CHANGELOG.md CHANGED
@@ -2,6 +2,49 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.12.4] - 2026-10-20
6
+
7
+ ### Added
8
+
9
+ - Added `mergeLineRanges` and an optional `BareLineMode` argument to `parseLineRanges` (`"single"` reads a lone bare `N` as that one line) ([#16435](https://github.com/can1357/oh-my-pi/pull/16435) by [@will-bogusz](https://github.com/will-bogusz))
10
+
11
+ ### Changed
12
+
13
+ - `selectorLineRanges()` reads a bare `N` compounded with `raw` (`17:raw`, `raw:17`) as the single line `N`; `parseLineRanges()` takes an optional `"single"` mode for the same rule ([#16438](https://github.com/can1357/oh-my-pi/pull/16438) by [@will-bogusz](https://github.com/will-bogusz))
14
+ - Collapsed `wait` cards show one row per finished job (or a single "waiting on N jobs" line) instead of re-printing the whole job tree on every poll; Ctrl+O shows the full tree ([#16486](https://github.com/can1357/oh-my-pi/pull/16486) by [@H4vC](https://github.com/H4vC))
15
+ - Bash cards show the elapsed time while a command runs, and wall time, timeout and backgrounded job in the bottom border instead of a separate `⟨…⟩` line ([#16486](https://github.com/can1357/oh-my-pi/pull/16486) by [@H4vC](https://github.com/H4vC))
16
+ - The terminal `/jobs` sheet shows the selected job's full command ([#16486](https://github.com/can1357/oh-my-pi/pull/16486) by [@H4vC](https://github.com/H4vC))
17
+ - Grep, glob, find, IRC message, and `proc://`/`agent://`/`cfg://` result rows start at the same column as other tool rows ([#16486](https://github.com/can1357/oh-my-pi/pull/16486) by [@H4vC](https://github.com/H4vC))
18
+
19
+ ### Fixed
20
+
21
+ - Fixed Tern sessions logging `TSP: terminal stopped acknowledging frames` every 5 seconds for as long as the terminal stops acknowledging frames; it now warns once per stall and logs the stall's length when acknowledgements resume ([#16393](https://github.com/can1357/oh-my-pi/pull/16393) by [@will-bogusz](https://github.com/will-bogusz))
22
+ - `splitPathAndSel` and `splitInternalUrlSel` peel comma line lists that include a tail chunk (`:1-12,-15`) or repeat the colon after a comma (`:1-30,:-30`, also beside `:raw`); `splitPathAndSel(path, { foldListColons: false })` keeps the repeated colon in the path ([#16435](https://github.com/can1357/oh-my-pi/pull/16435) by [@will-bogusz](https://github.com/will-bogusz))
23
+ - Generic tool cards now reveal the complete result when expanded ([#15335](https://github.com/can1357/oh-my-pi/pull/15335) by [@yuzu-octopus](https://github.com/yuzu-octopus))
24
+ - Added `footerMeta` to `OutputBlockOptions` and `ToolCardSnapshot` to draw short facts inside a frame's bottom border ([#16486](https://github.com/can1357/oh-my-pi/pull/16486) by [@H4vC](https://github.com/H4vC))
25
+ - Fixed markdown table rows shattering at narrow widths when a wide glyph sat in a one-cell column; the glyph is now clamped to its column instead of re-wrapping the row ([#16479](https://github.com/can1357/oh-my-pi/pull/16479) by [@adi-IL](https://github.com/adi-IL)).
26
+ - Fixed charts in answers drawing as blank bands, on screen and in scrollback, when iTerm2 drew them in a background tab; inline images now carry an explicit height in rows ([#16471](https://github.com/can1357/oh-my-pi/pull/16471) by [@galtamam-cmyk](https://github.com/galtamam-cmyk))
27
+ - Fixed an inline image (such as a table's chart) disappearing in iTerm2 when new output pushed it past the top of the screen; it now moves to scrollback whole ([#16467](https://github.com/can1357/oh-my-pi/pull/16467) by [@galtamam-cmyk](https://github.com/galtamam-cmyk))
28
+ - Fixed inline images, hyperlinks, notifications and styled underlines staying off in iTerm2 sessions reached over SSH, where the forwarded `LC_TERMINAL` marker was ignored ([#16450](https://github.com/can1357/oh-my-pi/pull/16450) by [@yuzu-octopus](https://github.com/yuzu-octopus))
29
+ - Added Eval `mcp_progress` status events, updated in place per call and evictable under the status-event cap, plus `formatMCPProgress()` and `MCPToolDetails.progress` for MCP progress display ([#16431](https://github.com/can1357/oh-my-pi/pull/16431) by [@alphastorm](https://github.com/alphastorm))
30
+
31
+ ## [18.12.3] - 2026-10-19
32
+
33
+ ### Added
34
+
35
+ - Added `IrcMessage.broadcast`, set on each copy of an `agent://all` broadcast so recipients can tell it from a direct message ([#16312](https://github.com/can1357/oh-my-pi/pull/16312) by [@will-bogusz](https://github.com/will-bogusz))
36
+ - `AutocompleteItem.descriptionMatch` marks a slash command matched only through its description; `Editor` Enter no longer applies such a row unless the user moved the selection onto it ([#16265](https://github.com/can1357/oh-my-pi/issues/16265))
37
+ - `ApprovalDialogComponent` accepts `grants` and `onGrant`: grant choices above **Approve Once**, led by a toggle that keeps them across sessions ([#16049](https://github.com/can1357/oh-my-pi/pull/16049) by [@Peribunt](https://github.com/Peribunt))
38
+ - Added `describeJobWidget`/`renderJobWidgetLines` to draw a background job's widget natively and as terminal lines, `describeJobTiles`/`renderJobTileLines` to draw jobs as tiles (status, title, figure, widget), and `renderSparkline` (with `peakBuckets`/`fitSparkValues`) for one-row block sparklines
39
+
40
+ ### Fixed
41
+
42
+ - Fixed transparent images with empty top rows disappearing inside Zellij ([#16346](https://github.com/can1357/oh-my-pi/pull/16346) by [@Bouska](https://github.com/Bouska))
43
+ - Fixed bash output rewritten by the output minimizer skipping the per-line column cap (`tools.outputMaxColumns`), so a line wider than the cap reached the model whole; the raw output stays in its artifact ([#16314](https://github.com/can1357/oh-my-pi/pull/16314) by [@will-bogusz](https://github.com/will-bogusz))
44
+ - Fixed the composer caret drifting one cell left per pasted image or video chip in terminals that draw the chip icon as a wide emoji (JetBrains terminal); the `unicode` preset now uses `📷`/`🎬` chip icons ([#16270](https://github.com/can1357/oh-my-pi/issues/16270))
45
+ - Fixed Tern hiding user text sent with `/skill:<name>` inside a collapsed skill card; only the loaded skill prompt is hidden ([#16311](https://github.com/can1357/oh-my-pi/issues/16311))
46
+ - Fixed SIXEL charts and images overlapping following content when their top rows scroll out of the viewport ([#16245](https://github.com/can1357/oh-my-pi/pull/16245) by [@JustasMasiulis](https://github.com/JustasMasiulis)).
47
+
5
48
  ## [18.12.2] - 2026-10-18
6
49
 
7
50
  ### Added
@@ -2430,51 +2473,4 @@
2430
2473
  - Fixed `@` file mention autocomplete stalling for seconds when the query references something outside the project root (e.g. `@../`, `@~/`, `@/abs/`). `CombinedAutocompleteProvider` now short-circuits to plain immediate-directory prefix listing in those cases instead of dispatching a recursive `fuzzyFind` walk over a sibling directory full of unrelated projects. Inside-cwd queries keep the existing fuzzy-then-prefix behavior. ([#1395](https://github.com/can1357/oh-my-pi/issues/1395))
2431
2474
  - Gated the Hangul Compatibility Jamo width correction (U+3131..U+318E → 1 cell, originally landed in 15.0.1 for the IME / hardware-cursor displacement bug) behind `process.platform === "darwin"` in the TS path and `cfg!(target_os = "macos")` in the `pi-natives` Rust path. macOS terminals (Ghostty / Terminal.app / iTerm2) render jamo as 1 cell despite UAX#11 classifying them as Wide, but WezTerm and most Linux terminals honor UAX#11 and render them as 2 cells. The unconditional correction therefore desynced the TUI's column bookkeeping from the terminal's actual rendering off-darwin, producing corrupted layout and broken Korean input on Linux. On non-darwin the helpers now defer entirely to `Bun.stringWidth` / `UnicodeWidthStr` (also a small perf win on the multi-char-grapheme path). ([#1410](https://github.com/can1357/oh-my-pi/issues/1410))
2432
2475
 
2433
- ## [15.4.0] - 2026-05-26
2434
-
2435
- ### Fixed
2436
-
2437
- - Fixed terminal scrollback gaining duplicate copies of the welcome screen (and any other header content) when the bottom tool cell mutated across the previous viewport boundary. Once a row scrolls into terminal history it cannot be retracted, so a subsequent shrink that would re-expose that row in the repainted viewport now clears stale scrollback and replays the transcript, then suppresses one immediate suffix-scroll frame so live status/editor chrome is not deposited twice. Multiplexer panes ignore `\x1b[3J`, so the recovery is gated on `!isMultiplexerSession()`.
2438
- - Fixed the IME / hardware cursor sticking to the bottom of the terminal after a resize that grew the viewport taller than the rendered transcript. `#emitViewportRepaint` always writes one row per screen line (padding empty rows past the content), so the post-write hardware cursor sits at screen row `height - 1`. The bookkeeping previously clamped the tracked cursor row to `lines.length - 1`, making `#cursorControlSequence`'s relative `rowDelta` underestimate the upward move by `(height - lines.length)` rows and pinning the cursor at the viewport bottom even though the focused component's `CURSOR_MARKER` was on a content row.
2439
-
2440
- ## [15.3.2] - 2026-05-25
2441
-
2442
- ### Fixed
2443
-
2444
- - Fixed `matchesKey(data, "ctrl+m")` (and the other named-key collisions: `ctrl+h`/`ctrl+i`/`ctrl+j`/`ctrl+[`) returning true for the bare `\r`/`\x08`/`\t`/`\n`/`\x1b` byte terminals send for Enter/Backspace/Tab/Escape in legacy mode. Binding a command to `Ctrl+M` no longer fires when the user presses Enter — the named key wins, and `ctrl+<colliding-letter>` matches only when the terminal disambiguates via the Kitty keyboard protocol or `modifyOtherKeys`. ([#1354](https://github.com/can1357/oh-my-pi/issues/1354))
2445
-
2446
- ## [15.2.3] - 2026-05-22
2447
-
2448
- ### Added
2449
-
2450
- - Added `SettingsList#setItems` to replace the entire settings list with a new items array while automatically clamping selection to a valid index
2451
-
2452
- ### Changed
2453
-
2454
- - Updated `Loader` to drive renders at ~60fps (16ms tick) while keeping spinner-frame advancement at 80ms so shimmer/animated message colorizers update smoothly without altering spinner cadence
2455
-
2456
- ## [15.1.9] - 2026-05-21
2457
-
2458
- ### Fixed
2459
-
2460
- - Fixed terminal probe responses (DA1, kitty keyboard, Mode 2031) leaking into the prompt as keystrokes when the response is split across stdin reads. `ProcessTerminal` now reassembles `\x1b[?<digits>...` private CSI fragments and dispatches the complete response through the existing pattern handlers. ([#1238](https://github.com/can1357/oh-my-pi/issues/1238))
2461
-
2462
- ## [15.1.4] - 2026-05-19
2463
-
2464
- ### Fixed
2465
-
2466
- - Fixed `renderInlineMarkdown` crashing with `TypeError: undefined is not an object (evaluating 'e.replace')` when called with a non-string value during streaming — partial JSON parsing leaves option label fields temporarily unpopulated, causing the ask tool renderer to fail. ([#1176](https://github.com/can1357/oh-my-pi/issues/1176))
2467
-
2468
- ## [15.0.2] - 2026-05-15
2469
-
2470
- ### Added
2471
-
2472
- - Restored the `Key` runtime helper on `@oh-my-pi/pi-tui` to mirror upstream `@mariozechner/pi-tui`'s surface. `Key.enter`, `Key.escape`, `Key.tab`, … return the canonical key-name strings; modifier methods (`Key.ctrl(k)`, `Key.shift(k)`, `Key.ctrlShift(k)`, etc.) build precisely-typed `KeyId` literals like `"ctrl+c"`. Pure runtime convenience for typed key-id construction — plugins built against the upstream package surface that import `Key` (e.g. `@plannotator/pi-extension`, `@juicesharp/rpiv-ask-user-question`) load again now that the specifier shim remaps them onto this package.
2473
-
2474
- ## [15.0.1] - 2026-05-14
2475
-
2476
- ### Breaking Changes
2477
-
2478
- - Increased the minimum required Bun version for the TUI package from >=1.3.7 to >=1.3.14
2479
-
2480
- Older entries are archived in [packages/tui/CHANGELOG.md@04d4ab14b45f](https://github.com/can1357/oh-my-pi/blob/04d4ab14b45f8dbd4055b675519f8815a1eb1841/packages/tui/CHANGELOG.md).
2476
+ Older entries are archived in [packages/tui/CHANGELOG.md@ec051608a87a](https://github.com/can1357/oh-my-pi/blob/ec051608a87ad78d4930a46af7f5582192005ada/packages/tui/CHANGELOG.md).
@@ -39,6 +39,12 @@ export interface AutocompleteItem {
39
39
  state?: string;
40
40
  /** Dim hint text shown inline after cursor when this item is selected */
41
41
  hint?: string;
42
+ /**
43
+ * Slash command matched only through its description, not its name or an alias:
44
+ * a browse hit, so Enter submits the typed text instead of running it unless the
45
+ * user moved the selection onto it.
46
+ */
47
+ descriptionMatch?: boolean;
42
48
  }
43
49
  type Awaitable<T> = T | Promise<T>;
44
50
  export interface SlashCommand {
@@ -20,10 +20,9 @@ export declare class SkillMessageComponent extends Container {
20
20
  setExpanded(expanded: boolean): void;
21
21
  handleNativeEvent(event: NativeUiEvent): void;
22
22
  /**
23
- * A user-toned card (role `omp.skill`): the skill chip (linked to its
24
- * SKILL.md) and prompt size in the head, the user's draft as markdown, and
25
- * the loaded skill prompt, described only while expanded because it can
26
- * be large.
23
+ * A user-toned card (role `omp.skill`): the skill chip and prompt size in
24
+ * the head, the user's draft always visible, and only the loaded skill
25
+ * prompt behind a disclosure.
27
26
  */
28
27
  describe(): NativeNode;
29
28
  /**
@@ -0,0 +1,34 @@
1
+ /**
2
+ * One-row block sparklines (`▁▂▃▅▇█`) for ANSI renderers: the usage history
3
+ * in `omp usage`, a job widget's series in the `wait` card and status line.
4
+ */
5
+ /** Block glyphs from lowest to highest. */
6
+ export declare const SPARK_LEVELS: readonly ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
7
+ /** How {@link renderSparkline} maps values to glyphs and styles them. */
8
+ export interface SparklineOptions {
9
+ /** Domain low end; values at or below it draw the lowest block. Default 0. */
10
+ readonly min?: number;
11
+ /** Domain high end; values at or above it draw the full block. Default the largest value. */
12
+ readonly max?: number;
13
+ /** Styles one glyph; `fraction` is the value's 0–1 position in the domain. */
14
+ readonly style?: (glyph: string, value: number, fraction: number) => string;
15
+ /** What a missing value draws, already styled. Default a space. */
16
+ readonly gap?: string;
17
+ }
18
+ /** The block glyph for a 0–1 fraction of the domain. */
19
+ export declare function sparkGlyph(fraction: number): string;
20
+ /** One cell per value, oldest first; `undefined` (and non-finite) values draw the gap. */
21
+ export declare function renderSparkline(values: readonly (number | undefined)[], options?: SparklineOptions): string;
22
+ /**
23
+ * `values` squeezed into at most `cells` points by equal-count bucket means,
24
+ * newest bucket last; shorter series come back unchanged.
25
+ */
26
+ export declare function fitSparkValues(values: readonly number[], cells: number): readonly number[];
27
+ /**
28
+ * The largest value per time bucket over `[sinceMs, nowMs]`, `cells` buckets
29
+ * wide; buckets without a point are `undefined` (a gap in the sparkline).
30
+ */
31
+ export declare function peakBuckets(points: Iterable<{
32
+ readonly at: number;
33
+ readonly value: number;
34
+ }>, sinceMs: number, nowMs: number, cells: number): (number | undefined)[];
@@ -24,6 +24,7 @@ export * from "./components/section.js";
24
24
  export * from "./components/select-list.js";
25
25
  export * from "./components/settings-list.js";
26
26
  export * from "./components/spacer.js";
27
+ export * from "./components/sparkline.js";
27
28
  export * from "./components/tab-bar.js";
28
29
  export * from "./components/table.js";
29
30
  export * from "./components/text.js";
@@ -9,7 +9,7 @@
9
9
  * ]);
10
10
  * }
11
11
  */
12
- import type { TspKind, TspProps, TspSpan, TspText } from "@oh-my-pi/pi-wire";
12
+ import type { TspKind, TspPropNode, TspProps, TspSpan, TspText } from "@oh-my-pi/pi-wire";
13
13
  import type { NativeChild, NativeNode } from "./node.js";
14
14
  /** A node of any kind. */
15
15
  export declare function node<K extends TspKind>(k: K, p?: TspProps<K>, c?: readonly NativeChild[], key?: string): NativeNode;
@@ -37,6 +37,12 @@ export declare const EMPTY_NODE: NativeNode;
37
37
  export declare function keyed(described: NativeNode, key: string): NativeNode;
38
38
  /** `described` mounted but not laid out when `hidden` (cheap visibility toggles keep ids and view state). */
39
39
  export declare function withHidden(described: NativeNode, hidden: boolean): NativeNode;
40
+ /**
41
+ * A described tree as the node tree a prop carries (a `hovercard`): plain
42
+ * nodes only, since nothing reconciles inside a prop; component children
43
+ * (which describe themselves per frame) are left out.
44
+ */
45
+ export declare function propNode(described: NativeNode): TspPropNode;
40
46
  /** Stable node key for an arbitrary identity string; keys join into `/` keypaths, so identities are hashed. */
41
47
  export declare function stableKey(identity: string): string;
42
48
  /** Drop absent entries (`undefined`, `null`, `false`) from a child list. */
@@ -17,6 +17,8 @@ export interface BackgroundChrome {
17
17
  }
18
18
  /** Map an omp background token to card tone/role. */
19
19
  export declare function backgroundChrome(bg: ThemeBg | undefined): BackgroundChrome;
20
+ /** The omp theme colour an ANSI renderer draws a TSP tone with (the inverse of {@link colorTone}). */
21
+ export declare function toneColor(tone: TspTone): ThemeColor;
20
22
  /**
21
23
  * Tone of an omp colour used as a severity or border colour; undefined for
22
24
  * colours that carry no tone (callers pick their own fallback).
@@ -5,11 +5,11 @@
5
5
  * - Table view: every registered agent except Main (Main IS the ambient
6
6
  * chat), live from the global AgentHubRegistry — status, unread irc count,
7
7
  * current/last task, last activity. Navigate with keys, wheel, hover, and
8
- * click; `r` revives a parked agent, `x` aborts + releases one.
8
+ * click; `r` revives a parked or killed agent, `x` aborts + releases one.
9
9
  * - Chat view: per-agent transcript (incremental session-file tail, absorbed
10
10
  * from the old session observer overlay) plus an input line. Submitting
11
- * revives a parked agent, then prompts/steers it; the message lands in the
12
- * agent's persisted history via the normal prompt path.
11
+ * revives a parked or killed agent, then prompts/steers it; the message
12
+ * lands in the agent's persisted history via the normal prompt path.
13
13
  *
14
14
  * Replaces the old SessionObserverOverlayComponent (ctrl+s observer).
15
15
  */
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Tool-approval prompt in the composer's place, presented like the ask
3
3
  * dialog: the approval title and its details over a list of choices —
4
- * Approve, an optional "approve for this session", and Deny — and an action
4
+ * optional grants (led by a toggle that keeps them across sessions), Approve,
5
+ * an optional "approve for this session", and Deny — and an action
5
6
  * bar. The arrows move between the choices and Enter takes the highlighted
6
7
  * one; `app.approval.approve` (Ctrl+Enter by default) approves this call
7
8
  * outright and Esc denies. Enter and the approve chord only arm
@@ -23,6 +24,13 @@ interface ApprovalDialogCallbacks {
23
24
  onApprove(): void;
24
25
  onDeny(): void;
25
26
  }
27
+ /** A choice that approves the call and remembers more than it: a folder, or the exact target. */
28
+ export interface ApprovalDialogGrant {
29
+ /** Label while the grant is remembered for this session. */
30
+ readonly label: string;
31
+ /** Label once the remember toggle keeps it across sessions. */
32
+ readonly alwaysLabel: string;
33
+ }
26
34
  /** The composer mounted beneath the dialog: it receives every key the dialog does not own. */
27
35
  export interface ApprovalDialogDraft {
28
36
  /** True while the composer holds a draft — text, attachments, or a paste still landing: keys then edit and send it. */
@@ -48,6 +56,12 @@ interface ApprovalDialogOptions {
48
56
  label: string;
49
57
  onApprove(): void;
50
58
  };
59
+ /**
60
+ * Grants to offer above Approve, led by a toggle that keeps them across sessions; Approve then
61
+ * reads "Approve Once". `onGrant` gets the chosen grant and whether the toggle was on.
62
+ */
63
+ grants?: readonly ApprovalDialogGrant[];
64
+ onGrant?(grant: ApprovalDialogGrant, always: boolean): void;
51
65
  }
52
66
  export declare class ApprovalDialogComponent implements Component {
53
67
  #private;
@@ -1,6 +1,7 @@
1
1
  import type { Component } from "../tui.js";
2
2
  import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
3
3
  import { type JobTreeAgent } from "./job-tree.js";
4
+ import { type JobWidgetView } from "../tools/job-widget.js";
4
5
  /** One async job as the session snapshots it. */
5
6
  export interface JobsPanelJob {
6
7
  readonly id: string;
@@ -35,6 +36,8 @@ export interface JobsPanelDetail {
35
36
  readonly output?: string;
36
37
  /** Artifact holding the full output when `output` is cut. */
37
38
  readonly artifactId?: string;
39
+ /** The job's live widget (frozen once it settles), drawn above the output. */
40
+ readonly widget?: JobWidgetView;
38
41
  }
39
42
  /** The session behind a {@link JobsSheet}. */
40
43
  export interface JobsSheetSource {
@@ -7,7 +7,7 @@ import { type ThemeColor } from "../theme/theme.js";
7
7
  import type { TspPickerColumn, TspPickerGroup, TspPickerItem, TspPickerMark } from "@oh-my-pi/pi-wire";
8
8
  import type { NativeChild, NativeNode, NativeUiEvent } from "../native/node.js";
9
9
  /** Canonical display ordering of built-in model roles. */
10
- export type ModelRole = "default" | "smol" | "slow" | "vision" | "plan" | "commit" | "tiny" | "memory" | "task" | "advisor" | "image" | "web" | "speech" | "dictation" | "judge";
10
+ export type ModelRole = "default" | "smol" | "slow" | "vision" | "plan" | "commit" | "tiny" | "memory" | "task" | "advisor" | "widget" | "image" | "web" | "speech" | "dictation" | "judge";
11
11
  export declare const MODEL_ROLE_IDS: ModelRole[];
12
12
  export declare const CHAT_MODEL_ROLE_IDS: ModelRole[];
13
13
  export declare const KIND_ROLE_IDS: ModelRole[];
@@ -10,6 +10,8 @@ import type { State } from "./types.js";
10
10
  export interface OutputBlockOptions {
11
11
  header?: string;
12
12
  headerMeta?: string;
13
+ /** Facts drawn inside the bottom border (`╰── Wall 0.16s · Timeout 300s ──╯`). */
14
+ footerMeta?: string;
13
15
  state?: State;
14
16
  sections?: Array<{
15
17
  label?: string;
@@ -22,6 +22,8 @@ export interface ToolCardSnapshot {
22
22
  /** Structured status header, rendered by the shared status-line primitive. */
23
23
  status?: StatusLineOptions;
24
24
  headerMeta?: string;
25
+ /** Short facts drawn inside the frame's bottom border (framed); a trailing row otherwise. */
26
+ footerMeta?: string;
25
27
  phase?: ToolCardPhase;
26
28
  body?: ToolCardContent;
27
29
  sections?: readonly ToolCardSection[];
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Give an empty first band an explicit transparent width. Zellij derives the
3
+ * decoded image width from its first pixel row, ignoring the raster minimum
4
+ * for transparent images; an omitted band otherwise makes the image invisible.
5
+ * Palette definitions stay before drawing so cropping can still parse them.
6
+ */
7
+ export declare function ensureSixelRasterWidth(sequence: string): string;
8
+ /**
9
+ * Crop integer pixel rows from a raw (not tmux-wrapped) SIXEL DCS image.
10
+ * Runs are shifted between adjacent six-pixel bands, never decoded to pixels.
11
+ * Palette selections, overdraw order, transparent gaps and DCS background mode
12
+ * are retained. A nonpositive crop returns the original sequence unchanged.
13
+ *
14
+ * The supported grammar is the native icy_sixel encoder's: one leading raster
15
+ * declaration with positive dimensions and square pixels, prefix RGB/HLS palette
16
+ * definitions, register selections, sixel characters, repeats, `$` and `-`.
17
+ * ESC DCS/ST framing only, as the TUI emits it. Palette definitions after
18
+ * drawing, additional raster declarations, other controls and malformed input
19
+ * throw; forwarding an unsupported image uncropped would reintroduce raster
20
+ * overflow.
21
+ *
22
+ * Without maxHeightPixels the crop is exact, including a partial final band with
23
+ * zero padding bits and the exact declared raster height. Some terminals still
24
+ * allocate all six rows of that final band. The TUI supplies its available pixel
25
+ * height to cap the result at a whole-band boundary, matching the native encoder's
26
+ * policy of dropping bottom pixels rather than overwriting the following row.
27
+ */
28
+ export declare function cropSixelTop(sequence: string, pixels: number, maxHeightPixels?: number): string;
@@ -1,6 +1,7 @@
1
1
  import type { AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import type { Tool, UsageLimit, UsageReport } from "@oh-my-pi/pi-ai";
3
3
  import type { Model } from "@oh-my-pi/pi-catalog/types";
4
+ import type { JobWidgetEntry } from "../tools/job-widget.js";
4
5
  import type { CompactionBoundaries } from "./context-usage.js";
5
6
  import type { StatusLineSettings, StatusResetExpiry } from "./types.js";
6
7
  export interface StatusAccountIdentity {
@@ -74,6 +75,8 @@ export interface StatusLineSession {
74
75
  agentId?: string;
75
76
  }[];
76
77
  } | null | undefined;
78
+ /** Widgets of the running background jobs, in job order; the jobs segment appends the freshest one's glance. */
79
+ getRunningJobWidgets?(): readonly JobWidgetEntry[];
77
80
  getGoalModeState(): {
78
81
  goal?: {
79
82
  status: string;
@@ -389,6 +389,11 @@ export declare function encodeITerm2(base64Data: string, options?: {
389
389
  preserveAspectRatio?: boolean;
390
390
  inline?: boolean;
391
391
  }): string;
392
+ /**
393
+ * The encoded image `encodeITerm2` wrote into `line`, without the size
394
+ * parameters a rewrap changes; undefined for a line without one.
395
+ */
396
+ export declare function iterm2ImagePayload(line: string): string | undefined;
392
397
  export declare function calculateImageRows(imageDimensions: ImageDimensions, targetWidthCells: number, cellDimensions?: CellDimensions): number;
393
398
  export declare function getPngDimensions(base64Data: string): ImageDimensions | null;
394
399
  export declare function getJpegDimensions(base64Data: string): ImageDimensions | null;
@@ -117,6 +117,7 @@ export declare function createShellRenderer<TArgs>(config: ShellRendererConfig<T
117
117
  }, args?: TArgs): NativeToolView;
118
118
  mergeCallAndResult: true;
119
119
  inline: true;
120
+ tickElapsed: true;
120
121
  };
121
122
  /** Renders bash command previews and output. */
122
123
  export declare const bashToolRenderer: {
@@ -146,4 +147,5 @@ export declare const bashToolRenderer: {
146
147
  }, args?: BashRenderArgs | undefined): NativeToolView;
147
148
  mergeCallAndResult: true;
148
149
  inline: true;
150
+ tickElapsed: true;
149
151
  };
@@ -23,6 +23,9 @@ export declare function formatDefaultToolExecution(input: DefaultToolRenderInput
23
23
  /**
24
24
  * TSP view of the generic fallback card: the tool label with a one-line args
25
25
  * summary as the head target; the result as a JSON tree or raw `ansi` output.
26
+ * The complete output goes over the wire — the card-level disclosure clamp the
27
+ * terminal applies is the only bound, so an expanded card keeps every row. JSON
28
+ * the tree's depth, node or scalar caps would cut keeps the raw path instead.
26
29
  */
27
30
  export declare function describeDefaultToolExecution(input: DefaultToolRenderInput): NativeToolView;
28
31
  /** Render the generic fallback as the state-tinted card used by direct custom tools. */
@@ -61,7 +61,7 @@ export interface EvalCellResult {
61
61
  durationMs?: number;
62
62
  exitCode?: number;
63
63
  statusEvents?: EvalStatusEvent[];
64
- /** Discrete events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
64
+ /** Evictable events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
65
65
  statusEventsElided?: number;
66
66
  }
67
67
  /** Tool result detail object surfaced to the UI/transcript. */
@@ -69,7 +69,7 @@ export interface EvalToolDetails {
69
69
  cells?: EvalCellResult[];
70
70
  images?: ImageContent[];
71
71
  statusEvents?: EvalStatusEvent[];
72
- /** Discrete events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
72
+ /** Evictable events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
73
73
  statusEventsElided?: number;
74
74
  isError?: boolean;
75
75
  meta?: OutputMeta;
@@ -104,7 +104,7 @@ interface EvalRenderContext {
104
104
  timeout?: number;
105
105
  }
106
106
  /**
107
- * Coalescing key of a progress-snapshot event: `agent` and `judge_batch`
107
+ * Coalescing key of a progress-snapshot event: `agent`, `judge_batch`, and `mcp_progress`
108
108
  * events keyed by `id`, where only the newest snapshot matters. Discrete
109
109
  * actions (everything else) have no key. Shared by {@link upsertStatusEvent}
110
110
  * and the executors' display collectors so both coalesce identically.
@@ -114,12 +114,12 @@ export declare function statusEventKey(event: {
114
114
  [key: string]: unknown;
115
115
  }): string | undefined;
116
116
  /**
117
- * Discrete status events a log keeps. A cell polling a helper in a loop emits
117
+ * Evictable status events a log keeps. A cell polling a helper in a loop emits
118
118
  * one event per call (hundreds of thousands), and every live update and the
119
119
  * persisted tool result would otherwise carry them all.
120
120
  */
121
121
  export declare const MAX_STATUS_EVENTS = 200;
122
- /** A status event list plus the count of discrete events dropped from its front. */
122
+ /** A status event list plus the count of evictable events dropped from its front. */
123
123
  export type StatusEventLog = Pick<EvalCellResult, "statusEvents" | "statusEventsElided">;
124
124
  /**
125
125
  * Append or replace a status event. Progress snapshots (see
@@ -129,9 +129,10 @@ export type StatusEventLog = Pick<EvalCellResult, "statusEvents" | "statusEvents
129
129
  export declare function upsertStatusEvent(events: EvalStatusEvent[], event: EvalStatusEvent): void;
130
130
  /**
131
131
  * {@link upsertStatusEvent} into a bounded log. Past {@link MAX_STATUS_EVENTS},
132
- * the oldest discrete event is dropped and counted. Snapshots stay, since agent
133
- * cards read them, and so does the newest committed `todo` result, which the
134
- * session todo panel refreshes from. Renderers already show only the newest
132
+ * the oldest discrete event or MCP progress snapshot is dropped and counted.
133
+ * Agent/judgment-batch snapshots stay, since agent cards read them, and so does
134
+ * the newest committed `todo` result, which the session todo panel refreshes
135
+ * from. Renderers already show only the newest
135
136
  * events behind an "… N earlier" row.
136
137
  */
137
138
  export declare function recordStatusEvent(log: StatusEventLog, event: EvalStatusEvent): void;
@@ -19,6 +19,12 @@ export interface IrcMessage {
19
19
  * ping-pong forever.
20
20
  */
21
21
  wakeRelay?: boolean;
22
+ /**
23
+ * One leg of an `all` broadcast. Like relays, broadcasts never draw an
24
+ * automatic wake-turn reply: every woken idle peer would otherwise answer
25
+ * the broadcaster, mostly to say the message was not for it.
26
+ */
27
+ broadcast?: boolean;
22
28
  }
23
29
  /** Delivery outcome for one peer recipient. */
24
30
  export interface IrcDeliveryReceipt {