@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
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Tokens } from "@linxiraos/pi-utils/marked";
|
|
2
|
+
import { type ChartPlan } from "../charts/chart-plan";
|
|
3
|
+
import { type TableAnalysis } from "../charts/table-data";
|
|
4
|
+
import type { ImageBudget } from "../components/image";
|
|
5
|
+
import type { NativeNode } from "../native/node";
|
|
6
|
+
import type { Component } from "../tui";
|
|
7
|
+
/**
|
|
8
|
+
* `smart`: a model refines the local guess where meaning decides (kind,
|
|
9
|
+
* columns, row names, ordering, polarity, focus, title; see {@link shouldJudge});
|
|
10
|
+
* `always`: the local best guess charts every table it reads as numeric;
|
|
11
|
+
* `off`: tables stay tables.
|
|
12
|
+
*/
|
|
13
|
+
export type TableChartMode = "smart" | "always" | "off";
|
|
14
|
+
/** A table the host's planner picks a chart for ({@link shouldJudge}). */
|
|
15
|
+
export interface TableChartRequest {
|
|
16
|
+
/** The table's Markdown source. */
|
|
17
|
+
readonly markdown: string;
|
|
18
|
+
readonly table: TableAnalysis;
|
|
19
|
+
/** The local best guess; the planner may keep it. */
|
|
20
|
+
readonly guess: ChartPlan;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Picks the chart for a multi-series table under `smart`: a plan, or `null`
|
|
24
|
+
* for no chart. A rejection falls back to the local guess.
|
|
25
|
+
*/
|
|
26
|
+
export type TableChartPlanner = (request: TableChartRequest) => Promise<ChartPlan | null>;
|
|
27
|
+
/** A drawn chart, ready to resolve against the theme. */
|
|
28
|
+
export interface TableChart {
|
|
29
|
+
/** SVG colored with figure tokens (`var(--accent)`, …). */
|
|
30
|
+
readonly svg: string;
|
|
31
|
+
readonly alt: string;
|
|
32
|
+
/** Size in SVG user units. */
|
|
33
|
+
readonly width: number;
|
|
34
|
+
readonly height: number;
|
|
35
|
+
}
|
|
36
|
+
/** The chart under a table: drawn, none, or a smart pick on its way (the promise settles once the cache holds it). */
|
|
37
|
+
export type ChartLookup = TableChart | null | Promise<void>;
|
|
38
|
+
/** One run of a Markdown block: prose (ending at a charted table), or the chart drawn after that table. */
|
|
39
|
+
export type ChartSegment = {
|
|
40
|
+
readonly kind: "markdown";
|
|
41
|
+
readonly text: string;
|
|
42
|
+
} | {
|
|
43
|
+
readonly kind: "chart";
|
|
44
|
+
readonly table: Tokens.Table;
|
|
45
|
+
};
|
|
46
|
+
/** Set how tables become charts (the host's `tui.autoGraph`) and its `smart` planner; the host rebuilds the transcript after. */
|
|
47
|
+
export declare function setTableCharts(mode: TableChartMode, planner?: TableChartPlanner): void;
|
|
48
|
+
/** How assistant tables currently become charts. */
|
|
49
|
+
export declare function tableChartMode(): TableChartMode;
|
|
50
|
+
/** Whether `markdown` may hold a table {@link splitTableCharts} would chart. */
|
|
51
|
+
export declare function hasChartTable(markdown: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Split `markdown` after each top-level table that has (or may get) a chart.
|
|
54
|
+
* A table still streaming at the block's tail is left whole: rows may follow.
|
|
55
|
+
*/
|
|
56
|
+
export declare function splitTableCharts(markdown: string, streaming: boolean): ChartSegment[];
|
|
57
|
+
/**
|
|
58
|
+
* The chart for `table` under the current mode, read once per table source.
|
|
59
|
+
* Under `smart` the first lookup of a multi-series table asks the planner.
|
|
60
|
+
*/
|
|
61
|
+
export declare function lookupTableChart(table: Tokens.Table): ChartLookup;
|
|
62
|
+
/**
|
|
63
|
+
* A native `image` node drawing `chart` from its SVG — no raster — resolved
|
|
64
|
+
* against the active theme; rebuilt when the theme changes.
|
|
65
|
+
*/
|
|
66
|
+
export declare function describeTableChart(chart: TableChart, key: string): NativeNode;
|
|
67
|
+
export interface TableChartFigureOptions {
|
|
68
|
+
/** Shared inline-image budget. */
|
|
69
|
+
budget?: ImageBudget;
|
|
70
|
+
/** The chart's rows changed outside a text update: its pick or raster landed. */
|
|
71
|
+
onChange: () => void;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The chart under one table, as a terminal image a blank row below it. Looks
|
|
75
|
+
* the chart up on first render — a block rebuilt mid-stream never asks for a
|
|
76
|
+
* pick it drops — and renders nothing until it is drawn, or when the table
|
|
77
|
+
* gets no chart.
|
|
78
|
+
*/
|
|
79
|
+
export declare class TableChartFigure implements Component {
|
|
80
|
+
#private;
|
|
81
|
+
constructor(options: TableChartFigureOptions);
|
|
82
|
+
/** Point the figure at `table`. */
|
|
83
|
+
update(table: Tokens.Table): void;
|
|
84
|
+
/** Whether the chart is still being looked up, picked or drawn. */
|
|
85
|
+
get pending(): boolean;
|
|
86
|
+
render(width: number): readonly string[];
|
|
87
|
+
invalidate(): void;
|
|
88
|
+
dispose(): void;
|
|
89
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Charts drawn under numeric tables in assistant answers (the host's
|
|
3
|
+
* `tui.autoGraph`). {@link splitTableCharts} cuts a Markdown block after each
|
|
4
|
+
* top-level table that gets a chart; {@link lookupTableChart} plans, builds
|
|
5
|
+
* and draws that chart — locally under `always`, through the host's
|
|
6
|
+
* model-backed {@link TableChartPlanner} under `smart` for the tables
|
|
7
|
+
* {@link shouldJudge} picks — and caches it per table source. {@link TableChartFigure} shows it
|
|
8
|
+
* as a rasterized terminal image; {@link describeTableChart} hands a TSP
|
|
9
|
+
* terminal the SVG itself. Both resolve the figure tokens against the live
|
|
10
|
+
* theme, so a chart follows theme switches like the prose around it.
|
|
11
|
+
*/
|
|
12
|
+
import { logger } from "@linxiraos/pi-utils";
|
|
13
|
+
import type { Token, Tokens } from "@linxiraos/pi-utils/marked";
|
|
14
|
+
import { type ChartPlan, buildChart, planChart, shouldJudge, worthCharting } from "../charts/chart-plan";
|
|
15
|
+
import { chartAlt, renderChartSvg } from "../charts/chart-svg";
|
|
16
|
+
import { analyzeTable, type TableAnalysis } from "../charts/table-data";
|
|
17
|
+
import type { ImageBudget } from "../components/image";
|
|
18
|
+
import { lexDocument } from "../components/markdown";
|
|
19
|
+
import { keyed } from "../native/describe";
|
|
20
|
+
import { nativeImageNode } from "../native/blobs";
|
|
21
|
+
import type { NativeNode } from "../native/node";
|
|
22
|
+
import { getThemeEpoch } from "../theme";
|
|
23
|
+
import type { Component } from "../tui";
|
|
24
|
+
import { SvgFigure, svgFigurePalette } from "./svg-figure";
|
|
25
|
+
import { prepareSvg } from "./svg-source";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* `smart`: a model refines the local guess where meaning decides (kind,
|
|
29
|
+
* columns, row names, ordering, polarity, focus, title; see {@link shouldJudge});
|
|
30
|
+
* `always`: the local best guess charts every table it reads as numeric;
|
|
31
|
+
* `off`: tables stay tables.
|
|
32
|
+
*/
|
|
33
|
+
export type TableChartMode = "smart" | "always" | "off";
|
|
34
|
+
|
|
35
|
+
/** A table the host's planner picks a chart for ({@link shouldJudge}). */
|
|
36
|
+
export interface TableChartRequest {
|
|
37
|
+
/** The table's Markdown source. */
|
|
38
|
+
readonly markdown: string;
|
|
39
|
+
readonly table: TableAnalysis;
|
|
40
|
+
/** The local best guess; the planner may keep it. */
|
|
41
|
+
readonly guess: ChartPlan;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Picks the chart for a multi-series table under `smart`: a plan, or `null`
|
|
46
|
+
* for no chart. A rejection falls back to the local guess.
|
|
47
|
+
*/
|
|
48
|
+
export type TableChartPlanner = (request: TableChartRequest) => Promise<ChartPlan | null>;
|
|
49
|
+
|
|
50
|
+
/** A drawn chart, ready to resolve against the theme. */
|
|
51
|
+
export interface TableChart {
|
|
52
|
+
/** SVG colored with figure tokens (`var(--accent)`, …). */
|
|
53
|
+
readonly svg: string;
|
|
54
|
+
readonly alt: string;
|
|
55
|
+
/** Size in SVG user units. */
|
|
56
|
+
readonly width: number;
|
|
57
|
+
readonly height: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The chart under a table: drawn, none, or a smart pick on its way (the promise settles once the cache holds it). */
|
|
61
|
+
export type ChartLookup = TableChart | null | Promise<void>;
|
|
62
|
+
|
|
63
|
+
/** One run of a Markdown block: prose (ending at a charted table), or the chart drawn after that table. */
|
|
64
|
+
export type ChartSegment =
|
|
65
|
+
| { readonly kind: "markdown"; readonly text: string }
|
|
66
|
+
| { readonly kind: "chart"; readonly table: Tokens.Table };
|
|
67
|
+
|
|
68
|
+
/** Tables cached per source; a long session keeps its recent charts without growing without bound. */
|
|
69
|
+
const CACHE_LIMIT = 256;
|
|
70
|
+
/** SVG user units per terminal column (16 per row on 1:2 cells), sizing native images. */
|
|
71
|
+
const UNITS_PER_COLUMN = 8;
|
|
72
|
+
/** A GFM delimiter row (`|---|:--:|`), the cheap test before lexing a block. */
|
|
73
|
+
const DELIMITER_ROW = /^ {0,3}\|?[ \t]*:?-+:?[ \t]*\|/m;
|
|
74
|
+
|
|
75
|
+
/** A table read once per source: its local guess and, once known, its chart. */
|
|
76
|
+
interface ChartEntry {
|
|
77
|
+
readonly analysis: TableAnalysis;
|
|
78
|
+
readonly guess: ChartPlan | undefined;
|
|
79
|
+
/** The host's planner picks this table's chart. */
|
|
80
|
+
readonly smart: boolean;
|
|
81
|
+
/** `undefined` until drawn (or judged chartless). */
|
|
82
|
+
chart?: TableChart | null;
|
|
83
|
+
pending?: Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let chartMode: TableChartMode = "off";
|
|
87
|
+
let chartPlanner: TableChartPlanner | undefined;
|
|
88
|
+
const charts = new Map<string, ChartEntry>();
|
|
89
|
+
/** The theme-resolved image node owning a chart's native bytes. */
|
|
90
|
+
const kNativeImage = Symbol("tableChart.nativeImage");
|
|
91
|
+
|
|
92
|
+
interface NativeTagged extends TableChart {
|
|
93
|
+
[kNativeImage]?: { epoch: number; image: NativeNode };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Set how tables become charts (the host's `tui.autoGraph`) and its `smart` planner; the host rebuilds the transcript after. */
|
|
97
|
+
export function setTableCharts(mode: TableChartMode, planner?: TableChartPlanner): void {
|
|
98
|
+
chartMode = mode;
|
|
99
|
+
chartPlanner = planner;
|
|
100
|
+
charts.clear();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** How assistant tables currently become charts. */
|
|
104
|
+
export function tableChartMode(): TableChartMode {
|
|
105
|
+
return chartMode;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Whether `markdown` may hold a table {@link splitTableCharts} would chart. */
|
|
109
|
+
export function hasChartTable(markdown: string): boolean {
|
|
110
|
+
return chartMode !== "off" && markdown.includes("|") && DELIMITER_ROW.test(markdown);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Split `markdown` after each top-level table that has (or may get) a chart.
|
|
115
|
+
* A table still streaming at the block's tail is left whole: rows may follow.
|
|
116
|
+
*/
|
|
117
|
+
export function splitTableCharts(markdown: string, streaming: boolean): ChartSegment[] {
|
|
118
|
+
if (chartMode === "off") return [{ kind: "markdown", text: markdown }];
|
|
119
|
+
const tokens = lexDocument(markdown);
|
|
120
|
+
const segments: ChartSegment[] = [];
|
|
121
|
+
let prose = "";
|
|
122
|
+
tokens.forEach((token, index) => {
|
|
123
|
+
prose += token.raw;
|
|
124
|
+
if (!isTable(token)) return;
|
|
125
|
+
const closed = !streaming || tokens.slice(index + 1).some(next => next.type !== "space");
|
|
126
|
+
const entry = closed ? chartEntry(token) : undefined;
|
|
127
|
+
if (!entry?.guess || entry.chart === null) return;
|
|
128
|
+
segments.push({ kind: "markdown", text: prose }, { kind: "chart", table: token });
|
|
129
|
+
prose = "";
|
|
130
|
+
});
|
|
131
|
+
if (prose.trim() || segments.length === 0) segments.push({ kind: "markdown", text: prose });
|
|
132
|
+
return segments;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function isTable(token: Token): token is Tokens.Table {
|
|
136
|
+
return token.type === "table";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The chart for `table` under the current mode, read once per table source.
|
|
141
|
+
* Under `smart` the first lookup of a multi-series table asks the planner.
|
|
142
|
+
*/
|
|
143
|
+
export function lookupTableChart(table: Tokens.Table): ChartLookup {
|
|
144
|
+
if (chartMode === "off") return null;
|
|
145
|
+
const entry = chartEntry(table);
|
|
146
|
+
if (entry.chart !== undefined) return entry.chart;
|
|
147
|
+
if (entry.pending) return entry.pending;
|
|
148
|
+
const { analysis, guess } = entry;
|
|
149
|
+
entry.pending = chartPlanner!({ markdown: table.raw, table: analysis, guess: guess! }).then(
|
|
150
|
+
plan => {
|
|
151
|
+
entry.chart = plan ? drawChart(analysis, plan) : null;
|
|
152
|
+
},
|
|
153
|
+
(error: unknown) => {
|
|
154
|
+
logger.debug("Smart table chart failed; drawing the local guess", { error: String(error) });
|
|
155
|
+
entry.chart = drawChart(analysis, guess!, true);
|
|
156
|
+
},
|
|
157
|
+
);
|
|
158
|
+
return entry.pending;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* `table` read under the current mode, cached per source. A table the local
|
|
163
|
+
* guess decides is drawn at once; a smart pick waits for its first lookup.
|
|
164
|
+
*/
|
|
165
|
+
function chartEntry(table: Tokens.Table): ChartEntry {
|
|
166
|
+
const key = table.raw;
|
|
167
|
+
const cached = charts.get(key);
|
|
168
|
+
if (cached) {
|
|
169
|
+
// Re-insert so eviction drops the least recently read table.
|
|
170
|
+
charts.delete(key);
|
|
171
|
+
charts.set(key, cached);
|
|
172
|
+
return cached;
|
|
173
|
+
}
|
|
174
|
+
if (charts.size >= CACHE_LIMIT) charts.delete(charts.keys().next().value!);
|
|
175
|
+
const analysis = analyzeTable(
|
|
176
|
+
table.header.map(cell => cell.text),
|
|
177
|
+
table.rows.map(row => row.map(cell => cell.text)),
|
|
178
|
+
);
|
|
179
|
+
const guess = planChart(analysis);
|
|
180
|
+
const smart = chartMode === "smart" && chartPlanner !== undefined && shouldJudge(analysis, guess);
|
|
181
|
+
const entry: ChartEntry = { analysis, guess, smart };
|
|
182
|
+
if (!smart) entry.chart = guess ? drawChart(analysis, guess, true) : null;
|
|
183
|
+
charts.set(key, entry);
|
|
184
|
+
return entry;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Draw `plan`. A guess must also pass {@link worthCharting}; a model's pick
|
|
189
|
+
* already judged the chart worth drawing.
|
|
190
|
+
*/
|
|
191
|
+
function drawChart(analysis: TableAnalysis, plan: ChartPlan, guessed = false): TableChart | null {
|
|
192
|
+
const spec = buildChart(analysis, plan);
|
|
193
|
+
if (!spec || (guessed && !worthCharting(spec))) return null;
|
|
194
|
+
return { ...renderChartSvg(spec), alt: chartAlt(spec) };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* A native `image` node drawing `chart` from its SVG — no raster — resolved
|
|
199
|
+
* against the active theme; rebuilt when the theme changes.
|
|
200
|
+
*/
|
|
201
|
+
export function describeTableChart(chart: TableChart, key: string): NativeNode {
|
|
202
|
+
const epoch = getThemeEpoch();
|
|
203
|
+
const tagged: NativeTagged = chart;
|
|
204
|
+
let entry = tagged[kNativeImage];
|
|
205
|
+
if (entry?.epoch !== epoch) {
|
|
206
|
+
const svg = prepareSvg(chart.svg, svgFigurePalette());
|
|
207
|
+
entry = {
|
|
208
|
+
epoch,
|
|
209
|
+
image: nativeImageNode(new TextEncoder().encode(svg), "image/svg+xml", {
|
|
210
|
+
alt: chart.alt,
|
|
211
|
+
w: chart.width,
|
|
212
|
+
h: chart.height,
|
|
213
|
+
max: { w: `${Math.round(chart.width / UNITS_PER_COLUMN)}ch` },
|
|
214
|
+
}),
|
|
215
|
+
};
|
|
216
|
+
tagged[kNativeImage] = entry;
|
|
217
|
+
}
|
|
218
|
+
return keyed(entry.image, key);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface TableChartFigureOptions {
|
|
222
|
+
/** Shared inline-image budget. */
|
|
223
|
+
budget?: ImageBudget;
|
|
224
|
+
/** The chart's rows changed outside a text update: its pick or raster landed. */
|
|
225
|
+
onChange: () => void;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The chart under one table, as a terminal image a blank row below it. Looks
|
|
230
|
+
* the chart up on first render — a block rebuilt mid-stream never asks for a
|
|
231
|
+
* pick it drops — and renders nothing until it is drawn, or when the table
|
|
232
|
+
* gets no chart.
|
|
233
|
+
*/
|
|
234
|
+
export class TableChartFigure implements Component {
|
|
235
|
+
readonly #options: TableChartFigureOptions;
|
|
236
|
+
readonly #figure: SvgFigure;
|
|
237
|
+
#table: Tokens.Table | undefined;
|
|
238
|
+
/** `undefined` while not looked up or waiting for a pick. */
|
|
239
|
+
#chart: TableChart | null | undefined;
|
|
240
|
+
#waiting = false;
|
|
241
|
+
#disposed = false;
|
|
242
|
+
|
|
243
|
+
constructor(options: TableChartFigureOptions) {
|
|
244
|
+
this.#options = options;
|
|
245
|
+
this.#figure = new SvgFigure({ budget: options.budget, onChange: options.onChange });
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Point the figure at `table`. */
|
|
249
|
+
update(table: Tokens.Table): void {
|
|
250
|
+
if (table.raw === this.#table?.raw) return;
|
|
251
|
+
this.#table = table;
|
|
252
|
+
this.#chart = undefined;
|
|
253
|
+
this.#waiting = false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Whether the chart is still being looked up, picked or drawn. */
|
|
257
|
+
get pending(): boolean {
|
|
258
|
+
return this.#table !== undefined && (this.#chart === undefined || (this.#chart !== null && this.#figure.pending));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
render(width: number): readonly string[] {
|
|
262
|
+
if (this.#chart === undefined && !this.#waiting) this.#resolve();
|
|
263
|
+
if (!this.#chart) return [];
|
|
264
|
+
const rows = this.#figure.render(width);
|
|
265
|
+
return rows.length ? ["", ...rows] : rows;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
invalidate(): void {
|
|
269
|
+
this.#figure.invalidate();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
dispose(): void {
|
|
273
|
+
this.#disposed = true;
|
|
274
|
+
this.#figure.dispose();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
#resolve(): void {
|
|
278
|
+
const table = this.#table;
|
|
279
|
+
if (!table) return;
|
|
280
|
+
const found = lookupTableChart(table);
|
|
281
|
+
if (found instanceof Promise) {
|
|
282
|
+
this.#waiting = true;
|
|
283
|
+
void found.then(() => {
|
|
284
|
+
if (this.#disposed || this.#table !== table) return;
|
|
285
|
+
this.#waiting = false;
|
|
286
|
+
this.#resolve();
|
|
287
|
+
this.#options.onChange();
|
|
288
|
+
});
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
this.#chart = found;
|
|
292
|
+
if (found) this.#figure.update(found.svg, true);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -90,6 +90,8 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
90
90
|
* component-scoped so the TUI reuses every other root subtree (issue #4377).
|
|
91
91
|
*/
|
|
92
92
|
tickSpinner(frame: number): void;
|
|
93
|
+
/** Whether the result's figure still waits for its raster; the transcript holds retirement meanwhile. */
|
|
94
|
+
isTranscriptBlockPending(): boolean;
|
|
93
95
|
/**
|
|
94
96
|
* Whether this block is ready to retire as immutable history. Partial
|
|
95
97
|
* results, including detached background tasks, remain active and mutable
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
import type { XdevMountedState } from "../tools/xdev";
|
|
49
49
|
import { isFramedBlockComponent, markFramedBlockComponent, renderStatusLine, WidthAwareText } from "../render/index";
|
|
50
50
|
import { cachedPngConversion, convertImageToPngShared, imagePayloadKey } from "./image-loading";
|
|
51
|
+
import { FenceFigure } from "./fence-figure";
|
|
51
52
|
import { sanitizeWithOptionalSixelPassthrough } from "../render/sixel";
|
|
52
53
|
import { renderDiff } from "../chrome/diff";
|
|
53
54
|
import { type AnimationFrame, trimBlankEdges } from "../chrome/transcript-container";
|
|
@@ -110,10 +111,13 @@ function resolveEditModeForTool(toolName: string, tool: AgentTool | undefined):
|
|
|
110
111
|
|
|
111
112
|
type ToolRendererStage = "call" | "result";
|
|
112
113
|
|
|
113
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* A renderer's preview as the fallback card's clamp (`tail` becomes a head
|
|
116
|
+
* clamp of the same size; `children` leaves the clamping to the body's own previews).
|
|
117
|
+
*/
|
|
114
118
|
function cardPreview(preview: NativeToolView["preview"]): TspPreview | undefined {
|
|
115
119
|
if (preview === undefined) return { lines: DEFAULT_TERMINAL_PREVIEW_LINES };
|
|
116
|
-
if (preview === "none") return undefined;
|
|
120
|
+
if (preview === "none" || preview === "children") return undefined;
|
|
117
121
|
if (preview !== "auto" && "tail" in preview) return { lines: preview.tail };
|
|
118
122
|
return preview;
|
|
119
123
|
}
|
|
@@ -169,6 +173,24 @@ class SafeToolRendererComponent implements Component {
|
|
|
169
173
|
invalidate.call(this.#component);
|
|
170
174
|
}
|
|
171
175
|
|
|
176
|
+
releaseRenderCaches(): void {
|
|
177
|
+
const release = this.#component.releaseRenderCaches;
|
|
178
|
+
if (release === undefined) return;
|
|
179
|
+
try {
|
|
180
|
+
release.call(this.#component);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
if (!this.#warned) {
|
|
183
|
+
this.#warned = true;
|
|
184
|
+
logger.warn("Tool renderer failed", {
|
|
185
|
+
tool: this.#toolName,
|
|
186
|
+
stage: this.#stage,
|
|
187
|
+
phase: "releaseRenderCaches",
|
|
188
|
+
error: String(err),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
172
194
|
setIgnoreTight(ignore: boolean): void {
|
|
173
195
|
const setIgnoreTight = this.#component.setIgnoreTight;
|
|
174
196
|
if (setIgnoreTight === undefined) return;
|
|
@@ -301,6 +323,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
301
323
|
#multiFileBoxes: (Box | Spacer)[] = []; // Extra boxes for multi-file edit results
|
|
302
324
|
#imageComponents: Image[] = [];
|
|
303
325
|
#imageSpacers: Spacer[] = [];
|
|
326
|
+
/** The renderer's {@link ToolRenderer.figure} drawing; kept across rebuilds while its language is unchanged, so it redraws in place and its raster survives them. */
|
|
327
|
+
#figure: FenceFigure | undefined;
|
|
304
328
|
readonly #instanceId = ++toolExecutionInstanceSeq;
|
|
305
329
|
#toolName: string;
|
|
306
330
|
#toolLabel: string;
|
|
@@ -759,6 +783,11 @@ export class ToolExecutionComponent extends Container {
|
|
|
759
783
|
}
|
|
760
784
|
}
|
|
761
785
|
|
|
786
|
+
/** Whether the result's figure still waits for its raster; the transcript holds retirement meanwhile. */
|
|
787
|
+
isTranscriptBlockPending(): boolean {
|
|
788
|
+
return this.#toolActivityVisible && this.#figure?.pending === true;
|
|
789
|
+
}
|
|
790
|
+
|
|
762
791
|
/**
|
|
763
792
|
* Whether this block is ready to retire as immutable history. Partial
|
|
764
793
|
* results, including detached background tasks, remain active and mutable
|
|
@@ -941,11 +970,13 @@ export class ToolExecutionComponent extends Container {
|
|
|
941
970
|
|
|
942
971
|
/**
|
|
943
972
|
* The native `collapsed` prop: the transcript's expand state, except that a
|
|
944
|
-
*
|
|
973
|
+
* view that asks to be {@link NativeToolView.open} never starts folded, and
|
|
974
|
+
* a call streaming its body (edit, write) stays open until it settles, then
|
|
945
975
|
* folds like a finished thought. The user's own toggle still wins meanwhile:
|
|
946
976
|
* the terminal keeps local collapse state until this prop changes.
|
|
947
977
|
*/
|
|
948
|
-
#nativeCollapsed(status: TspCardStatus): boolean {
|
|
978
|
+
#nativeCollapsed(status: TspCardStatus, view: NativeToolView): boolean {
|
|
979
|
+
if (view.open) return false;
|
|
949
980
|
const live = status === "pending" || status === "running";
|
|
950
981
|
return !this.#expanded && !(live && streamsBody(this.#toolName));
|
|
951
982
|
}
|
|
@@ -997,6 +1028,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
997
1028
|
target: head?.target,
|
|
998
1029
|
targetKind: head?.targetKind,
|
|
999
1030
|
lang: head?.lang,
|
|
1031
|
+
command: head?.command,
|
|
1000
1032
|
href: head?.href,
|
|
1001
1033
|
meta: head?.meta,
|
|
1002
1034
|
badges: badges.length > 0 ? badges : undefined,
|
|
@@ -1008,7 +1040,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
1008
1040
|
intent: typeof intent === "string" && intent ? plainText(intent) : undefined,
|
|
1009
1041
|
frame: inline ? "inline" : "card",
|
|
1010
1042
|
collapsible: hasBody,
|
|
1011
|
-
collapsed: hasBody ? this.#nativeCollapsed(status) : undefined,
|
|
1043
|
+
collapsed: hasBody ? this.#nativeCollapsed(status, view) : undefined,
|
|
1012
1044
|
preview: hasBody ? (preview === "auto" ? { lines: DEFAULT_TERMINAL_PREVIEW_LINES } : preview) : undefined,
|
|
1013
1045
|
tools: view.tools,
|
|
1014
1046
|
tone: view.tone,
|
|
@@ -1076,7 +1108,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
1076
1108
|
tone: view.tone ?? NATIVE_STATUS_TONE[status],
|
|
1077
1109
|
status,
|
|
1078
1110
|
collapsible: hasBody,
|
|
1079
|
-
collapsed: hasBody ? this.#nativeCollapsed(status) : undefined,
|
|
1111
|
+
collapsed: hasBody ? this.#nativeCollapsed(status, view) : undefined,
|
|
1080
1112
|
preview: hasBody ? cardPreview(view.preview) : undefined,
|
|
1081
1113
|
},
|
|
1082
1114
|
children,
|
|
@@ -1096,11 +1128,14 @@ export class ToolExecutionComponent extends Container {
|
|
|
1096
1128
|
* A renderer that throws falls back to the generic card.
|
|
1097
1129
|
*/
|
|
1098
1130
|
#nativeView(): NativeToolView {
|
|
1131
|
+
const status = this.#nativeStatus();
|
|
1099
1132
|
const options: RenderResultContextOptions = {
|
|
1100
1133
|
expanded: this.#expanded,
|
|
1101
1134
|
isPartial: this.#isPartial,
|
|
1102
1135
|
argsComplete: this.#argsComplete,
|
|
1103
1136
|
executionStarted: this.#executionStarted,
|
|
1137
|
+
elapsedMs: this.#elapsedMs(status),
|
|
1138
|
+
cancelled: status === "cancelled",
|
|
1104
1139
|
renderContext: this.#buildRenderContext(),
|
|
1105
1140
|
};
|
|
1106
1141
|
// Custom tools (MCP, extensions) carry their own describe hooks, mirroring
|
|
@@ -1132,6 +1167,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
1132
1167
|
body: [...(callView.body ?? []), ...(resultView.body ?? [])],
|
|
1133
1168
|
tone: resultView.tone ?? callView.tone,
|
|
1134
1169
|
preview: resultView.preview ?? callView.preview,
|
|
1170
|
+
open: resultView.open ?? callView.open,
|
|
1135
1171
|
inline: resultView.inline ?? callView.inline,
|
|
1136
1172
|
tools: resultView.tools ?? callView.tools,
|
|
1137
1173
|
};
|
|
@@ -1611,6 +1647,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
1611
1647
|
this.removeChild(spacer);
|
|
1612
1648
|
}
|
|
1613
1649
|
this.#imageSpacers = [];
|
|
1650
|
+
this.#syncFigure();
|
|
1614
1651
|
|
|
1615
1652
|
if (this.#result) {
|
|
1616
1653
|
const imageBlocks = this.#getAllImageBlocks();
|
|
@@ -1639,7 +1676,12 @@ export class ToolExecutionComponent extends Container {
|
|
|
1639
1676
|
imageData,
|
|
1640
1677
|
imageMimeType,
|
|
1641
1678
|
{ fallbackColor: (s: string) => theme.fg("toolOutput", s) },
|
|
1642
|
-
{
|
|
1679
|
+
{
|
|
1680
|
+
...resolveImageOptions(),
|
|
1681
|
+
budget: this.#ui.imageBudget,
|
|
1682
|
+
imageKey: `te${this.#instanceId}:${i}`,
|
|
1683
|
+
requestRender: () => this.#ui.requestRender(),
|
|
1684
|
+
},
|
|
1643
1685
|
);
|
|
1644
1686
|
this.#imageComponents.push(imageComponent);
|
|
1645
1687
|
this.addChild(imageComponent);
|
|
@@ -1649,6 +1691,43 @@ export class ToolExecutionComponent extends Container {
|
|
|
1649
1691
|
this.#renderedImageCount = this.#imageComponents.length;
|
|
1650
1692
|
}
|
|
1651
1693
|
|
|
1694
|
+
/**
|
|
1695
|
+
* Mount the built-in renderer's figure under the card and feed it the fence
|
|
1696
|
+
* as it stands: the mounted one stays while its language is unchanged, so it
|
|
1697
|
+
* redraws in place as the args stream.
|
|
1698
|
+
*/
|
|
1699
|
+
#syncFigure(): void {
|
|
1700
|
+
const result = this.#result;
|
|
1701
|
+
const renderer = this.#tool?.renderCall || this.#tool?.renderResult ? undefined : this.#renderer;
|
|
1702
|
+
const fence =
|
|
1703
|
+
this.#isBenignSkip() || isNativeRendering()
|
|
1704
|
+
? undefined
|
|
1705
|
+
: renderer?.figure?.(
|
|
1706
|
+
this.#args,
|
|
1707
|
+
result && { content: result.content, details: result.details, isError: result.isError },
|
|
1708
|
+
this.#renderState,
|
|
1709
|
+
);
|
|
1710
|
+
const drawable = fence !== undefined && FenceFigure.draws(fence, { showImages: this.#showImages });
|
|
1711
|
+
let figure = this.#figure;
|
|
1712
|
+
if (figure && (!drawable || figure.lang !== fence.lang)) {
|
|
1713
|
+
this.removeChild(figure);
|
|
1714
|
+
figure.dispose();
|
|
1715
|
+
figure = this.#figure = undefined;
|
|
1716
|
+
}
|
|
1717
|
+
if (!drawable) return;
|
|
1718
|
+
if (!figure) {
|
|
1719
|
+
figure = this.#figure = new FenceFigure(fence.lang, {
|
|
1720
|
+
budget: this.#ui.imageBudget,
|
|
1721
|
+
onChange: () => {
|
|
1722
|
+
this.#blockVersion++;
|
|
1723
|
+
this.#ui.requestRender();
|
|
1724
|
+
},
|
|
1725
|
+
});
|
|
1726
|
+
this.addChild(figure);
|
|
1727
|
+
}
|
|
1728
|
+
figure.update(fence);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1652
1731
|
#getCallArgsForRender(): unknown {
|
|
1653
1732
|
const renderArgs = this.#args;
|
|
1654
1733
|
if (!isEditLikeToolName(this.#toolName)) {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import type { AnimationFrame, TranscriptPresentationTarget } from "../chrome/transcript-container";
|
|
1
2
|
import { type Component, Container } from "../tui";
|
|
2
3
|
import type { ImageContent } from "@linxiraos/pi-ai";
|
|
3
4
|
import type { ReactionTarget } from "./reaction";
|
|
4
|
-
import { type NativeNode, type NativeUiEvent } from "../native/node";
|
|
5
|
+
import { type DescribeContext, type NativeNode, type NativeUiEvent } from "../native/node";
|
|
5
6
|
/** How a user bubble styles its prose and chips (see {@link userBubbleColor}). */
|
|
6
7
|
export interface UserBubbleOptions {
|
|
7
|
-
/**
|
|
8
|
+
/** Filesystem paths for attached image chips, indexed by chip number. */
|
|
8
9
|
imageLinks?: readonly (string | undefined)[];
|
|
9
10
|
/** The message's attached images in chip order (`#1` first); a native bubble shows them. */
|
|
10
11
|
images?: readonly ImageContent[];
|
|
@@ -30,9 +31,10 @@ export declare function userBubbleColor(options?: UserBubbleOptions, tokenRegex?
|
|
|
30
31
|
* (see {@link ReactionTarget}) drawn right-aligned in the bubble's top padding row;
|
|
31
32
|
* a live-steered message carries a `*` marker left-aligned in the same row.
|
|
32
33
|
*/
|
|
33
|
-
export declare class UserMessageComponent extends Container implements ReactionTarget {
|
|
34
|
+
export declare class UserMessageComponent extends Container implements ReactionTarget, TranscriptPresentationTarget {
|
|
34
35
|
#private;
|
|
35
36
|
constructor(text: string, options?: UserBubbleOptions);
|
|
37
|
+
releaseRenderCaches(): void;
|
|
36
38
|
setReaction(emoji: string): void;
|
|
37
39
|
/**
|
|
38
40
|
* A head-less user-toned frame with the prompt as markdown under its
|
|
@@ -42,9 +44,19 @@ export declare class UserMessageComponent extends Container implements ReactionT
|
|
|
42
44
|
* agent's reaction are chips at the bottom-right, so a reaction landing
|
|
43
45
|
* later updates the frame in place, even deep in scrollback.
|
|
44
46
|
*/
|
|
45
|
-
describe(): NativeNode;
|
|
47
|
+
describe(cx?: DescribeContext): NativeNode;
|
|
46
48
|
/** Hover toolbar clicks: zeta's own copy and rewind commands. */
|
|
47
49
|
handleNativeEvent(event: NativeUiEvent): void;
|
|
50
|
+
/** Apply the transcript allocator's current viewport reservation. */
|
|
51
|
+
setTranscriptAllocation(rows: number, _frame?: AnimationFrame): void;
|
|
52
|
+
isTranscriptBlockFinalized(): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Single-row emergency representation for the overflow transcript layout:
|
|
55
|
+
* renders the first content line instead of the blank top padding row, and
|
|
56
|
+
* omits OSC 133 shell integration markers so moving live blocks across the
|
|
57
|
+
* viewport does not leave stale prompt marks on lines it no longer occupies.
|
|
58
|
+
*/
|
|
59
|
+
renderTranscriptBlockEmergencyRow(width: number): string | undefined;
|
|
48
60
|
render(width: number): readonly string[];
|
|
49
61
|
}
|
|
50
62
|
/**
|
|
@@ -75,6 +87,7 @@ export declare class CollapsedSyntheticMessageComponent implements Component {
|
|
|
75
87
|
handleNativeEvent(event: NativeUiEvent): void;
|
|
76
88
|
setIgnoreTight(ignore: boolean): this;
|
|
77
89
|
invalidate(): void;
|
|
90
|
+
releaseRenderCaches(): void;
|
|
78
91
|
dispose(): void;
|
|
79
92
|
render(width: number): readonly string[];
|
|
80
93
|
}
|