@oh-my-pi/pi-tui 18.8.5 → 18.8.7
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.
- package/CHANGELOG.md +30 -16
- package/README.md +7 -5
- package/dist/types/chat/assistant-message.d.ts +1 -0
- package/dist/types/chat/compaction-summary-message.d.ts +1 -0
- package/dist/types/chat/user-message.d.ts +2 -0
- package/dist/types/components/box.d.ts +1 -0
- package/dist/types/components/disclosure.d.ts +1 -0
- package/dist/types/components/image.d.ts +1 -0
- package/dist/types/components/key-value-list.d.ts +1 -0
- package/dist/types/components/layout/row.d.ts +1 -0
- package/dist/types/components/layout/stack.d.ts +1 -0
- package/dist/types/components/markdown.d.ts +1 -0
- package/dist/types/components/scroll-view.d.ts +1 -0
- package/dist/types/components/section.d.ts +1 -0
- package/dist/types/components/table.d.ts +1 -0
- package/dist/types/components/text.d.ts +1 -0
- package/dist/types/components/truncated-text.d.ts +1 -0
- package/dist/types/native/blobs.d.ts +3 -1
- package/dist/types/overlays/session-selector.d.ts +6 -2
- package/dist/types/render/output-pane.d.ts +1 -0
- package/dist/types/render/render-utils.d.ts +1 -0
- package/dist/types/render/tool-card.d.ts +6 -0
- package/dist/types/render/width-aware-text.d.ts +2 -0
- package/dist/types/terminal.d.ts +10 -2
- package/dist/types/theme/theme.d.ts +1 -1
- package/dist/types/theme/tui-adapters.d.ts +3 -0
- package/dist/types/tools/write.d.ts +1 -1
- package/dist/types/tools/yield.d.ts +22 -0
- package/dist/types/tui.d.ts +11 -0
- package/package.json +13 -9
- package/src/chat/advisor-message.ts +11 -0
- package/src/chat/assistant-message.ts +8 -2
- package/src/chat/compaction-summary-message.ts +8 -0
- package/src/chat/read-tool-group.ts +6 -4
- package/src/chat/skill-message.ts +6 -0
- package/src/chat/table-chart.ts +17 -20
- package/src/chat/tool-execution.ts +18 -0
- package/src/chat/user-message.ts +14 -0
- package/src/chrome/transcript-container.ts +32 -1
- package/src/components/box.ts +5 -0
- package/src/components/disclosure.ts +8 -0
- package/src/components/image.ts +7 -5
- package/src/components/key-value-list.ts +4 -0
- package/src/components/layout/row.ts +7 -0
- package/src/components/layout/stack.ts +7 -0
- package/src/components/markdown.ts +190 -8
- package/src/components/scroll-view.ts +5 -0
- package/src/components/section.ts +5 -0
- package/src/components/table.ts +4 -0
- package/src/components/text.ts +7 -0
- package/src/components/truncated-text.ts +5 -0
- package/src/native/backend.ts +16 -15
- package/src/native/blobs.ts +43 -10
- package/src/native/reconcile.ts +4 -0
- package/src/overlays/model-hub.ts +39 -4
- package/src/overlays/session-selector.ts +40 -22
- package/src/overlays/snapcompact-shape-preview.ts +2 -3
- package/src/prompt/attachment-chips.ts +13 -10
- package/src/prompt/tips.txt +2 -1
- package/src/prompt/welcome.ts +46 -9
- package/src/render/output-pane.ts +6 -0
- package/src/render/render-utils.ts +11 -0
- package/src/render/tool-card.ts +15 -0
- package/src/render/width-aware-text.ts +5 -0
- package/src/terminal.ts +24 -3
- package/src/theme/theme.ts +1 -0
- package/src/theme/tui-adapters.ts +68 -0
- package/src/tools/bash.ts +10 -11
- package/src/tools/edit.ts +142 -120
- package/src/tools/fetch.ts +5 -6
- package/src/tools/index.ts +2 -0
- package/src/tools/mcp.ts +15 -2
- package/src/tools/read.ts +7 -5
- package/src/tools/write.ts +70 -56
- package/src/tools/yield.ts +225 -0
- package/src/tui.ts +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.8.7] - 2026-10-09
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added cache-release hooks for TUI components and tool cards, allowing extensions to discard derived render data without rebuilding content ([#13632](https://github.com/can1357/oh-my-pi/pull/13632) by [@iliaal](https://github.com/iliaal)).
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Subagent "Submit Result" cards now show the submitted result (its fields as a tree, or the report text), the section it fills, and why a submission was rejected, instead of only "Result submitted.".
|
|
14
|
+
- Reduced memory held by retired transcript history in long sessions ([#13632](https://github.com/can1357/oh-my-pi/pull/13632) by [@iliaal](https://github.com/iliaal)).
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Reduced memory retained by discarded TSP images and previews ([#14336](https://github.com/can1357/oh-my-pi/pull/14336) by [@iliaal](https://github.com/iliaal)).
|
|
19
|
+
- Fixed startup capability probes printing as text in the prompt (e.g. `25a1;stsp;q;{…}pppppp`) on terminals that cannot parse them, such as macOS Terminal.app.
|
|
20
|
+
- Fixed the `/resume` picker flashing while a search runs over a large session history: background fuzzy matches now land in one update instead of reordering the list dozens of times per keystroke.
|
|
21
|
+
|
|
22
|
+
## [18.8.6] - 2026-10-08
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Improved rendering performance for streaming long Markdown lists while preserving nested items, numbering, and reference links.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Added package exports for the native Tern/TSP modules, allowing extensions in compiled `omp` binaries to import them.
|
|
31
|
+
- Fixed the Tern `/model` picker's Roles tab so typing and Backspace consistently edit the search field without triggering role commands.
|
|
32
|
+
- Fixed the session picker so sessions retain and display their directory when switching between the current folder and all-project views.
|
|
33
|
+
|
|
5
34
|
## [18.8.5] - 2026-10-08
|
|
6
35
|
|
|
7
36
|
### Added
|
|
@@ -3011,19 +3040,4 @@ Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mon
|
|
|
3011
3040
|
- Cursor now moves to end of content on exit, preventing status line from being overwritten ([#629](https://github.com/badlogic/pi-mono/pull/629) by [@tallshort](https://github.com/tallshort))
|
|
3012
3041
|
- Reset ANSI styles after each rendered line to prevent style leakage
|
|
3013
3042
|
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
### Fixed
|
|
3017
|
-
|
|
3018
|
-
- Reduced flicker by only re-rendering changed lines ([#617](https://github.com/badlogic/pi-mono/pull/617) by [@ogulcancelik](https://github.com/ogulcancelik))
|
|
3019
|
-
- Cursor position tracking when content shrinks with unchanged remaining lines
|
|
3020
|
-
- TUI renders with wrong dimensions after suspend/resume if terminal was resized while suspended ([#599](https://github.com/badlogic/pi-mono/issues/599))
|
|
3021
|
-
- Pasted content containing Kitty key release patterns (e.g., `:3F` in MAC addresses) was incorrectly filtered out ([#623](https://github.com/badlogic/pi-mono/pull/623) by [@ogulcancelik](https://github.com/ogulcancelik))
|
|
3022
|
-
|
|
3023
|
-
## [0.39.0] - 2026-01-08
|
|
3024
|
-
|
|
3025
|
-
### Added
|
|
3026
|
-
|
|
3027
|
-
- **Experimental:** Overlay compositing for `ctx.ui.custom()` with `{ overlay: true }` option ([#558](https://github.com/badlogic/pi-mono/pull/558) by [@nicobailon](https://github.com/nicobailon))
|
|
3028
|
-
|
|
3029
|
-
Older entries are archived in [packages/tui/CHANGELOG.md@fa14205f838f](https://github.com/can1357/oh-my-pi/blob/fa14205f838f282fcea048c64fca74026789a492/packages/tui/CHANGELOG.md).
|
|
3043
|
+
Older entries are archived in [packages/tui/CHANGELOG.md@4787659281ba](https://github.com/can1357/oh-my-pi/blob/4787659281ba47f5a3707bbf5ee61742e9373c42/packages/tui/CHANGELOG.md).
|
package/README.md
CHANGED
|
@@ -66,14 +66,16 @@ interface Component {
|
|
|
66
66
|
render(width: number): readonly string[];
|
|
67
67
|
handleInput?(data: string): void;
|
|
68
68
|
invalidate?(): void;
|
|
69
|
+
releaseRenderCaches?(): void;
|
|
69
70
|
}
|
|
70
71
|
```
|
|
71
72
|
|
|
72
|
-
| Method
|
|
73
|
-
|
|
|
74
|
-
| `render(width)`
|
|
75
|
-
| `handleInput?(data)`
|
|
76
|
-
| `invalidate?()`
|
|
73
|
+
| Method | Description |
|
|
74
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
75
|
+
| `render(width)` | Returns an array of strings, one per line. Each line **must not exceed `width`** or the TUI will error. Use `truncateToWidth()` or manual wrapping to ensure this. The result is component-owned and immutable to callers; return the same array reference when unchanged (enables renderer memoization) and a new array when content changed. |
|
|
76
|
+
| `handleInput?(data)` | Called when the component has focus and receives keyboard input. The `data` string contains raw terminal input (may include ANSI escape sequences). |
|
|
77
|
+
| `invalidate?()` | Called to clear any cached render state. Components should re-render from scratch on the next `render()` call. |
|
|
78
|
+
| `releaseRenderCaches?()` | Drops only derived render caches. The next `render()` must return the same rows without eager rebuilds, renderer callbacks, image conversions, or child replacement. |
|
|
77
79
|
|
|
78
80
|
## Built-in Components
|
|
79
81
|
|
|
@@ -54,6 +54,7 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
54
54
|
*/
|
|
55
55
|
setServedModelMismatch(info: ServedModelMismatch | undefined): void;
|
|
56
56
|
invalidate(): void;
|
|
57
|
+
releaseRenderCaches(): void;
|
|
57
58
|
setHideThinkingBlock(hide: boolean): void;
|
|
58
59
|
/**
|
|
59
60
|
* Allow or withhold retiring finished lines into native scrollback while the
|
|
@@ -31,6 +31,7 @@ declare class SummaryMessageComponent implements Component {
|
|
|
31
31
|
handleNativeEvent(event: NativeUiEvent): void;
|
|
32
32
|
setIgnoreTight(ignore: boolean): this;
|
|
33
33
|
invalidate(): void;
|
|
34
|
+
releaseRenderCaches(): void;
|
|
34
35
|
dispose(): void;
|
|
35
36
|
render(width: number): readonly string[];
|
|
36
37
|
}
|
|
@@ -33,6 +33,7 @@ export declare function userBubbleColor(options?: UserBubbleOptions, tokenRegex?
|
|
|
33
33
|
export declare class UserMessageComponent extends Container implements ReactionTarget {
|
|
34
34
|
#private;
|
|
35
35
|
constructor(text: string, options?: UserBubbleOptions);
|
|
36
|
+
releaseRenderCaches(): void;
|
|
36
37
|
setReaction(emoji: string): void;
|
|
37
38
|
/**
|
|
38
39
|
* A head-less user-toned frame with the prompt as markdown under its
|
|
@@ -75,6 +76,7 @@ export declare class CollapsedSyntheticMessageComponent implements Component {
|
|
|
75
76
|
handleNativeEvent(event: NativeUiEvent): void;
|
|
76
77
|
setIgnoreTight(ignore: boolean): this;
|
|
77
78
|
invalidate(): void;
|
|
79
|
+
releaseRenderCaches(): void;
|
|
78
80
|
dispose(): void;
|
|
79
81
|
render(width: number): readonly string[];
|
|
80
82
|
}
|
|
@@ -30,6 +30,7 @@ export declare class Box implements Component {
|
|
|
30
30
|
setBgFn(bgFn?: (text: string) => string): void;
|
|
31
31
|
setBorder(border?: BoxBorder): void;
|
|
32
32
|
invalidate(): void;
|
|
33
|
+
releaseRenderCaches(): void;
|
|
33
34
|
/**
|
|
34
35
|
* A `card` when the box has a border or background: the background token
|
|
35
36
|
* picks tone/role (user message, tool state, selection), a border colour
|
|
@@ -36,6 +36,7 @@ export declare class Disclosure implements Component {
|
|
|
36
36
|
setExpanded(expanded: boolean): void;
|
|
37
37
|
setIgnoreTight(ignore: boolean): this;
|
|
38
38
|
invalidate(): void;
|
|
39
|
+
releaseRenderCaches(): void;
|
|
39
40
|
dispose(): void;
|
|
40
41
|
debugState(): Record<string, unknown>;
|
|
41
42
|
get debugChildren(): readonly Component[];
|
|
@@ -227,6 +227,7 @@ export declare class Image implements Component {
|
|
|
227
227
|
/** Return source metadata without exposing the encoded image buffer. */
|
|
228
228
|
debugState(): Record<string, unknown>;
|
|
229
229
|
invalidate(): void;
|
|
230
|
+
releaseRenderCaches(): void;
|
|
230
231
|
/**
|
|
231
232
|
* A native `image` backed by a content-addressed blob; the terminal fits
|
|
232
233
|
* it. Cell caps become `ch`/`lines` bounds. The inline-image budget and
|
|
@@ -21,6 +21,7 @@ export declare class KeyValueList implements Component {
|
|
|
21
21
|
constructor(rows: readonly KeyValueRow[], options: KeyValueListOptions);
|
|
22
22
|
setRows(rows: readonly KeyValueRow[]): boolean;
|
|
23
23
|
invalidate(): void;
|
|
24
|
+
releaseRenderCaches(): void;
|
|
24
25
|
/** An aligned `kv` grid; label width and value wrapping are the terminal's. */
|
|
25
26
|
describe(_cx: DescribeContext): NativeNode;
|
|
26
27
|
render(width: number): readonly string[];
|
|
@@ -48,6 +48,7 @@ export declare class Row implements Component, MouseRoutable {
|
|
|
48
48
|
setDecorations(prefix: LayoutDecoration | undefined, gap: LayoutDecoration | undefined, suffix: LayoutDecoration | undefined): void;
|
|
49
49
|
setIgnoreTight(ignore: boolean): this;
|
|
50
50
|
invalidate(): void;
|
|
51
|
+
releaseRenderCaches(): void;
|
|
51
52
|
dispose(): void;
|
|
52
53
|
/**
|
|
53
54
|
* A flex `row`: each child sits in a slot carrying its width bounds
|
|
@@ -43,6 +43,7 @@ export declare class Stack implements Component, MouseRoutable {
|
|
|
43
43
|
setHeight(height: number | undefined): void;
|
|
44
44
|
setIgnoreTight(ignore: boolean): this;
|
|
45
45
|
invalidate(): void;
|
|
46
|
+
releaseRenderCaches(): void;
|
|
46
47
|
dispose(): void;
|
|
47
48
|
/**
|
|
48
49
|
* A `col` of slots carrying each child's height bounds (fixed → min = max
|
|
@@ -124,6 +124,7 @@ export declare class Markdown implements Component {
|
|
|
124
124
|
debugState(): Record<string, unknown>;
|
|
125
125
|
setText(text: string): boolean;
|
|
126
126
|
invalidate(): void;
|
|
127
|
+
releaseRenderCaches(): void;
|
|
127
128
|
/**
|
|
128
129
|
* The unrendered source as an `md` node, `stream` while the streaming
|
|
129
130
|
* (transient) cache is on. Append-only growth yields a fresh node of the
|
|
@@ -92,6 +92,7 @@ export declare class ScrollView implements Component {
|
|
|
92
92
|
/** Apply Arrow, Shift+Arrow, Page, Home, and End navigation keys. */
|
|
93
93
|
handleScrollKey(data: string): boolean;
|
|
94
94
|
invalidate(): void;
|
|
95
|
+
releaseRenderCaches(): void;
|
|
95
96
|
/** Permanently release a wrapped child's timers, subscriptions, and other resources. */
|
|
96
97
|
dispose(): void;
|
|
97
98
|
/**
|
|
@@ -15,6 +15,7 @@ export declare class Section implements Component {
|
|
|
15
15
|
#private;
|
|
16
16
|
constructor(options: SectionOptions);
|
|
17
17
|
invalidate(): void;
|
|
18
|
+
releaseRenderCaches(): void;
|
|
18
19
|
dispose(): void;
|
|
19
20
|
/** A `section` headed by the styled title; the rule is the terminal's. */
|
|
20
21
|
describe(_cx: DescribeContext): NativeNode;
|
|
@@ -29,6 +29,7 @@ export declare class Table implements Component {
|
|
|
29
29
|
constructor(rows: readonly (readonly TableCell[])[], columns: readonly TableColumn[], options?: TableOptions);
|
|
30
30
|
setRows(rows: readonly (readonly TableCell[])[]): boolean;
|
|
31
31
|
invalidate(): void;
|
|
32
|
+
releaseRenderCaches(): void;
|
|
32
33
|
/**
|
|
33
34
|
* A native `table`. Column priorities carry over unchanged (lower gives
|
|
34
35
|
* way first); truncating columns truncate at the end, the rest keep
|
|
@@ -26,6 +26,7 @@ export declare class Text implements Component {
|
|
|
26
26
|
*/
|
|
27
27
|
setStyleFn(styleFn?: (text: string) => string): this;
|
|
28
28
|
invalidate(): void;
|
|
29
|
+
releaseRenderCaches(): void;
|
|
29
30
|
/**
|
|
30
31
|
* Wrapped text; styling re-derived from the styled source so a theme swap
|
|
31
32
|
* re-resolves tokens. A background fill becomes the node's tone.
|
|
@@ -9,6 +9,7 @@ export declare class TruncatedText implements Component {
|
|
|
9
9
|
/** Return bounded source text and the last-known truncation state. */
|
|
10
10
|
debugState(): Record<string, unknown>;
|
|
11
11
|
invalidate(): void;
|
|
12
|
+
releaseRenderCaches(): void;
|
|
12
13
|
/** First line only, clamped to one visual line with an end ellipsis. */
|
|
13
14
|
describe(_cx: DescribeContext): NativeNode;
|
|
14
15
|
render(width: number): readonly string[];
|
|
@@ -14,10 +14,12 @@ export interface NativeBlob {
|
|
|
14
14
|
readonly mime: string;
|
|
15
15
|
readonly bytes: Uint8Array;
|
|
16
16
|
}
|
|
17
|
-
/** Register
|
|
17
|
+
/** Register bytes for process-lifetime, id-only use. Prefer {@link nativeImageNode} for owned images. */
|
|
18
18
|
export declare function registerNativeBlob(bytes: Uint8Array, mime: string): string;
|
|
19
19
|
/** A registered blob by id. */
|
|
20
20
|
export declare function getNativeBlob(id: string): NativeBlob | undefined;
|
|
21
|
+
/** An image whose props own its bytes, including while hidden, unmounted, or awaiting upload. */
|
|
22
|
+
export declare function nativeImageNode(bytes: Uint8Array, mime: string, p?: Omit<TspProps<"image">, "blob" | "builtin">, key?: string): NativeNode;
|
|
21
23
|
/**
|
|
22
24
|
* An `image` node for a base64 payload: the bytes are registered as a blob and
|
|
23
25
|
* the pixel size probed from the header. Decoding and hashing cost real time,
|
|
@@ -71,7 +71,7 @@ declare class SessionList<T extends SessionSelectorEntry> implements Component {
|
|
|
71
71
|
onExit: () => void;
|
|
72
72
|
onToggleScope?: () => void;
|
|
73
73
|
onDeleteRequest?: (session: T) => void;
|
|
74
|
-
/** Re-render hook for async list updates (fuzzy scan
|
|
74
|
+
/** Re-render hook for async list updates (fuzzy scan completion, history merge). */
|
|
75
75
|
onRequestRender?: () => void;
|
|
76
76
|
constructor(sessions: T[], showCwd?: boolean, historyMatcher?: SessionHistoryMatcher, getTerminalRows?: () => number, pinnedIds?: ReadonlySet<string>, currentSessionPath?: string | (() => string | undefined));
|
|
77
77
|
/** Replace the visible dataset, e.g. when toggling folder/all-projects scope. */
|
|
@@ -129,7 +129,11 @@ export interface SessionSelectorOptions<T extends SessionSelectorEntry = Session
|
|
|
129
129
|
title?: string;
|
|
130
130
|
/** Fixed scope label, or false to omit the scope suffix. */
|
|
131
131
|
scopeLabel?: string | false;
|
|
132
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* Show each session's working directory in the list. Defaults to on when
|
|
134
|
+
* the session files live in more than one directory (e.g. the folder scope
|
|
135
|
+
* merging a repository's worktrees).
|
|
136
|
+
*/
|
|
133
137
|
showCwd?: boolean;
|
|
134
138
|
/**
|
|
135
139
|
* Reads the live terminal height so the visible window fits the viewport.
|
|
@@ -92,6 +92,7 @@ export declare class OutputPane implements Component {
|
|
|
92
92
|
describe(_cx: DescribeContext): NativeNode;
|
|
93
93
|
render(width: number): readonly string[];
|
|
94
94
|
invalidate(): void;
|
|
95
|
+
releaseRenderCaches(): void;
|
|
95
96
|
}
|
|
96
97
|
/** Default styling for plain tool output while preserving existing ANSI. */
|
|
97
98
|
export declare function styleToolOutputLine(line: string, theme: Theme): string;
|
|
@@ -298,6 +298,7 @@ export interface RenderedStringCache {
|
|
|
298
298
|
export declare function createRenderedStringCache(): RenderedStringCache;
|
|
299
299
|
/** Drop the memo so the next lookup re-renders (e.g. the render function identity changed). */
|
|
300
300
|
export declare function invalidateRenderedStringCache(cache: RenderedStringCache): void;
|
|
301
|
+
export declare function releaseRenderedStringCache(cache: RenderedStringCache): void;
|
|
301
302
|
/** Reuse a rendered string while its theme, expansion, content, and salt match. */
|
|
302
303
|
export declare function cachedRenderedString(cache: RenderedStringCache | undefined, theme: Theme, expanded: boolean, salt: string, content: string, render: () => string): string;
|
|
303
304
|
/**
|
|
@@ -46,6 +46,11 @@ export interface ToolCardOptions {
|
|
|
46
46
|
paddingY?: number;
|
|
47
47
|
ignoreTight?: boolean;
|
|
48
48
|
onInvalidate?: () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Drop builder-owned memos the next build recomputes. Called by
|
|
51
|
+
* {@link ToolCard.releaseRenderCaches}, which never calls `onInvalidate`.
|
|
52
|
+
*/
|
|
53
|
+
onReleaseRenderCaches?: () => void;
|
|
49
54
|
onDispose?: () => void;
|
|
50
55
|
}
|
|
51
56
|
/** Map transcript lifecycle terminology onto the output frame's visual states. */
|
|
@@ -71,6 +76,7 @@ export declare class ToolCard implements Component {
|
|
|
71
76
|
handleInput(data: string): void;
|
|
72
77
|
setIgnoreTight(ignore: boolean): void;
|
|
73
78
|
invalidate(): void;
|
|
79
|
+
releaseRenderCaches(): void;
|
|
74
80
|
dispose(): void;
|
|
75
81
|
}
|
|
76
82
|
/** Construct a lazy framed tool card. */
|
|
@@ -20,6 +20,8 @@ export declare class WidthAwareText implements Component {
|
|
|
20
20
|
setCustomBgFn(customBgFn?: (text: string) => string): void;
|
|
21
21
|
setIgnoreTight(ignore: boolean): this;
|
|
22
22
|
invalidate(): void;
|
|
23
|
+
/** The formatted text stays: the inner `Text` renders from it, so dropping it would free nothing. */
|
|
24
|
+
releaseRenderCaches(): void;
|
|
23
25
|
/**
|
|
24
26
|
* Re-run the formatter on the next render because its inputs changed.
|
|
25
27
|
* Unlike {@link invalidate}, the inner `Text` keeps its wrap cache, so a
|
package/dist/types/terminal.d.ts
CHANGED
|
@@ -128,13 +128,21 @@ export type TspHelloHandler = (hello: TspHello | null) => void;
|
|
|
128
128
|
export type CursorShape = "default" | "block" | "underline" | "bar";
|
|
129
129
|
export declare const CURSOR_SHAPE_CODES: Record<CursorShape, number>;
|
|
130
130
|
export interface Terminal {
|
|
131
|
+
/**
|
|
132
|
+
* Start the terminal with input, resize, and host-disconnect handlers.
|
|
133
|
+
* Unless input is deferred, this sends capability probes; a terminal that
|
|
134
|
+
* cannot parse one may leave concealed bytes on the cursor row, so the
|
|
135
|
+
* caller repaints after starting.
|
|
136
|
+
*/
|
|
131
137
|
start(onInput: (data: string) => void, onResize: () => void, onDisconnect?: () => void, options?: TerminalStartOptions): void;
|
|
132
138
|
/**
|
|
133
139
|
* Take ownership of stdin after a `deferInput` start: enable raw mode,
|
|
134
140
|
* attach input handlers, and run the capability probes start() skipped.
|
|
135
141
|
* Bytes the user typed in cooked mode meanwhile are replayed through
|
|
136
|
-
* `onInput`. No-op when input was never deferred.
|
|
137
|
-
*
|
|
142
|
+
* `onInput`. No-op when input was never deferred. Like {@link start}, the
|
|
143
|
+
* probes may leave concealed bytes on the cursor row, so the caller
|
|
144
|
+
* repaints afterwards. Optional so custom Terminals built against older
|
|
145
|
+
* pi-tui versions keep working.
|
|
138
146
|
*/
|
|
139
147
|
enableInput?(): void;
|
|
140
148
|
stop(): void;
|
|
@@ -6,7 +6,7 @@ export { getAvailableThemes, getAvailableThemesWithPaths, getThemeByName, type T
|
|
|
6
6
|
export { isValidThemeColor, type ThemeBg, type ThemeColor } from "./schema.js";
|
|
7
7
|
export { getAvailableSymbolPresets, isValidSymbolPreset, type SpinnerType, type SymbolKey, type SymbolPreset, } from "./symbols.js";
|
|
8
8
|
export { Theme } from "./theme-class.js";
|
|
9
|
-
export { createHighlightStream, getEditorTheme, getMarkdownTheme, getSelectListTheme, getSettingsListTheme, getSymbolTheme, highlightCode, setMarkdownMermaidRendering, warmHighlighter, } from "./tui-adapters.js";
|
|
9
|
+
export { createHighlightStream, getEditorTheme, getMarkdownTheme, getMarkdownThemeWithLinkTargets, getSelectListTheme, getSettingsListTheme, getSymbolTheme, highlightCode, setMarkdownMermaidRendering, warmHighlighter, } from "./tui-adapters.js";
|
|
10
10
|
/** Active theme; imports remain live across initialization, previews, and theme switches. */
|
|
11
11
|
export declare var theme: Theme;
|
|
12
12
|
type ThemeBinding = (value: Theme) => void;
|
|
@@ -16,6 +16,9 @@ export declare function createHighlightStream(lang?: string, highlightTheme?: Th
|
|
|
16
16
|
/** Warm native syntax grammars off-thread once per process. */
|
|
17
17
|
export declare function warmHighlighter(): Promise<void>;
|
|
18
18
|
export declare function getSymbolTheme(): SymbolTheme;
|
|
19
|
+
/** Only themes assembled here have stable callbacks and private link state. */
|
|
20
|
+
export declare function canCacheMarkdownListItems(candidate: MarkdownTheme): boolean;
|
|
21
|
+
export declare function getMarkdownThemeWithLinkTargets(targets: ReadonlyMap<string, string>): MarkdownTheme;
|
|
19
22
|
export declare function setMarkdownMermaidRendering(enabled: boolean): void;
|
|
20
23
|
export declare function getMarkdownTheme(): MarkdownTheme;
|
|
21
24
|
export declare function getSelectListTheme(): SelectListTheme;
|
|
@@ -81,7 +81,7 @@ export declare const writeToolRenderer: {
|
|
|
81
81
|
renderCall(args: WriteRenderArgs, options: RenderResultOptions & WriteStreamingPreviewStateCarrier & {
|
|
82
82
|
renderContext?: WriteRenderContext;
|
|
83
83
|
}, uiTheme: Theme): Component | undefined;
|
|
84
|
-
renderResult(result: WriteResult, options: RenderResultOptions & {
|
|
84
|
+
renderResult(result: WriteResult, options: RenderResultOptions & WriteStreamingPreviewStateCarrier & {
|
|
85
85
|
renderContext?: WriteRenderContext;
|
|
86
86
|
}, uiTheme: Theme, args?: WriteRenderArgs): Component;
|
|
87
87
|
describeCall(args: WriteRenderArgs, options: RenderResultOptions & {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Theme } from "../theme/theme.js";
|
|
2
|
+
import type { Component } from "../tui.js";
|
|
3
|
+
import type { NativeToolView, RenderResultContextOptions, RenderResultOptions, ToolRenderResult } from "./renderer.js";
|
|
4
|
+
import type { YieldItem } from "./task.js";
|
|
5
|
+
/** `yield` arguments as sent; strict-mode providers send omitted optionals as `null`. */
|
|
6
|
+
interface YieldRenderArgs {
|
|
7
|
+
type?: string | string[] | null;
|
|
8
|
+
data?: unknown;
|
|
9
|
+
error?: string | null;
|
|
10
|
+
/** 1-based workpool item number. */
|
|
11
|
+
key?: number;
|
|
12
|
+
}
|
|
13
|
+
/** Shows a `yield` call's submitted data instead of its model-facing acknowledgement. */
|
|
14
|
+
export declare const yieldToolRenderer: {
|
|
15
|
+
renderCall(args: YieldRenderArgs, options: RenderResultOptions, theme: Theme): Component;
|
|
16
|
+
renderResult(result: ToolRenderResult<YieldItem>, options: RenderResultContextOptions, theme: Theme, args?: YieldRenderArgs): Component;
|
|
17
|
+
describeCall(args: YieldRenderArgs, options: RenderResultOptions): NativeToolView;
|
|
18
|
+
describeResult(result: ToolRenderResult<YieldItem>, _options: RenderResultContextOptions, args?: YieldRenderArgs): NativeToolView;
|
|
19
|
+
mergeCallAndResult: true;
|
|
20
|
+
animatedPendingPreview: true;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
package/dist/types/tui.d.ts
CHANGED
|
@@ -169,6 +169,16 @@ export interface Component {
|
|
|
169
169
|
* Called when theme changes or when component needs to re-render from scratch.
|
|
170
170
|
*/
|
|
171
171
|
invalidate?(): void;
|
|
172
|
+
/**
|
|
173
|
+
* Optional hook to drop memoized render output (rows, parse and wrap state)
|
|
174
|
+
* that the next `render()` can rebuild from state the component keeps.
|
|
175
|
+
* Unlike {@link invalidate}, it must not rebuild anything eagerly: no
|
|
176
|
+
* renderer or extension callbacks, no image conversions, and no child
|
|
177
|
+
* replacement or disposal. The next render must return the same rows it
|
|
178
|
+
* would have returned without the release. Components without it are
|
|
179
|
+
* simply not released.
|
|
180
|
+
*/
|
|
181
|
+
releaseRenderCaches?(): void;
|
|
172
182
|
/**
|
|
173
183
|
* Optional hook to set whether this component ignores tight layout mode.
|
|
174
184
|
*/
|
|
@@ -308,6 +318,7 @@ export declare class Container implements Component {
|
|
|
308
318
|
/** Dispose every child, then detach it from this container. */
|
|
309
319
|
disposeChildren(): void;
|
|
310
320
|
invalidate(): void;
|
|
321
|
+
releaseRenderCaches(): void;
|
|
311
322
|
/**
|
|
312
323
|
* Propagate teardown to children. Call when the container's children are
|
|
313
324
|
* being permanently discarded (not when they are detached for reuse — use
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-tui",
|
|
4
|
-
"version": "18.8.
|
|
4
|
+
"version": "18.8.7",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": {
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"gen:glyphs": "bun scripts/gen-glyphs.ts"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@oh-my-pi/omptype": "18.8.
|
|
45
|
-
"@oh-my-pi/pi-agent-core": "18.8.
|
|
46
|
-
"@oh-my-pi/pi-ai": "18.8.
|
|
47
|
-
"@oh-my-pi/pi-catalog": "18.8.
|
|
48
|
-
"@oh-my-pi/pi-natives": "18.8.
|
|
49
|
-
"@oh-my-pi/pi-utils": "18.8.
|
|
50
|
-
"@oh-my-pi/pi-wire": "18.8.
|
|
51
|
-
"@oh-my-pi/snapcompact": "18.8.
|
|
44
|
+
"@oh-my-pi/omptype": "18.8.7",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "18.8.7",
|
|
46
|
+
"@oh-my-pi/pi-ai": "18.8.7",
|
|
47
|
+
"@oh-my-pi/pi-catalog": "18.8.7",
|
|
48
|
+
"@oh-my-pi/pi-natives": "18.8.7",
|
|
49
|
+
"@oh-my-pi/pi-utils": "18.8.7",
|
|
50
|
+
"@oh-my-pi/pi-wire": "18.8.7",
|
|
51
|
+
"@oh-my-pi/snapcompact": "18.8.7"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"kitty-vt-wasm": "^0.2.0"
|
|
@@ -105,6 +105,10 @@
|
|
|
105
105
|
"types": "./dist/types/components/*.d.ts",
|
|
106
106
|
"import": "./src/components/*.ts"
|
|
107
107
|
},
|
|
108
|
+
"./native/*": {
|
|
109
|
+
"types": "./dist/types/native/*.d.ts",
|
|
110
|
+
"import": "./src/native/*.ts"
|
|
111
|
+
},
|
|
108
112
|
"./*.js": "./src/*.ts"
|
|
109
113
|
}
|
|
110
114
|
}
|
|
@@ -52,6 +52,10 @@ class AdvisorHeader implements Component {
|
|
|
52
52
|
this.#uiTheme = uiTheme;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
releaseRenderCaches(): void {
|
|
56
|
+
this.#cache = undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
55
59
|
invalidate(): void {
|
|
56
60
|
this.#cache = undefined;
|
|
57
61
|
}
|
|
@@ -82,6 +86,10 @@ class AdvisorNotes implements Component {
|
|
|
82
86
|
this.#uiTheme = uiTheme;
|
|
83
87
|
}
|
|
84
88
|
|
|
89
|
+
releaseRenderCaches(): void {
|
|
90
|
+
this.#cache = undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
85
93
|
invalidate(): void {
|
|
86
94
|
this.#cache = undefined;
|
|
87
95
|
}
|
|
@@ -236,6 +244,9 @@ export function createAdvisorMessageCard(
|
|
|
236
244
|
invalidate(): void {
|
|
237
245
|
disclosure.invalidate();
|
|
238
246
|
},
|
|
247
|
+
releaseRenderCaches(): void {
|
|
248
|
+
disclosure.releaseRenderCaches();
|
|
249
|
+
},
|
|
239
250
|
dispose(): void {
|
|
240
251
|
disclosure.dispose();
|
|
241
252
|
},
|
|
@@ -9,7 +9,7 @@ import { formatDuration, formatNumber } from "@oh-my-pi/pi-utils";
|
|
|
9
9
|
import chalk from "@oh-my-pi/pi-utils/chalk";
|
|
10
10
|
import { LRUCache } from "@oh-my-pi/pi-utils/lru";
|
|
11
11
|
import type { AssistantThinkingRenderer } from "./extension-types";
|
|
12
|
-
import { ensureThemeSync, getMarkdownTheme, getThemeEpoch, theme } from "../theme";
|
|
12
|
+
import { ensureThemeSync, getMarkdownTheme, getMarkdownThemeWithLinkTargets, getThemeEpoch, theme } from "../theme";
|
|
13
13
|
import { card, col, elapsed, node, span, text } from "../native/describe";
|
|
14
14
|
import { hasTranscriptActions, runTranscriptAction } from "./transcript-actions";
|
|
15
15
|
import type { NativeChild, NativeNode, NativeUiEvent } from "../native/node";
|
|
@@ -394,7 +394,7 @@ export class AssistantMessageComponent extends Container {
|
|
|
394
394
|
if (this.#markdownTheme) return this.#markdownTheme;
|
|
395
395
|
const base = getMarkdownTheme();
|
|
396
396
|
const snapshot = this.#linkTargets;
|
|
397
|
-
const markdownTheme = snapshot.size > 0 ?
|
|
397
|
+
const markdownTheme = snapshot.size > 0 ? getMarkdownThemeWithLinkTargets(snapshot) : base;
|
|
398
398
|
this.#markdownTheme = markdownTheme;
|
|
399
399
|
return markdownTheme;
|
|
400
400
|
}
|
|
@@ -575,6 +575,12 @@ export class AssistantMessageComponent extends Container {
|
|
|
575
575
|
}
|
|
576
576
|
}
|
|
577
577
|
|
|
578
|
+
override releaseRenderCaches(): void {
|
|
579
|
+
super.releaseRenderCaches();
|
|
580
|
+
this.#dropStableRenders();
|
|
581
|
+
this.#emergencyText?.releaseRenderCaches();
|
|
582
|
+
}
|
|
583
|
+
|
|
578
584
|
setHideThinkingBlock(hide: boolean): void {
|
|
579
585
|
this.#hideThinkingBlock = hide;
|
|
580
586
|
this.#thinkingCollapsed.clear();
|
|
@@ -53,6 +53,10 @@ class DividerSummary implements Component {
|
|
|
53
53
|
this.#cache = undefined;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
releaseRenderCaches(): void {
|
|
57
|
+
this.#cache = undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
56
60
|
render(width: number): readonly string[] {
|
|
57
61
|
width = Math.max(1, width);
|
|
58
62
|
if (this.#cache?.width === width) return this.#cache.lines;
|
|
@@ -150,6 +154,10 @@ class SummaryMessageComponent implements Component {
|
|
|
150
154
|
if (this.#ignoreTight !== undefined) this.#disclosure.setIgnoreTight(this.#ignoreTight);
|
|
151
155
|
}
|
|
152
156
|
|
|
157
|
+
releaseRenderCaches(): void {
|
|
158
|
+
this.#disclosure.releaseRenderCaches();
|
|
159
|
+
}
|
|
160
|
+
|
|
153
161
|
dispose(): void {
|
|
154
162
|
if (this.#disposed) return;
|
|
155
163
|
this.#disposed = true;
|
|
@@ -1143,6 +1143,10 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
1143
1143
|
const title = pathDisplay ? `Read ${pathDisplay}` : "Read";
|
|
1144
1144
|
let cachedWidth: number | undefined;
|
|
1145
1145
|
let cachedLines: string[] | undefined;
|
|
1146
|
+
const dropCache = () => {
|
|
1147
|
+
cachedWidth = undefined;
|
|
1148
|
+
cachedLines = undefined;
|
|
1149
|
+
};
|
|
1146
1150
|
const expanded = this.#expanded;
|
|
1147
1151
|
const component: Component = {
|
|
1148
1152
|
render: (width: number) => {
|
|
@@ -1164,10 +1168,8 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
1164
1168
|
cachedWidth = width;
|
|
1165
1169
|
return cachedLines;
|
|
1166
1170
|
},
|
|
1167
|
-
invalidate:
|
|
1168
|
-
|
|
1169
|
-
cachedLines = undefined;
|
|
1170
|
-
},
|
|
1171
|
+
invalidate: dropCache,
|
|
1172
|
+
releaseRenderCaches: dropCache,
|
|
1171
1173
|
};
|
|
1172
1174
|
this.addChild(component);
|
|
1173
1175
|
}
|
|
@@ -271,6 +271,12 @@ class SkillCallout implements Component {
|
|
|
271
271
|
this.#lines = undefined;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
+
releaseRenderCaches(): void {
|
|
275
|
+
this.#source = undefined;
|
|
276
|
+
this.#lines = undefined;
|
|
277
|
+
this.#box.releaseRenderCaches();
|
|
278
|
+
}
|
|
279
|
+
|
|
274
280
|
render(width: number): readonly string[] {
|
|
275
281
|
const inner = this.#box.render(Math.max(1, width - 1));
|
|
276
282
|
if (this.#source === inner && this.#lines !== undefined) return this.#lines;
|