@linxiraos/pi-tui 1.1.27 → 1.2.1
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 +50 -461
- package/README.md +7 -5
- package/dist/types/app-keybindings.d.ts +1 -1
- package/dist/types/apps/cleanse-board.d.ts +1 -1
- package/dist/types/apps/debug/log-viewer.d.ts +4 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +2 -0
- package/dist/types/apps/git/git-tui.d.ts +2 -2
- package/dist/types/apps/git/help.d.ts +3 -1
- package/dist/types/apps/if-bench-board.d.ts +2 -2
- package/dist/types/apps/setup-model-picker.d.ts +1 -1
- package/dist/types/autocomplete.d.ts +5 -2
- package/dist/types/charts/chart-plan.d.ts +674 -0
- package/dist/types/charts/chart-svg.d.ts +59 -0
- package/dist/types/charts/table-data.d.ts +175 -0
- package/dist/types/chat/assistant-message.d.ts +5 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +2 -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/fence-figure.d.ts +42 -0
- package/dist/types/chat/figure-markdown.d.ts +42 -0
- package/dist/types/chat/messages.d.ts +1 -1
- package/dist/types/chat/svg-figure.d.ts +33 -0
- package/dist/types/chat/svg-source.d.ts +49 -0
- package/dist/types/chat/table-chart.d.ts +89 -0
- package/dist/types/chat/tool-execution.d.ts +2 -0
- package/dist/types/chat/user-message.d.ts +15 -2
- package/dist/types/chrome/shared.d.ts +9 -0
- package/dist/types/chrome/transcript-container.d.ts +6 -0
- package/dist/types/components/box.d.ts +1 -0
- package/dist/types/components/disclosure.d.ts +1 -0
- package/dist/types/components/editor.d.ts +15 -4
- package/dist/types/components/form.d.ts +1 -0
- package/dist/types/components/image.d.ts +12 -44
- 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 +36 -3
- 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/tree-view.d.ts +7 -0
- package/dist/types/components/truncated-text.d.ts +1 -0
- package/dist/types/fuzzy.d.ts +29 -1
- package/dist/types/key-hint-format.d.ts +1 -1
- package/dist/types/keybinding-matchers.d.ts +3 -0
- package/dist/types/keybindings.d.ts +1 -1
- package/dist/types/kitty-graphics.d.ts +2 -2
- package/dist/types/loop-watchdog.d.ts +8 -7
- package/dist/types/multiplexers/cmux.d.ts +16 -0
- package/dist/types/multiplexers/herdr.d.ts +26 -0
- package/dist/types/multiplexers/notify.d.ts +13 -0
- package/dist/types/multiplexers/orca.d.ts +12 -0
- package/dist/types/multiplexers/screen.d.ts +9 -0
- package/dist/types/multiplexers/tmux.d.ts +29 -0
- package/dist/types/multiplexers/types.d.ts +100 -0
- package/dist/types/multiplexers/wmux.d.ts +12 -0
- package/dist/types/multiplexers/zellij.d.ts +12 -0
- package/dist/types/native/backend.d.ts +3 -2
- package/dist/types/native/blobs.d.ts +7 -3
- package/dist/types/native/encode.d.ts +3 -4
- package/dist/types/native/overlay.d.ts +5 -0
- package/dist/types/overlays/agent-hub-projection.d.ts +6 -5
- package/dist/types/overlays/agent-hub-types.d.ts +9 -0
- package/dist/types/overlays/agent-hub.d.ts +2 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +11 -2
- package/dist/types/overlays/agents-hub.d.ts +9 -0
- package/dist/types/overlays/annotation-overlay.d.ts +19 -2
- package/dist/types/overlays/annotation-types.d.ts +2 -0
- package/dist/types/overlays/ask-dialog.d.ts +5 -2
- package/dist/types/overlays/history-search.d.ts +10 -0
- package/dist/types/overlays/hook-selector.d.ts +9 -4
- package/dist/types/overlays/jobs-panel.d.ts +1 -7
- package/dist/types/overlays/model-browser.d.ts +54 -7
- package/dist/types/overlays/model-hub.d.ts +23 -0
- package/dist/types/overlays/oauth-selector.d.ts +0 -1
- package/dist/types/overlays/plan-review-overlay.d.ts +3 -2
- package/dist/types/overlays/session-observer-registry.d.ts +2 -0
- package/dist/types/overlays/session-selector.d.ts +6 -2
- package/dist/types/overlays/settings-defs.d.ts +1 -0
- package/dist/types/overlays/usage-dashboard.d.ts +8 -4
- package/dist/types/overlays/usage-display.d.ts +3 -1
- package/dist/types/prompt/composer.d.ts +2 -7
- package/dist/types/prompt/custom-editor.d.ts +11 -8
- package/dist/types/prompt/image-source.d.ts +2 -1
- package/dist/types/prompt/interactive-context-helpers.d.ts +4 -1
- package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
- package/dist/types/prompt/welcome.d.ts +19 -42
- package/dist/types/render/composite.d.ts +2 -0
- 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/setup/scenes/splash.d.ts +1 -1
- package/dist/types/setup/scenes/types.d.ts +1 -0
- package/dist/types/status-line/component.d.ts +3 -0
- package/dist/types/status-line/host.d.ts +4 -1
- package/dist/types/status-line/segments.d.ts +2 -0
- package/dist/types/status-line/types.d.ts +14 -3
- package/dist/types/terminal-capabilities.d.ts +27 -35
- package/dist/types/terminal-multiplexer.d.ts +127 -14
- package/dist/types/terminal.d.ts +22 -6
- package/dist/types/theme/active-symbols.d.ts +1 -1
- package/dist/types/theme/schema.d.ts +11 -2
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/theme/theme-class.d.ts +7 -0
- package/dist/types/theme/theme.d.ts +1 -1
- package/dist/types/theme/tui-adapters.d.ts +3 -0
- package/dist/types/tmux.d.ts +11 -4
- package/dist/types/tools/daemon.d.ts +1 -1
- package/dist/types/tools/eval.d.ts +22 -3
- package/dist/types/tools/glob.d.ts +4 -0
- package/dist/types/tools/native-view.d.ts +47 -0
- package/dist/types/tools/output-meta.d.ts +11 -1
- package/dist/types/tools/renderer.d.ts +37 -2
- package/dist/types/tools/streaming-output.d.ts +20 -1
- package/dist/types/tools/task.d.ts +0 -4
- package/dist/types/tools/write.d.ts +9 -2
- package/dist/types/tools/yield.d.ts +22 -0
- package/dist/types/tui.d.ts +31 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/vim.d.ts +19 -5
- package/package.json +13 -9
- package/src/app-keybindings.d.ts +1 -1
- package/src/app-keybindings.ts +1 -1
- package/src/apps/autoresearch-dashboard.ts +7 -3
- package/src/apps/cleanse-board.ts +2 -2
- package/src/apps/cleanse-picker.ts +1 -1
- package/src/apps/debug/log-viewer.ts +188 -72
- package/src/apps/debug/raw-sse-buffer.ts +8 -0
- package/src/apps/debug/raw-sse.ts +39 -5
- package/src/apps/git/diff-pane.ts +26 -5
- package/src/apps/git/git-tui.ts +2 -2
- package/src/apps/git/help.ts +29 -20
- package/src/apps/if-bench-board.ts +2 -2
- package/src/apps/ps-top.ts +2 -2
- package/src/apps/setup-model-picker.ts +1 -1
- package/src/autocomplete.d.ts +5 -2
- package/src/autocomplete.ts +67 -43
- package/src/charts/chart-plan.d.ts +674 -0
- package/src/charts/chart-plan.ts +5081 -0
- package/src/charts/chart-svg.d.ts +59 -0
- package/src/charts/chart-svg.ts +4657 -0
- package/src/charts/table-data.d.ts +175 -0
- package/src/charts/table-data.ts +1478 -0
- package/src/chat/advisor-message.ts +11 -0
- package/src/chat/assistant-message.d.ts +5 -0
- package/src/chat/assistant-message.ts +219 -50
- package/src/chat/chat-transcript-builder.d.ts +2 -0
- package/src/chat/chat-transcript-builder.ts +5 -3
- package/src/chat/compaction-summary-message.d.ts +1 -0
- package/src/chat/compaction-summary-message.ts +8 -0
- package/src/chat/execution-shared.d.ts +6 -5
- package/src/chat/execution-shared.ts +42 -25
- package/src/chat/fence-figure.d.ts +42 -0
- package/src/chat/fence-figure.ts +80 -0
- package/src/chat/figure-markdown.d.ts +42 -0
- package/src/chat/figure-markdown.ts +174 -0
- package/src/chat/messages.d.ts +1 -1
- package/src/chat/messages.ts +1 -1
- package/src/chat/read-tool-group.ts +6 -4
- package/src/chat/skill-message.ts +6 -0
- package/src/chat/svg-figure.d.ts +33 -0
- package/src/chat/svg-figure.ts +399 -0
- package/src/chat/svg-source.d.ts +49 -0
- package/src/chat/svg-source.ts +188 -0
- package/src/chat/table-chart.d.ts +89 -0
- package/src/chat/table-chart.ts +294 -0
- package/src/chat/tool-execution.d.ts +2 -0
- package/src/chat/tool-execution.ts +80 -6
- package/src/chat/user-message.d.ts +15 -2
- package/src/chat/user-message.ts +55 -3
- package/src/chrome/shared.ts +53 -0
- package/src/chrome/transcript-container.d.ts +6 -0
- package/src/chrome/transcript-container.ts +93 -13
- package/src/components/box.d.ts +1 -0
- package/src/components/box.ts +5 -0
- package/src/components/disclosure.d.ts +1 -0
- package/src/components/disclosure.ts +8 -0
- package/src/components/editor.d.ts +15 -4
- package/src/components/editor.ts +294 -46
- package/src/components/form.d.ts +1 -0
- package/src/components/form.ts +8 -0
- package/src/components/image.d.ts +12 -44
- package/src/components/image.ts +47 -151
- package/src/components/key-value-list.d.ts +1 -0
- package/src/components/key-value-list.ts +4 -0
- package/src/components/layout/row.d.ts +1 -0
- package/src/components/layout/row.ts +7 -0
- package/src/components/layout/stack.d.ts +1 -0
- package/src/components/layout/stack.ts +7 -0
- package/src/components/markdown.d.ts +36 -3
- package/src/components/markdown.ts +433 -318
- package/src/components/scroll-view.d.ts +1 -0
- package/src/components/scroll-view.ts +5 -0
- package/src/components/section.d.ts +1 -0
- package/src/components/section.ts +5 -0
- package/src/components/settings-list.ts +2 -0
- package/src/components/table.d.ts +1 -0
- package/src/components/table.ts +4 -0
- package/src/components/text.d.ts +1 -0
- package/src/components/text.ts +7 -0
- package/src/components/tree-view.d.ts +7 -0
- package/src/components/tree-view.ts +38 -8
- package/src/components/truncated-text.d.ts +1 -0
- package/src/components/truncated-text.ts +5 -0
- package/src/desktop-notify.ts +1 -1
- package/src/fuzzy.d.ts +29 -1
- package/src/fuzzy.ts +115 -30
- package/src/key-hint-format.d.ts +1 -1
- package/src/key-hint-format.ts +1 -1
- package/src/keybinding-matchers.d.ts +3 -0
- package/src/keybinding-matchers.ts +6 -2
- package/src/keybindings.d.ts +1 -1
- package/src/keybindings.ts +1 -1
- package/src/kitty-graphics.d.ts +2 -2
- package/src/kitty-graphics.ts +4 -4
- package/src/loop-watchdog.d.ts +8 -7
- package/src/loop-watchdog.ts +18 -13
- package/src/multiplexers/cmux.d.ts +16 -0
- package/src/multiplexers/cmux.ts +29 -0
- package/src/multiplexers/herdr.d.ts +26 -0
- package/src/multiplexers/herdr.ts +64 -0
- package/src/multiplexers/notify.d.ts +13 -0
- package/src/multiplexers/notify.ts +24 -0
- package/src/multiplexers/orca.d.ts +12 -0
- package/src/multiplexers/orca.ts +16 -0
- package/src/multiplexers/screen.d.ts +9 -0
- package/src/multiplexers/screen.ts +15 -0
- package/src/multiplexers/tmux.d.ts +29 -0
- package/src/multiplexers/tmux.ts +40 -0
- package/src/multiplexers/types.d.ts +100 -0
- package/src/multiplexers/types.ts +110 -0
- package/src/multiplexers/wmux.d.ts +12 -0
- package/src/multiplexers/wmux.ts +16 -0
- package/src/multiplexers/zellij.d.ts +12 -0
- package/src/multiplexers/zellij.ts +24 -0
- package/src/native/backend.d.ts +3 -2
- package/src/native/backend.ts +174 -18
- package/src/native/blobs.d.ts +7 -3
- package/src/native/blobs.ts +47 -12
- package/src/native/encode.d.ts +3 -4
- package/src/native/encode.ts +58 -31
- package/src/native/overlay.d.ts +5 -0
- package/src/native/overlay.ts +13 -0
- package/src/native/reconcile.ts +4 -0
- package/src/overlays/agent-hub-projection.d.ts +6 -5
- package/src/overlays/agent-hub-projection.ts +124 -13
- package/src/overlays/agent-hub-types.d.ts +9 -0
- package/src/overlays/agent-hub-types.ts +6 -0
- package/src/overlays/agent-hub.ts +46 -31
- package/src/overlays/agent-transcript-viewer.ts +91 -23
- package/src/overlays/agents-hub.ts +28 -8
- package/src/overlays/annotation-overlay.ts +293 -90
- package/src/overlays/annotation-types.ts +2 -0
- package/src/overlays/ask-dialog.ts +7 -10
- package/src/overlays/btw-history-panel.ts +12 -1
- package/src/overlays/copy-selector.ts +30 -8
- package/src/overlays/extensions/state-manager.ts +52 -12
- package/src/overlays/history-search.ts +100 -7
- package/src/overlays/hook-selector.ts +12 -5
- package/src/overlays/jobs-panel.ts +28 -46
- package/src/overlays/model-browser.ts +341 -110
- package/src/overlays/model-hub.ts +300 -49
- package/src/overlays/move-overlay.ts +28 -14
- package/src/overlays/oauth-selector.ts +54 -70
- package/src/overlays/plan-review-overlay.ts +194 -70
- package/src/overlays/plugin-settings.ts +11 -5
- package/src/overlays/report-panel.ts +2 -2
- package/src/overlays/rewind-selector.ts +86 -17
- package/src/overlays/session-observer-registry.d.ts +2 -0
- package/src/overlays/session-observer-registry.ts +10 -2
- package/src/overlays/session-selector.ts +64 -26
- package/src/overlays/settings-defs.ts +4 -3
- package/src/overlays/settings-selector.ts +33 -8
- package/src/overlays/snapcompact-shape-preview.ts +2 -3
- package/src/overlays/stats-notice.ts +1 -1
- package/src/overlays/tree-selector.ts +41 -20
- package/src/overlays/usage-dashboard.ts +100 -50
- package/src/overlays/usage-display.ts +10 -4
- package/src/prompt/attachment-chips.ts +15 -11
- package/src/prompt/composer-attachments.ts +6 -4
- package/src/prompt/composer-cache.ts +4 -6
- package/src/prompt/composer.ts +6 -37
- package/src/prompt/custom-editor.ts +54 -26
- package/src/prompt/image-source.ts +2 -1
- package/src/prompt/interactive-context-helpers.ts +30 -18
- package/src/prompt/macos-spelling.ts +7 -0
- package/src/prompt/magic-keywords.ts +11 -2
- package/src/prompt/model-mention-autocomplete.ts +14 -14
- package/src/prompt/tips.txt +6 -5
- package/src/prompt/welcome.ts +235 -411
- package/src/prompt/word-completion.ts +38 -5
- package/src/render/composite.d.ts +2 -0
- package/src/render/composite.ts +64 -0
- package/src/render/output-pane.d.ts +1 -0
- package/src/render/output-pane.ts +6 -0
- package/src/render/render-utils.d.ts +1 -0
- package/src/render/render-utils.ts +11 -0
- package/src/render/tool-card.d.ts +6 -0
- package/src/render/tool-card.ts +15 -0
- package/src/render/width-aware-text.d.ts +2 -0
- package/src/render/width-aware-text.ts +5 -0
- package/src/setup/scenes/model.ts +2 -1
- package/src/setup/scenes/splash.ts +116 -53
- package/src/setup/scenes/types.ts +1 -0
- package/src/status-line/component.ts +292 -78
- package/src/status-line/host.ts +4 -1
- package/src/status-line/segments.ts +40 -22
- package/src/status-line/types.ts +15 -3
- package/src/terminal-capabilities.d.ts +27 -35
- package/src/terminal-capabilities.ts +75 -189
- package/src/terminal-multiplexer.d.ts +127 -14
- package/src/terminal-multiplexer.ts +112 -33
- package/src/terminal.d.ts +22 -6
- package/src/terminal.ts +139 -37
- package/src/theme/active-symbols.d.ts +1 -1
- package/src/theme/active-symbols.ts +1 -1
- package/src/theme/schema-validation.ts +1 -0
- package/src/theme/schema.d.ts +11 -2
- package/src/theme/schema.ts +14 -1
- package/src/theme/session-color.ts +1 -7
- package/src/theme/symbols.d.ts +1 -1
- package/src/theme/symbols.ts +6 -1
- package/src/theme/theme-class.d.ts +7 -0
- package/src/theme/theme-class.ts +26 -1
- package/src/theme/theme-schema.json +5 -1
- package/src/theme/theme.d.ts +1 -1
- package/src/theme/theme.ts +8 -4
- package/src/theme/tui-adapters.d.ts +3 -0
- package/src/theme/tui-adapters.ts +68 -0
- package/src/tmux.d.ts +11 -4
- package/src/tmux.ts +47 -11
- package/src/tools/ast-edit.ts +59 -35
- package/src/tools/ast-grep.ts +35 -16
- package/src/tools/bash.ts +92 -42
- package/src/tools/daemon.d.ts +1 -1
- package/src/tools/daemon.ts +1 -1
- package/src/tools/default-renderer.ts +35 -19
- package/src/tools/edit.ts +142 -120
- package/src/tools/eval-format/index.ts +28 -2
- package/src/tools/eval-format/javascript.ts +7 -5
- package/src/tools/eval.d.ts +22 -3
- package/src/tools/eval.ts +364 -208
- package/src/tools/fetch.ts +5 -6
- package/src/tools/glob.d.ts +4 -0
- package/src/tools/glob.ts +33 -65
- package/src/tools/grep.ts +81 -48
- package/src/tools/index.ts +2 -0
- package/src/tools/lsp.ts +81 -59
- package/src/tools/mcp.ts +111 -68
- package/src/tools/native-view.d.ts +47 -0
- package/src/tools/native-view.ts +102 -1
- package/src/tools/output-meta.d.ts +11 -1
- package/src/tools/output-meta.ts +23 -3
- package/src/tools/read.ts +7 -5
- package/src/tools/renderer.d.ts +37 -2
- package/src/tools/renderer.ts +42 -2
- package/src/tools/streaming-output.d.ts +20 -1
- package/src/tools/streaming-output.ts +149 -50
- package/src/tools/task.d.ts +0 -4
- package/src/tools/task.ts +112 -59
- package/src/tools/todo.ts +119 -30
- package/src/tools/wait.ts +34 -24
- package/src/tools/web-search.ts +1 -1
- package/src/tools/write.d.ts +9 -2
- package/src/tools/write.ts +147 -95
- package/src/tools/yield.d.ts +22 -0
- package/src/tools/yield.ts +225 -0
- package/src/tui.d.ts +31 -0
- package/src/tui.ts +309 -160
- package/src/utils.d.ts +6 -0
- package/src/utils.ts +19 -0
- package/src/vim.d.ts +19 -5
- package/src/vim.ts +333 -18
- package/src/windows-input-mode.ts +8 -0
|
@@ -31,6 +31,15 @@ export interface OutputSummary {
|
|
|
31
31
|
columnDroppedBytes?: number;
|
|
32
32
|
/** Number of distinct lines that hit the per-line column cap. */
|
|
33
33
|
columnTruncatedLines?: number;
|
|
34
|
+
/**
|
|
35
|
+
* 1-indexed first and last lines the column cap cut, numbered as in the
|
|
36
|
+
* artifact. Absent when the numbering cannot match the artifact (an inline
|
|
37
|
+
* substitute was capped, or `replace()` rewrote the buffer).
|
|
38
|
+
*/
|
|
39
|
+
columnTruncatedRange?: {
|
|
40
|
+
first: number;
|
|
41
|
+
last: number;
|
|
42
|
+
};
|
|
34
43
|
/** Configured per-line column cap in effect (UTF-8 bytes), when > 0. */
|
|
35
44
|
columnMax?: number;
|
|
36
45
|
/** Artifact ID for internal URL access (artifact://<id>) when truncated */
|
|
@@ -236,7 +245,8 @@ export declare class OutputSink {
|
|
|
236
245
|
constructor(options?: OutputSinkOptions);
|
|
237
246
|
/**
|
|
238
247
|
* Push a chunk of output. The buffer management and onChunk callback run
|
|
239
|
-
* synchronously
|
|
248
|
+
* synchronously; onChunk fires after the chunk is stored, so {@link preview}
|
|
249
|
+
* already includes it. File sink writes are deferred and serialized internally.
|
|
240
250
|
*
|
|
241
251
|
* `inline` substitutes a bounded representation for the in-memory buffer and
|
|
242
252
|
* live preview while the complete chunk is mirrored to the artifact.
|
|
@@ -260,6 +270,15 @@ export declare class OutputSink {
|
|
|
260
270
|
* branch in `dump()` against stale totals.
|
|
261
271
|
*/
|
|
262
272
|
replace(text: string): void;
|
|
273
|
+
/**
|
|
274
|
+
* Current inline view without finalizing: the body {@link dump} would
|
|
275
|
+
* return right now (head + elision marker + rolling tail), minus any notice
|
|
276
|
+
* and minus the newline `dump()` appends after output that ends in a bare
|
|
277
|
+
* carriage return. Each call trims the rolling tail to its budget (a copy
|
|
278
|
+
* of the tail window once it overflowed), so call it from a throttled
|
|
279
|
+
* onChunk (`chunkThrottleMs`), not once per raw chunk.
|
|
280
|
+
*/
|
|
281
|
+
preview(): string;
|
|
263
282
|
dump(notice?: string): Promise<OutputSummary>;
|
|
264
283
|
/**
|
|
265
284
|
* Release the artifact spill descriptor on an exit path that skips
|
|
@@ -52,6 +52,12 @@ export interface OutputSummary {
|
|
|
52
52
|
columnDroppedBytes?: number;
|
|
53
53
|
/** Number of distinct lines that hit the per-line column cap. */
|
|
54
54
|
columnTruncatedLines?: number;
|
|
55
|
+
/**
|
|
56
|
+
* 1-indexed first and last lines the column cap cut, numbered as in the
|
|
57
|
+
* artifact. Absent when the numbering cannot match the artifact (an inline
|
|
58
|
+
* substitute was capped, or `replace()` rewrote the buffer).
|
|
59
|
+
*/
|
|
60
|
+
columnTruncatedRange?: { first: number; last: number };
|
|
55
61
|
/** Configured per-line column cap in effect (UTF-8 bytes), when > 0. */
|
|
56
62
|
columnMax?: number;
|
|
57
63
|
/** Artifact ID for internal URL access (artifact://<id>) when truncated */
|
|
@@ -233,6 +239,10 @@ function truncateBytesWindowed(
|
|
|
233
239
|
? data.substring(0, Math.min(data.length, maxBytes))
|
|
234
240
|
: data.substring(Math.max(0, data.length - maxBytes));
|
|
235
241
|
|
|
242
|
+
// All-ASCII window: one byte per char, so it is exactly `maxBytes` bytes on a boundary.
|
|
243
|
+
const windowBytes = Buffer.byteLength(window, "utf-8");
|
|
244
|
+
if (windowBytes === window.length) return { text: window, bytes: windowBytes };
|
|
245
|
+
|
|
236
246
|
const buf = Buffer.from(window, "utf-8");
|
|
237
247
|
|
|
238
248
|
if (mode === "head") {
|
|
@@ -876,6 +886,8 @@ export class TailBuffer {
|
|
|
876
886
|
export class OutputSink {
|
|
877
887
|
#buffer = "";
|
|
878
888
|
#bufferBytes = 0;
|
|
889
|
+
/** The overflowed tail window may exceed its budget until {@link #trimTail} runs. */
|
|
890
|
+
#tailUntrimmed = false;
|
|
879
891
|
#head = "";
|
|
880
892
|
#headBytes = 0;
|
|
881
893
|
#headLines = 0; // newline count inside #head
|
|
@@ -895,6 +907,10 @@ export class OutputSink {
|
|
|
895
907
|
#columnEllipsisAdded = false;
|
|
896
908
|
#columnDroppedBytes = 0;
|
|
897
909
|
#columnTruncatedLines = 0;
|
|
910
|
+
#columnFirstCutLine = 0;
|
|
911
|
+
#columnLastCutLine = 0;
|
|
912
|
+
/** Set once a cut line's number may not match the artifact; the range is then withheld. */
|
|
913
|
+
#columnCutLinesUnmapped = false;
|
|
898
914
|
#file?: {
|
|
899
915
|
path: string;
|
|
900
916
|
artifactId?: string;
|
|
@@ -1002,7 +1018,8 @@ export class OutputSink {
|
|
|
1002
1018
|
|
|
1003
1019
|
/**
|
|
1004
1020
|
* Push a chunk of output. The buffer management and onChunk callback run
|
|
1005
|
-
* synchronously
|
|
1021
|
+
* synchronously; onChunk fires after the chunk is stored, so {@link preview}
|
|
1022
|
+
* already includes it. File sink writes are deferred and serialized internally.
|
|
1006
1023
|
*
|
|
1007
1024
|
* `inline` substitutes a bounded representation for the in-memory buffer and
|
|
1008
1025
|
* live preview while the complete chunk is mirrored to the artifact.
|
|
@@ -1015,6 +1032,8 @@ export class OutputSink {
|
|
|
1015
1032
|
const substituted = inline !== undefined;
|
|
1016
1033
|
const inlineChunk = inline === undefined ? chunk : sanitizeText(inline);
|
|
1017
1034
|
|
|
1035
|
+
this.#store(chunk, inlineChunk, substituted);
|
|
1036
|
+
|
|
1018
1037
|
// Throttled onChunk: coalesce chunks arriving inside the throttle window.
|
|
1019
1038
|
// A timer flushes quiet tails at the throttle boundary; dump() catches a
|
|
1020
1039
|
// final pending chunk when the process exits before that timer fires.
|
|
@@ -1029,9 +1048,15 @@ export class OutputSink {
|
|
|
1029
1048
|
this.#schedulePendingChunkFlush();
|
|
1030
1049
|
}
|
|
1031
1050
|
}
|
|
1051
|
+
}
|
|
1032
1052
|
|
|
1053
|
+
/** Count, cap, mirror, and retain one sanitized chunk. */
|
|
1054
|
+
#store(chunk: string, inlineChunk: string, substituted: boolean): void {
|
|
1033
1055
|
const rawBytes = Buffer.byteLength(chunk, "utf-8");
|
|
1034
1056
|
this.#totalBytes += rawBytes;
|
|
1057
|
+
// Line the chunk starts on, as numbered in the artifact; 0 when the capped
|
|
1058
|
+
// inline text is a substitute whose lines do not map onto the artifact.
|
|
1059
|
+
const firstLine = substituted ? 0 : this.#totalLines + 1;
|
|
1035
1060
|
|
|
1036
1061
|
if (chunk.length > 0) {
|
|
1037
1062
|
this.#sawData = true;
|
|
@@ -1042,7 +1067,7 @@ export class OutputSink {
|
|
|
1042
1067
|
// Per-line column cap. State persists across chunks so a mid-line split
|
|
1043
1068
|
// still respects the budget. Operates on the inline chunk; the complete
|
|
1044
1069
|
// chunk is mirrored to the artifact before any cap is applied.
|
|
1045
|
-
const capped = this.#maxColumns > 0 ? this.#applyColumnCap(inlineChunk) : inlineChunk;
|
|
1070
|
+
const capped = this.#maxColumns > 0 ? this.#applyColumnCap(inlineChunk, firstLine) : inlineChunk;
|
|
1046
1071
|
const cappedBytes = capped === inlineChunk ? inlineBytes : Buffer.byteLength(capped, "utf-8");
|
|
1047
1072
|
const cappedThisChunk = cappedBytes < inlineBytes;
|
|
1048
1073
|
if (substituted) this.#truncated = true;
|
|
@@ -1090,11 +1115,13 @@ export class OutputSink {
|
|
|
1090
1115
|
* cap; subsequent bytes are skipped until the next `\n`. State persists
|
|
1091
1116
|
* across calls so a long line split across chunks still produces one marker.
|
|
1092
1117
|
*/
|
|
1093
|
-
#applyColumnCap(chunk: string): string {
|
|
1118
|
+
#applyColumnCap(chunk: string, firstLine: number): string {
|
|
1094
1119
|
if (chunk.length === 0) return chunk;
|
|
1120
|
+
if (!this.#columnEllipsisAdded && this.#fitsColumnCap(chunk)) return chunk;
|
|
1095
1121
|
const max = this.#maxColumns;
|
|
1096
1122
|
const parts: string[] = [];
|
|
1097
1123
|
let cursor = 0;
|
|
1124
|
+
let line = firstLine;
|
|
1098
1125
|
while (cursor < chunk.length) {
|
|
1099
1126
|
const nlIdx = chunk.indexOf(NL, cursor);
|
|
1100
1127
|
const segEnd = nlIdx === -1 ? chunk.length : nlIdx;
|
|
@@ -1125,6 +1152,12 @@ export class OutputSink {
|
|
|
1125
1152
|
parts.push(ELLIPSIS);
|
|
1126
1153
|
this.#columnDroppedBytes += segBytes - keptBytes;
|
|
1127
1154
|
this.#columnTruncatedLines++;
|
|
1155
|
+
if (line > 0) {
|
|
1156
|
+
if (this.#columnFirstCutLine === 0) this.#columnFirstCutLine = line;
|
|
1157
|
+
this.#columnLastCutLine = line;
|
|
1158
|
+
} else {
|
|
1159
|
+
this.#columnCutLinesUnmapped = true;
|
|
1160
|
+
}
|
|
1128
1161
|
this.#currentLineBytes += keptBytes + ellipsisBytes;
|
|
1129
1162
|
this.#columnEllipsisAdded = true;
|
|
1130
1163
|
}
|
|
@@ -1135,10 +1168,37 @@ export class OutputSink {
|
|
|
1135
1168
|
this.#currentLineBytes = 0;
|
|
1136
1169
|
this.#columnEllipsisAdded = false;
|
|
1137
1170
|
cursor = nlIdx + 1;
|
|
1171
|
+
if (line > 0) line++;
|
|
1138
1172
|
}
|
|
1139
1173
|
return parts.join("");
|
|
1140
1174
|
}
|
|
1141
1175
|
|
|
1176
|
+
/**
|
|
1177
|
+
* Fast path for {@link #applyColumnCap}: when every line segment fits the
|
|
1178
|
+
* remaining cap even at the 3-bytes-per-code-unit UTF-8 worst case, the
|
|
1179
|
+
* chunk passes through unchanged and only the trailing line width is
|
|
1180
|
+
* measured. Returns false (state untouched) when any line might trip the cap.
|
|
1181
|
+
*/
|
|
1182
|
+
#fitsColumnCap(chunk: string): boolean {
|
|
1183
|
+
const max = this.#maxColumns;
|
|
1184
|
+
let room = max - this.#currentLineBytes;
|
|
1185
|
+
let cursor = 0;
|
|
1186
|
+
for (;;) {
|
|
1187
|
+
const nlIdx = chunk.indexOf(NL, cursor);
|
|
1188
|
+
const segEnd = nlIdx === -1 ? chunk.length : nlIdx;
|
|
1189
|
+
if ((segEnd - cursor) * 3 > room) return false;
|
|
1190
|
+
if (nlIdx === -1) break;
|
|
1191
|
+
cursor = nlIdx + 1;
|
|
1192
|
+
room = max;
|
|
1193
|
+
}
|
|
1194
|
+
if (cursor === 0) {
|
|
1195
|
+
this.#currentLineBytes += Buffer.byteLength(chunk, "utf-8");
|
|
1196
|
+
} else {
|
|
1197
|
+
this.#currentLineBytes = cursor === chunk.length ? 0 : Buffer.byteLength(chunk.substring(cursor), "utf-8");
|
|
1198
|
+
}
|
|
1199
|
+
return true;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1142
1202
|
// The rolling tail budget is whatever the head window has not consumed of
|
|
1143
1203
|
// the inline budget: `spillThreshold - #headBytes`. While the head window
|
|
1144
1204
|
// fills it shrinks toward `spillThreshold - headLimit`; after `replace()`
|
|
@@ -1172,15 +1232,27 @@ export class OutputSink {
|
|
|
1172
1232
|
const { text, bytes } = truncateTailBytes(chunk, threshold);
|
|
1173
1233
|
this.#buffer = text;
|
|
1174
1234
|
this.#bufferBytes = bytes;
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
this.#buffer += chunk;
|
|
1178
|
-
this.#bufferBytes += dataBytes;
|
|
1179
|
-
|
|
1180
|
-
const { text, bytes } = truncateTailBytes(this.#buffer, threshold);
|
|
1181
|
-
this.#buffer = text;
|
|
1182
|
-
this.#bufferBytes = bytes;
|
|
1235
|
+
this.#tailUntrimmed = false;
|
|
1236
|
+
return;
|
|
1183
1237
|
}
|
|
1238
|
+
// Amortize the trim: let the window grow to 2× the budget before cutting it
|
|
1239
|
+
// back, so steady-state chunks cost an append instead of a window copy.
|
|
1240
|
+
// `#trimTail()` restores the exact budget before the buffer is read.
|
|
1241
|
+
this.#buffer += chunk;
|
|
1242
|
+
this.#bufferBytes += dataBytes;
|
|
1243
|
+
this.#tailUntrimmed = true;
|
|
1244
|
+
if (this.#bufferBytes > threshold * 2) this.#trimTail();
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/** Cut an overflowed tail window back to the current tail budget. */
|
|
1248
|
+
#trimTail(): void {
|
|
1249
|
+
if (!this.#tailUntrimmed) return;
|
|
1250
|
+
this.#tailUntrimmed = false;
|
|
1251
|
+
const threshold = Math.max(0, this.#spillThreshold - this.#headBytes);
|
|
1252
|
+
if (this.#bufferBytes <= threshold) return;
|
|
1253
|
+
const { text, bytes } = truncateTailBytes(this.#buffer, threshold);
|
|
1254
|
+
this.#buffer = text;
|
|
1255
|
+
this.#bufferBytes = bytes;
|
|
1184
1256
|
}
|
|
1185
1257
|
|
|
1186
1258
|
/**
|
|
@@ -1372,6 +1444,7 @@ export class OutputSink {
|
|
|
1372
1444
|
this.#clearPendingChunkTimer();
|
|
1373
1445
|
this.#buffer = text;
|
|
1374
1446
|
this.#bufferBytes = Buffer.byteLength(text, "utf-8");
|
|
1447
|
+
this.#tailUntrimmed = false;
|
|
1375
1448
|
this.#head = "";
|
|
1376
1449
|
this.#headBytes = 0;
|
|
1377
1450
|
this.#headLines = 0;
|
|
@@ -1384,6 +1457,8 @@ export class OutputSink {
|
|
|
1384
1457
|
this.#columnEllipsisAdded = false;
|
|
1385
1458
|
this.#columnDroppedBytes = 0;
|
|
1386
1459
|
this.#columnTruncatedLines = 0;
|
|
1460
|
+
// The artifact keeps the replaced stream, so later line numbers no longer match it.
|
|
1461
|
+
this.#columnCutLinesUnmapped = true;
|
|
1387
1462
|
this.#pendingChunk = "";
|
|
1388
1463
|
this.#pendingCarriageReturn = false;
|
|
1389
1464
|
}
|
|
@@ -1458,22 +1533,31 @@ export class OutputSink {
|
|
|
1458
1533
|
}
|
|
1459
1534
|
}
|
|
1460
1535
|
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1536
|
+
/**
|
|
1537
|
+
* Current inline view without finalizing: the body {@link dump} would
|
|
1538
|
+
* return right now (head + elision marker + rolling tail), minus any notice
|
|
1539
|
+
* and minus the newline `dump()` appends after output that ends in a bare
|
|
1540
|
+
* carriage return. Each call trims the rolling tail to its budget (a copy
|
|
1541
|
+
* of the tail window once it overflowed), so call it from a throttled
|
|
1542
|
+
* onChunk (`chunkThrottleMs`), not once per raw chunk.
|
|
1543
|
+
*/
|
|
1544
|
+
preview(): string {
|
|
1545
|
+
return this.#composeBody().body;
|
|
1546
|
+
}
|
|
1467
1547
|
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1548
|
+
/**
|
|
1549
|
+
* Compose the visible output. With head retention, splice head + marker +
|
|
1550
|
+
* tail when content was elided. Otherwise return the rolling buffer.
|
|
1551
|
+
*/
|
|
1552
|
+
#composeBody(): {
|
|
1553
|
+
body: string;
|
|
1554
|
+
outputBytes: number;
|
|
1555
|
+
outputLines: number;
|
|
1556
|
+
elidedBytes?: number;
|
|
1557
|
+
elidedLines?: number;
|
|
1558
|
+
} {
|
|
1559
|
+
this.#trimTail();
|
|
1471
1560
|
const totalLines = this.#sawData ? this.#totalLines + 1 : 0;
|
|
1472
|
-
|
|
1473
|
-
await this.#finalizeFile();
|
|
1474
|
-
|
|
1475
|
-
// Compose the visible output. With head retention, splice head + marker
|
|
1476
|
-
// + tail when content was elided. Otherwise return the rolling buffer.
|
|
1477
1561
|
const headBytes = this.#headBytes;
|
|
1478
1562
|
const tailBuf = this.#buffer;
|
|
1479
1563
|
const tailBytes = this.#bufferBytes;
|
|
@@ -1484,39 +1568,50 @@ export class OutputSink {
|
|
|
1484
1568
|
// so column-dropped bytes don't inflate the "elided from middle" count.
|
|
1485
1569
|
const effectiveTotalBytes = Math.max(0, this.#totalBytes - this.#columnDroppedBytes);
|
|
1486
1570
|
|
|
1487
|
-
let body: string;
|
|
1488
|
-
let outputBytes: number;
|
|
1489
|
-
let outputLines: number;
|
|
1490
|
-
let elidedBytes: number | undefined;
|
|
1491
|
-
let elidedLines: number | undefined;
|
|
1492
|
-
|
|
1493
1571
|
if (headBytes > 0 && effectiveTotalBytes > headBytes + tailBytes) {
|
|
1494
1572
|
// Middle was elided. Emit head + marker + tail.
|
|
1495
|
-
elidedBytes = Math.max(0, effectiveTotalBytes - headBytes - tailBytes);
|
|
1496
|
-
elidedLines = Math.max(0, totalLines - headLines - tailLines);
|
|
1573
|
+
const elidedBytes = Math.max(0, effectiveTotalBytes - headBytes - tailBytes);
|
|
1574
|
+
const elidedLines = Math.max(0, totalLines - headLines - tailLines);
|
|
1497
1575
|
const marker = formatMiddleElisionMarker(elidedLines, elidedBytes);
|
|
1498
1576
|
const markerBytes = Buffer.byteLength(marker, "utf-8");
|
|
1499
1577
|
const headSep = this.#head.endsWith("\n") ? "" : "\n";
|
|
1500
1578
|
const tailSep = tailBuf.startsWith("\n") ? "" : "\n";
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
headBytes +
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
} else if (headBytes > 0) {
|
|
1579
|
+
return {
|
|
1580
|
+
body: `${this.#head}${headSep}${marker}${tailSep}${tailBuf}`,
|
|
1581
|
+
outputBytes: headBytes + markerBytes + tailBytes + headSep.length + tailSep.length,
|
|
1582
|
+
outputLines: headLines + 1 + tailLines,
|
|
1583
|
+
elidedBytes,
|
|
1584
|
+
elidedLines,
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
if (headBytes > 0) {
|
|
1511
1588
|
// Head + tail combine into the full buffered output (no overlap or elision).
|
|
1512
|
-
body = `${this.#head}${tailBuf}`;
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
outputLines = tailLines;
|
|
1589
|
+
const body = `${this.#head}${tailBuf}`;
|
|
1590
|
+
return {
|
|
1591
|
+
body,
|
|
1592
|
+
outputBytes: headBytes + tailBytes,
|
|
1593
|
+
outputLines: body.length > 0 ? countNewlines(body) + 1 : 0,
|
|
1594
|
+
};
|
|
1519
1595
|
}
|
|
1596
|
+
return { body: tailBuf, outputBytes: tailBytes, outputLines: tailLines };
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
async dump(notice?: string): Promise<OutputSummary> {
|
|
1600
|
+
if (this.#pendingCarriageReturn) {
|
|
1601
|
+
this.#pendingCarriageReturn = false;
|
|
1602
|
+
this.push(NL);
|
|
1603
|
+
}
|
|
1604
|
+
const noticeLine = notice ? `[${notice}]\n` : "";
|
|
1605
|
+
|
|
1606
|
+
// Flush any chunk still held back by the throttle so the live preview
|
|
1607
|
+
// ends with the complete stream.
|
|
1608
|
+
this.#flushPendingChunk();
|
|
1609
|
+
const totalLines = this.#sawData ? this.#totalLines + 1 : 0;
|
|
1610
|
+
|
|
1611
|
+
await this.#finalizeFile();
|
|
1612
|
+
|
|
1613
|
+
const { body, outputBytes, outputLines, elidedBytes, elidedLines } = this.#composeBody();
|
|
1614
|
+
if (elidedBytes !== undefined) this.#truncated = true;
|
|
1520
1615
|
|
|
1521
1616
|
return {
|
|
1522
1617
|
output: `${noticeLine}${body}`,
|
|
@@ -1530,6 +1625,10 @@ export class OutputSink {
|
|
|
1530
1625
|
columnDroppedBytes: this.#columnDroppedBytes > 0 ? this.#columnDroppedBytes : undefined,
|
|
1531
1626
|
columnTruncatedLines: this.#columnTruncatedLines > 0 ? this.#columnTruncatedLines : undefined,
|
|
1532
1627
|
columnMax: this.#columnTruncatedLines > 0 ? this.#maxColumns : undefined,
|
|
1628
|
+
columnTruncatedRange:
|
|
1629
|
+
this.#columnFirstCutLine > 0 && !this.#columnCutLinesUnmapped
|
|
1630
|
+
? { first: this.#columnFirstCutLine, last: this.#columnLastCutLine }
|
|
1631
|
+
: undefined,
|
|
1533
1632
|
artifactId: this.#artifactError ? undefined : this.#file?.artifactId,
|
|
1534
1633
|
artifactElidedBytes:
|
|
1535
1634
|
this.#artifactError || !this.#file?.artifactId || this.#artifactElidedBytes === 0
|
package/src/tools/task.d.ts
CHANGED
|
@@ -107,8 +107,6 @@ export interface TaskItem {
|
|
|
107
107
|
solutionSpace?: string;
|
|
108
108
|
/** Per-spawn thinking effort: lowest/middle/highest level the resolved model supports. Overrides the agent's default selector (e.g. `auto`). */
|
|
109
109
|
effort?: "lo" | "med" | "hi";
|
|
110
|
-
/** Per-spawn model selector or ordered selector array; overrides agent and settings preferences. */
|
|
111
|
-
model?: string | string[];
|
|
112
110
|
/** Caller-provided output schema; its presence overrides the selected agent's schema. */
|
|
113
111
|
outputSchema?: unknown;
|
|
114
112
|
/** Validation behavior for a caller-provided or inherited output schema. */
|
|
@@ -135,8 +133,6 @@ export interface TaskParams {
|
|
|
135
133
|
solutionSpace?: string;
|
|
136
134
|
/** Per-spawn thinking effort (flat form): lowest/middle/highest level the resolved model supports. */
|
|
137
135
|
effort?: "lo" | "med" | "hi";
|
|
138
|
-
/** Per-spawn model selector or ordered selector array; overrides agent and settings preferences. */
|
|
139
|
-
model?: string | string[];
|
|
140
136
|
/** Caller-provided output schema; its presence overrides the selected agent's schema. */
|
|
141
137
|
outputSchema?: unknown;
|
|
142
138
|
/** Validation behavior for a caller-provided or inherited output schema. */
|
package/src/tools/task.ts
CHANGED
|
@@ -47,7 +47,7 @@ import { assembleYieldResult, type YieldSectionShapes } from "./task-yield-assem
|
|
|
47
47
|
import type { TspAgentProps, TspTone } from "@linxiraos/pi-wire";
|
|
48
48
|
import { compact, kv, md, node, span, text } from "../native/describe";
|
|
49
49
|
import type { NativeNode } from "../native/node";
|
|
50
|
-
import { OwnerMemo } from "../native/memo";
|
|
50
|
+
import { OwnerMemo, sameItems } from "../native/memo";
|
|
51
51
|
import { plainText } from "../native/spans";
|
|
52
52
|
import { errorText, noteText, resultText } from "./native-view";
|
|
53
53
|
import { taskSummary } from "../overlays/agent-hub-renderer";
|
|
@@ -242,6 +242,39 @@ function renderTypedYieldSections(value: unknown, continuePrefix: string, expand
|
|
|
242
242
|
return lines;
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Per-frame memo for derived agent rows. Live task cards re-render at spinner
|
|
247
|
+
* cadence, while yield/recent-output arrays only change when the subagent
|
|
248
|
+
* reports. Entries are keyed by the source array (or object) and validated
|
|
249
|
+
* against a shallow snapshot of its elements plus the render deps, so in-place
|
|
250
|
+
* pushes/shifts invalidate correctly.
|
|
251
|
+
*/
|
|
252
|
+
interface SnapshotMemoEntry<T> {
|
|
253
|
+
items: unknown[];
|
|
254
|
+
deps: unknown[];
|
|
255
|
+
value: T;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function memoBySnapshot<T>(
|
|
259
|
+
cache: WeakMap<object, SnapshotMemoEntry<T>>,
|
|
260
|
+
source: unknown,
|
|
261
|
+
deps: unknown[],
|
|
262
|
+
compute: () => T,
|
|
263
|
+
): T {
|
|
264
|
+
if (source === null || typeof source !== "object") return compute();
|
|
265
|
+
const items: unknown[] = Array.isArray(source) ? source.slice() : [source];
|
|
266
|
+
const entry = cache.get(source);
|
|
267
|
+
if (entry && sameItems(entry.items, items) && sameItems(entry.deps, deps)) return entry.value;
|
|
268
|
+
const value = compute();
|
|
269
|
+
cache.set(source, { items, deps, value });
|
|
270
|
+
return value;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const yieldSectionsMemo = new WeakMap<object, SnapshotMemoEntry<string[]>>();
|
|
274
|
+
const completedReviewMemo = new WeakMap<object, SnapshotMemoEntry<string[] | null>>();
|
|
275
|
+
const recentOutputMemo = new WeakMap<object, SnapshotMemoEntry<string[]>>();
|
|
276
|
+
const agentResultMemo = new WeakMap<object, SnapshotMemoEntry<string[]>>();
|
|
277
|
+
|
|
245
278
|
/** Formats sanitized task identifiers as hierarchy breadcrumbs. */
|
|
246
279
|
export function formatTaskId(id: string): string {
|
|
247
280
|
// Ids are name-based (e.g. "Anna", "Anna-2"); a "." separates nesting levels
|
|
@@ -776,27 +809,32 @@ function renderAgentProgress(
|
|
|
776
809
|
// For completed tasks, render review verdicts assembled from incremental
|
|
777
810
|
// yield sections.
|
|
778
811
|
if (progress.status === "completed") {
|
|
779
|
-
const
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
812
|
+
const yieldValue = progress.extractedToolData.yield;
|
|
813
|
+
const reviewLines = memoBySnapshot(
|
|
814
|
+
completedReviewMemo,
|
|
815
|
+
yieldValue,
|
|
816
|
+
[continuePrefix, expanded, theme],
|
|
817
|
+
(): string[] | null => {
|
|
818
|
+
const completeData = normalizeYieldData(yieldValue);
|
|
819
|
+
const incrementalReview = extractIncrementalReviewResult(completeData);
|
|
820
|
+
if (incrementalReview) {
|
|
821
|
+
return renderReviewResult(
|
|
822
|
+
incrementalReview.summary,
|
|
823
|
+
incrementalReview.findings,
|
|
824
|
+
continuePrefix,
|
|
825
|
+
expanded,
|
|
826
|
+
theme,
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
const reviewData = completeData
|
|
830
|
+
.map(c => c.data as SubmitReviewDetails)
|
|
831
|
+
.filter(d => d && typeof d === "object" && "overall_correctness" in d);
|
|
832
|
+
if (reviewData.length === 0) return null;
|
|
833
|
+
return renderReviewResult(reviewData[reviewData.length - 1], [], continuePrefix, expanded, theme);
|
|
834
|
+
},
|
|
835
|
+
);
|
|
836
|
+
if (reviewLines) {
|
|
837
|
+
lines.push(...reviewLines);
|
|
800
838
|
return lines; // Review result handles its own rendering
|
|
801
839
|
}
|
|
802
840
|
}
|
|
@@ -804,7 +842,11 @@ function renderAgentProgress(
|
|
|
804
842
|
for (const toolName in progress.extractedToolData) {
|
|
805
843
|
const dataArray = progress.extractedToolData[toolName];
|
|
806
844
|
if (toolName === "yield") {
|
|
807
|
-
lines.push(
|
|
845
|
+
lines.push(
|
|
846
|
+
...memoBySnapshot(yieldSectionsMemo, dataArray, [continuePrefix, expanded, theme], () =>
|
|
847
|
+
renderTypedYieldSections(dataArray, continuePrefix, expanded, theme),
|
|
848
|
+
),
|
|
849
|
+
);
|
|
808
850
|
continue;
|
|
809
851
|
}
|
|
810
852
|
|
|
@@ -862,15 +904,19 @@ function renderAgentProgress(
|
|
|
862
904
|
// Expanded view: recent output and tools
|
|
863
905
|
if (expanded && progress.status === "running") {
|
|
864
906
|
const previewRows = previewWindowRows();
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
907
|
+
lines.push(
|
|
908
|
+
...memoBySnapshot(recentOutputMemo, progress.recentOutput, [continuePrefix, theme, previewRows], () => {
|
|
909
|
+
const output = capPreviewLines(
|
|
910
|
+
sanitizeRecentOutput([...progress.recentOutput].reverse().join("\n")).split("\n"),
|
|
911
|
+
theme,
|
|
912
|
+
{
|
|
913
|
+
max: previewRows,
|
|
914
|
+
expandHint: false,
|
|
915
|
+
},
|
|
916
|
+
).join("\n");
|
|
917
|
+
return renderOutputSection(output, continuePrefix, expanded, theme, 2, previewRows);
|
|
918
|
+
}),
|
|
919
|
+
);
|
|
874
920
|
}
|
|
875
921
|
|
|
876
922
|
return lines;
|
|
@@ -1347,7 +1393,7 @@ export function renderResult(
|
|
|
1347
1393
|
const aborted = abortedCount > 0;
|
|
1348
1394
|
const failed = failCount > 0;
|
|
1349
1395
|
const mergeFailed = mergeFailedCount > 0;
|
|
1350
|
-
const isError =
|
|
1396
|
+
const isError = aborted || failed;
|
|
1351
1397
|
const agentCount = hasResults ? details.results.length : (details.progress?.length ?? 0);
|
|
1352
1398
|
const icon: ToolUIStatus = options.isPartial ? "running" : isError ? "error" : mergeFailed ? "warning" : "success";
|
|
1353
1399
|
// Header meta is the spawn count only; each row carries its own ⟨agent⟩
|
|
@@ -1373,6 +1419,25 @@ export function renderResult(
|
|
|
1373
1419
|
theme,
|
|
1374
1420
|
);
|
|
1375
1421
|
|
|
1422
|
+
// Fallback text is fixed for this snapshot; derive its trailing notice rows
|
|
1423
|
+
// once instead of re-splitting on every spinner frame.
|
|
1424
|
+
const fallbackExtraLines: string[] = [];
|
|
1425
|
+
if (fallbackText.trim()) {
|
|
1426
|
+
const summaryLines = fallbackText.split("\n");
|
|
1427
|
+
const markerIndex = summaryLines.findIndex(
|
|
1428
|
+
line =>
|
|
1429
|
+
line.includes("<system-notification>") ||
|
|
1430
|
+
line.startsWith("Applied patches:") ||
|
|
1431
|
+
line.startsWith("No changes to apply."),
|
|
1432
|
+
);
|
|
1433
|
+
if (markerIndex >= 0) {
|
|
1434
|
+
for (let i = markerIndex; i < summaryLines.length; i++) {
|
|
1435
|
+
const line = summaryLines[i];
|
|
1436
|
+
if (line.trim()) fallbackExtraLines.push(theme.fg("dim", line));
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1376
1441
|
return framedToolCard(theme, ({ width, contentWidth }) => {
|
|
1377
1442
|
const { expanded, isPartial, spinnerFrame } = options;
|
|
1378
1443
|
const frozen = options.renderContext?.frozen === true;
|
|
@@ -1414,7 +1479,11 @@ export function renderResult(
|
|
|
1414
1479
|
const ordered = orderResultsForDisplay(details.results);
|
|
1415
1480
|
const visible = expanded ? ordered : selectCollapsedResults(ordered);
|
|
1416
1481
|
for (const res of visible) {
|
|
1417
|
-
lines.push(
|
|
1482
|
+
lines.push(
|
|
1483
|
+
...memoBySnapshot(agentResultMemo, res, [expanded, theme, contentWidth, isFeedModelBadgeEnabled()], () =>
|
|
1484
|
+
renderAgentResult(res, "", " ", expanded, theme, undefined, 0, contentWidth),
|
|
1485
|
+
),
|
|
1486
|
+
);
|
|
1418
1487
|
}
|
|
1419
1488
|
if (visible.length < ordered.length) {
|
|
1420
1489
|
const hint = formatExpandHint(theme, false, true);
|
|
@@ -1427,11 +1496,14 @@ export function renderResult(
|
|
|
1427
1496
|
// (their payloads deliver through jobs) — keep their rows visible
|
|
1428
1497
|
// beside the finalized inline results, live while running and
|
|
1429
1498
|
// settled once their jobs finish.
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1499
|
+
let supplementalProgress: AgentProgress[] = [];
|
|
1500
|
+
if (details.progress) {
|
|
1501
|
+
const resultIds = new Set<string>();
|
|
1502
|
+
for (const res of details.results) resultIds.add(res.id);
|
|
1503
|
+
supplementalProgress = orderProgressForDisplay(
|
|
1504
|
+
details.progress.filter(progress => !resultIds.has(progress.id)),
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1435
1507
|
for (const progress of supplementalProgress) {
|
|
1436
1508
|
lines.push(
|
|
1437
1509
|
...renderAgentProgress(
|
|
@@ -1484,22 +1556,7 @@ export function renderResult(
|
|
|
1484
1556
|
};
|
|
1485
1557
|
}
|
|
1486
1558
|
|
|
1487
|
-
|
|
1488
|
-
const summaryLines = fallbackText.split("\n");
|
|
1489
|
-
const markerIndex = summaryLines.findIndex(
|
|
1490
|
-
line =>
|
|
1491
|
-
line.includes("<system-notification>") ||
|
|
1492
|
-
line.startsWith("Applied patches:") ||
|
|
1493
|
-
line.startsWith("No changes to apply."),
|
|
1494
|
-
);
|
|
1495
|
-
if (markerIndex >= 0) {
|
|
1496
|
-
const extra = summaryLines.slice(markerIndex);
|
|
1497
|
-
for (const line of extra) {
|
|
1498
|
-
if (!line.trim()) continue;
|
|
1499
|
-
lines.push(theme.fg("dim", line));
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1559
|
+
for (const line of fallbackExtraLines) lines.push(line);
|
|
1503
1560
|
|
|
1504
1561
|
while (lines.length > 0 && lines[0].trim() === "") lines.shift();
|
|
1505
1562
|
return {
|
|
@@ -2149,8 +2206,6 @@ export interface TaskItem {
|
|
|
2149
2206
|
solutionSpace?: string;
|
|
2150
2207
|
/** Per-spawn thinking effort: lowest/middle/highest level the resolved model supports. Overrides the agent's default selector (e.g. `auto`). */
|
|
2151
2208
|
effort?: "lo" | "med" | "hi";
|
|
2152
|
-
/** Per-spawn model selector or ordered selector array; overrides agent and settings preferences. */
|
|
2153
|
-
model?: string | string[];
|
|
2154
2209
|
/** Caller-provided output schema; its presence overrides the selected agent's schema. */
|
|
2155
2210
|
outputSchema?: unknown;
|
|
2156
2211
|
/** Validation behavior for a caller-provided or inherited output schema. */
|
|
@@ -2178,8 +2233,6 @@ export interface TaskParams {
|
|
|
2178
2233
|
solutionSpace?: string;
|
|
2179
2234
|
/** Per-spawn thinking effort (flat form): lowest/middle/highest level the resolved model supports. */
|
|
2180
2235
|
effort?: "lo" | "med" | "hi";
|
|
2181
|
-
/** Per-spawn model selector or ordered selector array; overrides agent and settings preferences. */
|
|
2182
|
-
model?: string | string[];
|
|
2183
2236
|
/** Caller-provided output schema; its presence overrides the selected agent's schema. */
|
|
2184
2237
|
outputSchema?: unknown;
|
|
2185
2238
|
/** Validation behavior for a caller-provided or inherited output schema. */
|