@oh-my-pi/pi-tui 18.2.4 → 18.2.6
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 +23 -0
- package/README.md +43 -0
- package/dist/types/app-keybindings.d.ts +395 -0
- package/dist/types/apps/autoresearch-dashboard.d.ts +43 -0
- package/dist/types/apps/autoresearch-data.d.ts +15 -0
- package/dist/types/apps/cleanse-board.d.ts +66 -0
- package/dist/types/apps/cleanse-picker.d.ts +23 -0
- package/dist/types/apps/debug/log-formatting.d.ts +6 -0
- package/dist/types/apps/debug/log-viewer.d.ts +81 -0
- package/dist/types/apps/debug/protocol-probe.d.ts +42 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +58 -0
- package/dist/types/apps/debug/raw-sse.d.ts +26 -0
- package/dist/types/apps/debug/terminal-info.d.ts +34 -0
- package/dist/types/apps/debug/viewer-frame.d.ts +52 -0
- package/dist/types/apps/git/avatar.d.ts +9 -0
- package/dist/types/apps/git/colors.d.ts +49 -0
- package/dist/types/apps/git/diff-pane.d.ts +188 -0
- package/dist/types/apps/git/git-tui.d.ts +66 -0
- package/dist/types/apps/git/sidebar.d.ts +149 -0
- package/dist/types/apps/git/state.d.ts +117 -0
- package/dist/types/apps/if-bench-board.d.ts +75 -0
- package/dist/types/apps/live-visualizer.d.ts +33 -0
- package/dist/types/apps/ps-data.d.ts +51 -0
- package/dist/types/apps/ps-top.d.ts +33 -0
- package/dist/types/apps/session-picker.d.ts +26 -0
- package/dist/types/apps/setup-model-picker.d.ts +13 -0
- package/dist/types/apps/standalone-picker.d.ts +42 -0
- package/dist/types/autocomplete.d.ts +4 -0
- package/dist/types/chat/advisor-message.d.ts +11 -0
- package/dist/types/chat/assistant-message.d.ts +106 -0
- package/dist/types/chat/background-tan-message.d.ts +9 -0
- package/dist/types/chat/bash-execution.d.ts +47 -0
- package/dist/types/chat/cache-invalidation-marker.d.ts +50 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +50 -0
- package/dist/types/chat/collab-prompt-message.d.ts +10 -0
- package/dist/types/chat/compaction-summary-message.d.ts +54 -0
- package/dist/types/chat/custom-message.d.ts +10 -0
- package/dist/types/chat/display-preferences.d.ts +13 -0
- package/dist/types/chat/eval-execution.d.ts +29 -0
- package/dist/types/chat/execution-shared.d.ts +51 -0
- package/dist/types/chat/extension-types.d.ts +28 -0
- package/dist/types/chat/hook-message.d.ts +10 -0
- package/dist/types/chat/image-loading.d.ts +46 -0
- package/dist/types/chat/late-diagnostics-message.d.ts +21 -0
- package/dist/types/chat/messages.d.ts +189 -0
- package/dist/types/chat/reaction.d.ts +30 -0
- package/dist/types/chat/read-target.d.ts +4 -0
- package/dist/types/chat/read-tool-group.d.ts +67 -0
- package/dist/types/chat/served-model-marker.d.ts +47 -0
- package/dist/types/chat/skill-message.d.ts +33 -0
- package/dist/types/chat/skill-title-input.d.ts +14 -0
- package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/chat/thinking-display.d.ts +12 -0
- package/dist/types/chat/todo-reminder.d.ts +13 -0
- package/dist/types/chat/tool-execution.d.ts +138 -0
- package/dist/types/chat/transcript-browser.d.ts +93 -0
- package/dist/types/chat/transcript-entry.d.ts +45 -0
- package/dist/types/chat/transcript-outline.d.ts +86 -0
- package/dist/types/chat/transcript-render-helpers.d.ts +92 -0
- package/dist/types/chat/ttsr-notification.d.ts +23 -0
- package/dist/types/chat/user-message.d.ts +52 -0
- package/dist/types/chrome/chat-block.d.ts +64 -0
- package/dist/types/chrome/collab-qrcode.d.ts +28 -0
- package/dist/types/chrome/context-thresholds.d.ts +10 -0
- package/dist/types/chrome/countdown-timer.d.ts +14 -0
- package/dist/types/chrome/diff.d.ts +14 -0
- package/dist/types/chrome/dynamic-border.d.ts +16 -0
- package/dist/types/chrome/error-block.d.ts +17 -0
- package/dist/types/chrome/form-theme.d.ts +3 -0
- package/dist/types/chrome/format.d.ts +12 -0
- package/dist/types/chrome/index.d.ts +20 -0
- package/dist/types/chrome/keybinding-hints.d.ts +40 -0
- package/dist/types/chrome/live-board.d.ts +23 -0
- package/dist/types/chrome/local-date.d.ts +4 -0
- package/dist/types/chrome/message-divider.d.ts +22 -0
- package/dist/types/chrome/message-frame.d.ts +52 -0
- package/dist/types/chrome/message-notice.d.ts +35 -0
- package/dist/types/chrome/overlay-box.d.ts +74 -0
- package/dist/types/chrome/qrcode.d.ts +48 -0
- package/dist/types/chrome/segment-track.d.ts +27 -0
- package/dist/types/chrome/select-list-mouse-routing.d.ts +4 -0
- package/dist/types/chrome/selector-helpers.d.ts +52 -0
- package/dist/types/chrome/shared.d.ts +5 -0
- package/dist/types/chrome/streaming-panel.d.ts +19 -0
- package/dist/types/chrome/tool-activity.d.ts +17 -0
- package/dist/types/chrome/transcript-container.d.ts +129 -0
- package/dist/types/chrome/transcript-status.d.ts +12 -0
- package/dist/types/chrome/visual-truncate.d.ts +19 -0
- package/dist/types/components/disclosure.d.ts +42 -0
- package/dist/types/components/form.d.ts +130 -0
- package/dist/types/components/key-value-list.d.ts +24 -0
- package/dist/types/components/layout/geometry.d.ts +73 -0
- package/dist/types/components/layout/row.d.ts +55 -0
- package/dist/types/components/layout/split-pane.d.ts +80 -0
- package/dist/types/components/layout/stack.d.ts +50 -0
- package/dist/types/components/menu-selection.d.ts +71 -0
- package/dist/types/components/metric.d.ts +44 -0
- package/dist/types/components/progress-bar.d.ts +36 -0
- package/dist/types/components/scroll-view.d.ts +53 -19
- package/dist/types/components/scroll-viewport.d.ts +46 -0
- package/dist/types/components/section.d.ts +19 -0
- package/dist/types/components/select-list.d.ts +46 -2
- package/dist/types/components/settings-list.d.ts +20 -0
- package/dist/types/components/table.d.ts +32 -0
- package/dist/types/components/tree-view.d.ts +130 -0
- package/dist/types/components/wizard-step.d.ts +60 -0
- package/dist/types/hotkeys-markdown.d.ts +7 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/keybinding-matchers.d.ts +35 -0
- package/dist/types/keys.d.ts +2 -2
- package/dist/types/lang-from-path.d.ts +9 -0
- package/dist/types/overlays/advisor-config.d.ts +114 -0
- package/dist/types/overlays/agent-activity.d.ts +41 -0
- package/dist/types/overlays/agent-hub-projection.d.ts +33 -0
- package/dist/types/overlays/agent-hub-renderer.d.ts +53 -0
- package/dist/types/overlays/agent-hub-types.d.ts +99 -0
- package/dist/types/overlays/agent-hub.d.ts +126 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +71 -0
- package/dist/types/overlays/agents-hub.d.ts +72 -0
- package/dist/types/overlays/ask-dialog.d.ts +88 -0
- package/dist/types/overlays/bordered-loader.d.ts +11 -0
- package/dist/types/overlays/btw-history-panel.d.ts +29 -0
- package/dist/types/overlays/btw-history.d.ts +17 -0
- package/dist/types/overlays/btw-panel.d.ts +26 -0
- package/dist/types/overlays/cleanse-panel.d.ts +36 -0
- package/dist/types/overlays/codex-reset-fireworks.d.ts +52 -0
- package/dist/types/overlays/composer-shape-preview.d.ts +47 -0
- package/dist/types/overlays/composer-shape-registry.d.ts +50 -0
- package/dist/types/overlays/copy-selector.d.ts +48 -0
- package/dist/types/overlays/copy-targets.d.ts +63 -0
- package/dist/types/overlays/error-banner.d.ts +13 -0
- package/dist/types/overlays/extensions/display-text.d.ts +10 -0
- package/dist/types/overlays/extensions/extension-dashboard.d.ts +63 -0
- package/dist/types/overlays/extensions/extension-list.d.ts +54 -0
- package/dist/types/overlays/extensions/inspector-model.d.ts +109 -0
- package/dist/types/overlays/extensions/inspector-panel.d.ts +17 -0
- package/dist/types/overlays/extensions/live-tool-session.d.ts +28 -0
- package/dist/types/overlays/extensions/mcp-runtime.d.ts +107 -0
- package/dist/types/overlays/extensions/state-manager.d.ts +42 -0
- package/dist/types/overlays/extensions/types.d.ts +165 -0
- package/dist/types/overlays/history-search.d.ts +16 -0
- package/dist/types/overlays/hook-editor.d.ts +44 -0
- package/dist/types/overlays/hook-input.d.ts +20 -0
- package/dist/types/overlays/hook-selector.d.ts +71 -0
- package/dist/types/overlays/hub-frame.d.ts +77 -0
- package/dist/types/overlays/login-dialog.d.ts +43 -0
- package/dist/types/overlays/logout-account-selector.d.ts +15 -0
- package/dist/types/overlays/mcp-add-wizard.d.ts +87 -0
- package/dist/types/overlays/model-browser.d.ts +213 -0
- package/dist/types/overlays/model-hub.d.ts +72 -0
- package/dist/types/overlays/model-picker.d.ts +74 -0
- package/dist/types/overlays/model-selector.d.ts +52 -0
- package/dist/types/overlays/move-overlay.d.ts +39 -0
- package/dist/types/overlays/oauth-selector.d.ts +41 -0
- package/dist/types/overlays/omfg-panel.d.ts +20 -0
- package/dist/types/overlays/pause-screen.d.ts +43 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +89 -0
- package/dist/types/overlays/plan-save-overlay.d.ts +19 -0
- package/dist/types/overlays/plan-toc.d.ts +41 -0
- package/dist/types/overlays/plugin-selector.d.ts +28 -0
- package/dist/types/overlays/plugin-settings.d.ts +180 -0
- package/dist/types/overlays/queue-mode-selector.d.ts +11 -0
- package/dist/types/overlays/reset-usage-selector.d.ts +23 -0
- package/dist/types/overlays/rewind-selector.d.ts +61 -0
- package/dist/types/overlays/running-subagent-badge.d.ts +6 -0
- package/dist/types/overlays/session-account-selector.d.ts +24 -0
- package/dist/types/overlays/session-info-overlay.d.ts +17 -0
- package/dist/types/overlays/session-observer-registry.d.ts +77 -0
- package/dist/types/overlays/session-selector.d.ts +131 -0
- package/dist/types/overlays/settings-defs.d.ts +119 -0
- package/dist/types/overlays/settings-selector.d.ts +73 -0
- package/dist/types/overlays/show-images-selector.d.ts +11 -0
- package/dist/types/overlays/snapcompact-shape-preview.d.ts +31 -0
- package/dist/types/overlays/theme-selector.d.ts +12 -0
- package/dist/types/overlays/thinking-selector.d.ts +12 -0
- package/dist/types/overlays/tiny-title-download-progress.d.ts +21 -0
- package/dist/types/overlays/tree-selector.d.ts +92 -0
- package/dist/types/overlays/usage-dashboard.d.ts +94 -0
- package/dist/types/overlays/usage-display.d.ts +5 -0
- package/dist/types/overlays/usage-row.d.ts +17 -0
- package/dist/types/prompt/attachment-chips.d.ts +19 -0
- package/dist/types/prompt/composer-attachments.d.ts +71 -0
- package/dist/types/prompt/composer-cache.d.ts +37 -0
- package/dist/types/prompt/composer.d.ts +159 -0
- package/dist/types/prompt/custom-editor.d.ts +261 -0
- package/dist/types/prompt/editor-top-gap.d.ts +18 -0
- package/dist/types/prompt/emoji-autocomplete.d.ts +16 -0
- package/dist/types/prompt/github-ref-autocomplete.d.ts +35 -0
- package/dist/types/prompt/gradient-highlight.d.ts +32 -0
- package/dist/types/prompt/image-format.d.ts +4 -0
- package/dist/types/prompt/image-references.d.ts +26 -0
- package/dist/types/prompt/interactive-context-helpers.d.ts +43 -0
- package/dist/types/prompt/internal-url-autocomplete.d.ts +56 -0
- package/dist/types/prompt/macos-spelling.d.ts +44 -0
- package/dist/types/prompt/magic-keyword-boundary.d.ts +9 -0
- package/dist/types/prompt/magic-keywords.d.ts +26 -0
- package/dist/types/prompt/markdown-prose.d.ts +15 -0
- package/dist/types/prompt/model-mention-autocomplete.d.ts +25 -0
- package/dist/types/prompt/model-mention-syntax.d.ts +24 -0
- package/dist/types/prompt/orchestrate.d.ts +13 -0
- package/dist/types/prompt/prompt-action-autocomplete.d.ts +56 -0
- package/dist/types/prompt/queue-input.d.ts +8 -0
- package/dist/types/prompt/skill-tokens.d.ts +13 -0
- package/dist/types/prompt/tools-markdown.d.ts +12 -0
- package/dist/types/prompt/ultrathink.d.ts +13 -0
- package/dist/types/prompt/usage-amounts.d.ts +26 -0
- package/dist/types/prompt/video.d.ts +18 -0
- package/dist/types/prompt/welcome.d.ts +83 -0
- package/dist/types/prompt/workflow.d.ts +13 -0
- package/dist/types/render/code-cell.d.ts +51 -0
- package/dist/types/render/file-list.d.ts +22 -0
- package/dist/types/render/hyperlink.d.ts +80 -0
- package/dist/types/render/index.d.ts +16 -0
- package/dist/types/render/output-block.d.ts +54 -0
- package/dist/types/render/output-pane.d.ts +80 -0
- package/dist/types/render/render-utils.d.ts +312 -0
- package/dist/types/render/sixel.d.ts +21 -0
- package/dist/types/render/status-line.d.ts +23 -0
- package/dist/types/render/tool-card.d.ts +71 -0
- package/dist/types/render/tree-list.d.ts +29 -0
- package/dist/types/render/types.d.ts +17 -0
- package/dist/types/render/utils.d.ts +43 -0
- package/dist/types/render/width-aware-text.d.ts +23 -0
- package/dist/types/setup/lazy.d.ts +3 -0
- package/dist/types/setup/scenes/composer.d.ts +3 -0
- package/dist/types/setup/scenes/glyph.d.ts +3 -0
- package/dist/types/setup/scenes/model.d.ts +3 -0
- package/dist/types/setup/scenes/outro.d.ts +2 -0
- package/dist/types/setup/scenes/providers.d.ts +3 -0
- package/dist/types/setup/scenes/sign-in.d.ts +21 -0
- package/dist/types/setup/scenes/splash.d.ts +11 -0
- package/dist/types/setup/scenes/theme.d.ts +3 -0
- package/dist/types/setup/scenes/types.d.ts +110 -0
- package/dist/types/setup/scenes/web-search.d.ts +22 -0
- package/dist/types/setup/setup-version.d.ts +11 -0
- package/dist/types/setup/startup-splash.d.ts +9 -0
- package/dist/types/setup/wizard-overlay.d.ts +16 -0
- package/dist/types/setup/wizard.d.ts +25 -0
- package/dist/types/status-line/component.d.ts +182 -0
- package/dist/types/status-line/context-usage.d.ts +156 -0
- package/dist/types/status-line/footer.d.ts +30 -0
- package/dist/types/status-line/git-utils.d.ts +22 -0
- package/dist/types/status-line/host.d.ts +129 -0
- package/dist/types/status-line/index.d.ts +6 -0
- package/dist/types/status-line/loop.d.ts +18 -0
- package/dist/types/status-line/metrics.d.ts +21 -0
- package/dist/types/status-line/presets.d.ts +3 -0
- package/dist/types/status-line/schema.d.ts +15 -0
- package/dist/types/status-line/segments.d.ts +5 -0
- package/dist/types/status-line/separators.d.ts +3 -0
- package/dist/types/status-line/types.d.ts +236 -0
- package/dist/types/stdin-buffer.d.ts +4 -0
- package/dist/types/theme/color.d.ts +24 -0
- package/dist/types/theme/defaults/index.d.ts +9489 -0
- package/dist/types/theme/index.d.ts +4 -0
- package/dist/types/theme/loader.d.ts +23 -0
- package/dist/types/theme/mermaid-cache.d.ts +26 -0
- package/dist/types/theme/schema-validation.d.ts +3 -0
- package/dist/types/theme/schema.d.ts +25 -0
- package/dist/types/theme/session-color.d.ts +43 -0
- package/dist/types/theme/shimmer.d.ts +44 -0
- package/dist/types/theme/symbols.d.ts +34 -0
- package/dist/types/theme/theme-class.d.ts +299 -0
- package/dist/types/theme/theme.d.ts +111 -0
- package/dist/types/theme/tui-adapters.d.ts +30 -0
- package/dist/types/thinking.d.ts +165 -0
- package/dist/types/tools/agent-tree.d.ts +36 -0
- package/dist/types/tools/ask.d.ts +67 -0
- package/dist/types/tools/ast-edit.d.ts +53 -0
- package/dist/types/tools/ast-grep.d.ts +52 -0
- package/dist/types/tools/autoresearch.d.ts +156 -0
- package/dist/types/tools/bash-interactive.d.ts +28 -0
- package/dist/types/tools/bash.d.ts +103 -0
- package/dist/types/tools/conflict-detect.d.ts +43 -0
- package/dist/types/tools/debug.d.ts +60 -0
- package/dist/types/tools/default-renderer.d.ts +24 -0
- package/dist/types/tools/edit.d.ts +158 -0
- package/dist/types/tools/eval-format/code-mode-declarations.d.ts +5 -0
- package/dist/types/tools/eval-format/index.d.ts +5 -0
- package/dist/types/tools/eval-format/javascript.d.ts +2 -0
- package/dist/types/tools/eval-format/python.d.ts +2 -0
- package/dist/types/tools/eval.d.ts +94 -0
- package/dist/types/tools/fetch.d.ts +42 -0
- package/dist/types/tools/gh-format.d.ts +8 -0
- package/dist/types/tools/github.d.ts +144 -0
- package/dist/types/tools/glob.d.ts +44 -0
- package/dist/types/tools/goal.d.ts +42 -0
- package/dist/types/tools/grep.d.ts +64 -0
- package/dist/types/tools/grouped-file-output.d.ts +71 -0
- package/dist/types/tools/hashline-format.d.ts +28 -0
- package/dist/types/tools/hub.d.ts +340 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/json-tree.d.ts +59 -0
- package/dist/types/tools/line-ranges.d.ts +29 -0
- package/dist/types/tools/list-limit.d.ts +15 -0
- package/dist/types/tools/lsp.d.ts +72 -0
- package/dist/types/tools/match-line-format.d.ts +11 -0
- package/dist/types/tools/mcp.d.ts +81 -0
- package/dist/types/tools/memory.d.ts +67 -0
- package/dist/types/tools/output-meta.d.ts +151 -0
- package/dist/types/tools/read.d.ts +139 -0
- package/dist/types/tools/renderer.d.ts +98 -0
- package/dist/types/tools/report-tool-issue.d.ts +8 -0
- package/dist/types/tools/resolve.d.ts +47 -0
- package/dist/types/tools/streaming-output.d.ts +282 -0
- package/dist/types/tools/subprocess.d.ts +24 -0
- package/dist/types/tools/task-repair-args.d.ts +53 -0
- package/dist/types/tools/task-yield-assembly.d.ts +20 -0
- package/dist/types/tools/task.d.ts +425 -0
- package/dist/types/tools/terminal-output.d.ts +8 -0
- package/dist/types/tools/think.d.ts +13 -0
- package/dist/types/tools/todo.d.ts +118 -0
- package/dist/types/tools/tool-errors.d.ts +7 -0
- package/dist/types/tools/vibe.d.ts +120 -0
- package/dist/types/tools/web-search.d.ts +195 -0
- package/dist/types/tools/write.d.ts +76 -0
- package/dist/types/tools/xd-url.d.ts +13 -0
- package/dist/types/tools/xdev.d.ts +52 -0
- package/dist/types/tui.d.ts +18 -0
- package/dist/types/utils.d.ts +2 -0
- package/package.json +37 -3
- package/src/app-keybindings.ts +760 -0
- package/src/apps/autoresearch-dashboard.ts +500 -0
- package/src/apps/autoresearch-data.ts +64 -0
- package/src/apps/cleanse-board.ts +341 -0
- package/src/apps/cleanse-picker.ts +57 -0
- package/src/apps/debug/log-formatting.ts +53 -0
- package/src/apps/debug/log-viewer.ts +868 -0
- package/src/apps/debug/protocol-probe.ts +267 -0
- package/src/apps/debug/raw-sse-buffer.ts +449 -0
- package/src/apps/debug/raw-sse.ts +282 -0
- package/src/apps/debug/terminal-info.ts +115 -0
- package/src/apps/debug/viewer-frame.ts +174 -0
- package/src/apps/git/avatar.ts +52 -0
- package/src/apps/git/colors.ts +109 -0
- package/src/apps/git/diff-pane.ts +1512 -0
- package/src/apps/git/git-tui.ts +889 -0
- package/src/apps/git/sidebar.ts +1204 -0
- package/src/apps/git/state.ts +113 -0
- package/src/apps/if-bench-board.ts +324 -0
- package/src/apps/live-visualizer.ts +238 -0
- package/src/apps/ps-data.ts +116 -0
- package/src/apps/ps-top.ts +422 -0
- package/src/apps/session-picker.ts +95 -0
- package/src/apps/setup-model-picker.ts +21 -0
- package/src/apps/standalone-picker.ts +111 -0
- package/src/autocomplete.ts +9 -13
- package/src/chat/advisor-message.ts +175 -0
- package/src/chat/assistant-message.ts +1214 -0
- package/src/chat/background-tan-message.ts +35 -0
- package/src/chat/bash-execution.ts +394 -0
- package/src/chat/cache-invalidation-marker.ts +94 -0
- package/src/chat/chat-transcript-builder.ts +593 -0
- package/src/chat/collab-prompt-message.ts +34 -0
- package/src/chat/compaction-summary-message.ts +261 -0
- package/src/chat/custom-message.ts +23 -0
- package/src/chat/display-preferences.ts +24 -0
- package/src/chat/eval-execution.ts +172 -0
- package/src/chat/execution-shared.ts +113 -0
- package/src/chat/extension-types.ts +46 -0
- package/src/chat/hook-message.ts +20 -0
- package/src/chat/image-loading.ts +122 -0
- package/src/chat/late-diagnostics-message.ts +92 -0
- package/src/chat/messages.ts +305 -0
- package/src/chat/reaction.ts +65 -0
- package/src/chat/read-target.ts +7 -0
- package/src/chat/read-tool-group.ts +873 -0
- package/src/chat/served-model-marker.ts +91 -0
- package/src/chat/skill-message.ts +220 -0
- package/src/chat/skill-title-input.ts +41 -0
- package/src/chat/stripped-tool-calls-placeholder.ts +35 -0
- package/src/chat/thinking-display.ts +312 -0
- package/src/chat/todo-reminder.ts +33 -0
- package/src/chat/tool-execution.ts +1395 -0
- package/src/chat/transcript-browser.ts +268 -0
- package/src/chat/transcript-entry.ts +96 -0
- package/src/chat/transcript-outline.ts +260 -0
- package/src/chat/transcript-render-helpers.ts +315 -0
- package/src/chat/ttsr-notification.ts +123 -0
- package/src/chat/user-message.ts +287 -0
- package/src/chrome/chat-block.ts +110 -0
- package/src/chrome/collab-qrcode.ts +74 -0
- package/src/chrome/context-thresholds.ts +85 -0
- package/src/chrome/countdown-timer.ts +74 -0
- package/src/chrome/diff.ts +266 -0
- package/src/chrome/dynamic-border.ts +36 -0
- package/src/chrome/error-block.ts +63 -0
- package/src/chrome/form-theme.ts +10 -0
- package/src/chrome/format.ts +66 -0
- package/src/chrome/index.ts +21 -0
- package/src/chrome/keybinding-hints.ts +55 -0
- package/src/chrome/live-board.ts +123 -0
- package/src/chrome/local-date.ts +20 -0
- package/src/chrome/message-divider.ts +51 -0
- package/src/chrome/message-frame.ts +164 -0
- package/src/chrome/message-notice.ts +103 -0
- package/src/chrome/overlay-box.ts +301 -0
- package/src/chrome/qrcode.ts +539 -0
- package/src/chrome/segment-track.ts +86 -0
- package/src/chrome/select-list-mouse-routing.ts +11 -0
- package/src/chrome/selector-helpers.ts +119 -0
- package/src/chrome/shared.ts +27 -0
- package/src/chrome/streaming-panel.ts +72 -0
- package/src/chrome/tool-activity.ts +44 -0
- package/src/chrome/transcript-container.ts +902 -0
- package/src/chrome/transcript-status.ts +27 -0
- package/src/chrome/visual-truncate.ts +70 -0
- package/src/components/disclosure.ts +235 -0
- package/src/components/editor.ts +10 -12
- package/src/components/form.ts +566 -0
- package/src/components/input.ts +6 -27
- package/src/components/key-value-list.ts +88 -0
- package/src/components/layout/geometry.ts +202 -0
- package/src/components/layout/row.ts +283 -0
- package/src/components/layout/split-pane.ts +349 -0
- package/src/components/layout/stack.ts +261 -0
- package/src/components/markdown.ts +16 -12
- package/src/components/menu-selection.ts +248 -0
- package/src/components/metric.ts +132 -0
- package/src/components/progress-bar.ts +140 -0
- package/src/components/scroll-view.ts +372 -70
- package/src/components/scroll-viewport.ts +154 -0
- package/src/components/section.ts +77 -0
- package/src/components/select-list.ts +238 -159
- package/src/components/settings-list.ts +103 -80
- package/src/components/table.ts +127 -0
- package/src/components/tree-view.ts +481 -0
- package/src/components/wizard-step.ts +229 -0
- package/src/deccara.ts +1 -3
- package/src/hotkeys-markdown.ts +100 -0
- package/src/index.ts +18 -0
- package/src/keybinding-matchers.ts +99 -0
- package/src/keys.ts +2 -2
- package/src/lang-from-path.ts +252 -0
- package/src/overlays/advisor-config.ts +761 -0
- package/src/overlays/agent-activity.ts +113 -0
- package/src/overlays/agent-hub-projection.ts +250 -0
- package/src/overlays/agent-hub-renderer.ts +281 -0
- package/src/overlays/agent-hub-types.ts +74 -0
- package/src/overlays/agent-hub.ts +1562 -0
- package/src/overlays/agent-transcript-viewer.ts +669 -0
- package/src/overlays/agents-hub.ts +1203 -0
- package/src/overlays/ask-dialog.ts +1202 -0
- package/src/overlays/bordered-loader.ts +41 -0
- package/src/overlays/btw-history-panel.ts +591 -0
- package/src/overlays/btw-history.ts +33 -0
- package/src/overlays/btw-panel.ts +167 -0
- package/src/overlays/cleanse-panel.ts +167 -0
- package/src/overlays/codex-reset-fireworks.ts +375 -0
- package/src/overlays/composer-shape-preview.ts +137 -0
- package/src/overlays/composer-shape-registry.ts +82 -0
- package/src/overlays/copy-selector.ts +618 -0
- package/src/overlays/copy-targets.ts +210 -0
- package/src/overlays/error-banner.ts +39 -0
- package/src/overlays/extensions/display-text.ts +39 -0
- package/src/overlays/extensions/extension-dashboard.ts +645 -0
- package/src/overlays/extensions/extension-list.ts +667 -0
- package/src/overlays/extensions/inspector-model.ts +484 -0
- package/src/overlays/extensions/inspector-panel.ts +669 -0
- package/src/overlays/extensions/live-tool-session.ts +67 -0
- package/src/overlays/extensions/mcp-runtime.ts +289 -0
- package/src/overlays/extensions/state-manager.ts +337 -0
- package/src/overlays/extensions/types.ts +208 -0
- package/src/overlays/history-search.ts +268 -0
- package/src/overlays/hook-editor.ts +272 -0
- package/src/overlays/hook-input.ts +84 -0
- package/src/overlays/hook-selector.ts +635 -0
- package/src/overlays/hub-frame.ts +262 -0
- package/src/overlays/login-dialog.ts +231 -0
- package/src/overlays/logout-account-selector.ts +115 -0
- package/src/overlays/mcp-add-wizard.ts +1436 -0
- package/src/overlays/model-browser.ts +1176 -0
- package/src/overlays/model-hub.ts +2279 -0
- package/src/overlays/model-picker.ts +285 -0
- package/src/overlays/model-selector.ts +107 -0
- package/src/overlays/move-overlay.ts +197 -0
- package/src/overlays/oauth-selector.ts +446 -0
- package/src/overlays/omfg-panel.ts +136 -0
- package/src/overlays/pause-screen.ts +198 -0
- package/src/overlays/plan-review-overlay.ts +1227 -0
- package/src/overlays/plan-save-overlay.ts +74 -0
- package/src/overlays/plan-toc.ts +139 -0
- package/src/overlays/plugin-selector.ts +97 -0
- package/src/overlays/plugin-settings.ts +839 -0
- package/src/overlays/queue-mode-selector.ts +55 -0
- package/src/overlays/reset-usage-selector.ts +170 -0
- package/src/overlays/rewind-selector.ts +499 -0
- package/src/overlays/running-subagent-badge.ts +19 -0
- package/src/overlays/session-account-selector.ts +68 -0
- package/src/overlays/session-info-overlay.ts +96 -0
- package/src/overlays/session-observer-registry.ts +289 -0
- package/src/overlays/session-selector.ts +1137 -0
- package/src/overlays/settings-defs.ts +315 -0
- package/src/overlays/settings-selector.ts +1415 -0
- package/src/overlays/show-images-selector.ts +44 -0
- package/src/overlays/snapcompact-shape-preview-doc.md +14 -0
- package/src/overlays/snapcompact-shape-preview.ts +192 -0
- package/src/overlays/theme-selector.ts +62 -0
- package/src/overlays/thinking-selector.ts +51 -0
- package/src/overlays/tiny-title-download-progress.ts +102 -0
- package/src/overlays/tree-selector.ts +1121 -0
- package/src/overlays/usage-dashboard.ts +629 -0
- package/src/overlays/usage-display.ts +45 -0
- package/src/overlays/usage-row.ts +118 -0
- package/src/prompt/attachment-chips.ts +201 -0
- package/src/prompt/composer-attachments.ts +280 -0
- package/src/prompt/composer-cache.ts +304 -0
- package/src/prompt/composer.ts +934 -0
- package/src/prompt/custom-editor.ts +1392 -0
- package/src/prompt/data/emojis.json +1 -0
- package/src/prompt/editor-top-gap.ts +28 -0
- package/src/prompt/emoji-autocomplete.ts +285 -0
- package/src/prompt/github-ref-autocomplete.ts +75 -0
- package/src/prompt/gradient-highlight.ts +101 -0
- package/src/prompt/image-format.ts +28 -0
- package/src/prompt/image-references.ts +102 -0
- package/src/prompt/interactive-context-helpers.ts +126 -0
- package/src/prompt/internal-url-autocomplete.ts +155 -0
- package/src/prompt/macos-spelling.ts +456 -0
- package/src/prompt/magic-keyword-boundary.ts +23 -0
- package/src/prompt/magic-keywords.ts +42 -0
- package/src/prompt/markdown-prose.ts +245 -0
- package/src/prompt/model-mention-autocomplete.ts +94 -0
- package/src/prompt/model-mention-syntax.ts +41 -0
- package/src/prompt/orchestrate.ts +26 -0
- package/src/prompt/prompt-action-autocomplete.ts +337 -0
- package/src/prompt/queue-input.ts +132 -0
- package/src/prompt/skill-tokens.ts +36 -0
- package/src/prompt/tips.txt +27 -0
- package/src/prompt/tools-markdown.ts +29 -0
- package/src/prompt/ultrathink.ts +26 -0
- package/src/prompt/usage-amounts.ts +99 -0
- package/src/prompt/video.ts +47 -0
- package/src/prompt/welcome.ts +605 -0
- package/src/prompt/workflow.ts +26 -0
- package/src/render/code-cell.ts +244 -0
- package/src/render/file-list.ts +58 -0
- package/src/render/hyperlink.ts +192 -0
- package/src/render/index.ts +17 -0
- package/src/render/output-block.ts +267 -0
- package/src/render/output-pane.ts +299 -0
- package/src/render/render-utils.ts +1182 -0
- package/src/render/sixel.ts +69 -0
- package/src/render/status-line.ts +55 -0
- package/src/render/tool-card.ts +272 -0
- package/src/render/tree-list.ts +188 -0
- package/src/render/types.ts +19 -0
- package/src/render/utils.ts +109 -0
- package/src/render/width-aware-text.ts +60 -0
- package/src/setup/lazy.ts +17 -0
- package/src/setup/scenes/composer.ts +127 -0
- package/src/setup/scenes/glyph.ts +120 -0
- package/src/setup/scenes/model.ts +138 -0
- package/src/setup/scenes/outro.ts +24 -0
- package/src/setup/scenes/providers.ts +107 -0
- package/src/setup/scenes/sign-in.ts +373 -0
- package/src/setup/scenes/splash.ts +192 -0
- package/src/setup/scenes/theme.ts +343 -0
- package/src/setup/scenes/types.ts +111 -0
- package/src/setup/scenes/web-search.ts +165 -0
- package/src/setup/setup-version.ts +11 -0
- package/src/setup/startup-splash.ts +107 -0
- package/src/setup/wizard-overlay.ts +319 -0
- package/src/setup/wizard.ts +101 -0
- package/src/status-line/component.ts +3003 -0
- package/src/status-line/context-usage.ts +688 -0
- package/src/status-line/footer.ts +323 -0
- package/src/status-line/git-utils.ts +42 -0
- package/src/status-line/host.ts +97 -0
- package/src/status-line/index.ts +6 -0
- package/src/status-line/loop.ts +28 -0
- package/src/status-line/metrics.ts +94 -0
- package/src/status-line/presets.ts +107 -0
- package/src/status-line/schema.ts +57 -0
- package/src/status-line/segments.ts +934 -0
- package/src/status-line/separators.ts +55 -0
- package/src/status-line/types.ts +227 -0
- package/src/stdin-buffer.ts +4 -2
- package/src/theme/color.ts +95 -0
- package/src/theme/dark.json +95 -0
- package/src/theme/defaults/alabaster.json +93 -0
- package/src/theme/defaults/amethyst.json +96 -0
- package/src/theme/defaults/anthracite.json +93 -0
- package/src/theme/defaults/basalt.json +91 -0
- package/src/theme/defaults/birch.json +95 -0
- package/src/theme/defaults/dark-abyss.json +91 -0
- package/src/theme/defaults/dark-arctic.json +104 -0
- package/src/theme/defaults/dark-aurora.json +95 -0
- package/src/theme/defaults/dark-catppuccin.json +107 -0
- package/src/theme/defaults/dark-cavern.json +91 -0
- package/src/theme/defaults/dark-celestial.json +106 -0
- package/src/theme/defaults/dark-copper.json +95 -0
- package/src/theme/defaults/dark-cosmos.json +90 -0
- package/src/theme/defaults/dark-cyberpunk.json +102 -0
- package/src/theme/defaults/dark-dracula.json +98 -0
- package/src/theme/defaults/dark-eclipse.json +91 -0
- package/src/theme/defaults/dark-ember.json +95 -0
- package/src/theme/defaults/dark-equinox.json +90 -0
- package/src/theme/defaults/dark-forest.json +96 -0
- package/src/theme/defaults/dark-github.json +105 -0
- package/src/theme/defaults/dark-gruvbox.json +112 -0
- package/src/theme/defaults/dark-lavender.json +95 -0
- package/src/theme/defaults/dark-lunar.json +89 -0
- package/src/theme/defaults/dark-midnight.json +95 -0
- package/src/theme/defaults/dark-monochrome.json +94 -0
- package/src/theme/defaults/dark-monokai.json +98 -0
- package/src/theme/defaults/dark-nebula.json +90 -0
- package/src/theme/defaults/dark-nord.json +98 -0
- package/src/theme/defaults/dark-ocean.json +101 -0
- package/src/theme/defaults/dark-one.json +100 -0
- package/src/theme/defaults/dark-poimandres.json +115 -0
- package/src/theme/defaults/dark-rainforest.json +91 -0
- package/src/theme/defaults/dark-reef.json +91 -0
- package/src/theme/defaults/dark-retro.json +92 -0
- package/src/theme/defaults/dark-rose-pine.json +96 -0
- package/src/theme/defaults/dark-sakura.json +95 -0
- package/src/theme/defaults/dark-slate.json +95 -0
- package/src/theme/defaults/dark-solarized.json +97 -0
- package/src/theme/defaults/dark-solstice.json +90 -0
- package/src/theme/defaults/dark-starfall.json +91 -0
- package/src/theme/defaults/dark-sunset.json +99 -0
- package/src/theme/defaults/dark-swamp.json +90 -0
- package/src/theme/defaults/dark-synthwave.json +103 -0
- package/src/theme/defaults/dark-taiga.json +91 -0
- package/src/theme/defaults/dark-terminal.json +95 -0
- package/src/theme/defaults/dark-tokyo-night.json +101 -0
- package/src/theme/defaults/dark-tundra.json +91 -0
- package/src/theme/defaults/dark-twilight.json +91 -0
- package/src/theme/defaults/dark-volcanic.json +91 -0
- package/src/theme/defaults/graphite.json +92 -0
- package/src/theme/defaults/index.ts +201 -0
- package/src/theme/defaults/light-arctic.json +107 -0
- package/src/theme/defaults/light-aurora-day.json +91 -0
- package/src/theme/defaults/light-canyon.json +91 -0
- package/src/theme/defaults/light-catppuccin.json +106 -0
- package/src/theme/defaults/light-cirrus.json +90 -0
- package/src/theme/defaults/light-coral.json +95 -0
- package/src/theme/defaults/light-cyberpunk.json +96 -0
- package/src/theme/defaults/light-dawn.json +90 -0
- package/src/theme/defaults/light-dunes.json +91 -0
- package/src/theme/defaults/light-eucalyptus.json +95 -0
- package/src/theme/defaults/light-forest.json +100 -0
- package/src/theme/defaults/light-frost.json +95 -0
- package/src/theme/defaults/light-github.json +115 -0
- package/src/theme/defaults/light-glacier.json +91 -0
- package/src/theme/defaults/light-gruvbox.json +108 -0
- package/src/theme/defaults/light-haze.json +90 -0
- package/src/theme/defaults/light-honeycomb.json +95 -0
- package/src/theme/defaults/light-lagoon.json +91 -0
- package/src/theme/defaults/light-lavender.json +95 -0
- package/src/theme/defaults/light-meadow.json +91 -0
- package/src/theme/defaults/light-mint.json +95 -0
- package/src/theme/defaults/light-monochrome.json +101 -0
- package/src/theme/defaults/light-ocean.json +99 -0
- package/src/theme/defaults/light-one.json +99 -0
- package/src/theme/defaults/light-opal.json +91 -0
- package/src/theme/defaults/light-orchard.json +91 -0
- package/src/theme/defaults/light-paper.json +95 -0
- package/src/theme/defaults/light-poimandres.json +115 -0
- package/src/theme/defaults/light-prism.json +90 -0
- package/src/theme/defaults/light-retro.json +98 -0
- package/src/theme/defaults/light-sand.json +95 -0
- package/src/theme/defaults/light-savanna.json +91 -0
- package/src/theme/defaults/light-solarized.json +102 -0
- package/src/theme/defaults/light-soleil.json +90 -0
- package/src/theme/defaults/light-sunset.json +99 -0
- package/src/theme/defaults/light-synthwave.json +98 -0
- package/src/theme/defaults/light-tokyo-night.json +111 -0
- package/src/theme/defaults/light-wetland.json +91 -0
- package/src/theme/defaults/light-zenith.json +89 -0
- package/src/theme/defaults/limestone.json +94 -0
- package/src/theme/defaults/mahogany.json +97 -0
- package/src/theme/defaults/marble.json +93 -0
- package/src/theme/defaults/obsidian.json +91 -0
- package/src/theme/defaults/onyx.json +91 -0
- package/src/theme/defaults/pearl.json +93 -0
- package/src/theme/defaults/porcelain.json +91 -0
- package/src/theme/defaults/quartz.json +96 -0
- package/src/theme/defaults/sandstone.json +95 -0
- package/src/theme/defaults/titanium.json +90 -0
- package/src/theme/index.ts +5 -0
- package/src/theme/light.json +93 -0
- package/src/theme/loader.ts +200 -0
- package/src/theme/mermaid-cache.ts +92 -0
- package/src/theme/schema-validation.ts +119 -0
- package/src/theme/schema.ts +168 -0
- package/src/theme/session-color.ts +253 -0
- package/src/theme/shimmer.ts +307 -0
- package/src/theme/symbols.ts +1433 -0
- package/src/theme/theme-class.ts +787 -0
- package/src/theme/theme-schema.json +463 -0
- package/src/theme/theme.ts +810 -0
- package/src/theme/tui-adapters.ts +339 -0
- package/src/thinking.ts +380 -0
- package/src/tools/agent-tree.ts +128 -0
- package/src/tools/ask.ts +482 -0
- package/src/tools/ast-edit.ts +210 -0
- package/src/tools/ast-grep.ts +171 -0
- package/src/tools/autoresearch.ts +287 -0
- package/src/tools/bash-interactive.ts +295 -0
- package/src/tools/bash.ts +468 -0
- package/src/tools/conflict-detect.ts +77 -0
- package/src/tools/debug.ts +167 -0
- package/src/tools/default-renderer.ts +172 -0
- package/src/tools/edit.ts +1258 -0
- package/src/tools/eval-format/code-mode-declarations.ts +61 -0
- package/src/tools/eval-format/index.ts +16 -0
- package/src/tools/eval-format/javascript.ts +952 -0
- package/src/tools/eval-format/python.ts +544 -0
- package/src/tools/eval.ts +835 -0
- package/src/tools/fetch.ts +226 -0
- package/src/tools/gh-format.ts +18 -0
- package/src/tools/github.ts +686 -0
- package/src/tools/glob.ts +213 -0
- package/src/tools/goal.ts +153 -0
- package/src/tools/grep.ts +385 -0
- package/src/tools/grouped-file-output.ts +211 -0
- package/src/tools/hashline-format.ts +59 -0
- package/src/tools/hub.ts +1488 -0
- package/src/tools/index.ts +71 -0
- package/src/tools/json-tree.ts +388 -0
- package/src/tools/line-ranges.ts +98 -0
- package/src/tools/list-limit.ts +43 -0
- package/src/tools/lsp.ts +702 -0
- package/src/tools/match-line-format.ts +20 -0
- package/src/tools/mcp.ts +309 -0
- package/src/tools/memory.ts +220 -0
- package/src/tools/output-meta.ts +367 -0
- package/src/tools/read.ts +628 -0
- package/src/tools/renderer.ts +107 -0
- package/src/tools/report-tool-issue.ts +13 -0
- package/src/tools/resolve.ts +139 -0
- package/src/tools/streaming-output.ts +1576 -0
- package/src/tools/subprocess.ts +39 -0
- package/src/tools/task-repair-args.ts +118 -0
- package/src/tools/task-yield-assembly.ts +147 -0
- package/src/tools/task.ts +2110 -0
- package/src/tools/terminal-output.ts +153 -0
- package/src/tools/think.ts +28 -0
- package/src/tools/todo.ts +580 -0
- package/src/tools/tool-errors.ts +15 -0
- package/src/tools/vibe.ts +420 -0
- package/src/tools/web-search.ts +409 -0
- package/src/tools/write.ts +511 -0
- package/src/tools/xd-url.ts +28 -0
- package/src/tools/xdev.ts +201 -0
- package/src/tui.ts +57 -4
- package/src/utils.ts +8 -0
package/src/tools/ask.ts
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import type { ToolRenderer } from "./renderer";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type Component,
|
|
5
|
+
Markdown,
|
|
6
|
+
type MarkdownTheme,
|
|
7
|
+
renderInlineMarkdown,
|
|
8
|
+
replaceTabs,
|
|
9
|
+
Text,
|
|
10
|
+
truncateToWidth,
|
|
11
|
+
visibleWidth,
|
|
12
|
+
} from "../index";
|
|
13
|
+
|
|
14
|
+
import type { RenderResultOptions } from "./renderer";
|
|
15
|
+
|
|
16
|
+
import { getMarkdownTheme, type Theme } from "../theme/theme";
|
|
17
|
+
|
|
18
|
+
import { outputBlockContentWidth, renderStatusLine } from "../render";
|
|
19
|
+
import { framedToolCard } from "../render/tool-card";
|
|
20
|
+
|
|
21
|
+
import { formatErrorMessage, formatMeta, formatTitle, sanitizeCarriageReturns } from "../render/render-utils";
|
|
22
|
+
|
|
23
|
+
/** Result for a single question */
|
|
24
|
+
export interface QuestionResult {
|
|
25
|
+
id: string;
|
|
26
|
+
question: string;
|
|
27
|
+
options: string[];
|
|
28
|
+
multi: boolean;
|
|
29
|
+
selectedOptions: string[];
|
|
30
|
+
customInput?: string;
|
|
31
|
+
/** Optional note attached to the selected answer in the rich ask dialog. */
|
|
32
|
+
note?: string;
|
|
33
|
+
/** True when the answer was auto-selected because the dialog timed out. */
|
|
34
|
+
timedOut?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Answers and redirect metadata displayed for an ask tool result. */
|
|
38
|
+
export interface AskToolDetails {
|
|
39
|
+
question?: string;
|
|
40
|
+
options?: string[];
|
|
41
|
+
multi?: boolean;
|
|
42
|
+
selectedOptions?: string[];
|
|
43
|
+
customInput?: string;
|
|
44
|
+
/** Optional note attached to the selected answer in the rich ask dialog. */
|
|
45
|
+
note?: string;
|
|
46
|
+
/** True when the answer was auto-selected because the dialog timed out. */
|
|
47
|
+
timedOut?: boolean;
|
|
48
|
+
/** Multi-part question mode */
|
|
49
|
+
results?: QuestionResult[];
|
|
50
|
+
/** Chat redirect: the user chose "Chat about this" instead of answering. */
|
|
51
|
+
chatRedirect?: boolean;
|
|
52
|
+
/** Questions surfaced when chatRedirect is true. */
|
|
53
|
+
questions?: string[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// =============================================================================
|
|
57
|
+
// TUI Renderer
|
|
58
|
+
// =============================================================================
|
|
59
|
+
|
|
60
|
+
interface AskRenderOption {
|
|
61
|
+
label: string;
|
|
62
|
+
description?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface AskRenderArgs {
|
|
66
|
+
question?: string;
|
|
67
|
+
options?: AskRenderOption[];
|
|
68
|
+
multi?: boolean;
|
|
69
|
+
questions?: Array<{
|
|
70
|
+
id: string;
|
|
71
|
+
question: string;
|
|
72
|
+
options: AskRenderOption[];
|
|
73
|
+
multi?: boolean;
|
|
74
|
+
}>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Coerce an untrusted option list (streamed or model-mangled call args) into
|
|
79
|
+
* well-formed render options. Bare strings become labels; entries without a
|
|
80
|
+
* string label are dropped.
|
|
81
|
+
*/
|
|
82
|
+
function normalizeRenderOptions(raw: unknown): AskRenderOption[] | undefined {
|
|
83
|
+
if (!Array.isArray(raw)) return undefined;
|
|
84
|
+
const out: AskRenderOption[] = [];
|
|
85
|
+
for (const entry of raw) {
|
|
86
|
+
if (typeof entry === "string") {
|
|
87
|
+
out.push({ label: sanitizeCarriageReturns(entry) });
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (!entry || typeof entry !== "object") continue;
|
|
91
|
+
const { label, description } = entry as Partial<AskRenderOption>;
|
|
92
|
+
if (typeof label !== "string") continue;
|
|
93
|
+
out.push(
|
|
94
|
+
typeof description === "string"
|
|
95
|
+
? { label: sanitizeCarriageReturns(label), description: sanitizeCarriageReturns(description) }
|
|
96
|
+
: { label: sanitizeCarriageReturns(label) },
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Strip the `\r` runs degenerate models inject from persisted result details,
|
|
104
|
+
* so transcripts completed before params sanitization still render as prose.
|
|
105
|
+
* Display-only — the persisted payload is untouched.
|
|
106
|
+
*/
|
|
107
|
+
function sanitizeAskResultDetails(details: AskToolDetails): AskToolDetails {
|
|
108
|
+
return {
|
|
109
|
+
...details,
|
|
110
|
+
...(details.question !== undefined ? { question: sanitizeCarriageReturns(details.question) } : {}),
|
|
111
|
+
...(details.options !== undefined ? { options: details.options.map(sanitizeCarriageReturns) } : {}),
|
|
112
|
+
...(details.selectedOptions !== undefined
|
|
113
|
+
? { selectedOptions: details.selectedOptions.map(sanitizeCarriageReturns) }
|
|
114
|
+
: {}),
|
|
115
|
+
...(details.customInput !== undefined ? { customInput: sanitizeCarriageReturns(details.customInput) } : {}),
|
|
116
|
+
...(details.note !== undefined ? { note: sanitizeCarriageReturns(details.note) } : {}),
|
|
117
|
+
...(details.questions !== undefined ? { questions: details.questions.map(sanitizeCarriageReturns) } : {}),
|
|
118
|
+
...(details.results !== undefined
|
|
119
|
+
? {
|
|
120
|
+
results: details.results.map(entry => ({
|
|
121
|
+
...entry,
|
|
122
|
+
id: sanitizeCarriageReturns(entry.id),
|
|
123
|
+
question: sanitizeCarriageReturns(entry.question),
|
|
124
|
+
options: entry.options.map(sanitizeCarriageReturns),
|
|
125
|
+
selectedOptions: entry.selectedOptions.map(sanitizeCarriageReturns),
|
|
126
|
+
...(entry.customInput !== undefined
|
|
127
|
+
? { customInput: sanitizeCarriageReturns(entry.customInput) }
|
|
128
|
+
: {}),
|
|
129
|
+
...(entry.note !== undefined ? { note: sanitizeCarriageReturns(entry.note) } : {}),
|
|
130
|
+
})),
|
|
131
|
+
}
|
|
132
|
+
: {}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Coerce untrusted `questions` call args into a renderable array. Models
|
|
138
|
+
* occasionally double-encode the array as a JSON string — a bare string passes
|
|
139
|
+
* a truthy `.length` check but has no `.map`, which used to crash the TUI
|
|
140
|
+
* render loop. Partially streamed args can also be missing fields.
|
|
141
|
+
*/
|
|
142
|
+
function normalizeRenderQuestions(raw: unknown): NonNullable<AskRenderArgs["questions"]> | undefined {
|
|
143
|
+
if (typeof raw === "string") {
|
|
144
|
+
try {
|
|
145
|
+
raw = JSON.parse(raw);
|
|
146
|
+
} catch {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (!Array.isArray(raw)) return undefined;
|
|
151
|
+
const out: NonNullable<AskRenderArgs["questions"]> = [];
|
|
152
|
+
for (const entry of raw) {
|
|
153
|
+
if (!entry || typeof entry !== "object") continue;
|
|
154
|
+
const q = entry as Partial<NonNullable<AskRenderArgs["questions"]>[number]>;
|
|
155
|
+
out.push({
|
|
156
|
+
id: typeof q.id === "string" ? sanitizeCarriageReturns(q.id) : "?",
|
|
157
|
+
question: typeof q.question === "string" ? sanitizeCarriageReturns(q.question) : "",
|
|
158
|
+
options: normalizeRenderOptions(q.options) ?? [],
|
|
159
|
+
multi: q.multi === true,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Render a custom free-text answer as a status line plus indented continuation rows. */
|
|
166
|
+
function renderCustomInputLines(uiTheme: Theme, customInput: string): string[] {
|
|
167
|
+
const lines = customInput.split("\n");
|
|
168
|
+
const out: string[] = [
|
|
169
|
+
` ${uiTheme.styledSymbol("status.success", "success")} ${uiTheme.fg("toolOutput", lines[0] ?? "")}`,
|
|
170
|
+
];
|
|
171
|
+
for (let i = 1; i < lines.length; i++) out.push(` ${uiTheme.fg("toolOutput", lines[i])}`);
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Render an answer note with tab replacement and line-width clamping. */
|
|
176
|
+
function renderNoteLines(uiTheme: Theme, note: string, width: number): string[] {
|
|
177
|
+
const prefix = " Note: ";
|
|
178
|
+
const continuationPrefix = " ";
|
|
179
|
+
const firstLineWidth = Math.max(1, width - visibleWidth(prefix));
|
|
180
|
+
const continuationWidth = Math.max(1, width - visibleWidth(continuationPrefix));
|
|
181
|
+
return replaceTabs(note)
|
|
182
|
+
.split("\n")
|
|
183
|
+
.map((line, index) => {
|
|
184
|
+
const linePrefix = index === 0 ? `${uiTheme.fg("dim", " Note:")} ` : continuationPrefix;
|
|
185
|
+
const maxWidth = index === 0 ? firstLineWidth : continuationWidth;
|
|
186
|
+
return `${linePrefix}${uiTheme.fg("toolOutput", truncateToWidth(line, maxWidth))}`;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Marker glyph for a question option. Single-choice questions render circular radio
|
|
192
|
+
* buttons (pick one); multi-select questions render rectangular checkboxes (pick many).
|
|
193
|
+
*/
|
|
194
|
+
export function optionMarker(uiTheme: Theme, multi: boolean | undefined, selected: boolean): string {
|
|
195
|
+
if (multi) return selected ? uiTheme.checkbox.checked : uiTheme.checkbox.unchecked;
|
|
196
|
+
return selected ? uiTheme.radio.selected : uiTheme.radio.unselected;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Render the offered options for a question form as flat marker bullets (no tree guides). */
|
|
200
|
+
function renderQuestionOptionLines(
|
|
201
|
+
uiTheme: Theme,
|
|
202
|
+
mdTheme: MarkdownTheme,
|
|
203
|
+
options: AskRenderOption[],
|
|
204
|
+
multi: boolean | undefined,
|
|
205
|
+
): string[] {
|
|
206
|
+
const out: string[] = [];
|
|
207
|
+
for (const opt of options) {
|
|
208
|
+
const optLabel = renderInlineMarkdown(opt.label, mdTheme, t => uiTheme.fg("muted", t));
|
|
209
|
+
out.push(` ${uiTheme.fg("dim", optionMarker(uiTheme, multi, false))} ${optLabel}`);
|
|
210
|
+
if (opt.description?.trim()) {
|
|
211
|
+
const description = renderInlineMarkdown(opt.description.trim(), mdTheme, t => uiTheme.fg("dim", t));
|
|
212
|
+
out.push(` ${uiTheme.fg("dim", "↳")} ${description}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return out;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Resolve selected labels to option indices against the RAW persisted labels.
|
|
220
|
+
* Sanitizing can merge distinct options (`Retry\rnow`/`Retry now`) into one
|
|
221
|
+
* display label, after which a label set would mark every colliding row —
|
|
222
|
+
* indices survive normalization because it preserves order and length.
|
|
223
|
+
* Every option exactly matching a selected label is marked: the legacy
|
|
224
|
+
* selector recorded a single occurrence for duplicate rows it marked
|
|
225
|
+
* together, while the rich dialog recorded one entry per row, and both
|
|
226
|
+
* shapes must replay as originally shown.
|
|
227
|
+
* Returns undefined when raw options are missing so the caller falls back to
|
|
228
|
+
* label matching.
|
|
229
|
+
*/
|
|
230
|
+
function selectedIndicesFor(
|
|
231
|
+
rawOptions: string[] | undefined,
|
|
232
|
+
rawSelected: string[] | undefined,
|
|
233
|
+
): Set<number> | undefined {
|
|
234
|
+
if (!rawOptions || rawOptions.length === 0) return undefined;
|
|
235
|
+
const wanted = new Set(rawSelected ?? []);
|
|
236
|
+
const indices = new Set<number>();
|
|
237
|
+
rawOptions.forEach((option, index) => {
|
|
238
|
+
if (wanted.has(option)) indices.add(index);
|
|
239
|
+
});
|
|
240
|
+
return indices;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Render the answered option list for a question: every offered option with its
|
|
245
|
+
* selection marker filled in, plus any custom free-text answer. Flat marker
|
|
246
|
+
* bullets — the frame is the container, so no tree guides are drawn.
|
|
247
|
+
*/
|
|
248
|
+
function renderAnswerOptionLines(
|
|
249
|
+
uiTheme: Theme,
|
|
250
|
+
mdTheme: MarkdownTheme,
|
|
251
|
+
options: string[] | undefined,
|
|
252
|
+
selectedOptions: string[] | undefined,
|
|
253
|
+
multi: boolean | undefined,
|
|
254
|
+
customInput: string | undefined,
|
|
255
|
+
note: string | undefined,
|
|
256
|
+
width: number,
|
|
257
|
+
selectedIndices?: ReadonlySet<number>,
|
|
258
|
+
): string[] {
|
|
259
|
+
const selected = new Set(selectedOptions ?? []);
|
|
260
|
+
// Prefer the full recorded option set; fall back to the selected labels when
|
|
261
|
+
// details omit the options array.
|
|
262
|
+
const list = options && options.length > 0 ? options : (selectedOptions ?? []);
|
|
263
|
+
|
|
264
|
+
// Nothing was chosen (and no custom answer) → a lone cancelled marker.
|
|
265
|
+
if (selected.size === 0 && customInput === undefined && note === undefined) {
|
|
266
|
+
return [` ${uiTheme.styledSymbol("status.warning", "warning")} ${uiTheme.fg("warning", "Cancelled")}`];
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const out: string[] = [];
|
|
270
|
+
for (const [index, label] of list.entries()) {
|
|
271
|
+
const isSelected = selectedIndices !== undefined ? selectedIndices.has(index) : selected.has(label);
|
|
272
|
+
const marker = optionMarker(uiTheme, multi, isSelected);
|
|
273
|
+
const markerStyled = isSelected ? uiTheme.fg("success", marker) : uiTheme.fg("dim", marker);
|
|
274
|
+
const labelStyled = renderInlineMarkdown(label, mdTheme, t =>
|
|
275
|
+
isSelected ? uiTheme.fg("toolOutput", t) : uiTheme.fg("muted", t),
|
|
276
|
+
);
|
|
277
|
+
out.push(` ${markerStyled} ${labelStyled}`);
|
|
278
|
+
}
|
|
279
|
+
if (customInput !== undefined) out.push(...renderCustomInputLines(uiTheme, customInput));
|
|
280
|
+
if (note !== undefined) out.push(...renderNoteLines(uiTheme, note, width));
|
|
281
|
+
return out;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Render question forms and their recorded answers. */
|
|
285
|
+
export const askToolRenderer = {
|
|
286
|
+
mergeCallAndResult: true,
|
|
287
|
+
renderCall(args: AskRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
|
|
288
|
+
const label = formatTitle("Ask", uiTheme);
|
|
289
|
+
const mdTheme = getMarkdownTheme();
|
|
290
|
+
const accentStyle = { color: (t: string) => uiTheme.fg("accent", t) };
|
|
291
|
+
const md = (text: string, width: number) =>
|
|
292
|
+
new Markdown(text, 1, 0, mdTheme, accentStyle).render(Math.max(1, outputBlockContentWidth(width) + 1));
|
|
293
|
+
|
|
294
|
+
// Multi-part questions: one divider-labelled section per question.
|
|
295
|
+
// Call args are untrusted (partially streamed or model-mangled) and a
|
|
296
|
+
// throw here takes down the whole TUI render loop — normalize first.
|
|
297
|
+
const questions = normalizeRenderQuestions(args.questions);
|
|
298
|
+
if (questions && questions.length > 0) {
|
|
299
|
+
const header = `${label} ${uiTheme.fg("muted", `${questions.length} questions`)}`;
|
|
300
|
+
return framedToolCard(uiTheme, ({ width }) => {
|
|
301
|
+
const sections = questions.map(q => {
|
|
302
|
+
const meta: string[] = [];
|
|
303
|
+
if (q.multi) meta.push("multi");
|
|
304
|
+
if (q.options?.length) meta.push(`options:${q.options.length}`);
|
|
305
|
+
const metaStr = meta.length > 0 ? uiTheme.fg("dim", ` · ${meta.join(" · ")}`) : "";
|
|
306
|
+
// md() returns a shared cached array (module-level Markdown LRU) — copy before appending.
|
|
307
|
+
const mdLines = md(q.question, width);
|
|
308
|
+
const lines = q.options?.length
|
|
309
|
+
? [...mdLines, ...renderQuestionOptionLines(uiTheme, mdTheme, q.options, q.multi)]
|
|
310
|
+
: mdLines;
|
|
311
|
+
return { label: `${uiTheme.fg("dim", `[${q.id}]`)}${metaStr}`, content: lines };
|
|
312
|
+
});
|
|
313
|
+
return { header, sections, phase: "pending", borderColor: "borderMuted" };
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Single question
|
|
318
|
+
if (typeof args.question !== "string" || !args.question) {
|
|
319
|
+
const errorLine = formatErrorMessage("No question provided", uiTheme);
|
|
320
|
+
return framedToolCard(uiTheme, () => ({
|
|
321
|
+
header: errorLine,
|
|
322
|
+
sections: [],
|
|
323
|
+
phase: "error",
|
|
324
|
+
borderColor: "error",
|
|
325
|
+
}));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const question = sanitizeCarriageReturns(args.question);
|
|
329
|
+
const meta: string[] = [];
|
|
330
|
+
if (args.multi) meta.push("multi");
|
|
331
|
+
const questionOptions = normalizeRenderOptions(args.options);
|
|
332
|
+
if (questionOptions?.length) meta.push(`options:${questionOptions.length}`);
|
|
333
|
+
const header = `${label}${formatMeta(meta, uiTheme)}`;
|
|
334
|
+
const multi = args.multi;
|
|
335
|
+
return framedToolCard(uiTheme, ({ width }) => {
|
|
336
|
+
// md() returns a shared cached array (module-level Markdown LRU) — copy before appending.
|
|
337
|
+
const mdLines = md(question, width);
|
|
338
|
+
const bodyLines = questionOptions?.length
|
|
339
|
+
? [...mdLines, ...renderQuestionOptionLines(uiTheme, mdTheme, questionOptions, multi)]
|
|
340
|
+
: mdLines;
|
|
341
|
+
return {
|
|
342
|
+
header,
|
|
343
|
+
sections: bodyLines.length > 0 ? [{ content: bodyLines }] : [],
|
|
344
|
+
phase: "pending",
|
|
345
|
+
borderColor: "borderMuted",
|
|
346
|
+
};
|
|
347
|
+
});
|
|
348
|
+
},
|
|
349
|
+
|
|
350
|
+
renderResult(
|
|
351
|
+
result: { content: Array<{ type: string; text?: string }>; details?: AskToolDetails },
|
|
352
|
+
_options: RenderResultOptions,
|
|
353
|
+
uiTheme: Theme,
|
|
354
|
+
): Component {
|
|
355
|
+
const rawDetails = result.details;
|
|
356
|
+
const mdTheme = getMarkdownTheme();
|
|
357
|
+
const accentStyle = { color: (t: string) => uiTheme.fg("accent", t) };
|
|
358
|
+
const md = (text: string, width: number) =>
|
|
359
|
+
new Markdown(text, 1, 0, mdTheme, accentStyle).render(Math.max(1, outputBlockContentWidth(width) + 1));
|
|
360
|
+
|
|
361
|
+
if (!rawDetails) {
|
|
362
|
+
const txt = result.content[0];
|
|
363
|
+
const fallback = txt?.type === "text" && txt.text ? sanitizeCarriageReturns(txt.text) : "";
|
|
364
|
+
const header = renderStatusLine({ icon: "warning", title: "Ask" }, uiTheme);
|
|
365
|
+
const body = fallback ? `\n${uiTheme.fg("dim", fallback)}` : "";
|
|
366
|
+
return new Text(`${header}${body}`, 0, 0);
|
|
367
|
+
}
|
|
368
|
+
const details = sanitizeAskResultDetails(rawDetails);
|
|
369
|
+
|
|
370
|
+
// Chat redirect: user chose "Chat about this" instead of answering.
|
|
371
|
+
if (details.chatRedirect) {
|
|
372
|
+
const header = renderStatusLine({ icon: "info", title: "Ask", meta: ["chat redirect"] }, uiTheme);
|
|
373
|
+
const questions = details.questions ?? [];
|
|
374
|
+
return framedToolCard(uiTheme, ({ width }) => ({
|
|
375
|
+
header,
|
|
376
|
+
sections: questions.length > 0 ? [{ content: questions.flatMap(q => md(q, width)) }] : [],
|
|
377
|
+
phase: "warning",
|
|
378
|
+
borderColor: "borderMuted",
|
|
379
|
+
}));
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Multi-part results: one divider-labelled section per question.
|
|
383
|
+
if (details.results && details.results.length > 0) {
|
|
384
|
+
const results = details.results;
|
|
385
|
+
const hasAnySelection = results.some(
|
|
386
|
+
r =>
|
|
387
|
+
r.customInput !== undefined ||
|
|
388
|
+
r.note !== undefined ||
|
|
389
|
+
(r.selectedOptions && r.selectedOptions.length > 0),
|
|
390
|
+
);
|
|
391
|
+
const header = renderStatusLine(
|
|
392
|
+
{
|
|
393
|
+
icon: hasAnySelection ? "success" : "warning",
|
|
394
|
+
title: "Ask",
|
|
395
|
+
meta: [`${results.length} questions`],
|
|
396
|
+
},
|
|
397
|
+
uiTheme,
|
|
398
|
+
);
|
|
399
|
+
return framedToolCard(uiTheme, ({ width }) => {
|
|
400
|
+
const rawResults = rawDetails.results ?? [];
|
|
401
|
+
const sections = results.map((r, index) => {
|
|
402
|
+
// Sanitizing preserves order and length, so raw indices align with `r`.
|
|
403
|
+
const raw = rawResults[index];
|
|
404
|
+
// md() returns a shared cached array (module-level Markdown LRU) — copy before appending.
|
|
405
|
+
const lines = [
|
|
406
|
+
...md(r.question, width),
|
|
407
|
+
...renderAnswerOptionLines(
|
|
408
|
+
uiTheme,
|
|
409
|
+
mdTheme,
|
|
410
|
+
r.options,
|
|
411
|
+
r.selectedOptions,
|
|
412
|
+
r.multi,
|
|
413
|
+
r.customInput,
|
|
414
|
+
r.note,
|
|
415
|
+
width,
|
|
416
|
+
selectedIndicesFor(raw?.options, raw?.selectedOptions),
|
|
417
|
+
),
|
|
418
|
+
];
|
|
419
|
+
return { label: uiTheme.fg("dim", `[${r.id}]`), content: lines };
|
|
420
|
+
});
|
|
421
|
+
return {
|
|
422
|
+
header,
|
|
423
|
+
sections,
|
|
424
|
+
phase: hasAnySelection ? "success" : "warning",
|
|
425
|
+
borderColor: "borderMuted",
|
|
426
|
+
};
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Single question result
|
|
431
|
+
if (!details.question) {
|
|
432
|
+
const txt = result.content[0];
|
|
433
|
+
const fallback = txt?.type === "text" && txt.text ? sanitizeCarriageReturns(txt.text) : "";
|
|
434
|
+
return new Text(fallback, 0, 0);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const question = details.question;
|
|
438
|
+
const hasSelection =
|
|
439
|
+
details.customInput !== undefined ||
|
|
440
|
+
details.note !== undefined ||
|
|
441
|
+
(details.selectedOptions && details.selectedOptions.length > 0);
|
|
442
|
+
const header = renderStatusLine(
|
|
443
|
+
hasSelection
|
|
444
|
+
? { iconOverride: uiTheme.styledSymbol("tool.ask", "accent"), title: "Ask" }
|
|
445
|
+
: { icon: "warning", title: "Ask" },
|
|
446
|
+
uiTheme,
|
|
447
|
+
);
|
|
448
|
+
const dOptions = details.options;
|
|
449
|
+
const dSelected = details.selectedOptions;
|
|
450
|
+
const dMulti = details.multi;
|
|
451
|
+
const dCustom = details.customInput;
|
|
452
|
+
const dNote = details.note;
|
|
453
|
+
const dTimedOut = details.timedOut;
|
|
454
|
+
return framedToolCard(uiTheme, ({ width }) => {
|
|
455
|
+
// md() returns a shared cached array (module-level Markdown LRU) — copy before appending.
|
|
456
|
+
const bodyLines = [
|
|
457
|
+
...md(question, width),
|
|
458
|
+
...renderAnswerOptionLines(
|
|
459
|
+
uiTheme,
|
|
460
|
+
mdTheme,
|
|
461
|
+
dOptions,
|
|
462
|
+
dSelected,
|
|
463
|
+
dMulti,
|
|
464
|
+
dCustom,
|
|
465
|
+
dNote,
|
|
466
|
+
width,
|
|
467
|
+
selectedIndicesFor(rawDetails.options, rawDetails.selectedOptions),
|
|
468
|
+
),
|
|
469
|
+
];
|
|
470
|
+
if (dTimedOut) {
|
|
471
|
+
// Distinguish auto-selection from a real user choice in the transcript.
|
|
472
|
+
bodyLines.push(uiTheme.fg("dim", "auto-selected after timeout — not a user choice"));
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
header,
|
|
476
|
+
sections: bodyLines.length > 0 ? [{ content: bodyLines }] : [],
|
|
477
|
+
phase: hasSelection ? "success" : "warning",
|
|
478
|
+
borderColor: "borderMuted",
|
|
479
|
+
};
|
|
480
|
+
});
|
|
481
|
+
},
|
|
482
|
+
} satisfies ToolRenderer<AskRenderArgs, AskToolDetails>;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type { Component } from "../tui";
|
|
2
|
+
import { Text } from "../components/text";
|
|
3
|
+
import { replaceTabs } from "../utils";
|
|
4
|
+
import type { Theme } from "../theme/theme";
|
|
5
|
+
import { Ellipsis, fileHyperlink, renderStatusLine, truncateToWidth } from "../render";
|
|
6
|
+
import { framedToolCard } from "../render/tool-card";
|
|
7
|
+
import {
|
|
8
|
+
appendParseErrorsBulletList,
|
|
9
|
+
formatCount,
|
|
10
|
+
formatErrorDetail,
|
|
11
|
+
formatMoreItems,
|
|
12
|
+
formatParseErrorsCountLabel,
|
|
13
|
+
PREVIEW_LIMITS,
|
|
14
|
+
} from "../render/render-utils";
|
|
15
|
+
import { classifyGroupedLines, groupLineIndicesByBlank } from "./grouped-file-output";
|
|
16
|
+
import type { OutputMeta } from "./output-meta";
|
|
17
|
+
import type { RenderResultOptions, ToolRenderer } from "./renderer";
|
|
18
|
+
|
|
19
|
+
/** Display metadata returned by ast-edit. */
|
|
20
|
+
export interface AstEditToolDetails {
|
|
21
|
+
totalReplacements: number;
|
|
22
|
+
filesTouched: number;
|
|
23
|
+
filesSearched: number;
|
|
24
|
+
applied: boolean;
|
|
25
|
+
limitReached: boolean;
|
|
26
|
+
parseErrors?: string[];
|
|
27
|
+
/** Total parse error count before {@link PARSE_ERRORS_LIMIT} capping. Omitted when no errors. */
|
|
28
|
+
parseErrorsTotal?: number;
|
|
29
|
+
scopePath?: string;
|
|
30
|
+
files?: string[];
|
|
31
|
+
fileReplacements?: Array<{ path: string; count: number }>;
|
|
32
|
+
meta?: OutputMeta;
|
|
33
|
+
/** Pre-formatted text for the user-visible TUI render. Mirrors `result.text` lines but uses
|
|
34
|
+
* a `│` gutter (no model-only hashline anchors). The TUI uses this directly so it never parses model-facing text. */
|
|
35
|
+
displayContent?: string;
|
|
36
|
+
/** Absolute base directory used during the edit. Used by the renderer to resolve
|
|
37
|
+
* display-relative paths to absolute paths for OSC 8 hyperlinks. */
|
|
38
|
+
searchPath?: string;
|
|
39
|
+
/** Session cwd at edit time. Display header paths are cwd-relative, so the
|
|
40
|
+
* renderer resolves them against this; `searchPath` is the scope target. */
|
|
41
|
+
cwd?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface AstEditRenderArgs {
|
|
45
|
+
ops?: Array<{ pat?: string; out?: string }>;
|
|
46
|
+
paths?: string[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const COLLAPSED_CHANGE_LIMIT = PREVIEW_LIMITS.COLLAPSED_LINES * 2;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Flatten pre-styled change groups into frame body lines. Groups are separated
|
|
53
|
+
* by a blank line and carry no tree guides — the frame border is the container,
|
|
54
|
+
* so nested `├─ │` gutters would just be noise. Collapsed mode always shows at
|
|
55
|
+
* least the first group, then fills up to `budget` lines before summarizing the
|
|
56
|
+
* rest as `… N more changes`.
|
|
57
|
+
*/
|
|
58
|
+
function buildChangeBody(groups: string[][], expanded: boolean, budget: number, theme: Theme): string[] {
|
|
59
|
+
const lines: string[] = [];
|
|
60
|
+
let shown = 0;
|
|
61
|
+
for (let i = 0; i < groups.length; i++) {
|
|
62
|
+
const group = groups[i]!;
|
|
63
|
+
const separator = shown > 0 ? 1 : 0;
|
|
64
|
+
const remainingAfter = groups.length - (i + 1);
|
|
65
|
+
const reserved = !expanded && remainingAfter > 0 ? 1 : 0;
|
|
66
|
+
// Always emit the first group; budget only gates subsequent ones.
|
|
67
|
+
if (!expanded && shown > 0 && lines.length + separator + group.length + reserved > budget) break;
|
|
68
|
+
if (separator) lines.push("");
|
|
69
|
+
lines.push(...group);
|
|
70
|
+
shown++;
|
|
71
|
+
}
|
|
72
|
+
const remaining = groups.length - shown;
|
|
73
|
+
if (!expanded && remaining > 0) lines.push(theme.fg("muted", formatMoreItems(remaining, "change")));
|
|
74
|
+
return lines;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** One-line header preview of an AST pattern. `renderStatusLine` only flattens
|
|
78
|
+
* CR/LF, so a multi-line tab-indented pattern would otherwise punch raw tabs
|
|
79
|
+
* into the status line; collapse all whitespace runs to single spaces. */
|
|
80
|
+
function patternPreview(pat: string | undefined): string | undefined {
|
|
81
|
+
const collapsed = pat?.replace(/\s+/g, " ").trim();
|
|
82
|
+
return collapsed || undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Render AST edit calls and results. */
|
|
86
|
+
export const astEditToolRenderer = {
|
|
87
|
+
inline: true,
|
|
88
|
+
renderCall(args: AstEditRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
|
|
89
|
+
const meta: string[] = [];
|
|
90
|
+
if (args.paths?.length) meta.push(`in ${args.paths.join(", ")}`);
|
|
91
|
+
const rewriteCount = args.ops?.length ?? 0;
|
|
92
|
+
if (rewriteCount > 1) meta.push(`${rewriteCount} rewrites`);
|
|
93
|
+
|
|
94
|
+
const description =
|
|
95
|
+
rewriteCount === 1 ? patternPreview(args.ops?.[0]?.pat) : rewriteCount ? `${rewriteCount} rewrites` : "?";
|
|
96
|
+
const header = renderStatusLine({ icon: "pending", title: "AST Edit", description, meta }, uiTheme);
|
|
97
|
+
// Pending call has no body yet — a lone status line is sleeker than an empty frame.
|
|
98
|
+
return new Text(header, 0, 0);
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
renderResult(
|
|
102
|
+
result: { content: Array<{ type: string; text?: string }>; details?: AstEditToolDetails; isError?: boolean },
|
|
103
|
+
options: RenderResultOptions,
|
|
104
|
+
uiTheme: Theme,
|
|
105
|
+
args?: AstEditRenderArgs,
|
|
106
|
+
): Component {
|
|
107
|
+
const details = result.details;
|
|
108
|
+
|
|
109
|
+
if (result.isError) {
|
|
110
|
+
const errorText = result.content?.find(c => c.type === "text")?.text || "Unknown error";
|
|
111
|
+
const header = renderStatusLine({ icon: "error", title: "AST Edit" }, uiTheme);
|
|
112
|
+
return framedToolCard(uiTheme, () => ({
|
|
113
|
+
header,
|
|
114
|
+
sections: [{ content: formatErrorDetail(errorText, uiTheme).split("\n") }],
|
|
115
|
+
phase: "error",
|
|
116
|
+
borderColor: "error",
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const totalReplacements = details?.totalReplacements ?? 0;
|
|
121
|
+
const filesTouched = details?.filesTouched ?? 0;
|
|
122
|
+
const filesSearched = details?.filesSearched ?? 0;
|
|
123
|
+
const limitReached = details?.limitReached ?? false;
|
|
124
|
+
|
|
125
|
+
if (totalReplacements === 0) {
|
|
126
|
+
const rewriteCount = args?.ops?.length ?? 0;
|
|
127
|
+
const description = rewriteCount === 1 ? patternPreview(args?.ops?.[0]?.pat) : undefined;
|
|
128
|
+
const meta = ["0 replacements"];
|
|
129
|
+
if (details?.scopePath) meta.push(`in ${details.scopePath}`);
|
|
130
|
+
if (filesSearched > 0) meta.push(`searched ${filesSearched}`);
|
|
131
|
+
const header = renderStatusLine({ icon: "warning", title: "AST Edit", description, meta }, uiTheme);
|
|
132
|
+
// The "0 replacements" count already rides on the status line; only parse
|
|
133
|
+
// errors are worth a body, so frame solely when there are some.
|
|
134
|
+
const bodyLines: string[] = [];
|
|
135
|
+
appendParseErrorsBulletList(bodyLines, details?.parseErrors, uiTheme, details?.parseErrorsTotal);
|
|
136
|
+
if (bodyLines.length === 0) return new Text(header, 0, 0);
|
|
137
|
+
return framedToolCard(uiTheme, () => ({
|
|
138
|
+
header,
|
|
139
|
+
sections: [{ content: bodyLines }],
|
|
140
|
+
phase: "warning",
|
|
141
|
+
borderColor: "borderMuted",
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const summaryParts = [formatCount("replacement", totalReplacements), formatCount("file", filesTouched)];
|
|
146
|
+
const meta = [...summaryParts];
|
|
147
|
+
if (details?.scopePath) meta.push(`in ${details.scopePath}`);
|
|
148
|
+
meta.push(`searched ${filesSearched}`);
|
|
149
|
+
if (limitReached) meta.push(uiTheme.fg("warning", "limit reached"));
|
|
150
|
+
const rewriteCount = args?.ops?.length ?? 0;
|
|
151
|
+
const description = rewriteCount === 1 ? patternPreview(args?.ops?.[0]?.pat) : undefined;
|
|
152
|
+
|
|
153
|
+
const textContent = result.details?.displayContent ?? result.content?.find(c => c.type === "text")?.text ?? "";
|
|
154
|
+
const allLines = textContent.split("\n");
|
|
155
|
+
// Resolve hyperlinks over the whole output so nested directory headers
|
|
156
|
+
// reconstruct across the blank-line groups the tree list collapses by.
|
|
157
|
+
const contexts = classifyGroupedLines(allLines, details?.cwd ?? details?.searchPath, details?.searchPath);
|
|
158
|
+
const styledLines = allLines.map((line, index) => {
|
|
159
|
+
const ctx = contexts[index]!;
|
|
160
|
+
// Swap the inner code-frame gutter `│` for a space so it does not nest a
|
|
161
|
+
// second vertical bar inside the frame border.
|
|
162
|
+
const display = replaceTabs(line.replace("│", " "));
|
|
163
|
+
if (ctx.kind === "dir") {
|
|
164
|
+
const styled = uiTheme.fg("accent", display);
|
|
165
|
+
return ctx.headerPath ? fileHyperlink(ctx.headerPath, styled) : styled;
|
|
166
|
+
}
|
|
167
|
+
if (ctx.kind === "file") {
|
|
168
|
+
const styled = uiTheme.fg(ctx.depth === 1 ? "accent" : "dim", display);
|
|
169
|
+
return ctx.headerPath ? fileHyperlink(ctx.headerPath, styled) : styled;
|
|
170
|
+
}
|
|
171
|
+
if (display.startsWith("+")) return uiTheme.fg("toolDiffAdded", display);
|
|
172
|
+
if (display.startsWith("-")) return uiTheme.fg("toolDiffRemoved", display);
|
|
173
|
+
return uiTheme.fg("toolOutput", display);
|
|
174
|
+
});
|
|
175
|
+
const changeGroups = groupLineIndicesByBlank(allLines)
|
|
176
|
+
.filter(indices => {
|
|
177
|
+
const first = allLines[indices[0]!]!;
|
|
178
|
+
return !first.startsWith("Safety cap reached") && !first.startsWith("Parse issues:");
|
|
179
|
+
})
|
|
180
|
+
.map(indices => indices.map(index => styledLines[index]!));
|
|
181
|
+
|
|
182
|
+
const badge = { label: "proposed", color: "warning" as const };
|
|
183
|
+
const header = renderStatusLine(
|
|
184
|
+
{ icon: limitReached ? "warning" : "success", title: "AST Edit", description, badge, meta },
|
|
185
|
+
uiTheme,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const extraLines: string[] = [];
|
|
189
|
+
if (limitReached) {
|
|
190
|
+
extraLines.push(uiTheme.fg("warning", "limit reached; narrow path"));
|
|
191
|
+
}
|
|
192
|
+
if (details?.parseErrors?.length) {
|
|
193
|
+
extraLines.push(
|
|
194
|
+
uiTheme.fg("warning", formatParseErrorsCountLabel(details.parseErrors, details.parseErrorsTotal)),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
return framedToolCard(uiTheme, ({ contentWidth }) => {
|
|
198
|
+
const changeLines = buildChangeBody(changeGroups, Boolean(options.expanded), COLLAPSED_CHANGE_LIMIT, uiTheme);
|
|
199
|
+
const bodyLines = [...changeLines, ...extraLines].map(l => truncateToWidth(l, contentWidth, Ellipsis.Omit));
|
|
200
|
+
while (bodyLines.length > 0 && bodyLines[0].trim() === "") bodyLines.shift();
|
|
201
|
+
return {
|
|
202
|
+
header,
|
|
203
|
+
sections: bodyLines.length > 0 ? [{ content: bodyLines }] : [],
|
|
204
|
+
phase: options.isPartial ? "partial" : "success",
|
|
205
|
+
borderColor: "borderMuted",
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
mergeCallAndResult: true,
|
|
210
|
+
} satisfies ToolRenderer<AstEditRenderArgs, AstEditToolDetails>;
|