@oh-my-pi/pi-tui 18.8.6 → 18.8.8
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 +45 -79
- 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/execution-shared.d.ts +6 -5
- 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/keybinding-matchers.d.ts +3 -0
- package/dist/types/native/blobs.d.ts +3 -1
- package/dist/types/overlays/annotation-overlay.d.ts +12 -0
- package/dist/types/overlays/annotation-types.d.ts +2 -0
- package/dist/types/overlays/hook-selector.d.ts +9 -4
- package/dist/types/overlays/model-browser.d.ts +2 -2
- package/dist/types/overlays/model-hub.d.ts +21 -4
- package/dist/types/overlays/session-observer-registry.d.ts +2 -0
- package/dist/types/overlays/session-selector.d.ts +1 -1
- package/dist/types/overlays/usage-dashboard.d.ts +3 -1
- 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/status-line/types.d.ts +1 -1
- package/dist/types/terminal.d.ts +10 -2
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/tools/eval.d.ts +1 -1
- package/dist/types/tools/native-view.d.ts +47 -0
- package/dist/types/tools/renderer.d.ts +15 -2
- package/dist/types/tools/write.d.ts +1 -1
- package/dist/types/tools/yield.d.ts +22 -0
- package/dist/types/tui.d.ts +31 -0
- package/dist/types/vim.d.ts +19 -5
- package/package.json +9 -9
- package/src/chat/advisor-message.ts +11 -0
- package/src/chat/assistant-message.ts +6 -0
- package/src/chat/compaction-summary-message.ts +8 -0
- package/src/chat/execution-shared.ts +42 -25
- 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 +27 -2
- 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/editor.ts +182 -5
- 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 +8 -0
- 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/keybinding-matchers.ts +6 -2
- package/src/native/backend.ts +16 -15
- package/src/native/blobs.ts +43 -10
- package/src/native/reconcile.ts +4 -0
- package/src/overlays/agent-hub.ts +7 -3
- package/src/overlays/annotation-overlay.ts +87 -6
- package/src/overlays/annotation-types.ts +2 -0
- package/src/overlays/hook-selector.ts +12 -5
- package/src/overlays/model-browser.ts +3 -3
- package/src/overlays/model-hub.ts +107 -27
- package/src/overlays/session-observer-registry.ts +10 -2
- package/src/overlays/session-selector.ts +29 -19
- package/src/overlays/snapcompact-shape-preview.ts +2 -3
- package/src/overlays/usage-dashboard.ts +70 -23
- package/src/prompt/attachment-chips.ts +13 -10
- package/src/prompt/composer.ts +1 -0
- 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/status-line/segments.ts +3 -0
- package/src/status-line/types.ts +1 -1
- package/src/terminal.ts +24 -3
- package/src/theme/symbols.ts +5 -0
- package/src/tools/bash.ts +92 -42
- package/src/tools/edit.ts +142 -120
- package/src/tools/eval.ts +149 -123
- package/src/tools/fetch.ts +5 -6
- package/src/tools/index.ts +2 -0
- package/src/tools/mcp.ts +15 -2
- package/src/tools/native-view.ts +102 -1
- package/src/tools/read.ts +7 -5
- package/src/tools/renderer.ts +15 -2
- package/src/tools/write.ts +70 -56
- package/src/tools/yield.ts +225 -0
- package/src/tui.ts +93 -0
- package/src/vim.ts +333 -18
|
@@ -2,7 +2,7 @@ export type SymbolPreset = "unicode" | "nerd" | "ascii";
|
|
|
2
2
|
/**
|
|
3
3
|
* All available symbol keys organized by category.
|
|
4
4
|
*/
|
|
5
|
-
export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "progress.filled" | "progress.empty" | "context.speculation" | "context.compaction" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxDotted.horizontal" | "boxDotted.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.powerlineCapLeft" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.prewalk" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.worktree" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.pin" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.subscription" | "icon.advisor" | "icon.advisorClosed" | "icon.time" | "icon.omp" | "icon.ghost" | "icon.agents" | "icon.job" | "icon.cache" | "icon.cacheMiss" | "icon.input" | "icon.output" | "icon.throughput" | "icon.intelligence" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.vimNormal" | "icon.vimInsert" | "icon.vimVisual" | "icon.vimVisualLine" | "cmd.action" | "cmd.prompt" | "cmd.extension" | "cmd.settings" | "cmd.gear" | "cmd.shield" | "cmd.wave" | "cmd.compass" | "cmd.inbox" | "cmd.swap" | "cmd.expand" | "cmd.computer" | "cmd.eye" | "cmd.todo" | "cmd.stats" | "cmd.news" | "cmd.keyboard" | "cmd.export" | "cmd.clipboard" | "cmd.share" | "cmd.broadcast" | "cmd.globe" | "cmd.copy" | "cmd.plus" | "cmd.restart" | "cmd.eraser" | "cmd.trash" | "cmd.compress" | "cmd.vibrate" | "cmd.handoff" | "cmd.history" | "cmd.question" | "cmd.rocket" | "cmd.stethoscope" | "cmd.redo" | "cmd.bug" | "cmd.memory" | "cmd.pencil" | "cmd.folderMove" | "cmd.folderPlus" | "cmd.folderMinus" | "cmd.hammer" | "cmd.power" | "cmd.cart" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.max" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "advisor.rail" | "skill.rail" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.julia" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "chip.image" | "chip.video" | "chip.paste" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.files" | "tab.shell" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.launch" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.goal" | "tool.irc" | "tool.delete" | "tool.move" | "key.ctrl" | "key.ctrlMac" | "key.shift" | "key.alt" | "key.altMac" | "key.super" | "key.superMac" | "key.joiner" | "key.enter" | "key.esc" | "key.tab" | "key.backspace" | "key.delete" | "key.space" | "key.up" | "key.down" | "key.left" | "key.right";
|
|
5
|
+
export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "progress.filled" | "progress.empty" | "context.speculation" | "context.compaction" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxDotted.horizontal" | "boxDotted.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.powerlineCapLeft" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.prewalk" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.worktree" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.pin" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.subscription" | "icon.advisor" | "icon.advisorClosed" | "icon.time" | "icon.omp" | "icon.ghost" | "icon.agents" | "icon.job" | "icon.cache" | "icon.cacheMiss" | "icon.input" | "icon.output" | "icon.throughput" | "icon.intelligence" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.vimNormal" | "icon.vimInsert" | "icon.vimVisual" | "icon.vimVisualLine" | "icon.vimReplace" | "cmd.action" | "cmd.prompt" | "cmd.extension" | "cmd.settings" | "cmd.gear" | "cmd.shield" | "cmd.wave" | "cmd.compass" | "cmd.inbox" | "cmd.swap" | "cmd.expand" | "cmd.computer" | "cmd.eye" | "cmd.todo" | "cmd.stats" | "cmd.news" | "cmd.keyboard" | "cmd.export" | "cmd.clipboard" | "cmd.share" | "cmd.broadcast" | "cmd.globe" | "cmd.copy" | "cmd.plus" | "cmd.restart" | "cmd.eraser" | "cmd.trash" | "cmd.compress" | "cmd.vibrate" | "cmd.handoff" | "cmd.history" | "cmd.question" | "cmd.rocket" | "cmd.stethoscope" | "cmd.redo" | "cmd.bug" | "cmd.memory" | "cmd.pencil" | "cmd.folderMove" | "cmd.folderPlus" | "cmd.folderMinus" | "cmd.hammer" | "cmd.power" | "cmd.cart" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.max" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "advisor.rail" | "skill.rail" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.julia" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "chip.image" | "chip.video" | "chip.paste" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.files" | "tab.shell" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.launch" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.goal" | "tool.irc" | "tool.delete" | "tool.move" | "key.ctrl" | "key.ctrlMac" | "key.shift" | "key.alt" | "key.altMac" | "key.super" | "key.superMac" | "key.joiner" | "key.enter" | "key.esc" | "key.tab" | "key.backspace" | "key.delete" | "key.space" | "key.up" | "key.down" | "key.left" | "key.right";
|
|
6
6
|
export type SymbolMap = Record<SymbolKey, string>;
|
|
7
7
|
/**
|
|
8
8
|
* Icon vocabulary for slash-command autocomplete type indicators. Each name
|
|
@@ -95,7 +95,7 @@ export declare const evalToolRenderer: {
|
|
|
95
95
|
}, options: RenderResultOptions & {
|
|
96
96
|
renderContext?: EvalRenderContext;
|
|
97
97
|
}, uiTheme: Theme, _args?: EvalRenderArgs): Component;
|
|
98
|
-
describeCall(args: EvalRenderArgs,
|
|
98
|
+
describeCall(args: EvalRenderArgs, options: RenderResultOptions): NativeToolView;
|
|
99
99
|
describeResult(result: {
|
|
100
100
|
content: Array<{
|
|
101
101
|
type: string;
|
|
@@ -72,6 +72,53 @@ export declare function truncationNotice(meta: OutputMeta | undefined): NativeNo
|
|
|
72
72
|
* truncation / artifact-capture notice from `meta`; undefined when empty.
|
|
73
73
|
*/
|
|
74
74
|
export declare function footnoteText(parts: readonly string[], meta?: OutputMeta): NativeNode | undefined;
|
|
75
|
+
/** Drawn lines of a run's input (command, cell code) before its "N more lines" button. */
|
|
76
|
+
export declare const RUN_INPUT_PREVIEW_LINES = 6;
|
|
77
|
+
/**
|
|
78
|
+
* What a run's foot names: `running` (live clock), `background` (an async job
|
|
79
|
+
* outlives the call), and the settled outcomes. A failure with an exit code
|
|
80
|
+
* reads `exit N`; without one, `Failed`.
|
|
81
|
+
*/
|
|
82
|
+
export type RunState = "running" | "background" | "done" | "failed" | "cancelled" | "timed-out";
|
|
83
|
+
/** Inputs of {@link runFoot}. */
|
|
84
|
+
export interface RunFootInput {
|
|
85
|
+
readonly state: RunState;
|
|
86
|
+
/** Exit code of a `failed` run; a non-zero code names the state `exit N`. */
|
|
87
|
+
readonly exitCode?: number;
|
|
88
|
+
/** Milliseconds run so far (`running`) or in total; the time is omitted when undefined. */
|
|
89
|
+
readonly elapsedMs?: number;
|
|
90
|
+
/** Quiet facts (job id, service state, artifact), muted and ` · `-joined. */
|
|
91
|
+
readonly facts?: readonly string[];
|
|
92
|
+
/** Truncation / artifact-capture notices, appended to the facts in `warning`. */
|
|
93
|
+
readonly meta?: OutputMeta;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The foot line of a run box (`omp.run.foot`): the state word in its tone,
|
|
97
|
+
* the run time (a live clock while running, frozen once settled) and the
|
|
98
|
+
* quiet facts. Glyphs are the terminal's styling, never text.
|
|
99
|
+
*/
|
|
100
|
+
export declare function runFoot(input: RunFootInput): NativeNode;
|
|
101
|
+
/** A run's input section: the command or cell source, clamped to {@link RUN_INPUT_PREVIEW_LINES}. */
|
|
102
|
+
export declare function runInput(source: string, p: {
|
|
103
|
+
role: string;
|
|
104
|
+
lang: string;
|
|
105
|
+
wrap: boolean;
|
|
106
|
+
}): NativeNode;
|
|
107
|
+
/** A run's terminal output: follows its tail, clamped to the last `previewLines` lines while folded. */
|
|
108
|
+
export declare function runOutput(output: string, p: {
|
|
109
|
+
role: string;
|
|
110
|
+
previewLines: number;
|
|
111
|
+
key?: string;
|
|
112
|
+
}): NativeNode;
|
|
113
|
+
/**
|
|
114
|
+
* One run as one box (`omp.run`): input, output, status lines and foot in
|
|
115
|
+
* order. `tone` tints the box: `error` for a failed run, `warning` for a
|
|
116
|
+
* timed-out one.
|
|
117
|
+
*/
|
|
118
|
+
export declare function runBox(children: readonly (NativeChild | undefined | false)[], p: {
|
|
119
|
+
key: string;
|
|
120
|
+
tone?: TspTone;
|
|
121
|
+
}): NativeNode;
|
|
75
122
|
/** A diagnostic's severity glyph: `x-circle` error, `warn` warning, `info`, `lightbulb` hint, in the severity tone. */
|
|
76
123
|
export declare function diagnosticGlyph(severity: ParsedDiagnostic["severity"]): NativeNode;
|
|
77
124
|
/**
|
|
@@ -25,6 +25,14 @@ export interface RenderResultOptions {
|
|
|
25
25
|
* Streamed `xd://` previews stay queued until this is set.
|
|
26
26
|
*/
|
|
27
27
|
executionStarted?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Milliseconds since this call began executing (`tool_execution_start`),
|
|
30
|
+
* or its total once settled; undefined before it starts. Native describe
|
|
31
|
+
* hooks only.
|
|
32
|
+
*/
|
|
33
|
+
elapsedMs?: number;
|
|
34
|
+
/** The call was abandoned without a final result (turn aborted, sealed). Native describe hooks only. */
|
|
35
|
+
cancelled?: boolean;
|
|
28
36
|
}
|
|
29
37
|
/** Render options for a result, plus the tool-specific context the transcript threads through. */
|
|
30
38
|
export type RenderResultContextOptions = RenderResultOptions & {
|
|
@@ -85,6 +93,8 @@ export interface NativeToolHead {
|
|
|
85
93
|
readonly targetKind?: TspToolProps["targetKind"];
|
|
86
94
|
/** Language for `command` targets. */
|
|
87
95
|
readonly lang?: string;
|
|
96
|
+
/** The raw command line the head's Copy command button copies (set implicitly by a `command` target). */
|
|
97
|
+
readonly command?: string;
|
|
88
98
|
/** `file://` link for path targets. */
|
|
89
99
|
readonly href?: string;
|
|
90
100
|
/** Short facts after the target (`+8 −1`, `5 matches · 2 files`). */
|
|
@@ -111,10 +121,13 @@ export interface NativeToolView {
|
|
|
111
121
|
readonly body?: readonly NativeChild[];
|
|
112
122
|
/** Tone override; the frame otherwise derives it from the call status. */
|
|
113
123
|
readonly tone?: TspTone;
|
|
114
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* Body clamp while collapsed; `{tail}` keeps the end (terminal output). Defaults to the transcript's preview size.
|
|
126
|
+
* `children`: the body stays whole while collapsed and its own `ansi`/`code` previews clamp instead.
|
|
127
|
+
*/
|
|
115
128
|
readonly preview?: TspPreview | {
|
|
116
129
|
readonly tail: number;
|
|
117
|
-
} | "none";
|
|
130
|
+
} | "none" | "children";
|
|
118
131
|
/** Starts expanded whatever the transcript's expand state (the todo checklist); the user can still fold it. */
|
|
119
132
|
readonly open?: boolean;
|
|
120
133
|
/** Render frameless (`frame:"inline"`): a head line plus a disclosed body. */
|
|
@@ -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
|
@@ -78,6 +78,10 @@ export interface TUIStartOptions {
|
|
|
78
78
|
* Paint without owning stdin: the terminal stays in cooked mode (kernel
|
|
79
79
|
* echo + line editing at the hardware cursor) until {@link TUI.enableInput}
|
|
80
80
|
* switches to raw input and replays the kernel-buffered keystrokes.
|
|
81
|
+
*
|
|
82
|
+
* A terminal expected to speak TSP needs raw input from the start, so it
|
|
83
|
+
* gets it; its keystrokes are held instead (TSP events and the cell-size
|
|
84
|
+
* reply still apply) until {@link TUI.releaseHeldInput} replays them.
|
|
81
85
|
*/
|
|
82
86
|
deferInput?: boolean;
|
|
83
87
|
}
|
|
@@ -169,6 +173,16 @@ export interface Component {
|
|
|
169
173
|
* Called when theme changes or when component needs to re-render from scratch.
|
|
170
174
|
*/
|
|
171
175
|
invalidate?(): void;
|
|
176
|
+
/**
|
|
177
|
+
* Optional hook to drop memoized render output (rows, parse and wrap state)
|
|
178
|
+
* that the next `render()` can rebuild from state the component keeps.
|
|
179
|
+
* Unlike {@link invalidate}, it must not rebuild anything eagerly: no
|
|
180
|
+
* renderer or extension callbacks, no image conversions, and no child
|
|
181
|
+
* replacement or disposal. The next render must return the same rows it
|
|
182
|
+
* would have returned without the release. Components without it are
|
|
183
|
+
* simply not released.
|
|
184
|
+
*/
|
|
185
|
+
releaseRenderCaches?(): void;
|
|
172
186
|
/**
|
|
173
187
|
* Optional hook to set whether this component ignores tight layout mode.
|
|
174
188
|
*/
|
|
@@ -308,6 +322,7 @@ export declare class Container implements Component {
|
|
|
308
322
|
/** Dispose every child, then detach it from this container. */
|
|
309
323
|
disposeChildren(): void;
|
|
310
324
|
invalidate(): void;
|
|
325
|
+
releaseRenderCaches(): void;
|
|
311
326
|
/**
|
|
312
327
|
* Propagate teardown to children. Call when the container's children are
|
|
313
328
|
* being permanently discarded (not when they are detached for reuse — use
|
|
@@ -458,6 +473,22 @@ export declare class TUI extends Container {
|
|
|
458
473
|
* path. Idempotent; no-op when input was never deferred.
|
|
459
474
|
*/
|
|
460
475
|
enableInput(): void;
|
|
476
|
+
/**
|
|
477
|
+
* Replay the keystrokes held since a TSP `deferInput` start through the
|
|
478
|
+
* normal input path, then deliver input live. Call once the app's key
|
|
479
|
+
* handlers are installed so a hotkey pressed during startup still fires.
|
|
480
|
+
* Only keys typed while the start-time focus owner had focus are held. The
|
|
481
|
+
* hold survives a stop/start until released. Idempotent; no-op when nothing
|
|
482
|
+
* is held.
|
|
483
|
+
*/
|
|
484
|
+
releaseHeldInput(): void;
|
|
485
|
+
/**
|
|
486
|
+
* Hand held-key ownership from `previous` to `next` when the app replaces
|
|
487
|
+
* the component focused at start (a swapped-in custom editor), so keys
|
|
488
|
+
* typed into the replacement stay queued behind the held ones instead of
|
|
489
|
+
* overtaking them. No-op unless `previous` owns the held keys.
|
|
490
|
+
*/
|
|
491
|
+
replaceHeldFocus(previous: Component, next: Component): void;
|
|
461
492
|
addStartListener(listener: StartListener): () => void;
|
|
462
493
|
addInputListener(listener: InputListener): () => void;
|
|
463
494
|
removeInputListener(listener: InputListener): void;
|
package/dist/types/vim.d.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* This is a usable subset of Vim, not a reimplementation of it (see issue #3299): Normal and Visual
|
|
9
9
|
* modes, the common motions, and operators built from those motions.
|
|
10
10
|
*/
|
|
11
|
-
export type VimMode = "insert" | "normal" | "visual" | "visual-line";
|
|
12
|
-
export type VimOperator = "d" | "y" | "c";
|
|
11
|
+
export type VimMode = "insert" | "normal" | "visual" | "visual-line" | "replace";
|
|
12
|
+
export type VimOperator = "d" | "y" | "c" | ">" | "<";
|
|
13
13
|
export interface VimPosition {
|
|
14
14
|
line: number;
|
|
15
15
|
col: number;
|
|
@@ -50,6 +50,20 @@ export type VimCommand = {
|
|
|
50
50
|
count: number;
|
|
51
51
|
} | {
|
|
52
52
|
kind: "undo";
|
|
53
|
+
} | {
|
|
54
|
+
kind: "replace";
|
|
55
|
+
from: VimPosition;
|
|
56
|
+
to: VimPosition;
|
|
57
|
+
text: string;
|
|
58
|
+
} | {
|
|
59
|
+
kind: "join";
|
|
60
|
+
fromLine: number;
|
|
61
|
+
lines: number;
|
|
62
|
+
} | {
|
|
63
|
+
kind: "indent";
|
|
64
|
+
fromLine: number;
|
|
65
|
+
toLine: number;
|
|
66
|
+
out: boolean;
|
|
53
67
|
};
|
|
54
68
|
/** Start offset of the grapheme after `col`, clamped to `text.length`. */
|
|
55
69
|
export declare function nextGraphemeStart(text: string, col: number): number;
|
|
@@ -62,11 +76,11 @@ export declare class VimState {
|
|
|
62
76
|
mode: VimMode;
|
|
63
77
|
/** Fixed end of a Visual selection; the cursor is the moving end. */
|
|
64
78
|
anchor: VimPosition | null;
|
|
65
|
-
/** True while a count, operator, `g`,
|
|
79
|
+
/** True while a count, operator, `g`, text-object, find, or `r` prefix is half-typed — Escape cancels it. */
|
|
66
80
|
get pending(): boolean;
|
|
67
81
|
/**
|
|
68
|
-
* The half-typed command as Vim would echo it (`"2"`, `"d"`, `"2d"`, `"di"`) — empty
|
|
69
|
-
* nothing is pending. Hosts render this next to the mode so a partially entered operator is
|
|
82
|
+
* The half-typed command as Vim would echo it (`"2"`, `"d"`, `"2d"`, `"di"`, `"df"`, `"r"`) — empty
|
|
83
|
+
* when nothing is pending. Hosts render this next to the mode so a partially entered operator is
|
|
70
84
|
* visible instead of silently swallowing the next keystroke.
|
|
71
85
|
*/
|
|
72
86
|
get pendingText(): string;
|
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.8",
|
|
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.8",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "18.8.8",
|
|
46
|
+
"@oh-my-pi/pi-ai": "18.8.8",
|
|
47
|
+
"@oh-my-pi/pi-catalog": "18.8.8",
|
|
48
|
+
"@oh-my-pi/pi-natives": "18.8.8",
|
|
49
|
+
"@oh-my-pi/pi-utils": "18.8.8",
|
|
50
|
+
"@oh-my-pi/pi-wire": "18.8.8",
|
|
51
|
+
"@oh-my-pi/snapcompact": "18.8.8"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"kitty-vt-wasm": "^0.2.0"
|
|
@@ -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
|
},
|
|
@@ -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;
|
|
@@ -20,6 +20,7 @@ import { DEFAULT_TERMINAL_PREVIEW_LINES, expandKeyHint } from "../render/render-
|
|
|
20
20
|
import type { TspCardStatus, TspSpan, TspText, TspTone } from "@oh-my-pi/pi-wire";
|
|
21
21
|
import { card, node, span, text } from "../native/describe";
|
|
22
22
|
import type { NativeChild, NativeNode } from "../native/node";
|
|
23
|
+
import { runBox, runFoot, runInput, runOutput, type RunState } from "../tools/native-view";
|
|
23
24
|
|
|
24
25
|
/** Output rows shown while an execution is collapsed. */
|
|
25
26
|
export const PREVIEW_LINES = 20;
|
|
@@ -190,7 +191,7 @@ export interface ExecutionToolInput {
|
|
|
190
191
|
/** Tool name for the head icon (`bash`, `eval`). */
|
|
191
192
|
readonly name: string;
|
|
192
193
|
readonly title: string;
|
|
193
|
-
/** The command / cell source
|
|
194
|
+
/** The command / cell source: the run box's input and the head's Copy command. */
|
|
194
195
|
readonly command: string;
|
|
195
196
|
readonly lang: string;
|
|
196
197
|
/** Excluded from context (`!!`/`$$`). */
|
|
@@ -208,39 +209,55 @@ export interface ExecutionToolInput {
|
|
|
208
209
|
readonly artifactError?: OutputArtifactError;
|
|
209
210
|
}
|
|
210
211
|
|
|
212
|
+
const EXECUTION_RUN_STATE: Record<ExecutionStatus, RunState> = {
|
|
213
|
+
running: "running",
|
|
214
|
+
complete: "done",
|
|
215
|
+
cancelled: "cancelled",
|
|
216
|
+
error: "failed",
|
|
217
|
+
};
|
|
218
|
+
|
|
211
219
|
/**
|
|
212
|
-
* A user `!`/`$` run as the agent's `tool` frame (§6.6):
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
220
|
+
* A user `!`/`$` run as the agent's `tool` frame (§6.6): a head with a `you`
|
|
221
|
+
* badge (plus `not sent` when excluded from context) and the command for Copy
|
|
222
|
+
* command; the body is one run box — the source, the output as an `ansi` mini
|
|
223
|
+
* terminal following its tail, and the foot (state, time, truncation) — with
|
|
224
|
+
* any images below it. Timer, exit chip and cancelled note stay head data.
|
|
216
225
|
*/
|
|
217
226
|
export function describeExecutionTool(input: ExecutionToolInput): NativeNode {
|
|
218
227
|
const running = input.status === "running";
|
|
219
|
-
const
|
|
220
|
-
if (input.output) body.push(node("ansi", { text: input.output, follow: running }, undefined, "output"));
|
|
221
|
-
if (input.images) body.push(...input.images);
|
|
222
|
-
const notes: string[] = [];
|
|
223
|
-
if (input.truncation) notes.push(formatTruncationMetaNotice(input.truncation));
|
|
224
|
-
if (input.artifactError) notes.push(formatArtifactErrorNotice(input.artifactError));
|
|
225
|
-
if (notes.length > 0) {
|
|
226
|
-
body.push({
|
|
227
|
-
...text([span(notes.join(" · "), "muted")], { wrap: "word", role: "omp.tool.notice" }),
|
|
228
|
-
key: "foot",
|
|
229
|
-
});
|
|
230
|
-
}
|
|
228
|
+
const shell = input.name === "bash";
|
|
231
229
|
const ms = Math.max(0, Math.round((input.endedAt ?? performance.now()) - input.startedAt));
|
|
230
|
+
const state = EXECUTION_RUN_STATE[input.status];
|
|
231
|
+
const box = runBox(
|
|
232
|
+
[
|
|
233
|
+
runInput(input.command, {
|
|
234
|
+
role: shell ? "omp.tool.bash.command" : "omp.tool.eval.input",
|
|
235
|
+
lang: input.lang,
|
|
236
|
+
wrap: shell,
|
|
237
|
+
}),
|
|
238
|
+
input.output.length > 0 &&
|
|
239
|
+
runOutput(input.output, {
|
|
240
|
+
role: shell ? "omp.tool.bash.output" : "omp.tool.eval.output",
|
|
241
|
+
previewLines: DEFAULT_TERMINAL_PREVIEW_LINES,
|
|
242
|
+
}),
|
|
243
|
+
runFoot({
|
|
244
|
+
state,
|
|
245
|
+
exitCode: input.exitCode,
|
|
246
|
+
elapsedMs: ms,
|
|
247
|
+
meta: { truncation: input.truncation, artifactError: input.artifactError },
|
|
248
|
+
}),
|
|
249
|
+
],
|
|
250
|
+
{ key: "run", tone: state === "failed" ? "error" : undefined },
|
|
251
|
+
);
|
|
232
252
|
const badges: { text: string; tone?: TspTone; title?: string }[] = [{ text: "you", tone: "user" }];
|
|
233
253
|
if (input.excluded) badges.push({ text: "not sent", title: "Not sent to the model", tone: "muted" });
|
|
234
|
-
const hasBody = body.length > 0;
|
|
235
254
|
return node(
|
|
236
255
|
"tool",
|
|
237
256
|
{
|
|
238
257
|
role: input.role,
|
|
239
258
|
name: input.name,
|
|
240
259
|
title: input.title,
|
|
241
|
-
|
|
242
|
-
targetKind: "command",
|
|
243
|
-
lang: input.lang,
|
|
260
|
+
command: input.command,
|
|
244
261
|
badges,
|
|
245
262
|
status: EXECUTION_CARD_STATUS[input.status],
|
|
246
263
|
age: running ? ms : undefined,
|
|
@@ -248,11 +265,11 @@ export function describeExecutionTool(input: ExecutionToolInput): NativeNode {
|
|
|
248
265
|
exit: input.status === "error" ? input.exitCode : undefined,
|
|
249
266
|
note: input.status === "cancelled" ? "cancelled" : undefined,
|
|
250
267
|
frame: "card",
|
|
251
|
-
collapsible:
|
|
252
|
-
collapsed:
|
|
253
|
-
preview:
|
|
268
|
+
collapsible: true,
|
|
269
|
+
collapsed: !input.expanded,
|
|
270
|
+
preview: "children",
|
|
254
271
|
},
|
|
255
|
-
|
|
272
|
+
[box, ...(input.images ?? [])],
|
|
256
273
|
);
|
|
257
274
|
}
|
|
258
275
|
|
|
@@ -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;
|
package/src/chat/table-chart.ts
CHANGED
|
@@ -16,8 +16,8 @@ import { chartAlt, renderChartSvg } from "../charts/chart-svg";
|
|
|
16
16
|
import { analyzeTable, type TableAnalysis } from "../charts/table-data";
|
|
17
17
|
import type { ImageBudget } from "../components/image";
|
|
18
18
|
import { lexDocument } from "../components/markdown";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
19
|
+
import { keyed } from "../native/describe";
|
|
20
|
+
import { nativeImageNode } from "../native/blobs";
|
|
21
21
|
import type { NativeNode } from "../native/node";
|
|
22
22
|
import { getThemeEpoch } from "../theme";
|
|
23
23
|
import type { Component } from "../tui";
|
|
@@ -85,11 +85,11 @@ interface ChartEntry {
|
|
|
85
85
|
let chartMode: TableChartMode = "off";
|
|
86
86
|
let chartPlanner: TableChartPlanner | undefined;
|
|
87
87
|
const charts = new Map<string, ChartEntry>();
|
|
88
|
-
/** The theme-resolved
|
|
89
|
-
const
|
|
88
|
+
/** The theme-resolved image node owning a chart's native bytes. */
|
|
89
|
+
const kNativeImage = Symbol("tableChart.nativeImage");
|
|
90
90
|
|
|
91
91
|
interface NativeTagged extends TableChart {
|
|
92
|
-
[
|
|
92
|
+
[kNativeImage]?: { epoch: number; image: NativeNode };
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/** Set how tables become charts (the host's `tui.autoGraph`) and its `smart` planner; the host rebuilds the transcript after. */
|
|
@@ -205,24 +205,21 @@ function drawChart(analysis: TableAnalysis, plan: ChartPlan, guessed = false): T
|
|
|
205
205
|
export function describeTableChart(chart: TableChart, key: string): NativeNode {
|
|
206
206
|
const epoch = getThemeEpoch();
|
|
207
207
|
const tagged: NativeTagged = chart;
|
|
208
|
-
let entry = tagged[
|
|
208
|
+
let entry = tagged[kNativeImage];
|
|
209
209
|
if (entry?.epoch !== epoch) {
|
|
210
210
|
const svg = prepareSvg(chart.svg, svgFigurePalette());
|
|
211
|
-
entry = {
|
|
212
|
-
|
|
211
|
+
entry = {
|
|
212
|
+
epoch,
|
|
213
|
+
image: nativeImageNode(new TextEncoder().encode(svg), "image/svg+xml", {
|
|
214
|
+
alt: chart.alt,
|
|
215
|
+
w: chart.width,
|
|
216
|
+
h: chart.height,
|
|
217
|
+
max: { w: `${Math.round(chart.width / UNITS_PER_COLUMN)}ch` },
|
|
218
|
+
}),
|
|
219
|
+
};
|
|
220
|
+
tagged[kNativeImage] = entry;
|
|
213
221
|
}
|
|
214
|
-
return
|
|
215
|
-
"image",
|
|
216
|
-
{
|
|
217
|
-
blob: entry.blob,
|
|
218
|
-
alt: chart.alt,
|
|
219
|
-
w: chart.width,
|
|
220
|
-
h: chart.height,
|
|
221
|
-
max: { w: `${Math.round(chart.width / UNITS_PER_COLUMN)}ch` },
|
|
222
|
-
},
|
|
223
|
-
undefined,
|
|
224
|
-
key,
|
|
225
|
-
);
|
|
222
|
+
return keyed(entry.image, key);
|
|
226
223
|
}
|
|
227
224
|
|
|
228
225
|
export interface TableChartFigureOptions {
|
|
@@ -111,10 +111,13 @@ function resolveEditModeForTool(toolName: string, tool: AgentTool | undefined):
|
|
|
111
111
|
|
|
112
112
|
type ToolRendererStage = "call" | "result";
|
|
113
113
|
|
|
114
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* A renderer's preview as the fallback card's clamp (`tail` becomes a head
|
|
116
|
+
* clamp of the same size; `children` leaves the clamping to the body's own previews).
|
|
117
|
+
*/
|
|
115
118
|
function cardPreview(preview: NativeToolView["preview"]): TspPreview | undefined {
|
|
116
119
|
if (preview === undefined) return { lines: DEFAULT_TERMINAL_PREVIEW_LINES };
|
|
117
|
-
if (preview === "none") return undefined;
|
|
120
|
+
if (preview === "none" || preview === "children") return undefined;
|
|
118
121
|
if (preview !== "auto" && "tail" in preview) return { lines: preview.tail };
|
|
119
122
|
return preview;
|
|
120
123
|
}
|
|
@@ -170,6 +173,24 @@ class SafeToolRendererComponent implements Component {
|
|
|
170
173
|
invalidate.call(this.#component);
|
|
171
174
|
}
|
|
172
175
|
|
|
176
|
+
releaseRenderCaches(): void {
|
|
177
|
+
const release = this.#component.releaseRenderCaches;
|
|
178
|
+
if (release === undefined) return;
|
|
179
|
+
try {
|
|
180
|
+
release.call(this.#component);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
if (!this.#warned) {
|
|
183
|
+
this.#warned = true;
|
|
184
|
+
logger.warn("Tool renderer failed", {
|
|
185
|
+
tool: this.#toolName,
|
|
186
|
+
stage: this.#stage,
|
|
187
|
+
phase: "releaseRenderCaches",
|
|
188
|
+
error: String(err),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
173
194
|
setIgnoreTight(ignore: boolean): void {
|
|
174
195
|
const setIgnoreTight = this.#component.setIgnoreTight;
|
|
175
196
|
if (setIgnoreTight === undefined) return;
|
|
@@ -1007,6 +1028,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
1007
1028
|
target: head?.target,
|
|
1008
1029
|
targetKind: head?.targetKind,
|
|
1009
1030
|
lang: head?.lang,
|
|
1031
|
+
command: head?.command,
|
|
1010
1032
|
href: head?.href,
|
|
1011
1033
|
meta: head?.meta,
|
|
1012
1034
|
badges: badges.length > 0 ? badges : undefined,
|
|
@@ -1106,11 +1128,14 @@ export class ToolExecutionComponent extends Container {
|
|
|
1106
1128
|
* A renderer that throws falls back to the generic card.
|
|
1107
1129
|
*/
|
|
1108
1130
|
#nativeView(): NativeToolView {
|
|
1131
|
+
const status = this.#nativeStatus();
|
|
1109
1132
|
const options: RenderResultContextOptions = {
|
|
1110
1133
|
expanded: this.#expanded,
|
|
1111
1134
|
isPartial: this.#isPartial,
|
|
1112
1135
|
argsComplete: this.#argsComplete,
|
|
1113
1136
|
executionStarted: this.#executionStarted,
|
|
1137
|
+
elapsedMs: this.#elapsedMs(status),
|
|
1138
|
+
cancelled: status === "cancelled",
|
|
1114
1139
|
renderContext: this.#buildRenderContext(),
|
|
1115
1140
|
};
|
|
1116
1141
|
// Custom tools (MCP, extensions) carry their own describe hooks, mirroring
|