@linxiraos/pi-tui 1.1.26 → 1.2.0
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 +51 -491
- package/README.md +13 -7
- package/dist/types/active-terminal.d.ts +30 -0
- package/dist/types/app-keybindings.d.ts +7 -2
- 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 +5 -4
- 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 +11 -1
- package/dist/types/chat/chat-transcript-builder.d.ts +3 -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 +17 -4
- package/dist/types/chrome/shared.d.ts +9 -0
- package/dist/types/chrome/status-notice.d.ts +15 -3
- 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 +23 -5
- package/dist/types/components/form.d.ts +1 -0
- package/dist/types/components/image.d.ts +26 -44
- package/dist/types/components/input.d.ts +2 -1
- 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/loader.d.ts +5 -6
- package/dist/types/components/markdown.d.ts +47 -5
- 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 +9 -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/apply.d.ts +4 -3
- package/dist/types/native/backend.d.ts +5 -4
- package/dist/types/native/blobs.d.ts +7 -3
- package/dist/types/native/encode.d.ts +8 -6
- package/dist/types/native/node.d.ts +36 -5
- package/dist/types/native/overlay.d.ts +8 -3
- package/dist/types/native/settle.d.ts +4 -3
- 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 +3 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +12 -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/btw-history-panel.d.ts +13 -1
- package/dist/types/overlays/copy-selector.d.ts +1 -0
- package/dist/types/overlays/history-search.d.ts +10 -0
- package/dist/types/overlays/hook-selector.d.ts +9 -4
- package/dist/types/overlays/hub-frame.d.ts +4 -1
- 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 +37 -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/report-panel.d.ts +68 -0
- package/dist/types/overlays/rewind-selector.d.ts +1 -0
- 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/thinking-selector.d.ts +2 -2
- package/dist/types/overlays/usage-dashboard.d.ts +12 -8
- package/dist/types/overlays/usage-display.d.ts +3 -1
- package/dist/types/prompt/composer-cache.d.ts +0 -16
- package/dist/types/prompt/composer.d.ts +18 -3
- package/dist/types/prompt/custom-editor.d.ts +25 -13
- package/dist/types/prompt/image-source.d.ts +2 -1
- package/dist/types/prompt/interactive-context-helpers.d.ts +5 -1
- package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
- package/dist/types/prompt/welcome.d.ts +7 -2
- 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/types.d.ts +1 -0
- package/dist/types/space-hold.d.ts +40 -25
- package/dist/types/status-line/component.d.ts +3 -0
- package/dist/types/status-line/context-usage.d.ts +7 -5
- 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 +41 -36
- package/dist/types/terminal-multiplexer.d.ts +127 -14
- package/dist/types/terminal.d.ts +23 -16
- 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/thinking.d.ts +1 -1
- package/dist/types/tmux.d.ts +11 -4
- package/dist/types/tools/bash.d.ts +7 -2
- 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 +2 -3
- package/dist/types/tools/write.d.ts +9 -2
- package/dist/types/tools/yield.d.ts +22 -0
- package/dist/types/tui.d.ts +36 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/vim.d.ts +19 -5
- package/dist/types/windows-input-mode.d.ts +33 -1
- package/package.json +13 -9
- package/src/active-terminal.d.ts +30 -0
- package/src/active-terminal.ts +80 -0
- package/src/app-keybindings.d.ts +7 -2
- package/src/app-keybindings.ts +7 -2
- 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 +96 -23
- package/src/apps/git/git-tui.ts +23 -16
- package/src/apps/git/help.ts +29 -20
- package/src/apps/git/sidebar.ts +8 -3
- 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/bracketed-paste.ts +10 -3
- 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 +11 -1
- package/src/chat/assistant-message.ts +245 -54
- package/src/chat/chat-transcript-builder.d.ts +3 -0
- package/src/chat/chat-transcript-builder.ts +9 -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 +86 -7
- package/src/chat/user-message.d.ts +17 -4
- package/src/chat/user-message.ts +71 -8
- package/src/chrome/shared.ts +53 -0
- package/src/chrome/status-notice.ts +25 -7
- package/src/chrome/transcript-container.d.ts +6 -0
- package/src/chrome/transcript-container.ts +162 -19
- 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 +23 -5
- package/src/components/editor.ts +316 -47
- package/src/components/form.d.ts +1 -0
- package/src/components/form.ts +8 -0
- package/src/components/image.d.ts +26 -44
- package/src/components/image.ts +115 -152
- package/src/components/input.d.ts +2 -1
- package/src/components/input.ts +17 -7
- 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/loader.d.ts +5 -6
- package/src/components/loader.ts +10 -17
- package/src/components/markdown.d.ts +47 -5
- package/src/components/markdown.ts +786 -303
- 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 +3 -2
- package/src/fuzzy.d.ts +29 -1
- package/src/fuzzy.ts +115 -30
- package/src/hotkeys-markdown.ts +9 -2
- package/src/key-hint-format.d.ts +9 -1
- package/src/key-hint-format.ts +26 -11
- 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 +11 -5
- 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/apply.d.ts +4 -3
- package/src/native/apply.ts +4 -3
- package/src/native/backend.d.ts +5 -4
- package/src/native/backend.ts +199 -22
- package/src/native/blobs.d.ts +7 -3
- package/src/native/blobs.ts +47 -12
- package/src/native/encode.d.ts +8 -6
- package/src/native/encode.ts +76 -34
- package/src/native/node.d.ts +36 -5
- package/src/native/node.ts +31 -5
- package/src/native/overlay.d.ts +8 -3
- package/src/native/overlay.ts +17 -4
- package/src/native/reconcile.ts +16 -4
- package/src/native/settle.d.ts +4 -3
- package/src/native/settle.ts +4 -3
- 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 +48 -29
- package/src/overlays/agent-transcript-viewer.ts +93 -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 +10 -17
- package/src/overlays/btw-history-panel.ts +136 -39
- package/src/overlays/copy-selector.d.ts +1 -0
- package/src/overlays/copy-selector.ts +32 -8
- package/src/overlays/extensions/extension-dashboard.ts +4 -4
- 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/hub-frame.ts +19 -1
- package/src/overlays/jobs-panel.ts +33 -52
- package/src/overlays/model-browser.ts +367 -122
- package/src/overlays/model-hub.ts +435 -59
- package/src/overlays/move-overlay.ts +28 -14
- package/src/overlays/oauth-selector.ts +54 -70
- package/src/overlays/pause-screen.ts +2 -2
- package/src/overlays/plan-review-overlay.ts +208 -70
- package/src/overlays/plugin-settings.ts +3 -3
- package/src/overlays/report-panel.ts +191 -0
- package/src/overlays/rewind-selector.ts +88 -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 +5 -4
- 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/thinking-selector.ts +11 -10
- package/src/overlays/tree-selector.ts +41 -20
- package/src/overlays/usage-dashboard.ts +117 -58
- package/src/overlays/usage-display.ts +10 -4
- package/src/overlays/usage-row.ts +22 -8
- package/src/prompt/attachment-chips.ts +15 -11
- package/src/prompt/composer-attachments.ts +6 -4
- package/src/prompt/composer-cache.ts +7 -86
- package/src/prompt/composer.ts +37 -26
- package/src/prompt/custom-editor.ts +282 -105
- package/src/prompt/image-source.ts +2 -1
- package/src/prompt/interactive-context-helpers.ts +32 -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/queued-messages.ts +6 -4
- package/src/prompt/tips.txt +13 -9
- package/src/prompt/welcome.ts +64 -46
- 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 +16 -1
- 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/types.ts +1 -0
- package/src/space-hold.d.ts +40 -25
- package/src/space-hold.ts +156 -52
- package/src/status-line/component.ts +292 -78
- package/src/status-line/context-usage.ts +21 -46
- 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 +41 -36
- package/src/terminal-capabilities.ts +137 -213
- package/src/terminal-multiplexer.d.ts +127 -14
- package/src/terminal-multiplexer.ts +112 -33
- package/src/terminal.d.ts +23 -16
- package/src/terminal.ts +203 -99
- 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 +11 -4
- 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/thinking.d.ts +1 -1
- package/src/thinking.ts +1 -1
- 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.d.ts +7 -2
- package/src/tools/bash.ts +116 -47
- 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 +154 -50
- package/src/tools/task.d.ts +2 -3
- package/src/tools/task.ts +115 -62
- 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 +36 -0
- package/src/tui.ts +666 -217
- 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.d.ts +33 -1
- package/src/windows-input-mode.ts +212 -6
package/src/tools/task.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Usage } from "@linxiraos/pi-ai";
|
|
2
|
-
import { isRecord } from "@linxiraos/pi-utils";
|
|
2
|
+
import { isRecord, sanitizeText } from "@linxiraos/pi-utils";
|
|
3
3
|
import type { ThemeColor } from "../theme/theme";
|
|
4
4
|
import type { ConfiguredThinkingLevel } from "../render/render-utils";
|
|
5
|
-
import type { ToolRenderer } from "./renderer";
|
|
5
|
+
import type { ToolRenderer, RenderResultOptions, NativeToolView, ToolRenderResult } from "./renderer";
|
|
6
6
|
/**
|
|
7
7
|
* TUI rendering for task tool.
|
|
8
8
|
*
|
|
@@ -14,8 +14,6 @@ import { Container, type Component } from "../tui";
|
|
|
14
14
|
import { Markdown } from "../components/markdown";
|
|
15
15
|
import { Text } from "../components/text";
|
|
16
16
|
import { visibleWidth, wrapTextWithAnsi } from "../utils";
|
|
17
|
-
import { sanitizeText } from "@linxiraos/pi-utils";
|
|
18
|
-
import type { RenderResultOptions } from "./renderer";
|
|
19
17
|
import { formatAgentStatRun, renderAgentTreeRow } from "./agent-tree";
|
|
20
18
|
import { getMarkdownTheme, type Theme } from "../theme/theme";
|
|
21
19
|
import { stripGeneratedOutputNotice, stripRawOutputArtifactNotice, stripTrailingNotice } from "./output-meta";
|
|
@@ -42,19 +40,17 @@ import {
|
|
|
42
40
|
} from "../render/render-utils";
|
|
43
41
|
import { renderStatusLine } from "../render/index";
|
|
44
42
|
import { framedToolCard } from "../render/tool-card";
|
|
45
|
-
import { formatOutputInline, renderJsonTreeLines } from "./json-tree";
|
|
43
|
+
import { formatOutputInline, renderJsonTreeLines, describeJsonTree } from "./json-tree";
|
|
46
44
|
import { repairDoubleEncodedJsonString } from "./task-repair-args";
|
|
47
45
|
import { getSubprocessToolRenderer } from "./subprocess";
|
|
48
46
|
import { assembleYieldResult, type YieldSectionShapes } from "./task-yield-assembly";
|
|
49
47
|
import type { TspAgentProps, TspTone } from "@linxiraos/pi-wire";
|
|
50
48
|
import { compact, kv, md, node, span, text } from "../native/describe";
|
|
51
49
|
import type { NativeNode } from "../native/node";
|
|
52
|
-
import { OwnerMemo } from "../native/memo";
|
|
50
|
+
import { OwnerMemo, sameItems } from "../native/memo";
|
|
53
51
|
import { plainText } from "../native/spans";
|
|
54
52
|
import { errorText, noteText, resultText } from "./native-view";
|
|
55
|
-
import { describeJsonTree } from "./json-tree";
|
|
56
53
|
import { taskSummary } from "../overlays/agent-hub-renderer";
|
|
57
|
-
import type { NativeToolView, ToolRenderResult } from "./renderer";
|
|
58
54
|
|
|
59
55
|
/** Render context threaded in from `ToolExecutionComponent.#buildRenderContext`. */
|
|
60
56
|
interface TaskRenderContext {
|
|
@@ -246,6 +242,39 @@ function renderTypedYieldSections(value: unknown, continuePrefix: string, expand
|
|
|
246
242
|
return lines;
|
|
247
243
|
}
|
|
248
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
|
+
|
|
249
278
|
/** Formats sanitized task identifiers as hierarchy breadcrumbs. */
|
|
250
279
|
export function formatTaskId(id: string): string {
|
|
251
280
|
// Ids are name-based (e.g. "Anna", "Anna-2"); a "." separates nesting levels
|
|
@@ -780,27 +809,32 @@ function renderAgentProgress(
|
|
|
780
809
|
// For completed tasks, render review verdicts assembled from incremental
|
|
781
810
|
// yield sections.
|
|
782
811
|
if (progress.status === "completed") {
|
|
783
|
-
const
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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);
|
|
804
838
|
return lines; // Review result handles its own rendering
|
|
805
839
|
}
|
|
806
840
|
}
|
|
@@ -808,7 +842,11 @@ function renderAgentProgress(
|
|
|
808
842
|
for (const toolName in progress.extractedToolData) {
|
|
809
843
|
const dataArray = progress.extractedToolData[toolName];
|
|
810
844
|
if (toolName === "yield") {
|
|
811
|
-
lines.push(
|
|
845
|
+
lines.push(
|
|
846
|
+
...memoBySnapshot(yieldSectionsMemo, dataArray, [continuePrefix, expanded, theme], () =>
|
|
847
|
+
renderTypedYieldSections(dataArray, continuePrefix, expanded, theme),
|
|
848
|
+
),
|
|
849
|
+
);
|
|
812
850
|
continue;
|
|
813
851
|
}
|
|
814
852
|
|
|
@@ -866,15 +904,19 @@ function renderAgentProgress(
|
|
|
866
904
|
// Expanded view: recent output and tools
|
|
867
905
|
if (expanded && progress.status === "running") {
|
|
868
906
|
const previewRows = previewWindowRows();
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
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
|
+
);
|
|
878
920
|
}
|
|
879
921
|
|
|
880
922
|
return lines;
|
|
@@ -1377,6 +1419,25 @@ export function renderResult(
|
|
|
1377
1419
|
theme,
|
|
1378
1420
|
);
|
|
1379
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
|
+
|
|
1380
1441
|
return framedToolCard(theme, ({ width, contentWidth }) => {
|
|
1381
1442
|
const { expanded, isPartial, spinnerFrame } = options;
|
|
1382
1443
|
const frozen = options.renderContext?.frozen === true;
|
|
@@ -1418,7 +1479,11 @@ export function renderResult(
|
|
|
1418
1479
|
const ordered = orderResultsForDisplay(details.results);
|
|
1419
1480
|
const visible = expanded ? ordered : selectCollapsedResults(ordered);
|
|
1420
1481
|
for (const res of visible) {
|
|
1421
|
-
lines.push(
|
|
1482
|
+
lines.push(
|
|
1483
|
+
...memoBySnapshot(agentResultMemo, res, [expanded, theme, contentWidth, isFeedModelBadgeEnabled()], () =>
|
|
1484
|
+
renderAgentResult(res, "", " ", expanded, theme, undefined, 0, contentWidth),
|
|
1485
|
+
),
|
|
1486
|
+
);
|
|
1422
1487
|
}
|
|
1423
1488
|
if (visible.length < ordered.length) {
|
|
1424
1489
|
const hint = formatExpandHint(theme, false, true);
|
|
@@ -1431,11 +1496,14 @@ export function renderResult(
|
|
|
1431
1496
|
// (their payloads deliver through jobs) — keep their rows visible
|
|
1432
1497
|
// beside the finalized inline results, live while running and
|
|
1433
1498
|
// settled once their jobs finish.
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
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
|
+
}
|
|
1439
1507
|
for (const progress of supplementalProgress) {
|
|
1440
1508
|
lines.push(
|
|
1441
1509
|
...renderAgentProgress(
|
|
@@ -1488,22 +1556,7 @@ export function renderResult(
|
|
|
1488
1556
|
};
|
|
1489
1557
|
}
|
|
1490
1558
|
|
|
1491
|
-
|
|
1492
|
-
const summaryLines = fallbackText.split("\n");
|
|
1493
|
-
const markerIndex = summaryLines.findIndex(
|
|
1494
|
-
line =>
|
|
1495
|
-
line.includes("<system-notification>") ||
|
|
1496
|
-
line.startsWith("Applied patches:") ||
|
|
1497
|
-
line.startsWith("No changes to apply."),
|
|
1498
|
-
);
|
|
1499
|
-
if (markerIndex >= 0) {
|
|
1500
|
-
const extra = summaryLines.slice(markerIndex);
|
|
1501
|
-
for (const line of extra) {
|
|
1502
|
-
if (!line.trim()) continue;
|
|
1503
|
-
lines.push(theme.fg("dim", line));
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1559
|
+
for (const line of fallbackExtraLines) lines.push(line);
|
|
1507
1560
|
|
|
1508
1561
|
while (lines.length > 0 && lines[0].trim() === "") lines.shift();
|
|
1509
1562
|
return {
|
|
@@ -2314,7 +2367,7 @@ export interface AgentProgress {
|
|
|
2314
2367
|
resolvedModelRoute?: string;
|
|
2315
2368
|
/** True when a live advisor was attached to this run's session, not merely enabled in settings. */
|
|
2316
2369
|
advisor?: boolean;
|
|
2317
|
-
/** The agent's latest self-estimate of task completion (0–100), from the periodic `task.
|
|
2370
|
+
/** The agent's latest self-estimate of task completion (0–100), from the periodic `task.completionProbe` side request. */
|
|
2318
2371
|
completionPercent?: number;
|
|
2319
2372
|
/** Data extracted by registered subprocess tool handlers (keyed by tool name) */
|
|
2320
2373
|
extractedToolData?: Record<string, unknown[]>;
|
package/src/tools/todo.ts
CHANGED
|
@@ -65,11 +65,31 @@ export interface TodoToolDetails {
|
|
|
65
65
|
* that would collide across unrelated todos. */
|
|
66
66
|
const TODO_DESCRIPTION_MIN_OVERLAP = 6;
|
|
67
67
|
|
|
68
|
+
/** Bound on {@link normalizedTodoCache}; cleared wholesale when exceeded. */
|
|
69
|
+
const NORMALIZED_TODO_CACHE_LIMIT = 1024;
|
|
70
|
+
const normalizedTodoCache = new Map<string, string>();
|
|
71
|
+
|
|
68
72
|
function normalizeForTodoMatch(value: string): string {
|
|
69
|
-
|
|
73
|
+
let normalized = normalizedTodoCache.get(value);
|
|
74
|
+
if (normalized !== undefined) return normalized;
|
|
75
|
+
normalized = value
|
|
70
76
|
.toLowerCase()
|
|
71
77
|
.replace(/[^\p{L}\p{N}]+/gu, " ")
|
|
72
78
|
.trim();
|
|
79
|
+
if (normalizedTodoCache.size >= NORMALIZED_TODO_CACHE_LIMIT) normalizedTodoCache.clear();
|
|
80
|
+
normalizedTodoCache.set(value, normalized);
|
|
81
|
+
return normalized;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Match a pre-normalized target against pre-normalized, non-empty candidates. */
|
|
85
|
+
function matchesNormalizedCandidates(target: string, candidates: readonly string[]): boolean {
|
|
86
|
+
if (!target) return false;
|
|
87
|
+
for (const candidate of candidates) {
|
|
88
|
+
if (target === candidate) return true;
|
|
89
|
+
if (target.length >= TODO_DESCRIPTION_MIN_OVERLAP && candidate.includes(target)) return true;
|
|
90
|
+
if (candidate.length >= TODO_DESCRIPTION_MIN_OVERLAP && target.includes(candidate)) return true;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
73
93
|
}
|
|
74
94
|
|
|
75
95
|
/**
|
|
@@ -88,14 +108,12 @@ function normalizeForTodoMatch(value: string): string {
|
|
|
88
108
|
export function todoMatchesAnyDescription(content: string, descriptions: readonly string[]): boolean {
|
|
89
109
|
const target = normalizeForTodoMatch(content);
|
|
90
110
|
if (!target) return false;
|
|
111
|
+
const candidates: string[] = [];
|
|
91
112
|
for (const desc of descriptions) {
|
|
92
113
|
const candidate = normalizeForTodoMatch(desc);
|
|
93
|
-
if (
|
|
94
|
-
if (target === candidate) return true;
|
|
95
|
-
if (target.length >= TODO_DESCRIPTION_MIN_OVERLAP && candidate.includes(target)) return true;
|
|
96
|
-
if (candidate.length >= TODO_DESCRIPTION_MIN_OVERLAP && target.includes(candidate)) return true;
|
|
114
|
+
if (candidate) candidates.push(candidate);
|
|
97
115
|
}
|
|
98
|
-
return
|
|
116
|
+
return matchesNormalizedCandidates(target, candidates);
|
|
99
117
|
}
|
|
100
118
|
|
|
101
119
|
/** Whether a todo is settled: completed or deliberately abandoned. Shared so
|
|
@@ -144,13 +162,16 @@ const COLLAPSED_CLOSED_CONTEXT = 1;
|
|
|
144
162
|
* 3. When active tasks alone exceed `cap`, only the first `cap` active tasks are
|
|
145
163
|
* shown and the summary counts the hidden *active* todos, never replacing
|
|
146
164
|
* them with unrelated pending rows.
|
|
165
|
+
*
|
|
166
|
+
* The summary occupies a row, so a summary that would hide exactly one task is
|
|
167
|
+
* replaced by that task: the selection spends at most `cap + 1` rows.
|
|
147
168
|
*/
|
|
148
169
|
function selectWithinCap<T extends { status: TodoStatus }>(
|
|
149
170
|
base: T[],
|
|
150
171
|
isMatched: (task: T) => boolean,
|
|
151
172
|
cap: number,
|
|
152
173
|
): CollapsedTodoSelection<T> {
|
|
153
|
-
if (base.length <= cap) return { items: base, summary: "" };
|
|
174
|
+
if (base.length <= cap + 1) return { items: base, summary: "" };
|
|
154
175
|
|
|
155
176
|
const active = base.filter(task => isActiveTodo(task, isMatched));
|
|
156
177
|
// Only when active work strictly exceeds the cap do we drop pending rows and
|
|
@@ -311,24 +332,37 @@ function strikethroughText(text: string): string {
|
|
|
311
332
|
return `${STRIKE_START}${text}${STRIKE_END}`;
|
|
312
333
|
}
|
|
313
334
|
|
|
314
|
-
|
|
335
|
+
/** Display label for a todo row, with its code points split once for the strike animation. */
|
|
336
|
+
interface TodoLabel {
|
|
337
|
+
text: string;
|
|
338
|
+
chars?: string[];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function labelChars(label: TodoLabel): string[] {
|
|
342
|
+
label.chars ??= [...label.text];
|
|
343
|
+
return label.chars;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function partialStrikethrough(label: TodoLabel, visibleChars: number): string {
|
|
347
|
+
const text = label.text;
|
|
315
348
|
if (visibleChars <= 0) return text;
|
|
316
|
-
const chars =
|
|
349
|
+
const chars = labelChars(label);
|
|
317
350
|
if (visibleChars >= chars.length) return strikethroughText(text);
|
|
318
351
|
return `${strikethroughText(chars.slice(0, visibleChars).join(""))}${chars.slice(visibleChars).join("")}`;
|
|
319
352
|
}
|
|
320
353
|
|
|
321
|
-
function strikeRevealCount(
|
|
354
|
+
function strikeRevealCount(label: TodoLabel, frame: number | undefined): number | undefined {
|
|
322
355
|
if (frame === undefined) return undefined;
|
|
323
356
|
if (frame <= TODO_STRIKE_HOLD_FRAMES) return 0;
|
|
324
|
-
const
|
|
325
|
-
if (
|
|
357
|
+
const count = labelChars(label).length;
|
|
358
|
+
if (count === 0) return undefined;
|
|
326
359
|
const revealFrame = Math.min(frame - TODO_STRIKE_HOLD_FRAMES, TODO_STRIKE_REVEAL_FRAMES);
|
|
327
|
-
return Math.ceil((
|
|
360
|
+
return Math.ceil((count * revealFrame) / TODO_STRIKE_REVEAL_FRAMES);
|
|
328
361
|
}
|
|
329
362
|
|
|
330
363
|
function formatTodoLine(
|
|
331
364
|
item: TodoItem,
|
|
365
|
+
label: TodoLabel,
|
|
332
366
|
uiTheme: Theme,
|
|
333
367
|
prefix: string,
|
|
334
368
|
completionKeys: Set<string>,
|
|
@@ -336,31 +370,27 @@ function formatTodoLine(
|
|
|
336
370
|
matched = false,
|
|
337
371
|
): string {
|
|
338
372
|
const checkbox = uiTheme.checkbox;
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
|
|
342
|
-
// everywhere else: it is the identity key the local list is looked up by
|
|
343
|
-
// (`findTaskByContent`) and what gets persisted.
|
|
344
|
-
const label = forDisplay(item.content);
|
|
373
|
+
// `label` is the display-sanitized content (see `forDisplay`); `item.content`
|
|
374
|
+
// stays raw everywhere else as the identity key and persisted value.
|
|
375
|
+
const text = label.text;
|
|
345
376
|
switch (item.status) {
|
|
346
377
|
case "completed": {
|
|
347
378
|
const revealCount = completionKeys.has(item.content) ? strikeRevealCount(label, frame) : undefined;
|
|
348
|
-
const content =
|
|
349
|
-
revealCount === undefined ? strikethroughText(label) : partialStrikethrough(label, revealCount);
|
|
379
|
+
const content = revealCount === undefined ? strikethroughText(text) : partialStrikethrough(label, revealCount);
|
|
350
380
|
return uiTheme.fg("success", `${prefix}${checkbox.checked} ${content}`);
|
|
351
381
|
}
|
|
352
382
|
case "in_progress":
|
|
353
|
-
return uiTheme.fg("accent", `${prefix}${checkbox.unchecked} ${
|
|
383
|
+
return uiTheme.fg("accent", `${prefix}${checkbox.unchecked} ${text}`);
|
|
354
384
|
case "abandoned":
|
|
355
|
-
return uiTheme.fg("error", `${prefix}${checkbox.unchecked} ${strikethroughText(
|
|
385
|
+
return uiTheme.fg("error", `${prefix}${checkbox.unchecked} ${strikethroughText(text)}`);
|
|
356
386
|
case "blocked": {
|
|
357
387
|
const note = item.blocker ? `blocked: ${forDisplay(item.blocker)}` : "blocked";
|
|
358
|
-
return uiTheme.fg("warning", `${prefix}${checkbox.unchecked} ${
|
|
388
|
+
return uiTheme.fg("warning", `${prefix}${checkbox.unchecked} ${text} (${note})`);
|
|
359
389
|
}
|
|
360
390
|
default:
|
|
361
391
|
// A pending todo lit by a live subagent match renders accent, matching
|
|
362
392
|
// the sticky HUD's convention (#5873).
|
|
363
|
-
return uiTheme.fg(matched ? "accent" : "dim", `${prefix}${checkbox.unchecked} ${
|
|
393
|
+
return uiTheme.fg(matched ? "accent" : "dim", `${prefix}${checkbox.unchecked} ${text}`);
|
|
364
394
|
}
|
|
365
395
|
}
|
|
366
396
|
|
|
@@ -499,6 +529,7 @@ function describeTodoResult(
|
|
|
499
529
|
tool: { title: "Todo", target: `${closed}/${total}`, targetKind: "text" },
|
|
500
530
|
body: [node("checklist", { mode: "full", phases: todoChecklistPhases(phases, isMatched) }, [], "checklist")],
|
|
501
531
|
preview: "none",
|
|
532
|
+
open: true,
|
|
502
533
|
};
|
|
503
534
|
}
|
|
504
535
|
|
|
@@ -592,6 +623,40 @@ export const todoToolRenderer = {
|
|
|
592
623
|
return new Text(`${header}\n ${uiTheme.fg("dim", fallback)}`, 0, 0);
|
|
593
624
|
}
|
|
594
625
|
|
|
626
|
+
// Everything below is fixed for this result; only the spinner frame and
|
|
627
|
+
// the live subagent description set vary per frame, so derive labels,
|
|
628
|
+
// touched phases and normalized match state once and reuse them.
|
|
629
|
+
const labels = new Map<TodoItem, TodoLabel>();
|
|
630
|
+
const labelFor = (task: TodoItem): TodoLabel => {
|
|
631
|
+
let label = labels.get(task);
|
|
632
|
+
if (!label) {
|
|
633
|
+
// Sanitize only for display: a mirrored Cursor snapshot carries
|
|
634
|
+
// provider text verbatim (ANSI/C0 would rewrite the terminal).
|
|
635
|
+
label = { text: forDisplay(task.content) };
|
|
636
|
+
labels.set(task, label);
|
|
637
|
+
}
|
|
638
|
+
return label;
|
|
639
|
+
};
|
|
640
|
+
let touchedComputed = false;
|
|
641
|
+
let touchedPhases: Set<string> | null = null;
|
|
642
|
+
let lastDescs: readonly string[] | undefined;
|
|
643
|
+
let candidates: string[] = [];
|
|
644
|
+
const matchByContent = new Map<string, boolean>();
|
|
645
|
+
const syncActiveDescs = (descs: readonly string[]): void => {
|
|
646
|
+
if (lastDescs === descs) return;
|
|
647
|
+
if (lastDescs && lastDescs.length === descs.length && lastDescs.every((d, i) => d === descs[i])) {
|
|
648
|
+
lastDescs = descs;
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
lastDescs = descs;
|
|
652
|
+
candidates = [];
|
|
653
|
+
for (const desc of descs) {
|
|
654
|
+
const candidate = normalizeForTodoMatch(desc);
|
|
655
|
+
if (candidate) candidates.push(candidate);
|
|
656
|
+
}
|
|
657
|
+
matchByContent.clear();
|
|
658
|
+
};
|
|
659
|
+
|
|
595
660
|
return framedToolCard(uiTheme, () => {
|
|
596
661
|
const { expanded, spinnerFrame } = options;
|
|
597
662
|
const multiPhase = phases.length > 1;
|
|
@@ -599,13 +664,28 @@ export const todoToolRenderer = {
|
|
|
599
664
|
// Collapse phases this update didn't touch down to a one-line summary so
|
|
600
665
|
// a single task flip doesn't redraw every phase's full task list. The
|
|
601
666
|
// manual expand toggle (and the no-signal fallback) still shows all.
|
|
602
|
-
|
|
667
|
+
let touched: Set<string> | null = null;
|
|
668
|
+
if (!expanded && multiPhase) {
|
|
669
|
+
if (!touchedComputed) {
|
|
670
|
+
touchedPhases = computeTouchedPhases(args, phases, completedTasks);
|
|
671
|
+
touchedComputed = true;
|
|
672
|
+
}
|
|
673
|
+
touched = touchedPhases;
|
|
674
|
+
}
|
|
603
675
|
// A pending todo counts as active work when an in-flight subagent is
|
|
604
676
|
// executing it — the transient result surfaces the same active set the
|
|
605
677
|
// sticky HUD does (#5873). Empty outside an interactive session.
|
|
606
678
|
const activeDescs = expanded ? [] : activeTodoDescriptionsProvider();
|
|
607
|
-
|
|
608
|
-
|
|
679
|
+
if (activeDescs.length > 0) syncActiveDescs(activeDescs);
|
|
680
|
+
const isMatched = (task: TodoItem): boolean => {
|
|
681
|
+
if (activeDescs.length === 0) return false;
|
|
682
|
+
let matched = matchByContent.get(task.content);
|
|
683
|
+
if (matched === undefined) {
|
|
684
|
+
matched = matchesNormalizedCandidates(normalizeForTodoMatch(task.content), candidates);
|
|
685
|
+
matchByContent.set(task.content, matched);
|
|
686
|
+
}
|
|
687
|
+
return matched;
|
|
688
|
+
};
|
|
609
689
|
const bodyLines: string[] = [];
|
|
610
690
|
for (let p = 0; p < phases.length; p++) {
|
|
611
691
|
const phase = phases[p];
|
|
@@ -631,7 +711,8 @@ export const todoToolRenderer = {
|
|
|
631
711
|
items: phase.tasks,
|
|
632
712
|
expanded,
|
|
633
713
|
itemType: "todo",
|
|
634
|
-
renderItem: todo =>
|
|
714
|
+
renderItem: todo =>
|
|
715
|
+
formatTodoLine(todo, labelFor(todo), uiTheme, "", completionKeys, spinnerFrame),
|
|
635
716
|
},
|
|
636
717
|
uiTheme,
|
|
637
718
|
)
|
|
@@ -643,7 +724,15 @@ export const todoToolRenderer = {
|
|
|
643
724
|
itemType: "todo",
|
|
644
725
|
trailingSummary: selection.summary,
|
|
645
726
|
renderItem: todo =>
|
|
646
|
-
formatTodoLine(
|
|
727
|
+
formatTodoLine(
|
|
728
|
+
todo,
|
|
729
|
+
labelFor(todo),
|
|
730
|
+
uiTheme,
|
|
731
|
+
"",
|
|
732
|
+
completionKeys,
|
|
733
|
+
spinnerFrame,
|
|
734
|
+
isMatched(todo),
|
|
735
|
+
),
|
|
647
736
|
},
|
|
648
737
|
uiTheme,
|
|
649
738
|
);
|
package/src/tools/wait.ts
CHANGED
|
@@ -275,6 +275,39 @@ function jobsRenderResult(
|
|
|
275
275
|
});
|
|
276
276
|
|
|
277
277
|
let cached: RenderCache | undefined;
|
|
278
|
+
// Per-job preview rows are invariant across spinner/shimmer frames (the job
|
|
279
|
+
// snapshots are frozen for this result), so the envelope strip, flatten and
|
|
280
|
+
// wrap run once per (job, expanded, width) instead of every animated frame.
|
|
281
|
+
const previewRows = new Map<JobSnapshot, { expanded: boolean; width: number; lines: readonly string[] }>();
|
|
282
|
+
const jobPreviewRows = (job: JobSnapshot, expanded: boolean, continuationWidth: number): readonly string[] => {
|
|
283
|
+
const hit = previewRows.get(job);
|
|
284
|
+
if (hit !== undefined && hit.expanded === expanded && hit.width === continuationWidth) return hit.lines;
|
|
285
|
+
const artifactError = job.meta?.artifactError ?? job.artifactError;
|
|
286
|
+
// Legacy rows did not retain full metadata. Strip the known warning
|
|
287
|
+
// footer so the dedicated row/root warning remains the only copy.
|
|
288
|
+
const previewError =
|
|
289
|
+
artifactError ?? (outputMeta?.source?.type !== "report" ? outputMeta?.artifactError : undefined);
|
|
290
|
+
const previewMeta = job.meta ?? (previewError ? { artifactError: previewError } : undefined);
|
|
291
|
+
const preview = flattenStructuredPreview(
|
|
292
|
+
stripTaskResultEnvelope(
|
|
293
|
+
stripOutputNotice(job.errorText?.trim() || job.resultText?.trim() || "", previewMeta).trim(),
|
|
294
|
+
),
|
|
295
|
+
);
|
|
296
|
+
const lines: string[] = [];
|
|
297
|
+
if (preview) {
|
|
298
|
+
const maxLines = expanded ? PREVIEW_LINES_EXPANDED : PREVIEW_LINES_COLLAPSED;
|
|
299
|
+
const previewLines = getPreviewLines(
|
|
300
|
+
preview,
|
|
301
|
+
maxLines,
|
|
302
|
+
Math.min(PREVIEW_LINE_WIDTH, continuationWidth),
|
|
303
|
+
Ellipsis.Unicode,
|
|
304
|
+
);
|
|
305
|
+
const tone = job.errorText ? "error" : "dim";
|
|
306
|
+
for (const pl of previewLines) lines.push(` ${uiTheme.fg(tone, pl)}`);
|
|
307
|
+
}
|
|
308
|
+
previewRows.set(job, { expanded, width: continuationWidth, lines });
|
|
309
|
+
return lines;
|
|
310
|
+
};
|
|
278
311
|
return {
|
|
279
312
|
render(width: number): readonly string[] {
|
|
280
313
|
const expanded = options.expanded;
|
|
@@ -377,30 +410,7 @@ function jobsRenderResult(
|
|
|
377
410
|
);
|
|
378
411
|
}
|
|
379
412
|
|
|
380
|
-
|
|
381
|
-
// footer so the dedicated row/root warning remains the only copy.
|
|
382
|
-
const previewError =
|
|
383
|
-
artifactError ?? (outputMeta?.source?.type !== "report" ? outputMeta?.artifactError : undefined);
|
|
384
|
-
const previewMeta = job.meta ?? (previewError ? { artifactError: previewError } : undefined);
|
|
385
|
-
|
|
386
|
-
const preview = flattenStructuredPreview(
|
|
387
|
-
stripTaskResultEnvelope(
|
|
388
|
-
stripOutputNotice(job.errorText?.trim() || job.resultText?.trim() || "", previewMeta).trim(),
|
|
389
|
-
),
|
|
390
|
-
);
|
|
391
|
-
if (preview) {
|
|
392
|
-
const maxLines = expanded ? PREVIEW_LINES_EXPANDED : PREVIEW_LINES_COLLAPSED;
|
|
393
|
-
const previewLines = getPreviewLines(
|
|
394
|
-
preview,
|
|
395
|
-
maxLines,
|
|
396
|
-
Math.min(PREVIEW_LINE_WIDTH, continuationWidth),
|
|
397
|
-
Ellipsis.Unicode,
|
|
398
|
-
);
|
|
399
|
-
const tone = job.errorText ? "error" : "dim";
|
|
400
|
-
for (const pl of previewLines) {
|
|
401
|
-
lines.push(` ${uiTheme.fg(tone, pl)}`);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
413
|
+
for (const previewLine of jobPreviewRows(job, expanded, continuationWidth)) lines.push(previewLine);
|
|
404
414
|
return lines;
|
|
405
415
|
},
|
|
406
416
|
},
|
package/src/tools/web-search.ts
CHANGED
|
@@ -171,7 +171,7 @@ export function renderSearchResult(
|
|
|
171
171
|
if (renderedAnswer.length === 0) {
|
|
172
172
|
answerLines = [theme.fg("muted", tuiText("wsNoAnswerText", "No answer text returned"))];
|
|
173
173
|
} else if (args?.maxAnswerLines !== undefined && !expanded) {
|
|
174
|
-
// CLI compact mode (`
|
|
174
|
+
// CLI compact mode (`zetacode q`) caps the answer; the TUI passes no cap and shows it in full.
|
|
175
175
|
// `renderedAnswer` is the Markdown component's shared cache — slice copies before appending.
|
|
176
176
|
const capped = renderedAnswer.slice(0, args.maxAnswerLines);
|
|
177
177
|
const remaining = renderedAnswer.length - capped.length;
|
package/src/tools/write.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type ProcWriteDetails } from "./proc-render";
|
|
|
6
6
|
import { type CfgWriteDetails } from "./cfg-render";
|
|
7
7
|
import type { FileDiagnosticsResult } from "./lsp";
|
|
8
8
|
import type { OutputMeta } from "./output-meta";
|
|
9
|
-
import type { NativeToolView, RenderResultOptions, ToolActivityContext, ToolActivitySummary } from "./renderer";
|
|
9
|
+
import type { NativeToolView, RenderResultOptions, ToolActivityContext, ToolActivitySummary, ToolFigure } from "./renderer";
|
|
10
10
|
import { type XdevRenderDispatch, type XdevMountedRenderer } from "./xdev";
|
|
11
11
|
/** Details returned by the write tool for transcript rendering. */
|
|
12
12
|
export interface WriteToolDetails {
|
|
@@ -37,6 +37,12 @@ interface WriteResult {
|
|
|
37
37
|
details?: WriteToolDetails;
|
|
38
38
|
isError?: boolean;
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* The fence a file write draws as while its content streams and after: its
|
|
42
|
+
* extension names a figure language and it has content, closed once the args
|
|
43
|
+
* are final. None for URL-card writes, or after an error.
|
|
44
|
+
*/
|
|
45
|
+
declare function writeFigure(args: WriteRenderArgs | undefined, result: WriteResult | undefined, options: RenderResultOptions): ToolFigure | undefined;
|
|
40
46
|
declare const writeStreamingPreviewStateKey: unique symbol;
|
|
41
47
|
/**
|
|
42
48
|
* Per-component state for incrementally rendering a streamed write.
|
|
@@ -75,7 +81,7 @@ export declare const writeToolRenderer: {
|
|
|
75
81
|
renderCall(args: WriteRenderArgs, options: RenderResultOptions & WriteStreamingPreviewStateCarrier & {
|
|
76
82
|
renderContext?: WriteRenderContext;
|
|
77
83
|
}, uiTheme: Theme): Component | undefined;
|
|
78
|
-
renderResult(result: WriteResult, options: RenderResultOptions & {
|
|
84
|
+
renderResult(result: WriteResult, options: RenderResultOptions & WriteStreamingPreviewStateCarrier & {
|
|
79
85
|
renderContext?: WriteRenderContext;
|
|
80
86
|
}, uiTheme: Theme, args?: WriteRenderArgs): Component;
|
|
81
87
|
describeCall(args: WriteRenderArgs, options: RenderResultOptions & {
|
|
@@ -84,6 +90,7 @@ export declare const writeToolRenderer: {
|
|
|
84
90
|
describeResult(result: WriteResult, options: RenderResultOptions & {
|
|
85
91
|
renderContext?: WriteRenderContext;
|
|
86
92
|
}, args?: WriteRenderArgs): NativeToolView | undefined;
|
|
93
|
+
figure: typeof writeFigure;
|
|
87
94
|
mergeCallAndResult: true;
|
|
88
95
|
forceFirstResultViewportRepaint: (args: unknown, options: RenderResultOptions) => boolean;
|
|
89
96
|
};
|