@oh-my-pi/pi-tui 18.10.0 → 18.10.2

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 (78) hide show
  1. package/CHANGELOG.md +42 -154
  2. package/THIRD-PARTY-NOTICES.txt +3 -3
  3. package/dist/types/app-keybindings.d.ts +8 -8
  4. package/dist/types/apps/git/diff-pane.d.ts +5 -0
  5. package/dist/types/apps/git/state.d.ts +11 -0
  6. package/dist/types/chat/assistant-message.d.ts +9 -4
  7. package/dist/types/chat/tool-execution.d.ts +32 -20
  8. package/dist/types/chat/user-message.d.ts +3 -2
  9. package/dist/types/chrome/countdown-timer.d.ts +3 -2
  10. package/dist/types/native/backend.d.ts +5 -4
  11. package/dist/types/native/blobs.d.ts +13 -1
  12. package/dist/types/overlays/annotation-overlay.d.ts +19 -0
  13. package/dist/types/overlays/ask-dialog.d.ts +9 -4
  14. package/dist/types/overlays/btw-history-panel.d.ts +2 -6
  15. package/dist/types/overlays/hook-editor.d.ts +7 -2
  16. package/dist/types/overlays/hook-input.d.ts +12 -4
  17. package/dist/types/overlays/jobs-panel.d.ts +8 -7
  18. package/dist/types/overlays/login-dialog.d.ts +8 -3
  19. package/dist/types/overlays/mcp-add-wizard.d.ts +9 -1
  20. package/dist/types/overlays/model-browser.d.ts +6 -1
  21. package/dist/types/overlays/pause-screen.d.ts +5 -0
  22. package/dist/types/overlays/report-panel.d.ts +5 -1
  23. package/dist/types/overlays/reset-usage-selector.d.ts +7 -5
  24. package/dist/types/overlays/session-account-selector.d.ts +4 -0
  25. package/dist/types/overlays/session-info-overlay.d.ts +7 -3
  26. package/dist/types/overlays/usage-dashboard.d.ts +6 -6
  27. package/dist/types/status-line/context-usage.d.ts +1 -1
  28. package/dist/types/tools/bash.d.ts +2 -1
  29. package/dist/types/tools/eval.d.ts +2 -2
  30. package/dist/types/tools/grouped-file-output.d.ts +4 -1
  31. package/dist/types/tools/native-view.d.ts +1 -1
  32. package/dist/types/tools/read.d.ts +7 -1
  33. package/dist/types/tools/renderer.d.ts +2 -0
  34. package/package.json +9 -9
  35. package/src/app-keybindings.ts +8 -8
  36. package/src/apps/autoresearch-dashboard.ts +440 -27
  37. package/src/apps/git/diff-pane.ts +39 -35
  38. package/src/apps/git/git-tui.ts +53 -4
  39. package/src/apps/git/state.ts +12 -0
  40. package/src/chat/assistant-message.ts +68 -19
  41. package/src/chat/tool-execution.ts +73 -30
  42. package/src/chat/user-message.ts +32 -19
  43. package/src/chrome/countdown-timer.ts +3 -3
  44. package/src/native/backend.ts +13 -5
  45. package/src/native/blobs.ts +34 -1
  46. package/src/native/reconcile.ts +24 -6
  47. package/src/overlays/advisor-config.ts +259 -8
  48. package/src/overlays/annotation-overlay.ts +420 -168
  49. package/src/overlays/ask-dialog.ts +154 -90
  50. package/src/overlays/btw-history-panel.ts +178 -124
  51. package/src/overlays/hook-editor.ts +90 -32
  52. package/src/overlays/hook-input.ts +105 -19
  53. package/src/overlays/jobs-panel.ts +154 -132
  54. package/src/overlays/login-dialog.ts +201 -91
  55. package/src/overlays/mcp-add-wizard.ts +559 -279
  56. package/src/overlays/model-browser.ts +23 -1
  57. package/src/overlays/model-hub.ts +2 -9
  58. package/src/overlays/pause-screen.ts +81 -23
  59. package/src/overlays/plugin-selector.ts +17 -1
  60. package/src/overlays/queue-mode-selector.ts +10 -0
  61. package/src/overlays/report-panel.ts +6 -2
  62. package/src/overlays/reset-usage-selector.ts +130 -21
  63. package/src/overlays/session-account-selector.ts +36 -0
  64. package/src/overlays/session-info-overlay.ts +197 -76
  65. package/src/overlays/show-images-selector.ts +1 -0
  66. package/src/overlays/theme-selector.ts +6 -1
  67. package/src/overlays/thinking-selector.ts +8 -4
  68. package/src/overlays/tree-selector.ts +117 -2
  69. package/src/overlays/usage-dashboard.ts +495 -143
  70. package/src/status-line/context-usage.ts +154 -57
  71. package/src/tools/bash.ts +9 -8
  72. package/src/tools/eval.ts +2 -2
  73. package/src/tools/grep.ts +1 -0
  74. package/src/tools/grouped-file-output.ts +11 -2
  75. package/src/tools/native-view.ts +2 -2
  76. package/src/tools/read.ts +12 -4
  77. package/src/tools/renderer.ts +2 -0
  78. package/src/tools/wait.ts +16 -30
package/CHANGELOG.md CHANGED
@@ -2,6 +2,47 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.10.2] - 2026-10-12
6
+
7
+ ### Added
8
+
9
+ - Added opt-in `/tree` branch navigation across visible branches and nested fork depths; bind `app.tree.previousBranch` / `app.tree.nextBranch` (e.g. to `Shift+Left` / `Shift+Right`) in `keybindings.yml` ([#12623](https://github.com/can1357/oh-my-pi/pull/12623) by [@azain47](https://github.com/azain47)).
10
+
11
+ ### Changed
12
+
13
+ - The `wait` tool's native job rows (`omp.wait.job`) are a single `row`: badge, id and label, progress and clock, without the output preview or capture notice beneath
14
+ - The native bash run foot reads In background with a live clock (`omp.run.time` without `stopped`) while a parked job's frames stream (`details.async.state === "running"`, partial), instead of Running
15
+ - Native model pickers (/model, the quick switch and the advisor's) mark providers with their logo (`mark.icon: "provider:<id>"`, initials where the terminal has none), and every model row leads with its provider's mark
16
+
17
+ ### Removed
18
+
19
+ - Removed the unused `app.tree.foldOrUp` / `app.tree.unfoldOrDown` keybinding ids, which no longer did anything.
20
+ - Added `parksAsBackground(toolName, details)`, `asyncJobState(details)`, `isSettledJobFrame(details)` and `settleWithJobFrame(component, frame, toolCallId)` (`chat/tool-execution`): whether a returned call's card stays live for its background job's frames (`task` always; `bash` and `eval` under native rendering), the job state a frame reports, and settling the card with the job's last frame (a cancelled job keeps its output and seals as cancelled)
21
+ - `BashToolDetails.async.state` and `EvalToolDetails.async.state` gain `cancelled` for a job killed before it finished
22
+
23
+ ## [18.10.1] - 2026-10-12
24
+
25
+ ### Added
26
+
27
+ - `AssistantMessageComponent`'s native turn footer leads with a Copy icon (`omp.turn.copy`) and a dot instead of the clock icon; it copies the answer's text and shows when the host handles transcript actions
28
+
29
+ ### Changed
30
+
31
+ - `UserMessageComponent`'s native hover toolbar (`omp.user.tools`) leads with Copy and Rewind icon buttons (`copy`, `rewind`) instead of text labels, then a dot and the time, like the turn usage footer
32
+ - `ContextUsageView`'s native body (on terminals with `meter`) leads with the tokens used and the room left before auto-compaction, then one stacked bar ticked at the threshold, the breakdown as rows (`omp.context.cat`, `.cat.free`, `.cat.buffer`: swatch, name, tokens, share; the exact count in the row's `title`) and the snapcompact estimate as labelled rows (`omp.context.snap`); the blocks meter and legend `kv` are gone, and `contextUsageHead` no longer repeats the window size
33
+ - `AskDialogComponent`'s native root is `omp.editor.ask` (collapsed: `omp.editor.ask.hidden`, the countdown, the question as `omp.ask.summary`, Skip and Show): a chosen answer is the `accent`-toned row (a check also carries the check icon) instead of the highlighted one; multi-select Other… is `omp.ask.other.check`; the question tabs check answered questions and say their keys in the strip's `title`; the countdown moves from the head to the action bar beside Hide; the preview is `omp.ask.preview`; the Review tab leads with `omp.ask.notice` and lists answers (`omp.ask.answers`) by question name with inline code mono and no `(Recommended)` suffix; option descriptions run inline code mono, notes ride the row's detail as `em`; Submit/Next's tooltip names only Enter (and Space on a multi-select)
34
+ - `MCPAddWizard`'s native sheet asks one question per step: a phase strip (`omp.mcpAdd.progress` of `omp.mcpAdd.phase`, toned done/current/upcoming and `neutral` when no auth was needed), the question and its lead (`omp.mcpAdd.title`, `omp.mcpAdd.tag` for optional fields, `omp.mcpAdd.lead`), then a mono field with a placeholder and its rule or refusal (`omp.mcpAdd.field`, `tone: "error"`; `omp.mcpAdd.note`), choice rows with icons and mono tags (`omp.mcpAdd.choices`), status lines (`omp.mcpAdd.status`, `omp.mcpAdd.checks`, `omp.mcpAdd.error`) or the review rows (`omp.mcpAdd.summary`). Cancel, Back and Continue / Save server buttons run Ctrl+C, Esc and Enter instead of a key-hint strip. The connection test shows its own busy step, the OAuth client secret field is masked, and the review saves on Enter (no Yes/No choice)
35
+ - `ReportPanel`'s native body carries the role `omp.report.body`
36
+ - `HookInputComponent` describes a dock sheet (`omp.overlay.hook-input` col) like `HookEditorComponent`'s: the title's first line (`omp.hook-input.title`, the countdown as `omp.hook-input.timer`) over its further lines (`omp.hook-input.detail`), the field (`omp.hook-input.field`, `tone: "error"` while a submit was refused) with its placeholder, and Cancel / Submit buttons that run Esc / Enter; the key legend under the field is terminal-only
37
+ - `JobsSheet`'s native body is a master–detail split (`omp.jobs.split`: `omp.jobs.master` | `omp.jobs.detail`): the job list grouped Running / Recent (`omp.jobs.group` labels), each row a type icon tinted by status with its duration, beside the selected job's status pill, live elapsed and Cancel job (`omp.jobs.status`), its task title or command (`omp.jobs.title` / `omp.jobs.command`), facts (`omp.jobs.facts`: agent, directory, pids, exit code, artifact) and output (`omp.jobs.out`, `omp.jobs.nooutput`); the footer counts running and recent jobs (`omp.jobs.summary`), and no jobs shows an empty state (`omp.jobs.empty`). Task jobs no longer draw an `agent` node here
38
+ - `BtwHistoryPanel`'s native sheet is centered and reads like a mail reader: the questions as two-line rows (`omp.btw.history`, list `omp.btw.list` / `omp.btw.list.idle` while the answer has the keys) beside the selected thread (`omp.btw.reader` › `omp.btw.thread` › `omp.btw.turn`: `omp.btw.question` / `omp.btw.followup`, `omp.btw.meta`, `omp.btw.answer`, `omp.btw.error`), the follow-up field under the last answer (`omp.btw.composer`), and footer buttons Stop answer, Copy answer, Close and Follow up (Cancel and Send while composing) in place of the focus labels and key-hint strip; an empty history is an `md` sheet (`omp.btw.empty`)
39
+
40
+ ### Fixed
41
+
42
+ - `CountdownTimer`'s native `elapsed` no longer sends `stopped: 0`, which froze every native countdown (extension input, selector and editor prompts) at zero from the start
43
+ - The native backend's focus now reaches a field inside an `overlay`/`picker` sheet hoisted into the layer from a dock component (the MCP add wizard, login), so that field shows the live caret and focus ring
44
+ - `MCPAddWizard` keeps a refused name or URL in its field, clears a stale refusal on Back, ignores a connection test that settles after the user stepped back, and Edit OAuth settings after a failed sign-in opens the settings again instead of doing nothing
45
+
5
46
  ## [18.10.0] - 2026-10-12
6
47
 
7
48
  ### Breaking Changes
@@ -2731,157 +2772,4 @@
2731
2772
 
2732
2773
  - Optimized padding operations across all components to use pre-allocated space buffer for better performance
2733
2774
 
2734
- ## [9.2.2] - 2026-01-31
2735
-
2736
- ### Added
2737
-
2738
- - Added setAutocompleteMaxVisible() configuration (3-20 items)
2739
- - Added image detection to terminal capabilities (containsImage method)
2740
- - Added stdin monitoring to detect stalled input events and log warnings
2741
-
2742
- ### Changed
2743
-
2744
- - Improved blockquote rendering with text wrapping in Markdown component
2745
- - Restructured terminal capabilities from interface-based to class-based model
2746
- - Improved table column width calculation with word-aware wrapping
2747
- - Refactored text utilities to use native WASM implementations for strings >256 chars with JS fast path
2748
-
2749
- ### Fixed
2750
-
2751
- - Simplified terminal write error handling to mark terminal as dead on any write failure
2752
- - Fixed multi-line strings in renderOutputBlock causing width overflow
2753
- - Fixed slash command autocomplete applying stale completion when typing quickly
2754
-
2755
- ### Removed
2756
-
2757
- - Removed TUI layout engine exports from public API (BoxNode, ColumnNode, LayoutNode, etc.)
2758
-
2759
- ## [8.12.7] - 2026-01-29
2760
-
2761
- ### Fixed
2762
-
2763
- - Fixed slash command autocomplete applying stale completion when typing quickly
2764
-
2765
- ## [8.4.1] - 2026-01-25
2766
-
2767
- ### Added
2768
-
2769
- - Added fuzzy match function for autocomplete suggestions
2770
-
2771
- ## [8.4.0] - 2026-01-25
2772
-
2773
- ### Changed
2774
-
2775
- - Added Ctrl+Backspace as a delete-word-backward keybinding and improved modified backspace matching
2776
-
2777
- ### Fixed
2778
-
2779
- - Terminal gracefully handles write failures by marking dead instead of exiting the process
2780
- - Reserved cursor space for zero padding and corrected end-of-line cursor rendering to prevent wrap glitches
2781
- - Corrected editor end-of-line cursor rendering assertion to use includes() instead of endsWith()
2782
-
2783
- ## [8.2.0] - 2026-01-24
2784
-
2785
- ### Added
2786
-
2787
- - Added mermaid diagram rendering engine (renderMermaidToPng) with mmdc CLI integration
2788
- - Added terminal graphics encoding (iTerm2/Kitty) for mermaid diagrams with automatic width scaling
2789
- - Added mermaid block extraction and deduplication utilities (extractMermaidBlocks)
2790
-
2791
- ### Changed
2792
-
2793
- - Updated TypeScript configuration for better publish-time configuration handling with tsconfig.publish.json
2794
- - Migrated file system operations from synchronous to asynchronous APIs in autocomplete provider for non-blocking I/O
2795
- - Migrated node module imports from named to namespace imports across all packages for consistency with project guidelines
2796
-
2797
- ### Fixed
2798
-
2799
- - Fixed crash when terminal becomes unavailable (EIO errors) by exiting gracefully instead of throwing
2800
- - Fixed potential errors during emergency terminal restore when terminal is already dead
2801
- - Fixed autocomplete race condition by tracking request ID to prevent stale suggestion results
2802
-
2803
- ## [6.8.3] - 2026-01-21
2804
-
2805
- ### Added
2806
-
2807
- - Added undo support in the editor via `Ctrl+-`
2808
- - Added `Alt+Delete` as a delete-word-forward shortcut
2809
- - Added configurable code block indentation for Markdown rendering
2810
- - Added undo support in the editor via `Ctrl+-`.
2811
- - Added configurable code block indentation for Markdown rendering.
2812
- - Added `Alt+Delete` as a delete-word-forward shortcut.
2813
-
2814
- ### Changed
2815
-
2816
- - Improved fuzzy matching to handle alphanumeric swaps
2817
- - Normalized keybinding definitions to lowercase internally
2818
- - Improved fuzzy matching to handle alphanumeric swaps.
2819
- - Normalized keybinding definitions to lowercase internally.
2820
-
2821
- ### Fixed
2822
-
2823
- - Added legacy terminal support for `Ctrl+` symbol key combinations
2824
- - Added legacy terminal support for `Ctrl+` symbol key combinations.
2825
-
2826
- ## [6.8.1] - 2026-01-20
2827
-
2828
- ### Fixed
2829
-
2830
- - Fixed viewport tracking after partial renders to prevent autocomplete list artifacts
2831
-
2832
- ## [5.6.7] - 2026-01-18
2833
-
2834
- ### Added
2835
-
2836
- - Added configurable editor padding via `editorPaddingX` theme option
2837
- - Added `setMaxHeight()` method to limit editor height with scrolling
2838
- - Added Emacs-style kill ring for text deletion operations
2839
- - Added `Alt+D` keybinding to delete words forward
2840
- - Added `Ctrl+Y` keybinding to yank from kill ring
2841
- - Added `waitForRender()` method to await pending renders
2842
- - Added Focusable interface and hardware cursor marker support for IME positioning
2843
- - Added support for shifted symbol keys in keybindings
2844
-
2845
- ### Changed
2846
-
2847
- - Updated tab bar rendering to wrap text across multiple lines when content exceeds available width
2848
- - Expanded Kitty keyboard protocol coverage for non-Latin layouts and legacy Alt sequences
2849
- - Improved cursor positioning with safer bounds checking
2850
- - Updated editor layout to respect configurable padding
2851
- - Refactored scrolling logic for better viewport management
2852
-
2853
- ### Fixed
2854
-
2855
- - Fixed key detection for shifted symbol characters
2856
- - Fixed backspace handling with additional codepoint support
2857
- - Fixed Alt+letter key combinations for better recognition
2858
-
2859
- ## [5.3.1] - 2026-01-15
2860
-
2861
- ### Fixed
2862
-
2863
- - Fixed rendering issues on Windows by preventing re-entrant renders
2864
-
2865
- ## [5.1.0] - 2026-01-14
2866
-
2867
- ### Added
2868
-
2869
- - Added `pageUp` and `pageDown` key support with `selectPageUp`/`selectPageDown` editor actions
2870
- - Added `isPageUp()` and `isPageDown()` helper functions
2871
- - Added `SizeValue` type for CSS-like overlay sizing (absolute or percentage strings like `"50%"`)
2872
- - Added `OverlayHandle` interface with `hide()`, `setHidden()`, `isHidden()` methods for overlay visibility control
2873
- - Added `visible` callback to `OverlayOptions` for dynamic visibility based on terminal dimensions
2874
- - Added `pad` parameter to `truncateToWidth()` for padding result with spaces to exact width
2875
-
2876
- ### Changed
2877
-
2878
- - Changed `OverlayOptions` to use `SizeValue` type for `width`, `maxHeight`, `row`, and `col` properties
2879
- - Changed `showOverlay()` to return `OverlayHandle` for controlling overlay visibility
2880
- - Removed `widthPercent`, `maxHeightPercent`, `rowPercent`, `colPercent` from `OverlayOptions` (use percentage strings instead)
2881
-
2882
- ### Fixed
2883
-
2884
- - Fixed numbered list items showing "1." for all items when code blocks break list continuity
2885
- - Fixed width overflow protection in overlay compositing to prevent TUI crashes
2886
-
2887
- Older entries are archived in [packages/tui/CHANGELOG.md@60347ef0f214](https://github.com/can1357/oh-my-pi/blob/60347ef0f214fa63df596d143477268da3f0c904/packages/tui/CHANGELOG.md).
2775
+ Older entries are archived in [packages/tui/CHANGELOG.md@e19bb3cb2344](https://github.com/can1357/oh-my-pi/blob/e19bb3cb2344a8953dc04aa398b810230f0e24c3/packages/tui/CHANGELOG.md).
@@ -79,9 +79,9 @@ uutils coreutils (https://github.com/uutils/coreutils), MIT
79
79
  --------------------------------------------------------------------------------
80
80
  Covers: base32, base64, basename, cat, cksum (shared checksum machinery),
81
81
  b2sum, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, comm, cp,
82
- cut, date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv, nproc, paste,
83
- printenv, readlink, realpath, rm, seq, sort, stat, tac, tail, tee, touch, tr,
84
- truncate, uname, uniq, wc, whoami, yes.
82
+ cut, date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv, nl, nproc,
83
+ paste, printenv, readlink, realpath, rm, seq, sort, stat, tac, tail, tee,
84
+ touch, tr, truncate, uname, uniq, wc, whoami, yes.
85
85
 
86
86
  Copyright (c) uutils developers
87
87
 
@@ -37,8 +37,8 @@ interface AppKeybindings {
37
37
  "app.session.rename": true;
38
38
  "app.session.delete": true;
39
39
  "app.session.deleteNoninvasive": true;
40
- "app.tree.foldOrUp": true;
41
- "app.tree.unfoldOrDown": true;
40
+ "app.tree.previousBranch": true;
41
+ "app.tree.nextBranch": true;
42
42
  "app.plan.toggle": true;
43
43
  "app.history.search": true;
44
44
  "app.stt.pushToTalk": true;
@@ -319,13 +319,13 @@ export declare const KEYBINDINGS: {
319
319
  readonly defaultKeys: "ctrl+backspace";
320
320
  readonly description: "Delete session (non-invasive)";
321
321
  };
322
- readonly "app.tree.foldOrUp": {
323
- readonly defaultKeys: ["ctrl+left", "alt+left"];
324
- readonly description: "Fold or move up";
322
+ readonly "app.tree.previousBranch": {
323
+ readonly defaultKeys: [];
324
+ readonly description: "Jump to the previous branch in /tree";
325
325
  };
326
- readonly "app.tree.unfoldOrDown": {
327
- readonly defaultKeys: ["ctrl+right", "alt+right"];
328
- readonly description: "Unfold or move down";
326
+ readonly "app.tree.nextBranch": {
327
+ readonly defaultKeys: [];
328
+ readonly description: "Jump to the next branch in /tree";
329
329
  };
330
330
  readonly "app.plan.toggle": {
331
331
  readonly defaultKeys: "alt+shift+p";
@@ -118,6 +118,11 @@ export type PaneClick = {
118
118
  } | {
119
119
  type: "handled";
120
120
  } | null;
121
+ /**
122
+ * The heading of one side of a media/binary change (`Before · PNG · Git LFS`):
123
+ * `label` plus the side's kind, shared by the ANSI pane and the native compare.
124
+ */
125
+ export declare function assetTitle(label: string, side: FileAssetSide): string;
121
126
  /**
122
127
  * Scrollable diff viewport. The root component feeds it key/mouse input and
123
128
  * composes its rendered lines into the frame.
@@ -73,11 +73,22 @@ export interface TextFileContents {
73
73
  readonly newText: string;
74
74
  readonly streamResult: DiffStreamResult;
75
75
  }
76
+ /** Where one side of a change lives, so a host viewer (Tern's TSP `media` node) can load it by path. */
77
+ export interface MediaRef {
78
+ /** Absolute path of the file (repository root joined with its repository path). */
79
+ readonly path: string;
80
+ /** Git revision holding this side (`HEAD`, a sha, `:0` for the index); absent for the worktree file. */
81
+ readonly rev?: string;
82
+ }
76
83
  /** Non-text sides rendered as previews or explicit placeholders. */
77
84
  export interface AssetFileContents {
78
85
  readonly kind: "asset";
79
86
  readonly old: FileAssetSide;
80
87
  readonly new: FileAssetSide;
88
+ /** Source of {@link old}; absent when that side is empty. */
89
+ readonly oldRef?: MediaRef;
90
+ /** Source of {@link new}; absent when that side is empty. */
91
+ readonly newRef?: MediaRef;
81
92
  }
82
93
  /** Loaded file content selected for text diffing or asset preview. */
83
94
  export type FileContents = TextFileContents | AssetFileContents;
@@ -2,7 +2,7 @@ import type { AssistantMessage, ImageContent } from "@oh-my-pi/pi-ai";
2
2
  import { type Component, Container } from "../tui.js";
3
3
  import { type ImageBudget } from "../components/image.js";
4
4
  import type { AssistantThinkingRenderer } from "./extension-types.js";
5
- import type { NativeNode, NativeUiEvent } from "../native/node.js";
5
+ import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
6
6
  import { type CacheInvalidation } from "./cache-invalidation-marker.js";
7
7
  import { type ServedModelMismatch } from "./served-model-marker.js";
8
8
  import { type TranscriptStableRow } from "../chrome/transcript-container.js";
@@ -99,13 +99,13 @@ export declare class AssistantMessageComponent extends Container {
99
99
  * head's `title`. With `hideThinkingBlock` only the live head shows (collapsed)
100
100
  * and a finished thought emits nothing.
101
101
  */
102
- describe(): NativeNode;
102
+ describe(cx?: DescribeContext): NativeNode;
103
103
  /**
104
104
  * A TTSR rule rewound this partial answer: a native terminal dims it and
105
105
  * tags it `↺ rewound` (the ANSI render leaves it as it stopped).
106
106
  */
107
107
  markRewound(): void;
108
- /** Mirrors a thinking section collapsed or expanded in the terminal. */
108
+ /** Mirrors a thinking section collapsed or expanded in the terminal; runs its controls' clicks. */
109
109
  handleNativeEvent(event: NativeUiEvent): void;
110
110
  /** Width-independent stable identities for the streamed leading thinking run. */
111
111
  getTranscriptStableRows(): readonly TranscriptStableRow[];
@@ -130,7 +130,12 @@ export declare class AssistantMessageComponent extends Container {
130
130
  setTableChartsVisible(visible: boolean): void;
131
131
  /** Toggle only images produced by tool results; assistant-native images remain governed by setImagesVisible. */
132
132
  setToolResultImagesVisible(visible: boolean): void;
133
- setToolResultImages(toolCallId: string, images: ImageContent[]): void;
133
+ /**
134
+ * A grouped read's result images, and `mediaPath`: the file it read that Tern's media viewer
135
+ * shows (read details), which a native host supporting `media` shows by path instead of the
136
+ * images. A media-only result (a model, a PDF) passes no images.
137
+ */
138
+ setToolResultImages(toolCallId: string, images: ImageContent[], mediaPath?: string): void;
134
139
  updateContent(message: AssistantMessage, opts?: {
135
140
  transient?: boolean;
136
141
  }): void;
@@ -17,19 +17,21 @@ export interface ToolExecutionOptions {
17
17
  /** Allow the name-keyed renderer registry only when the active tool is the built-in implementation. */
18
18
  useBuiltInRenderer?: boolean;
19
19
  }
20
+ /** A tool result or progress frame as a card shows it. */
21
+ export interface ToolResultFrame {
22
+ content: Array<{
23
+ type: string;
24
+ text?: string;
25
+ data?: string;
26
+ mimeType?: string;
27
+ }>;
28
+ details?: unknown;
29
+ isError?: boolean;
30
+ }
20
31
  export interface ToolExecutionHandle extends Component {
21
32
  updateArgs(args: unknown, toolCallId?: string): void;
22
33
  updateStreamPreview?(update: unknown): void;
23
- updateResult(result: {
24
- content: Array<{
25
- type: string;
26
- text?: string;
27
- data?: string;
28
- mimeType?: string;
29
- }>;
30
- details?: unknown;
31
- isError?: boolean;
32
- }, isPartial?: boolean, toolCallId?: string): void;
34
+ updateResult(result: ToolResultFrame, isPartial?: boolean, toolCallId?: string): void;
33
35
  setArgsComplete(toolCallId?: string): void;
34
36
  setExecutionStarted(toolCallId?: string): void;
35
37
  setExpanded(expanded: boolean): void;
@@ -39,6 +41,25 @@ export interface ToolExecutionHandle extends Component {
39
41
  /** Seal the block as final history and stop its animations. */
40
42
  seal(): void;
41
43
  }
44
+ /**
45
+ * Whether a call that returned with `details.async.state === "running"` stays
46
+ * parked ({@link ToolExecutionHandle.parkAsBackground}) so its job's later
47
+ * frames keep filling the card until a `completed`/`failed` frame settles it.
48
+ * Detached `task` spawns always do; backgrounded `bash`/`eval` jobs only under
49
+ * native rendering, where the terminal transcript keeps them frozen instead.
50
+ * Shared by the live event controller and the transcript rebuild.
51
+ */
52
+ export declare function parksAsBackground(toolName: string, details: unknown): boolean;
53
+ /** The background job state a tool result reports (`details.async.state`: running, completed, failed, cancelled). */
54
+ export declare function asyncJobState(details: unknown): string | undefined;
55
+ /** Whether a frame is a background job's last one: it completed, failed or was cancelled. */
56
+ export declare function isSettledJobFrame(details: unknown): boolean;
57
+ /**
58
+ * Settle a parked card ({@link parksAsBackground}) with its job's last frame
59
+ * ({@link isSettledJobFrame}): a completed or failed job is the call's result;
60
+ * a cancelled one keeps the output it got to and seals the card as cancelled.
61
+ */
62
+ export declare function settleWithJobFrame(component: ToolExecutionHandle, frame: ToolResultFrame, toolCallId: string): void;
42
63
  /** Phase-locked spinner glyph index shared by every live tool block so parallel
43
64
  * spinners advance in lockstep instead of each tracking its own start time. */
44
65
  export declare function sharedSpinnerFrame(frameCount: number, now?: number): number;
@@ -74,16 +95,7 @@ export declare class ToolExecutionComponent extends Container {
74
95
  */
75
96
  whenPreviewSettled(timeoutMs?: number): Promise<void>;
76
97
  updateStreamPreview(update: unknown): void;
77
- updateResult(result: {
78
- content: Array<{
79
- type: string;
80
- text?: string;
81
- data?: string;
82
- mimeType?: string;
83
- }>;
84
- details?: unknown;
85
- isError?: boolean;
86
- }, isPartial?: boolean, _toolCallId?: string): void;
98
+ updateResult(result: ToolResultFrame, isPartial?: boolean, _toolCallId?: string): void;
87
99
  /**
88
100
  * Advance to the shared spinner glyph and repaint just this block. Driven by
89
101
  * the single shared spinner ticker (see `registerSpinnerBlock`); the tick is
@@ -39,8 +39,9 @@ export declare class UserMessageComponent extends Container implements ReactionT
39
39
  /**
40
40
  * A head-less user-toned frame with the prompt as markdown under its
41
41
  * attached images (titled `#N` like their chips, opening the materialized
42
- * file on click): the fill says "you". A quiet toolbar (time, Copy, Rewind) fades in on hover when the
43
- * host handles transcript actions. The live-steering marker and the
42
+ * file on click): the fill says "you". A quiet footer like a turn's usage line
43
+ * (`⧉ ⏪ · 09:45`: Copy, Rewind, the time sent) fades in at its bottom-left on hover when
44
+ * the host handles transcript actions. The live-steering marker and the
44
45
  * agent's reaction are chips at the bottom-right, so a reaction landing
45
46
  * later updates the frame in place, even deep in scrollback.
46
47
  */
@@ -8,8 +8,9 @@ export declare class CountdownTimer {
8
8
  constructor(timeoutMs: number, tui: TUI | undefined, onTick: (seconds: number) => void, onExpire: () => void);
9
9
  /**
10
10
  * The remaining time as a terminal-clocked `elapsed` node: its age is the
11
- * negative remaining time (the start lies in the future), so it counts up
12
- * toward zero and freezes there at expiry. The age is taken on the first
11
+ * negative remaining time (the start lies in the future), so it counts down
12
+ * to zero and holds there at expiry (no `stopped`: that would freeze it at
13
+ * zero from the start). The age is taken on the first
13
14
  * call after a (re)start, when the node is first written, and the node is
14
15
  * reused until {@link reset}.
15
16
  */
@@ -47,10 +47,11 @@ export interface NativeBackendOptions {
47
47
  }
48
48
  /**
49
49
  * The reply a v1 terminal is assumed to give before its real `hello` arrives
50
- * (the `TERM_PROGRAM=tern` optimistic start): the whole vocabulary, the
51
- * default APC limit and credits, the terminal's width, the appearance omp
52
- * already detected, full motion, and `blobs`, so a resumed session's images
53
- * are asked about rather than resent before the reply comes.
50
+ * (the `TERM_PROGRAM=tern` optimistic start): the whole vocabulary except
51
+ * {@link UNASSUMED_KINDS}, the default APC limit and credits, the terminal's
52
+ * width, the appearance omp already detected, full motion, and `blobs`, so a
53
+ * resumed session's images are asked about rather than resent before the
54
+ * reply comes.
54
55
  */
55
56
  export declare function assumedTspHello(terminal: Terminal): TspHello;
56
57
  export declare class NativeBackend {
@@ -8,7 +8,7 @@
8
8
  * references it.
9
9
  */
10
10
  import type { TspProps } from "@oh-my-pi/pi-wire";
11
- import type { NativeNode } from "./node.js";
11
+ import type { NativeChild, NativeNode } from "./node.js";
12
12
  export interface NativeBlob {
13
13
  readonly id: string;
14
14
  readonly mime: string;
@@ -31,3 +31,15 @@ export declare class NativeImageCache {
31
31
  #private;
32
32
  get(key: string, data: string, mimeType: string): NativeNode;
33
33
  }
34
+ /** The disk file a tool result's image was read from (`read` details `mediaPath`), when it has one. */
35
+ export declare function readMediaPath(details: unknown): string | undefined;
36
+ /**
37
+ * A `media` node the host loads by path, capped at the inline image preview
38
+ * height. Callers check `cx.supports("media")` first.
39
+ */
40
+ export declare function nativeMediaNode(path: string, key: string): NativeNode;
41
+ /** Blob ids of the `image` nodes and paths of the `media` nodes under `children` (described nodes only). */
42
+ export declare function shownMedia(children: readonly NativeChild[] | undefined): {
43
+ blobs: Set<string>;
44
+ paths: Set<string>;
45
+ };
@@ -2,6 +2,7 @@ import { type Focusable, type TUI } from "../index.js";
2
2
  import { type KeybindingsManager } from "../app-keybindings.js";
3
3
  import { type Theme } from "../theme/theme.js";
4
4
  import type { CodeReviewAnnotation, CodeReviewOverlayResult, ReviewDiffFile, TextReviewAnnotation, TextReviewOverlayResult, TextReviewSource } from "./annotation-types.js";
5
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
5
6
  import { type NativeNode, type NativeUiEvent } from "../native/node.js";
6
7
  export declare const CONTINUE_CODE_REVIEW_ACTION = "Continue with LLM review";
7
8
  export declare const PASTE_CODE_REVIEW_ACTION = "Paste annotations into prompt";
@@ -21,6 +22,12 @@ export interface TextReviewOverlayCallbacks extends AnnotationOverlayCallbacks {
21
22
  }
22
23
  /** Splits a text source into the overlay's 1-based annotatable lines. */
23
24
  export declare function splitTextLines(text: string): string[];
25
+ /** The native sheet: full-pane glass, titled by the review kind with what is under review after it. */
26
+ interface NativeSheet {
27
+ readonly role: "omp.overlay.codeReview" | "omp.overlay.annotateText";
28
+ readonly size: "full";
29
+ readonly head: TspSpan[];
30
+ }
24
31
  /** A fullscreen, annotated diff picker that only relies on public OMP APIs. */
25
32
  export declare class AnnotationOverlay implements Focusable {
26
33
  #private;
@@ -44,7 +51,19 @@ export declare class AnnotationOverlay implements Focusable {
44
51
  */
45
52
  replaceTextSource(text: string): number;
46
53
  handleInput(data: string): void;
54
+ /**
55
+ * The terminal draws the frame: a full-pane glass sheet titled `Code review`
56
+ * (or `Annotate text`), then what is under review as a quieter subtitle.
57
+ */
58
+ get nativeOverlay(): NativeSheet;
59
+ /**
60
+ * The sheet's body: the file rail (totals over the changed files) beside
61
+ * the current file's diff (text: its numbered lines), the note composer
62
+ * docked under the lines while a note is open, and a footer of key hints
63
+ * and the actions.
64
+ */
47
65
  describe(): NativeNode;
48
66
  handleNativeEvent(event: NativeUiEvent): void;
49
67
  render(width: number): readonly string[];
50
68
  }
69
+ export {};
@@ -101,10 +101,15 @@ export declare class AskDialogComponent implements Component {
101
101
  render(width: number): readonly string[];
102
102
  /**
103
103
  * In the dock, in the composer's place and framed as the composer is: a
104
- * `col` with the prompt editor's root role (`omp.editor`), so the terminal
105
- * gives it the composer's insets and spacing. Not a modal `overlay` sheet:
106
- * one anchored at the bottom covered the transcript rows that explain the
107
- * question and blocked scrolling until the question was answered.
104
+ * `col` with an `omp.editor.*` root role (`omp.editor.ask`, collapsed
105
+ * `omp.editor.ask.hidden`), so the terminal draws the composer's shell
106
+ * around it. Not a modal `overlay` sheet: one anchored at the bottom
107
+ * covered the transcript rows that explain the question and blocked
108
+ * scrolling until the question was answered.
109
+ *
110
+ * Anatomy: the question tabs (several questions), the question, its
111
+ * answers as radio/check rows, and the action bar as the footer (the
112
+ * countdown, Hide, then Note, Skip and the primary Submit/Next).
108
113
  */
109
114
  describe(cx: DescribeContext): NativeNode;
110
115
  /**
@@ -40,12 +40,8 @@ export declare class BtwHistoryPanel implements Component, Focusable {
40
40
  /** Enhanced clipboard pastes belong only to the active composer. */
41
41
  pasteText(text: string): void;
42
42
  handleInput(data: string): void;
43
- /** A large glass sheet titled "BTW history". */
44
- readonly nativeOverlay: {
45
- readonly role: "omp.overlay.btwHistory";
46
- readonly size: "lg";
47
- readonly head: "BTW history";
48
- };
43
+ /** A large glass sheet (the list beside the reader), palette-sized while there is nothing to list. */
44
+ get nativeOverlay(): NonNullable<Component["nativeOverlay"]>;
49
45
  describe(): NativeNode;
50
46
  handleNativeEvent(event: NativeUiEvent): void;
51
47
  render(width: number): readonly string[];
@@ -10,7 +10,7 @@
10
10
  import type { ImageContent } from "@oh-my-pi/pi-ai";
11
11
  import { type Focusable, type TUI } from "../index.js";
12
12
  import { OverlayPanel } from "../chrome/overlay-box.js";
13
- import type { DescribeContext, NativeNode } from "../native/node.js";
13
+ import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
14
14
  /**
15
15
  * `prefix` and `question` flattened onto one line, wrapped to the terminal's width and cut to
16
16
  * {@link MAX_PROMPT_TITLE_ROWS} rows (the last ends in `…` when cut). For terminal rendering only:
@@ -58,8 +58,13 @@ export declare class HookEditorComponent extends OverlayPanel implements Focusab
58
58
  /** Focus state mirrored to the nested editor during rendering. */
59
59
  focused: boolean;
60
60
  constructor(tui: TUI, title: string, prefill: string | undefined, onSubmit: (value: string, images?: ImageContent[]) => void, onCancel: () => void, options?: HookEditorOptions);
61
- /** The editor (which describes itself) under the title and detail lines, with the key hints below. */
61
+ /**
62
+ * A sheet in the composer's place: the title (or, answering a question, the question under the
63
+ * prompt's name) over a hairline, the editor, and Open in editor · Cancel · Submit.
64
+ */
62
65
  describe(_cx: DescribeContext): NativeNode;
66
+ /** The action bar's buttons run what their keys run. */
67
+ handleNativeEvent(event: NativeUiEvent): void;
63
68
  /** Keep the nested editor's software/hardware cursor mode aligned with the dialog focus target. */
64
69
  setUseTerminalCursor(useTerminalCursor: boolean): void;
65
70
  /** Render the dialog after forwarding its focus state to the nested editor. */
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Simple text input component for hooks.
2
+ * One-line text prompt an extension (hook) asks the user.
3
3
  */
4
4
  import { type TUI } from "../index.js";
5
5
  import { OverlayPanel } from "../chrome/overlay-box.js";
6
- import type { DescribeContext, NativeNode } from "../native/node.js";
6
+ import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
7
7
  export interface HookInputOptions {
8
8
  tui?: TUI;
9
9
  timeout?: number;
@@ -11,13 +11,21 @@ export interface HookInputOptions {
11
11
  }
12
12
  export declare class HookInputComponent extends OverlayPanel {
13
13
  #private;
14
- constructor(title: string, _placeholder: string | undefined, onSubmit: (value: string) => void, onCancel: () => void, opts?: HookInputOptions);
14
+ constructor(title: string, placeholder: string | undefined, onSubmit: (value: string) => void, onCancel: () => void, opts?: HookInputOptions);
15
15
  handleInput(keyData: string): void;
16
16
  /** Route non-bracketed paste transports (e.g. kitty's OSC 5522 enhanced clipboard)
17
17
  * into the inner field, mirroring bracketed-paste semantics. Pasting counts as
18
18
  * interaction, so the timeout countdown resets like any keystroke. */
19
19
  pasteText(text: string): void;
20
+ /** Submit and Cancel run what Enter and the interrupt key run. */
21
+ handleNativeEvent(event: NativeUiEvent): void;
20
22
  dispose(): void;
21
- /** A card over the form, headed by the title plus the countdown `elapsed` while a timeout runs. */
23
+ /**
24
+ * A sheet in the composer's place, built like the extension editor's: the
25
+ * title's first line (the countdown at its end while a timeout runs) over
26
+ * any further lines as detail, the field written on the sheet (tinted, the
27
+ * reason under it, while a submit was refused), and Cancel · Submit, whose
28
+ * keys live in their tooltips.
29
+ */
22
30
  describe(_cx: DescribeContext): NativeNode;
23
31
  }