@oh-my-pi/pi-tui 18.4.3 → 18.4.4
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 +36 -0
- package/dist/types/apps/cleanse-board.d.ts +17 -0
- package/dist/types/apps/git/help.d.ts +16 -0
- package/dist/types/apps/git/sidebar.d.ts +18 -0
- package/dist/types/apps/live-visualizer.d.ts +10 -0
- package/dist/types/apps/ps-top.d.ts +15 -0
- package/dist/types/apps/standalone-picker.d.ts +3 -0
- package/dist/types/autocomplete.d.ts +8 -0
- package/dist/types/chat/advisor-message.d.ts +12 -2
- package/dist/types/chat/assistant-message.d.ts +20 -0
- package/dist/types/chat/bash-execution.d.ts +9 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +6 -1
- package/dist/types/chat/collab-prompt-message.d.ts +4 -0
- package/dist/types/chat/compaction-summary-message.d.ts +15 -0
- package/dist/types/chat/eval-execution.d.ts +8 -0
- package/dist/types/chat/execution-shared.d.ts +58 -0
- package/dist/types/chat/late-diagnostics-message.d.ts +15 -1
- package/dist/types/chat/read-tool-group.d.ts +15 -0
- package/dist/types/chat/skill-message.d.ts +9 -0
- package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +3 -0
- package/dist/types/chat/todo-reminder.d.ts +4 -1
- package/dist/types/chat/tool-execution.d.ts +25 -1
- package/dist/types/chat/transcript-actions.d.ts +37 -0
- package/dist/types/chat/transcript-entry.d.ts +3 -1
- package/dist/types/chat/user-message.d.ts +25 -0
- package/dist/types/chrome/collab-qrcode.d.ts +7 -0
- package/dist/types/chrome/context-thresholds.d.ts +11 -0
- package/dist/types/chrome/countdown-timer.d.ts +9 -3
- package/dist/types/chrome/diff.d.ts +12 -0
- package/dist/types/chrome/dynamic-border.d.ts +3 -0
- package/dist/types/chrome/format.d.ts +6 -0
- package/dist/types/chrome/message-divider.d.ts +13 -0
- package/dist/types/chrome/message-frame.d.ts +10 -0
- package/dist/types/chrome/message-notice.d.ts +23 -0
- package/dist/types/chrome/overlay-box.d.ts +11 -2
- package/dist/types/chrome/qrcode.d.ts +7 -0
- package/dist/types/chrome/segment-track.d.ts +7 -0
- package/dist/types/chrome/selector-helpers.d.ts +0 -6
- package/dist/types/chrome/status-notice.d.ts +14 -0
- package/dist/types/chrome/streaming-panel.d.ts +3 -0
- package/dist/types/chrome/tool-activity.d.ts +3 -0
- package/dist/types/chrome/transcript-container.d.ts +13 -0
- package/dist/types/chrome/transcript-status.d.ts +15 -3
- package/dist/types/components/box.d.ts +7 -0
- package/dist/types/components/disclosure.d.ts +9 -0
- package/dist/types/components/editor.d.ts +37 -0
- package/dist/types/components/form.d.ts +14 -0
- package/dist/types/components/image.d.ts +7 -0
- package/dist/types/components/input.d.ts +20 -1
- package/dist/types/components/key-value-list.d.ts +3 -0
- package/dist/types/components/layout/geometry.d.ts +16 -0
- package/dist/types/components/layout/row.d.ts +7 -0
- package/dist/types/components/layout/split-pane.d.ts +8 -0
- package/dist/types/components/layout/stack.d.ts +6 -0
- package/dist/types/components/loader.d.ts +48 -0
- package/dist/types/components/markdown.d.ts +8 -0
- package/dist/types/components/metric.d.ts +7 -0
- package/dist/types/components/progress-bar.d.ts +3 -0
- package/dist/types/components/scroll-view.d.ts +6 -0
- package/dist/types/components/section.d.ts +3 -0
- package/dist/types/components/select-list.d.ts +33 -0
- package/dist/types/components/settings-list.d.ts +68 -0
- package/dist/types/components/spacer.d.ts +4 -0
- package/dist/types/components/tab-bar.d.ts +9 -0
- package/dist/types/components/table.d.ts +7 -0
- package/dist/types/components/text.d.ts +6 -0
- package/dist/types/components/tree-view.d.ts +9 -0
- package/dist/types/components/truncated-text.d.ts +3 -0
- package/dist/types/components/wizard-step.d.ts +6 -0
- package/dist/types/hotkeys-markdown.d.ts +24 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/latex-block.d.ts +7 -0
- package/dist/types/native/apply.d.ts +39 -0
- package/dist/types/native/backend.d.ts +94 -0
- package/dist/types/native/blobs.d.ts +29 -0
- package/dist/types/native/describe.d.ts +56 -0
- package/dist/types/native/encode.d.ts +50 -0
- package/dist/types/native/icons.d.ts +18 -0
- package/dist/types/native/memo.d.ts +27 -0
- package/dist/types/native/node.d.ts +107 -0
- package/dist/types/native/overlay.d.ts +64 -0
- package/dist/types/native/picker.d.ts +124 -0
- package/dist/types/native/reconcile.d.ts +41 -0
- package/dist/types/native/settle.d.ts +11 -0
- package/dist/types/native/spans.d.ts +21 -0
- package/dist/types/native/state.d.ts +6 -0
- package/dist/types/native/tone.d.ts +24 -0
- package/dist/types/overlays/advisor-config.d.ts +20 -0
- package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
- package/dist/types/overlays/agent-hub.d.ts +10 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
- package/dist/types/overlays/agents-hub.d.ts +8 -0
- package/dist/types/overlays/annotation-overlay.d.ts +3 -0
- package/dist/types/overlays/ask-dialog.d.ts +23 -0
- package/dist/types/overlays/bordered-loader.d.ts +3 -0
- package/dist/types/overlays/btw-history-panel.d.ts +9 -0
- package/dist/types/overlays/btw-panel.d.ts +3 -0
- package/dist/types/overlays/cleanse-panel.d.ts +5 -2
- package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
- package/dist/types/overlays/copy-selector.d.ts +38 -0
- package/dist/types/overlays/error-banner.d.ts +9 -0
- package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
- package/dist/types/overlays/history-search.d.ts +18 -0
- package/dist/types/overlays/hook-editor.d.ts +28 -1
- package/dist/types/overlays/hook-input.d.ts +3 -0
- package/dist/types/overlays/hook-selector.d.ts +10 -0
- package/dist/types/overlays/hub-frame.d.ts +18 -0
- package/dist/types/overlays/jobs-panel.d.ts +24 -0
- package/dist/types/overlays/login-dialog.d.ts +10 -0
- package/dist/types/overlays/logout-account-selector.d.ts +4 -0
- package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
- package/dist/types/overlays/model-browser.d.ts +69 -0
- package/dist/types/overlays/model-hub.d.ts +7 -0
- package/dist/types/overlays/model-picker.d.ts +7 -0
- package/dist/types/overlays/move-overlay.d.ts +3 -0
- package/dist/types/overlays/oauth-selector.d.ts +4 -0
- package/dist/types/overlays/omfg-panel.d.ts +3 -0
- package/dist/types/overlays/pause-screen.d.ts +12 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
- package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
- package/dist/types/overlays/plugin-selector.d.ts +4 -0
- package/dist/types/overlays/plugin-settings.d.ts +30 -0
- package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
- package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
- package/dist/types/overlays/rewind-selector.d.ts +5 -0
- package/dist/types/overlays/session-info-overlay.d.ts +19 -1
- package/dist/types/overlays/session-selector.d.ts +64 -1
- package/dist/types/overlays/settings-defs.d.ts +14 -0
- package/dist/types/overlays/settings-selector.d.ts +21 -0
- package/dist/types/overlays/show-images-selector.d.ts +4 -0
- package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
- package/dist/types/overlays/stats-notice.d.ts +8 -0
- package/dist/types/overlays/theme-selector.d.ts +11 -0
- package/dist/types/overlays/thinking-selector.d.ts +4 -0
- package/dist/types/overlays/tree-selector.d.ts +60 -2
- package/dist/types/overlays/usage-dashboard.d.ts +26 -3
- package/dist/types/overlays/usage-row.d.ts +36 -2
- package/dist/types/prompt/attachment-chips.d.ts +8 -0
- package/dist/types/prompt/composer-attachments.d.ts +15 -3
- package/dist/types/prompt/composer.d.ts +18 -1
- package/dist/types/prompt/custom-editor.d.ts +48 -2
- package/dist/types/prompt/editor-top-gap.d.ts +2 -0
- package/dist/types/prompt/macos-spelling.d.ts +6 -0
- package/dist/types/prompt/magic-keywords.d.ts +9 -0
- package/dist/types/prompt/queued-messages.d.ts +23 -0
- package/dist/types/prompt/skill-tokens.d.ts +4 -2
- package/dist/types/prompt/welcome.d.ts +16 -0
- package/dist/types/render/code-cell.d.ts +10 -0
- package/dist/types/render/file-list.d.ts +8 -0
- package/dist/types/render/hyperlink.d.ts +14 -0
- package/dist/types/render/output-block.d.ts +43 -0
- package/dist/types/render/output-pane.d.ts +17 -0
- package/dist/types/render/tool-card.d.ts +8 -0
- package/dist/types/render/tree-list.d.ts +8 -0
- package/dist/types/render/width-aware-text.d.ts +7 -0
- package/dist/types/setup/scenes/outro.d.ts +7 -0
- package/dist/types/setup/scenes/sign-in.d.ts +7 -0
- package/dist/types/setup/scenes/splash.d.ts +8 -0
- package/dist/types/setup/scenes/types.d.ts +6 -1
- package/dist/types/setup/wizard-overlay.d.ts +9 -0
- package/dist/types/status-line/component.d.ts +49 -5
- package/dist/types/status-line/context-usage.d.ts +20 -0
- package/dist/types/status-line/footer.d.ts +8 -0
- package/dist/types/status-line/metrics.d.ts +1 -2
- package/dist/types/status-line/segments.d.ts +10 -1
- package/dist/types/status-line/types.d.ts +40 -1
- package/dist/types/terminal-capabilities.d.ts +1 -1
- package/dist/types/terminal.d.ts +27 -0
- package/dist/types/theme/defaults/index.d.ts +100 -0
- package/dist/types/theme/schema.d.ts +2 -0
- package/dist/types/theme/shimmer.d.ts +8 -0
- package/dist/types/theme/theme-class.d.ts +2 -0
- package/dist/types/theme/theme.d.ts +33 -1
- package/dist/types/tools/ask.d.ts +3 -0
- package/dist/types/tools/ast-edit.d.ts +10 -1
- package/dist/types/tools/ast-grep.d.ts +10 -1
- package/dist/types/tools/autoresearch.d.ts +21 -4
- package/dist/types/tools/bash.d.ts +30 -1
- package/dist/types/tools/cfg-render.d.ts +5 -1
- package/dist/types/tools/debug.d.ts +3 -1
- package/dist/types/tools/default-renderer.d.ts +6 -1
- package/dist/types/tools/edit.d.ts +14 -1
- package/dist/types/tools/eval.d.ts +12 -1
- package/dist/types/tools/fetch.d.ts +16 -1
- package/dist/types/tools/find.d.ts +15 -1
- package/dist/types/tools/github.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +14 -1
- package/dist/types/tools/goal.d.ts +3 -1
- package/dist/types/tools/grep.d.ts +14 -1
- package/dist/types/tools/grouped-file-output.d.ts +58 -0
- package/dist/types/tools/json-tree.d.ts +20 -0
- package/dist/types/tools/lsp.d.ts +3 -10
- package/dist/types/tools/mcp.d.ts +16 -1
- package/dist/types/tools/memory.d.ts +26 -0
- package/dist/types/tools/native-view.d.ts +90 -0
- package/dist/types/tools/proc-render.d.ts +7 -1
- package/dist/types/tools/read.d.ts +23 -1
- package/dist/types/tools/renderer.d.ts +57 -0
- package/dist/types/tools/report-tool-issue.d.ts +3 -0
- package/dist/types/tools/resolve.d.ts +14 -1
- package/dist/types/tools/task.d.ts +3 -0
- package/dist/types/tools/think.d.ts +3 -0
- package/dist/types/tools/todo.d.ts +12 -0
- package/dist/types/tools/vibe.d.ts +3 -1
- package/dist/types/tools/wait.d.ts +3 -0
- package/dist/types/tools/web-search.d.ts +8 -0
- package/dist/types/tools/write.d.ts +14 -1
- package/dist/types/tools/xdev.d.ts +13 -0
- package/dist/types/tui.d.ts +49 -0
- package/package.json +9 -9
- package/src/apps/autoresearch-dashboard.ts +362 -4
- package/src/apps/cleanse-board.ts +219 -1
- package/src/apps/cleanse-picker.ts +9 -1
- package/src/apps/debug/log-viewer.ts +15 -15
- package/src/apps/debug/protocol-probe.ts +2 -20
- package/src/apps/git/avatar.ts +2 -22
- package/src/apps/git/git-tui.ts +406 -59
- package/src/apps/git/help.ts +130 -0
- package/src/apps/git/sidebar.ts +491 -0
- package/src/apps/live-visualizer.ts +65 -0
- package/src/apps/ps-top.ts +448 -17
- package/src/apps/session-picker.ts +1 -0
- package/src/apps/setup-model-picker.ts +5 -1
- package/src/apps/standalone-picker.ts +55 -1
- package/src/autocomplete.ts +44 -1
- package/src/chat/advisor-message.ts +72 -3
- package/src/chat/assistant-message.ts +346 -11
- package/src/chat/background-tan-message.ts +4 -4
- package/src/chat/bash-execution.ts +81 -0
- package/src/chat/cache-invalidation-marker.ts +8 -0
- package/src/chat/chat-transcript-builder.ts +37 -6
- package/src/chat/collab-prompt-message.ts +15 -3
- package/src/chat/compaction-summary-message.ts +74 -1
- package/src/chat/custom-message.ts +3 -1
- package/src/chat/eval-execution.ts +57 -0
- package/src/chat/execution-shared.ts +153 -1
- package/src/chat/hook-message.ts +1 -0
- package/src/chat/late-diagnostics-message.ts +85 -2
- package/src/chat/read-tool-group.ts +341 -1
- package/src/chat/served-model-marker.ts +8 -0
- package/src/chat/skill-message.ts +63 -0
- package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
- package/src/chat/todo-reminder.ts +34 -4
- package/src/chat/tool-execution.ts +385 -10
- package/src/chat/transcript-actions.ts +38 -0
- package/src/chat/transcript-browser.ts +2 -9
- package/src/chat/transcript-entry.ts +10 -1
- package/src/chat/transcript-render-helpers.ts +16 -15
- package/src/chat/ttsr-notification.ts +38 -1
- package/src/chat/user-message.ts +167 -4
- package/src/chrome/collab-qrcode.ts +27 -2
- package/src/chrome/context-thresholds.ts +34 -0
- package/src/chrome/countdown-timer.ts +24 -1
- package/src/chrome/diff.ts +60 -1
- package/src/chrome/dynamic-border.ts +7 -0
- package/src/chrome/format.ts +12 -0
- package/src/chrome/message-divider.ts +33 -1
- package/src/chrome/message-frame.ts +53 -10
- package/src/chrome/message-notice.ts +71 -0
- package/src/chrome/overlay-box.ts +45 -2
- package/src/chrome/qrcode.ts +28 -0
- package/src/chrome/segment-track.ts +26 -0
- package/src/chrome/selector-helpers.ts +1 -17
- package/src/chrome/status-notice.ts +46 -0
- package/src/chrome/streaming-panel.ts +25 -1
- package/src/chrome/tool-activity.ts +20 -0
- package/src/chrome/transcript-container.ts +37 -0
- package/src/chrome/transcript-status.ts +40 -11
- package/src/components/box.ts +51 -0
- package/src/components/disclosure.ts +33 -0
- package/src/components/editor.ts +216 -27
- package/src/components/form.ts +93 -9
- package/src/components/image.ts +30 -0
- package/src/components/input.ts +77 -26
- package/src/components/key-value-list.ts +18 -0
- package/src/components/layout/geometry.ts +44 -0
- package/src/components/layout/row.ts +30 -0
- package/src/components/layout/split-pane.ts +65 -0
- package/src/components/layout/stack.ts +27 -0
- package/src/components/loader.ts +183 -1
- package/src/components/markdown.ts +21 -0
- package/src/components/metric.ts +39 -0
- package/src/components/progress-bar.ts +28 -0
- package/src/components/scroll-view.ts +23 -0
- package/src/components/section.ts +16 -0
- package/src/components/select-list.ts +174 -25
- package/src/components/settings-list.ts +264 -7
- package/src/components/spacer.ts +17 -0
- package/src/components/tab-bar.ts +42 -0
- package/src/components/table.ts +34 -0
- package/src/components/text.ts +23 -0
- package/src/components/tree-view.ts +65 -0
- package/src/components/truncated-text.ts +14 -0
- package/src/components/wizard-step.ts +18 -9
- package/src/debug-server.ts +14 -7
- package/src/hotkeys-markdown.ts +251 -69
- package/src/index.ts +6 -0
- package/src/latex-block.ts +11 -0
- package/src/native/apply.ts +275 -0
- package/src/native/backend.ts +682 -0
- package/src/native/blobs.ts +70 -0
- package/src/native/describe.ts +124 -0
- package/src/native/encode.ts +233 -0
- package/src/native/icons.ts +184 -0
- package/src/native/memo.ts +64 -0
- package/src/native/node.ts +112 -0
- package/src/native/overlay.ts +131 -0
- package/src/native/picker.ts +333 -0
- package/src/native/reconcile.ts +1063 -0
- package/src/native/settle.ts +23 -0
- package/src/native/spans.ts +308 -0
- package/src/native/state.ts +28 -0
- package/src/native/tone.ts +79 -0
- package/src/overlays/advisor-config.ts +420 -0
- package/src/overlays/agent-hub-renderer.ts +155 -18
- package/src/overlays/agent-hub.ts +1037 -44
- package/src/overlays/agent-transcript-viewer.ts +129 -0
- package/src/overlays/agents-hub.ts +688 -53
- package/src/overlays/annotation-overlay.ts +391 -52
- package/src/overlays/ask-dialog.ts +435 -24
- package/src/overlays/bordered-loader.ts +17 -0
- package/src/overlays/btw-history-panel.ts +182 -0
- package/src/overlays/btw-panel.ts +68 -2
- package/src/overlays/cleanse-panel.ts +105 -15
- package/src/overlays/codex-reset-fireworks.ts +65 -5
- package/src/overlays/composer-shape-preview.ts +26 -1
- package/src/overlays/copy-selector.ts +545 -23
- package/src/overlays/error-banner.ts +44 -0
- package/src/overlays/extensions/extension-list.ts +23 -17
- package/src/overlays/history-search.ts +175 -33
- package/src/overlays/hook-editor.ts +113 -6
- package/src/overlays/hook-input.ts +22 -1
- package/src/overlays/hook-selector.ts +311 -22
- package/src/overlays/hub-frame.ts +80 -0
- package/src/overlays/jobs-panel.ts +112 -0
- package/src/overlays/login-dialog.ts +183 -1
- package/src/overlays/logout-account-selector.ts +102 -4
- package/src/overlays/mcp-add-wizard.ts +232 -53
- package/src/overlays/model-browser.ts +681 -22
- package/src/overlays/model-hub.ts +1402 -78
- package/src/overlays/model-picker.ts +175 -1
- package/src/overlays/move-overlay.ts +45 -0
- package/src/overlays/oauth-selector.ts +227 -23
- package/src/overlays/omfg-panel.ts +86 -2
- package/src/overlays/pause-screen.ts +55 -4
- package/src/overlays/plan-review-overlay.ts +352 -0
- package/src/overlays/plan-save-overlay.ts +45 -0
- package/src/overlays/plugin-selector.ts +21 -1
- package/src/overlays/plugin-settings.ts +195 -5
- package/src/overlays/queue-mode-selector.ts +19 -1
- package/src/overlays/reset-usage-selector.ts +110 -40
- package/src/overlays/rewind-selector.ts +458 -44
- package/src/overlays/session-account-selector.ts +1 -1
- package/src/overlays/session-info-overlay.ts +137 -1
- package/src/overlays/session-selector.ts +807 -46
- package/src/overlays/settings-defs.ts +41 -0
- package/src/overlays/settings-selector.ts +583 -23
- package/src/overlays/show-images-selector.ts +18 -1
- package/src/overlays/snapcompact-shape-preview.ts +48 -3
- package/src/overlays/stats-notice.ts +31 -0
- package/src/overlays/theme-selector.ts +31 -1
- package/src/overlays/thinking-selector.ts +22 -1
- package/src/overlays/tree-selector.ts +570 -110
- package/src/overlays/usage-dashboard.ts +587 -12
- package/src/overlays/usage-row.ts +161 -25
- package/src/prompt/attachment-chips.ts +60 -0
- package/src/prompt/composer-attachments.ts +31 -9
- package/src/prompt/composer.ts +55 -2
- package/src/prompt/custom-editor.ts +302 -4
- package/src/prompt/editor-top-gap.ts +8 -0
- package/src/prompt/macos-spelling.ts +24 -9
- package/src/prompt/magic-keywords.ts +22 -1
- package/src/prompt/model-mention-autocomplete.ts +1 -0
- package/src/prompt/queued-messages.ts +101 -0
- package/src/prompt/skill-tokens.ts +5 -3
- package/src/prompt/welcome.ts +213 -6
- package/src/render/code-cell.ts +103 -2
- package/src/render/file-list.ts +29 -0
- package/src/render/hyperlink.ts +32 -0
- package/src/render/output-block.ts +110 -0
- package/src/render/output-pane.ts +37 -0
- package/src/render/tool-card.ts +137 -0
- package/src/render/tree-list.ts +39 -0
- package/src/render/width-aware-text.ts +20 -0
- package/src/setup/scenes/composer.ts +29 -0
- package/src/setup/scenes/glyph.ts +15 -0
- package/src/setup/scenes/model.ts +36 -8
- package/src/setup/scenes/outro.ts +28 -1
- package/src/setup/scenes/sign-in.ts +122 -13
- package/src/setup/scenes/splash.ts +28 -1
- package/src/setup/scenes/theme.ts +88 -3
- package/src/setup/scenes/types.ts +7 -1
- package/src/setup/startup-splash.ts +46 -9
- package/src/setup/wizard-overlay.ts +140 -23
- package/src/status-line/component.ts +398 -16
- package/src/status-line/context-usage.ts +279 -50
- package/src/status-line/footer.ts +94 -1
- package/src/status-line/metrics.ts +3 -6
- package/src/status-line/segments.ts +463 -97
- package/src/status-line/separators.ts +3 -16
- package/src/status-line/types.ts +43 -1
- package/src/terminal-capabilities.ts +7 -0
- package/src/terminal.ts +130 -2
- package/src/theme/defaults/dark-neon-noir.json +100 -0
- package/src/theme/defaults/index.ts +2 -0
- package/src/theme/defaults/light-prism.json +5 -5
- package/src/theme/defaults/onyx.json +62 -62
- package/src/theme/schema.ts +15 -0
- package/src/theme/shimmer.ts +33 -0
- package/src/theme/theme-class.ts +24 -19
- package/src/theme/theme.ts +111 -9
- package/src/tools/ask.ts +157 -1
- package/src/tools/ast-edit.ts +174 -1
- package/src/tools/ast-grep.ts +82 -2
- package/src/tools/autoresearch.ts +149 -1
- package/src/tools/bash.ts +180 -49
- package/src/tools/cfg-render.ts +66 -1
- package/src/tools/debug.ts +78 -1
- package/src/tools/default-renderer.ts +35 -1
- package/src/tools/edit.ts +247 -2
- package/src/tools/eval.ts +257 -1
- package/src/tools/fetch.ts +102 -3
- package/src/tools/find.ts +127 -1
- package/src/tools/github.ts +119 -10
- package/src/tools/glob.ts +116 -1
- package/src/tools/goal.ts +56 -1
- package/src/tools/grep.ts +83 -2
- package/src/tools/grouped-file-output.ts +205 -0
- package/src/tools/json-tree.ts +116 -1
- package/src/tools/lsp.ts +318 -1
- package/src/tools/mcp.ts +80 -1
- package/src/tools/memory.ts +93 -11
- package/src/tools/native-view.ts +292 -0
- package/src/tools/proc-render.ts +221 -1
- package/src/tools/read.ts +199 -4
- package/src/tools/renderer.ts +61 -0
- package/src/tools/report-tool-issue.ts +7 -1
- package/src/tools/resolve.ts +63 -1
- package/src/tools/task.ts +406 -4
- package/src/tools/think.ts +19 -1
- package/src/tools/todo.ts +89 -0
- package/src/tools/vibe.ts +230 -2
- package/src/tools/wait.ts +181 -1
- package/src/tools/web-search.ts +113 -1
- package/src/tools/write.ts +144 -5
- package/src/tools/xdev.ts +64 -1
- package/src/tui.ts +294 -3
package/src/tools/write.ts
CHANGED
|
@@ -22,23 +22,47 @@ import {
|
|
|
22
22
|
truncateToWidth,
|
|
23
23
|
} from "../render/render-utils";
|
|
24
24
|
import type { CoordinationDetails } from "./wait";
|
|
25
|
-
import {
|
|
26
|
-
|
|
25
|
+
import {
|
|
26
|
+
describeAgentWrite,
|
|
27
|
+
describeProcWrite,
|
|
28
|
+
renderAgentWrite,
|
|
29
|
+
renderProcWrite,
|
|
30
|
+
type ProcWriteAction,
|
|
31
|
+
type ProcWriteDetails,
|
|
32
|
+
} from "./proc-render";
|
|
33
|
+
import type { TspTone } from "@oh-my-pi/pi-wire";
|
|
34
|
+
import { code, compact, node, span } from "../native/describe";
|
|
35
|
+
import type { NativeChild } from "../native/node";
|
|
36
|
+
import { diagnosticsBadge, diagnosticsSection, displayPath, errorText, fileHref, resultText } from "./native-view";
|
|
37
|
+
import { describeCfgWrite, renderCfgWrite, type CfgWriteDetails } from "./cfg-render";
|
|
27
38
|
import type { FileDiagnosticsResult } from "./lsp";
|
|
28
39
|
import type { OutputMeta } from "./output-meta";
|
|
29
40
|
import type { CardToolResult } from "./result-card";
|
|
30
|
-
import type {
|
|
41
|
+
import type {
|
|
42
|
+
NativeToolHead,
|
|
43
|
+
NativeToolView,
|
|
44
|
+
RenderResultOptions,
|
|
45
|
+
ToolActivityContext,
|
|
46
|
+
ToolActivitySummary,
|
|
47
|
+
ToolRenderer,
|
|
48
|
+
} from "./renderer";
|
|
31
49
|
import { splitUrlScheme } from "./url-scheme-host";
|
|
32
50
|
import { couldBecomeXdUrl, parseXdUrl } from "./xd-url";
|
|
33
51
|
import {
|
|
52
|
+
describeXdevCall,
|
|
53
|
+
describeXdevResult,
|
|
34
54
|
renderXdevCall,
|
|
35
55
|
renderXdevResult,
|
|
36
56
|
xdevActivitySummary,
|
|
37
57
|
type XdevRenderDispatch,
|
|
38
58
|
type XdevMountedRenderer,
|
|
39
59
|
} from "./xdev";
|
|
40
|
-
import { isResolutionDeviceName, renderResolutionDeviceCall } from "./resolve";
|
|
41
|
-
import {
|
|
60
|
+
import { describeResolutionDeviceCall, isResolutionDeviceName, renderResolutionDeviceCall } from "./resolve";
|
|
61
|
+
import {
|
|
62
|
+
describeReportIssueDeviceCall,
|
|
63
|
+
REPORT_ISSUE_DEVICE_NAME,
|
|
64
|
+
renderReportIssueDeviceCall,
|
|
65
|
+
} from "./report-tool-issue";
|
|
42
66
|
import { pendingFileLinkPath } from "./read";
|
|
43
67
|
|
|
44
68
|
/** Details returned by the write tool for transcript rendering. */
|
|
@@ -64,6 +88,8 @@ interface WriteRenderArgs {
|
|
|
64
88
|
}
|
|
65
89
|
|
|
66
90
|
const WRITE_PREVIEW_LINES = 6;
|
|
91
|
+
/** Collapsed native write body: the first lines of the file (§7.3). */
|
|
92
|
+
const NATIVE_WRITE_PREVIEW = { lines: 8 } as const;
|
|
67
93
|
|
|
68
94
|
function countLines(text: string): number {
|
|
69
95
|
if (!text) return 0;
|
|
@@ -416,6 +442,48 @@ function couldBecomeWriteCardUrl(lowerPath: string): boolean {
|
|
|
416
442
|
return false;
|
|
417
443
|
}
|
|
418
444
|
|
|
445
|
+
/** Native view of a `proc://`, `agent://` or `cfg://` write. */
|
|
446
|
+
function describeWriteUrl(
|
|
447
|
+
routed: { card: WriteUrlCard; target: string },
|
|
448
|
+
url: string,
|
|
449
|
+
content: unknown,
|
|
450
|
+
result: CardToolResult | undefined,
|
|
451
|
+
details: WriteToolDetails | undefined,
|
|
452
|
+
): NativeToolView {
|
|
453
|
+
const body = typeof content === "string" ? content : undefined;
|
|
454
|
+
switch (routed.card.detailsKey) {
|
|
455
|
+
case "message":
|
|
456
|
+
return describeAgentWrite(routed.target, body ?? "", result, details?.message);
|
|
457
|
+
case "proc": {
|
|
458
|
+
const { id, action } = procWriteTarget(routed.target);
|
|
459
|
+
return describeProcWrite(id, action, body, result, details?.proc);
|
|
460
|
+
}
|
|
461
|
+
case "cfg":
|
|
462
|
+
return describeCfgWrite(url, body, result, details?.cfg);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/** Native write head shared by the call and result: `Write · path · 22 lines`, executable/diagnostics chips. */
|
|
467
|
+
function writeToolHead(
|
|
468
|
+
rawPath: string,
|
|
469
|
+
content: string,
|
|
470
|
+
details?: Pick<WriteToolDetails, "madeExecutable" | "resolvedPath" | "diagnostics">,
|
|
471
|
+
): NativeToolHead {
|
|
472
|
+
const lineCount = countLines(content);
|
|
473
|
+
const badges: { text: string; tone?: TspTone }[] = [];
|
|
474
|
+
if (details?.madeExecutable) badges.push({ text: "executable", tone: "success" });
|
|
475
|
+
const diagnostics = diagnosticsBadge([details?.diagnostics]);
|
|
476
|
+
if (diagnostics) badges.push(diagnostics);
|
|
477
|
+
return {
|
|
478
|
+
title: "Write",
|
|
479
|
+
target: rawPath ? displayPath(rawPath) : undefined,
|
|
480
|
+
targetKind: "path",
|
|
481
|
+
href: fileHref(details?.resolvedPath),
|
|
482
|
+
meta: lineCount > 0 ? [`${lineCount} line${lineCount === 1 ? "" : "s"}`] : undefined,
|
|
483
|
+
badges: badges.length > 0 ? badges : undefined,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
419
487
|
/** Render file writes and delegated tool-device calls. */
|
|
420
488
|
export const writeToolRenderer = {
|
|
421
489
|
/** Compact one-line activity: device writes read as the mounted tool (`LSP · references foo`), file writes as `Write · <path>`. */
|
|
@@ -618,6 +686,77 @@ export const writeToolRenderer = {
|
|
|
618
686
|
};
|
|
619
687
|
});
|
|
620
688
|
},
|
|
689
|
+
describeCall(
|
|
690
|
+
args: WriteRenderArgs,
|
|
691
|
+
options: RenderResultOptions & { renderContext?: WriteRenderContext },
|
|
692
|
+
): NativeToolView | undefined {
|
|
693
|
+
const rawPath =
|
|
694
|
+
typeof args.file_path === "string" ? args.file_path : typeof args.path === "string" ? args.path : "";
|
|
695
|
+
// Same gating as renderCall: nothing until the path provably is not a device/card URL.
|
|
696
|
+
if (args.path === undefined && args.file_path === undefined) return undefined;
|
|
697
|
+
const pathSettled = args.content !== undefined || options.argsComplete === true;
|
|
698
|
+
const hasStringPath = typeof args.file_path === "string" || typeof args.path === "string";
|
|
699
|
+
if (hasStringPath && !pathSettled && couldBecomeWriteCardUrl(rawPath.toLowerCase())) return undefined;
|
|
700
|
+
const routed = writeUrlCard(rawPath);
|
|
701
|
+
if (routed) return describeWriteUrl(routed, rawPath, args.content, undefined, undefined);
|
|
702
|
+
if (rawPath && couldBecomeXdUrl(rawPath)) {
|
|
703
|
+
const xdev = parseXdUrl(rawPath);
|
|
704
|
+
if (!xdev?.name || args.content === undefined) return undefined;
|
|
705
|
+
if (isResolutionDeviceName(xdev.name)) return describeResolutionDeviceCall(xdev.name, args.content);
|
|
706
|
+
if (xdev.name === REPORT_ISSUE_DEVICE_NAME) return describeReportIssueDeviceCall(args.content);
|
|
707
|
+
return describeXdevCall(xdev.name, args.content, options, options.renderContext?.resolveXdevMounted);
|
|
708
|
+
}
|
|
709
|
+
const content = normalizeDisplayText(args.content);
|
|
710
|
+
return {
|
|
711
|
+
tool: writeToolHead(rawPath, content),
|
|
712
|
+
body: content
|
|
713
|
+
? [
|
|
714
|
+
code(content, {
|
|
715
|
+
lang: rawPath ? getLanguageFromPath(rawPath) : undefined,
|
|
716
|
+
numbers: true,
|
|
717
|
+
}),
|
|
718
|
+
]
|
|
719
|
+
: [],
|
|
720
|
+
preview: NATIVE_WRITE_PREVIEW,
|
|
721
|
+
};
|
|
722
|
+
},
|
|
723
|
+
|
|
724
|
+
describeResult(
|
|
725
|
+
result: { content: Array<{ type: string; text?: string }>; details?: WriteToolDetails; isError?: boolean },
|
|
726
|
+
options: RenderResultOptions & { renderContext?: WriteRenderContext },
|
|
727
|
+
args?: WriteRenderArgs,
|
|
728
|
+
): NativeToolView | undefined {
|
|
729
|
+
const cardPath =
|
|
730
|
+
typeof args?.path === "string" ? args.path : typeof args?.file_path === "string" ? args.file_path : "";
|
|
731
|
+
const routed = writeUrlCard(cardPath, result.details);
|
|
732
|
+
if (routed) return describeWriteUrl(routed, cardPath, args?.content, result, result.details);
|
|
733
|
+
const xdev = result.details?.xdev;
|
|
734
|
+
if (xdev) return describeXdevResult(xdev, result, options, options.renderContext?.resolveXdevMounted);
|
|
735
|
+
const rawPath =
|
|
736
|
+
typeof args?.file_path === "string" ? args.file_path : typeof args?.path === "string" ? args.path : "";
|
|
737
|
+
const fileContent = normalizeDisplayText(args?.content);
|
|
738
|
+
const isPartial = options.isPartial === true;
|
|
739
|
+
const diagnostics = isPartial ? undefined : result.details?.diagnostics;
|
|
740
|
+
const tool = writeToolHead(rawPath, fileContent, {
|
|
741
|
+
madeExecutable: !isPartial && result.details?.madeExecutable === true,
|
|
742
|
+
resolvedPath: result.details?.resolvedPath,
|
|
743
|
+
diagnostics,
|
|
744
|
+
});
|
|
745
|
+
if (result.isError) return { tool, tone: "error", body: [errorText(resultText(result))] };
|
|
746
|
+
const progressText = resultText(result);
|
|
747
|
+
const body = compact<NativeChild>([
|
|
748
|
+
isPartial &&
|
|
749
|
+
progressText.length > 0 &&
|
|
750
|
+
node("text", { spans: [span(progressText, "muted")], truncate: "end" }),
|
|
751
|
+
fileContent.length > 0 &&
|
|
752
|
+
code(fileContent, {
|
|
753
|
+
lang: rawPath ? getLanguageFromPath(rawPath) : undefined,
|
|
754
|
+
numbers: true,
|
|
755
|
+
}),
|
|
756
|
+
diagnosticsSection(diagnostics),
|
|
757
|
+
]);
|
|
758
|
+
return { tool, body, preview: NATIVE_WRITE_PREVIEW };
|
|
759
|
+
},
|
|
621
760
|
mergeCallAndResult: true,
|
|
622
761
|
// The collapsed pending preview follows the streaming edge with a tail
|
|
623
762
|
// window once the content outgrows it (`… (N earlier lines)` + last rows);
|
package/src/tools/xdev.ts
CHANGED
|
@@ -4,12 +4,16 @@ import { type Component, Container, Text } from "../index";
|
|
|
4
4
|
import type { Theme } from "../theme/theme";
|
|
5
5
|
import { replaceTabs } from "../render/render-utils";
|
|
6
6
|
import type { RenderResultOptions, ToolActivitySummary, ToolRenderer } from "./renderer";
|
|
7
|
-
import { renderDefaultToolExecution } from "./default-renderer";
|
|
7
|
+
import { describeDefaultToolExecution, renderDefaultToolExecution } from "./default-renderer";
|
|
8
|
+
import type { NativeToolView } from "./renderer";
|
|
9
|
+
import { text } from "../native/describe";
|
|
8
10
|
import { parseMCPToolName } from "./mcp";
|
|
9
11
|
|
|
10
12
|
/** Mounted device display callbacks, independent of tool execution state. */
|
|
11
13
|
export interface XdevMountedRenderer {
|
|
12
14
|
label?: string;
|
|
15
|
+
describeCall?: ToolRenderer["describeCall"];
|
|
16
|
+
describeResult?: ToolRenderer["describeResult"];
|
|
13
17
|
renderCall?(...args: Parameters<ToolRenderer["renderCall"]>): unknown;
|
|
14
18
|
renderResult?(...args: Parameters<ToolRenderer["renderResult"]>): unknown;
|
|
15
19
|
mergeCallAndResult?: boolean;
|
|
@@ -162,6 +166,65 @@ export function renderXdevCall(
|
|
|
162
166
|
return renderDefaultToolExecution({ label: mounted?.label ?? name, args, options }, theme);
|
|
163
167
|
}
|
|
164
168
|
|
|
169
|
+
/** Native form of {@link resolveDeviceRenderer}: the first renderer that can describe. */
|
|
170
|
+
function resolveDeviceDescriber(
|
|
171
|
+
name: string,
|
|
172
|
+
mounted: XdevMountedRenderer | undefined,
|
|
173
|
+
): XdevMountedRenderer | undefined {
|
|
174
|
+
if (mounted && (mounted.describeCall || mounted.describeResult)) return mounted;
|
|
175
|
+
return rendererLookup?.(name);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** TSP call view for an `xd://` write: queued card until execution, then the device renderer's own view. */
|
|
179
|
+
export function describeXdevCall(
|
|
180
|
+
name: string,
|
|
181
|
+
content: unknown,
|
|
182
|
+
options: RenderResultOptions,
|
|
183
|
+
resolveMounted?: (name: string) => XdevMountedRenderer | undefined,
|
|
184
|
+
): NativeToolView | undefined {
|
|
185
|
+
const mounted = resolveMounted?.(name);
|
|
186
|
+
const args = decodeInnerArgs(content);
|
|
187
|
+
if (!options.executionStarted) {
|
|
188
|
+
return describeDefaultToolExecution({
|
|
189
|
+
label: `queued ${displayDeviceLabel(name, mounted)}`,
|
|
190
|
+
args: displayDeviceArgs(args),
|
|
191
|
+
options: { ...options, isPartial: true, spinnerFrame: undefined },
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const renderer = resolveDeviceDescriber(name, mounted);
|
|
195
|
+
if (renderer?.describeCall) return renderer.describeCall(args, options);
|
|
196
|
+
return describeDefaultToolExecution({ label: mounted?.label ?? name, args, options });
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** TSP result view for an `xd://` dispatch, forwarded to the device renderer. */
|
|
200
|
+
export function describeXdevResult(
|
|
201
|
+
dispatch: XdevRenderDispatch,
|
|
202
|
+
result: { content: Array<{ type: string; text?: string }>; isError?: boolean },
|
|
203
|
+
options: RenderResultOptions,
|
|
204
|
+
resolveMounted?: (name: string) => XdevMountedRenderer | undefined,
|
|
205
|
+
): NativeToolView | undefined {
|
|
206
|
+
const output = result.content
|
|
207
|
+
.map(block => (block.type === "text" ? block.text : ""))
|
|
208
|
+
.filter(Boolean)
|
|
209
|
+
.join("\n");
|
|
210
|
+
if (dispatch.mode === "help") return output ? { body: [text(output, { wrap: "word" })] } : undefined;
|
|
211
|
+
const mounted = resolveMounted?.(dispatch.tool);
|
|
212
|
+
const renderer = resolveDeviceDescriber(dispatch.tool, mounted);
|
|
213
|
+
if (renderer?.describeResult) {
|
|
214
|
+
const innerResult = { content: result.content, details: dispatch.inner, isError: result.isError };
|
|
215
|
+
const view = renderer.describeResult(innerResult, options, dispatch.args ?? {});
|
|
216
|
+
if (!view || renderer.mergeCallAndResult || !renderer.describeCall) return view;
|
|
217
|
+
const call = renderer.describeCall(dispatch.args ?? {}, { ...options, isPartial: false });
|
|
218
|
+
return { ...view, head: view.head ?? call?.head, body: [...(call?.body ?? []), ...(view.body ?? [])] };
|
|
219
|
+
}
|
|
220
|
+
return describeDefaultToolExecution({
|
|
221
|
+
label: mounted?.label ?? dispatch.tool,
|
|
222
|
+
args: dispatch.args ?? {},
|
|
223
|
+
result: { output, isError: result.isError },
|
|
224
|
+
options,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
165
228
|
/** Forward an `xd://` dispatch result to the mounted tool's renderer. */
|
|
166
229
|
export function renderXdevResult(
|
|
167
230
|
dispatch: XdevRenderDispatch,
|
package/src/tui.ts
CHANGED
|
@@ -18,11 +18,16 @@ import { getDebugLogPath } from "@oh-my-pi/pi-utils/dirs";
|
|
|
18
18
|
import { $flag } from "@oh-my-pi/pi-utils/env";
|
|
19
19
|
import * as logger from "@oh-my-pi/pi-utils/logger";
|
|
20
20
|
import * as postmortem from "@oh-my-pi/pi-utils/postmortem";
|
|
21
|
+
import type { TspFrame, TspNode, TspText } from "@oh-my-pi/pi-wire";
|
|
21
22
|
import { DEFAULT_MAX_INLINE_IMAGES, ImageBudget } from "./components/image";
|
|
22
23
|
import { TuiDebugServer } from "./debug-server";
|
|
23
24
|
import { isKeyRelease, matchesKey } from "./keys";
|
|
24
25
|
import { KITTY_PLACEHOLDER } from "./kitty-graphics";
|
|
25
26
|
import { LoopWatchdog } from "./loop-watchdog";
|
|
27
|
+
import { assumedTspHello, NativeBackend, type NativeHost } from "./native/backend";
|
|
28
|
+
import { col } from "./native/describe";
|
|
29
|
+
import { TSP_PREFIX, type TspHello } from "./native/encode";
|
|
30
|
+
import type { DescribeContext, NativeNode, NativeSurfaceProvider, NativeUiEvent } from "./native/node";
|
|
26
31
|
import { STDOUT_BACKLOG_CLEAR_BYTES, setAltScreenActive, type Terminal } from "./terminal";
|
|
27
32
|
import {
|
|
28
33
|
encodeKittyDeleteAllImages,
|
|
@@ -239,6 +244,39 @@ export interface Component {
|
|
|
239
244
|
*/
|
|
240
245
|
render(width: number): readonly string[];
|
|
241
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Describe the component semantically for a Tern Surface Protocol
|
|
249
|
+
* terminal (see `native/node.ts`). Called instead of `render()` when the
|
|
250
|
+
* native backend is active. Return the same node object while nothing
|
|
251
|
+
* changed; return null to fall back to `render()` rows.
|
|
252
|
+
*/
|
|
253
|
+
describe?(cx: DescribeContext): NativeNode | null;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Props for the native `overlay` wrapper when this component is shown as
|
|
257
|
+
* an overlay: the sheet's `role` (Tern styles `omp.overlay.*` roles as
|
|
258
|
+
* glass sheets, so the component's own root must not draw a second frame),
|
|
259
|
+
* `head` spans for the sheet's title row, and `size`/`anchor` overriding
|
|
260
|
+
* the ones derived from the overlay options.
|
|
261
|
+
*/
|
|
262
|
+
nativeOverlay?: {
|
|
263
|
+
role?: string;
|
|
264
|
+
head?: TspText;
|
|
265
|
+
size?: "sm" | "md" | "lg" | "full";
|
|
266
|
+
anchor?: "center" | "top" | "bottom";
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* True when this component, shown as an overlay, describes a data-first
|
|
271
|
+
* sheet (`picker`, `prefs`) that is its own frame: the backend puts it
|
|
272
|
+
* directly in `layer` with no `overlay` wrapper. Usually
|
|
273
|
+
* `cx.supports("picker")`, so older terminals keep the wrapped fallback.
|
|
274
|
+
*/
|
|
275
|
+
nativeSheet?(cx: DescribeContext): boolean;
|
|
276
|
+
|
|
277
|
+
/** User actions on nodes this component described (toggle, select, activate, custom). */
|
|
278
|
+
handleNativeEvent?(event: NativeUiEvent): void;
|
|
279
|
+
|
|
242
280
|
/**
|
|
243
281
|
* Optional handler for keyboard input when component has focus
|
|
244
282
|
*/
|
|
@@ -450,6 +488,10 @@ export class Container implements Component {
|
|
|
450
488
|
#memoLines: string[] | undefined;
|
|
451
489
|
#memoChildLines: (readonly string[])[] = [];
|
|
452
490
|
#memoWidth = -1;
|
|
491
|
+
// Memoized native description: rebuilt only when the child list changes, so
|
|
492
|
+
// the reconciler can skip an unchanged container by reference.
|
|
493
|
+
#nativeNode: NativeNode | undefined;
|
|
494
|
+
#nativeChildren: readonly Component[] = [];
|
|
453
495
|
|
|
454
496
|
#ignoreTight = false;
|
|
455
497
|
|
|
@@ -535,6 +577,17 @@ export class Container implements Component {
|
|
|
535
577
|
this.#memoLines = lines;
|
|
536
578
|
return lines;
|
|
537
579
|
}
|
|
580
|
+
|
|
581
|
+
describe(_cx: DescribeContext): NativeNode | null {
|
|
582
|
+
const children = this.children;
|
|
583
|
+
const previous = this.#nativeChildren;
|
|
584
|
+
let unchanged = this.#nativeNode !== undefined && previous.length === children.length;
|
|
585
|
+
for (let i = 0; unchanged && i < children.length; i++) unchanged = previous[i] === children[i];
|
|
586
|
+
if (unchanged) return this.#nativeNode!;
|
|
587
|
+
this.#nativeChildren = children.slice();
|
|
588
|
+
this.#nativeNode = col(this.#nativeChildren);
|
|
589
|
+
return this.#nativeNode;
|
|
590
|
+
}
|
|
538
591
|
}
|
|
539
592
|
|
|
540
593
|
interface HardwareCursorState {
|
|
@@ -915,6 +968,26 @@ export class TUI extends Container {
|
|
|
915
968
|
// atomically. It must survive a deferred Ghostty image frame.
|
|
916
969
|
#pendingAltExit = "";
|
|
917
970
|
|
|
971
|
+
// Tern Surface Protocol backend, created when the terminal answers the
|
|
972
|
+
// `hello` probe, or at start when the environment names Tern. Kept across
|
|
973
|
+
// stop/start so a restart adopts the surface.
|
|
974
|
+
#native: NativeBackend | undefined;
|
|
975
|
+
#nativeLive = false;
|
|
976
|
+
// Holds the first paint while the `hello` probe is outstanding, so a TSP
|
|
977
|
+
// terminal never sees a row paint it would have to erase.
|
|
978
|
+
#nativeHoldTimer: RenderTimer | undefined;
|
|
979
|
+
static readonly #NATIVE_PROBE_HOLD_MS = 300;
|
|
980
|
+
// Optimistic start (`TERM_PROGRAM=tern`): the surface is live on assumed
|
|
981
|
+
// capabilities until the real `hello` reply confirms it. Without a reply
|
|
982
|
+
// by the deadline the surface closes and rows repaint.
|
|
983
|
+
#nativeUnconfirmed = false;
|
|
984
|
+
#nativeConfirmTimer: RenderTimer | undefined;
|
|
985
|
+
static readonly #NATIVE_CONFIRM_MS = 1000;
|
|
986
|
+
// A deadline that fires this late ran after an event-loop stall (module
|
|
987
|
+
// loading), possibly with the reply already queued on stdin: re-arm for
|
|
988
|
+
// this long so input gets a turn before giving up.
|
|
989
|
+
static readonly #NATIVE_CONFIRM_GRACE_MS = 100;
|
|
990
|
+
|
|
918
991
|
// Overlay stack for modal components rendered on top of base content
|
|
919
992
|
overlayStack: {
|
|
920
993
|
component: Component;
|
|
@@ -1246,7 +1319,12 @@ export class TUI extends Container {
|
|
|
1246
1319
|
this.#debugServer = new TuiDebugServer(this, debugPath);
|
|
1247
1320
|
this.#debugServer.start();
|
|
1248
1321
|
}
|
|
1249
|
-
|
|
1322
|
+
// A terminal expected to speak TSP gets its surface from the first frame,
|
|
1323
|
+
// and a live surface needs raw input from the start: its events (resize,
|
|
1324
|
+
// acks) would otherwise be echoed into the grid by the cooked tty, and the
|
|
1325
|
+
// `hello` query must go out now to confirm the surface.
|
|
1326
|
+
const nativeExpected = this.terminal.tspExpected === true;
|
|
1327
|
+
this.#inputDeferred = options?.deferInput === true && !nativeExpected;
|
|
1250
1328
|
this.#watchdog.start();
|
|
1251
1329
|
this.#ghosttyInitialImageDelayDone = false;
|
|
1252
1330
|
this.#ghosttyImageReadyAtMs = this.#renderScheduler.now() + TUI.#GHOSTTY_INITIAL_IMAGE_DELAY_MS;
|
|
@@ -1275,9 +1353,16 @@ export class TUI extends Container {
|
|
|
1275
1353
|
this.invalidate();
|
|
1276
1354
|
this.requestRender(true);
|
|
1277
1355
|
});
|
|
1356
|
+
this.terminal.onTspHello?.(hello => this.#onTspHello(hello));
|
|
1278
1357
|
this.terminal.start(
|
|
1279
1358
|
data => this.#handleInput(data),
|
|
1280
1359
|
() => {
|
|
1360
|
+
if (this.#nativeLive) {
|
|
1361
|
+
// The terminal lays the surface out: a resize only refreshes the
|
|
1362
|
+
// width `rows` fallback nodes render at. No replay.
|
|
1363
|
+
this.#native!.noteTerminalColumns(this.terminal.columns);
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1281
1366
|
if (this.#resizeProbe) {
|
|
1282
1367
|
// Warp echoes a height-only ±1 SIGWINCH on CSI ?1049l. The echo
|
|
1283
1368
|
// must not restart the alt borrow (that is the flicker loop),
|
|
@@ -1346,8 +1431,191 @@ export class TUI extends Container {
|
|
|
1346
1431
|
this.#querySixelSupport();
|
|
1347
1432
|
this.#queryCellSize();
|
|
1348
1433
|
}
|
|
1434
|
+
if (nativeExpected && this.terminal.tspProbePending && !this.#nativeLive) {
|
|
1435
|
+
this.#startNative(assumedTspHello(this.terminal));
|
|
1436
|
+
this.#nativeUnconfirmed = true;
|
|
1437
|
+
this.#armNativeConfirm(TUI.#NATIVE_CONFIRM_MS);
|
|
1438
|
+
} else if (this.terminal.tspProbePending && !this.#nativeLive) {
|
|
1439
|
+
this.#nativeHoldTimer = this.#renderScheduler.scheduleRender(() => {
|
|
1440
|
+
this.#nativeHoldTimer = undefined;
|
|
1441
|
+
if (!this.#stopped && !this.#nativeLive) this.requestRender(true);
|
|
1442
|
+
}, TUI.#NATIVE_PROBE_HOLD_MS);
|
|
1443
|
+
}
|
|
1349
1444
|
this.requestRender(true, { clearScrollback: options?.clearScrollback === true });
|
|
1350
1445
|
}
|
|
1446
|
+
|
|
1447
|
+
/** Whether frames go to a Tern Surface Protocol surface instead of the row renderer. */
|
|
1448
|
+
get nativeRendering(): boolean {
|
|
1449
|
+
return this.#nativeLive;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Close the TSP surfaces ahead of {@link stop}, before the exit drains
|
|
1454
|
+
* input: the terminal answers nothing once they are closed, and whatever it
|
|
1455
|
+
* already sent (acks, events) is read and dropped here instead of reaching
|
|
1456
|
+
* the shell as typed text. A render already requested (the exit's status
|
|
1457
|
+
* line) goes out first; none is forced, and nothing renders from now until
|
|
1458
|
+
* `stop()`.
|
|
1459
|
+
*/
|
|
1460
|
+
closeNative(): void {
|
|
1461
|
+
if (!this.#nativeLive) return;
|
|
1462
|
+
if (this.#renderRequested) {
|
|
1463
|
+
this.#renderTimer?.cancel();
|
|
1464
|
+
this.#runScheduledRender();
|
|
1465
|
+
}
|
|
1466
|
+
this.#native!.stop();
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
/** Reference document the TSP terminal should hold (debug mirror only). */
|
|
1470
|
+
getNativeDocument(): TspNode | undefined {
|
|
1471
|
+
return this.#nativeLive ? this.#native?.document() : undefined;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
/** Most recent TSP frames sent (debug mirror only). */
|
|
1475
|
+
getNativeFrames(count?: number): readonly TspFrame[] {
|
|
1476
|
+
return this.#native?.recentFrames(count) ?? [];
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
/** `rows` fallback nodes in the last native frame. */
|
|
1480
|
+
get nativeFallbackCount(): number {
|
|
1481
|
+
return this.#native?.fallbackCount ?? 0;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
#onTspHello(hello: TspHello | null): void {
|
|
1485
|
+
const held = this.#nativeHoldTimer !== undefined;
|
|
1486
|
+
this.#nativeHoldTimer?.cancel();
|
|
1487
|
+
this.#nativeHoldTimer = undefined;
|
|
1488
|
+
if (this.#stopped) return;
|
|
1489
|
+
if (this.#nativeUnconfirmed) {
|
|
1490
|
+
if (hello === null) {
|
|
1491
|
+
this.#revokeNative("the DA1 sentinel came before a TSP hello reply, or the reply's version is unsupported");
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
this.#clearNativeConfirm();
|
|
1495
|
+
this.#native!.confirm(hello);
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
if (this.#nativeLive) return;
|
|
1499
|
+
if (hello === null) {
|
|
1500
|
+
if (held) this.requestRender(true);
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
this.#startNative(hello);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
/** Switch to the surface (adopting the one a stop/start cycle closed). */
|
|
1507
|
+
#startNative(hello: TspHello): void {
|
|
1508
|
+
this.#eraseRowPaintForNative();
|
|
1509
|
+
this.#nativeLive = true;
|
|
1510
|
+
if (this.#native) {
|
|
1511
|
+
this.#native.resume(hello);
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
this.#native = new NativeBackend(this.#nativeHost(), hello, { mirror: this.#debugServer !== undefined });
|
|
1515
|
+
this.#native.start();
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
/**
|
|
1519
|
+
* Deadline for the `hello` reply after an optimistic start. A deadline that
|
|
1520
|
+
* fired late ran after an event-loop stall, possibly with the reply already
|
|
1521
|
+
* queued on stdin, so it re-arms briefly to let input run first.
|
|
1522
|
+
*/
|
|
1523
|
+
#armNativeConfirm(delayMs: number): void {
|
|
1524
|
+
const due = this.#renderScheduler.now() + delayMs;
|
|
1525
|
+
this.#nativeConfirmTimer = this.#renderScheduler.scheduleRender(() => {
|
|
1526
|
+
this.#nativeConfirmTimer = undefined;
|
|
1527
|
+
if (!this.#nativeUnconfirmed || this.#stopped) return;
|
|
1528
|
+
if (this.#renderScheduler.now() - due > TUI.#NATIVE_CONFIRM_GRACE_MS) {
|
|
1529
|
+
this.#armNativeConfirm(TUI.#NATIVE_CONFIRM_GRACE_MS);
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
this.#revokeNative(`no TSP hello reply within ${TUI.#NATIVE_CONFIRM_MS} ms`);
|
|
1533
|
+
}, delayMs);
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
#clearNativeConfirm(): void {
|
|
1537
|
+
this.#nativeUnconfirmed = false;
|
|
1538
|
+
this.#nativeConfirmTimer?.cancel();
|
|
1539
|
+
this.#nativeConfirmTimer = undefined;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* The optimistic surface was never confirmed: close it without keeping
|
|
1544
|
+
* anything and repaint every row. A reply that still arrives later switches
|
|
1545
|
+
* to a fresh surface the usual way.
|
|
1546
|
+
*/
|
|
1547
|
+
#revokeNative(reason: string): void {
|
|
1548
|
+
this.#clearNativeConfirm();
|
|
1549
|
+
logger.warn("TSP: terminal did not confirm the surface; falling back to rows", { reason });
|
|
1550
|
+
this.#nativeLive = false;
|
|
1551
|
+
this.#native?.stop(false);
|
|
1552
|
+
this.#native = undefined;
|
|
1553
|
+
this.requestRender(true);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
/**
|
|
1557
|
+
* The handshake landed after the row renderer painted (deferred input):
|
|
1558
|
+
* leave the alternate screen if borrowed and erase the painted viewport so
|
|
1559
|
+
* the surface opens where the rows began.
|
|
1560
|
+
*/
|
|
1561
|
+
#eraseRowPaintForNative(): void {
|
|
1562
|
+
this.#cancelResizeProbe();
|
|
1563
|
+
this.#resizeSettleTimer?.cancel();
|
|
1564
|
+
this.#resizeSettleTimer = undefined;
|
|
1565
|
+
if (this.#altActive || this.#resizeAltActive) {
|
|
1566
|
+
this.terminal.write(`${this.#keyboardEnhancementExit()}\x1b[?1049l`);
|
|
1567
|
+
setAltScreenActive(false);
|
|
1568
|
+
this.#altActive = false;
|
|
1569
|
+
this.#resizeAltActive = false;
|
|
1570
|
+
}
|
|
1571
|
+
this.#setMouseTracking("off");
|
|
1572
|
+
if (this.#previousFrameLength > 0) {
|
|
1573
|
+
const lineDiff = this.#providerViewportTop - this.#hardwareCursorRow;
|
|
1574
|
+
if (lineDiff > 0) this.terminal.write(`\x1b[${lineDiff}B`);
|
|
1575
|
+
else if (lineDiff < 0) this.terminal.write(`\x1b[${-lineDiff}A`);
|
|
1576
|
+
this.terminal.write("\r\x1b[J");
|
|
1577
|
+
this.#previousFrameLength = 0;
|
|
1578
|
+
this.#providerWindow = [];
|
|
1579
|
+
this.#providerPreparedRows = [];
|
|
1580
|
+
}
|
|
1581
|
+
this.terminal.hideCursor();
|
|
1582
|
+
this.#forgetHardwareCursorState();
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
#nativeHost(): NativeHost {
|
|
1586
|
+
return {
|
|
1587
|
+
terminal: this.terminal,
|
|
1588
|
+
describeSurface: cx => {
|
|
1589
|
+
const provider = this.#frameProvider as
|
|
1590
|
+
| (TerminalFrameProvider & Partial<NativeSurfaceProvider>)
|
|
1591
|
+
| undefined;
|
|
1592
|
+
if (provider?.describeSurface) return provider.describeSurface(cx);
|
|
1593
|
+
return { main: this.children, dock: [] };
|
|
1594
|
+
},
|
|
1595
|
+
overlays: () => {
|
|
1596
|
+
const visible = [];
|
|
1597
|
+
for (const entry of this.overlayStack) {
|
|
1598
|
+
if (!this.#isOverlayVisible(entry)) continue;
|
|
1599
|
+
visible.push({
|
|
1600
|
+
component: entry.component,
|
|
1601
|
+
options: entry.options,
|
|
1602
|
+
focused: isOverlayFocusTarget(entry.component, this.#focusedComponent),
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
return visible;
|
|
1606
|
+
},
|
|
1607
|
+
focused: () => this.#focusedComponent,
|
|
1608
|
+
requestRender: () => this.requestRender(),
|
|
1609
|
+
appearanceChanged: () => {
|
|
1610
|
+
this.terminal.refreshAppearance?.();
|
|
1611
|
+
},
|
|
1612
|
+
motionChanged: () => {
|
|
1613
|
+
this.invalidate();
|
|
1614
|
+
this.requestRender();
|
|
1615
|
+
},
|
|
1616
|
+
invalidate: () => this.invalidate(),
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1351
1619
|
/**
|
|
1352
1620
|
* Whether a resize repaints the visible window in place — no alternate-screen
|
|
1353
1621
|
* borrow. Warp-only: Warp re-reports its size on alt-buffer toggles, so borrowing
|
|
@@ -1974,6 +2242,14 @@ export class TUI extends Container {
|
|
|
1974
2242
|
this.#cancelPostmortemRestore = undefined;
|
|
1975
2243
|
this.#debugServer?.stop();
|
|
1976
2244
|
this.#debugServer = undefined;
|
|
2245
|
+
this.#nativeHoldTimer?.cancel();
|
|
2246
|
+
this.#nativeHoldTimer = undefined;
|
|
2247
|
+
this.#clearNativeConfirm();
|
|
2248
|
+
const nativeWasLive = this.#nativeLive;
|
|
2249
|
+
if (nativeWasLive) {
|
|
2250
|
+
this.#native!.stop();
|
|
2251
|
+
this.#nativeLive = false;
|
|
2252
|
+
}
|
|
1977
2253
|
this.#resizeSettleTimer?.cancel();
|
|
1978
2254
|
this.#resizeSettleTimer = undefined;
|
|
1979
2255
|
if (this.#resizeInPlaceActive && this.terminal.rows > 0) {
|
|
@@ -2021,7 +2297,8 @@ export class TUI extends Container {
|
|
|
2021
2297
|
// erase native history and re-stream the whole transcript at quit; drop
|
|
2022
2298
|
// the latch so the flush below writes only un-retired rows.
|
|
2023
2299
|
this.#clearScrollbackOnNextRender = false;
|
|
2024
|
-
|
|
2300
|
+
// The surface already holds the transcript; there's no row history to retire.
|
|
2301
|
+
if (!nativeWasLive) this.#flushHistoryBeforeStop();
|
|
2025
2302
|
// Deliberately leave transmitted images in the terminal's graphics store:
|
|
2026
2303
|
// placeholder cells committed to native scrollback render only while their
|
|
2027
2304
|
// image data lives, so a delete-by-id here blanks every transcript image
|
|
@@ -2193,7 +2470,9 @@ export class TUI extends Container {
|
|
|
2193
2470
|
const adaptiveFloor = Math.min(TUI.#MAX_ADAPTIVE_RENDER_MS, this.#lastFrameCostMs * 2);
|
|
2194
2471
|
const adaptiveDelay = Math.max(0, adaptiveFloor - elapsed);
|
|
2195
2472
|
const inputGraceDelay = Math.max(0, this.#inputRenderGraceUntilMs - now);
|
|
2196
|
-
|
|
2473
|
+
// Native frames are paced by the terminal's acknowledgements (credits),
|
|
2474
|
+
// not by the row renderer's cadence.
|
|
2475
|
+
const delay = this.#nativeLive ? 0 : Math.max(cadenceDelay, adaptiveDelay, inputGraceDelay);
|
|
2197
2476
|
this.#renderTimer = this.#renderScheduler.scheduleRender(this.#runScheduledRender, delay);
|
|
2198
2477
|
}
|
|
2199
2478
|
|
|
@@ -2227,6 +2506,12 @@ export class TUI extends Container {
|
|
|
2227
2506
|
}
|
|
2228
2507
|
|
|
2229
2508
|
#handleInput(data: string): void {
|
|
2509
|
+
// Tern Surface Protocol events (acks, pointer actions, resize, theme)
|
|
2510
|
+
// are terminal reports, never keystrokes.
|
|
2511
|
+
if (data.startsWith(TSP_PREFIX)) {
|
|
2512
|
+
if (this.#nativeLive) this.#native!.handleInput(data);
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2230
2515
|
// Consume CPR replies (CSI row;col R) while an anchor probe is unanswered;
|
|
2231
2516
|
// they are terminal reports, never keystrokes, and must not reach the
|
|
2232
2517
|
// focused component.
|
|
@@ -2982,6 +3267,12 @@ export class TUI extends Container {
|
|
|
2982
3267
|
/** Render one frame: alt-screen modal, provider plan, or children fallback. */
|
|
2983
3268
|
#doRender(): void {
|
|
2984
3269
|
if (this.#stopped) return;
|
|
3270
|
+
if (this.#nativeLive) {
|
|
3271
|
+
this.#native!.render();
|
|
3272
|
+
return;
|
|
3273
|
+
}
|
|
3274
|
+
// Awaiting the TSP hello: its resolution (or the hold timeout) repaints.
|
|
3275
|
+
if (this.#nativeHoldTimer) return;
|
|
2985
3276
|
const width = this.terminal.columns;
|
|
2986
3277
|
const height = this.terminal.rows;
|
|
2987
3278
|
if (this.#resizeAltActive) {
|