@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/hotkeys-markdown.ts
CHANGED
|
@@ -1,24 +1,67 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
keyHintPlatform,
|
|
7
|
-
} from "./app-keybindings";
|
|
1
|
+
import type { TspSpan } from "@oh-my-pi/pi-wire";
|
|
2
|
+
import { type AppKeybinding, formatKeyHint, type KeybindingsManager, keyHintPlatform } from "./app-keybindings";
|
|
3
|
+
import { Markdown } from "./components/markdown";
|
|
4
|
+
import { matchesSelectCancel } from "./keybinding-matchers";
|
|
5
|
+
import type { KeyName } from "./key-hint-format";
|
|
8
6
|
import { canonicalKeyId } from "./keybindings";
|
|
7
|
+
import { col, node, span } from "./native/describe";
|
|
8
|
+
import type { NativeNode, NativeUiEvent } from "./native/node";
|
|
9
|
+
import { actionBar, actionButton } from "./native/overlay";
|
|
10
|
+
import { getMarkdownTheme } from "./theme/theme";
|
|
11
|
+
import type { Component } from "./tui";
|
|
9
12
|
|
|
10
13
|
/** Effective keybinding operations used to render the hotkey reference. */
|
|
11
14
|
export interface HotkeysMarkdownBindings {
|
|
12
15
|
keybindings: Pick<KeybindingsManager, "getDisplayString" | "getKeys" | "matchesCanonical">;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
/**
|
|
19
|
+
* One piece of a shortcut cell: formatted key hints (alternatives, one keycap
|
|
20
|
+
* each), a literal typed token (`#<number>`, `!!`), or connecting prose.
|
|
21
|
+
*/
|
|
22
|
+
type HotkeyPart =
|
|
23
|
+
| {
|
|
24
|
+
/** Formatted for the markdown table (`⌃R`); `Disabled` when unbound. */
|
|
25
|
+
keys: readonly string[];
|
|
26
|
+
/** Key ids (`ctrl+r`) for native keycaps, which the terminal draws with platform glyphs. */
|
|
27
|
+
ids: readonly KeyName[];
|
|
28
|
+
action?: AppKeybinding;
|
|
29
|
+
}
|
|
30
|
+
| { token: string }
|
|
31
|
+
| { text: string };
|
|
32
|
+
|
|
33
|
+
interface HotkeyRow {
|
|
34
|
+
readonly keys: readonly HotkeyPart[];
|
|
35
|
+
readonly action: string;
|
|
17
36
|
}
|
|
18
37
|
|
|
19
|
-
|
|
20
|
-
|
|
38
|
+
interface HotkeyGroup {
|
|
39
|
+
readonly title: string;
|
|
40
|
+
readonly rows: readonly HotkeyRow[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Formatted hints for key ids. */
|
|
44
|
+
function hints(keys: readonly KeyName[]): HotkeyPart {
|
|
45
|
+
return { keys: keys.map(formatKeyHint), ids: keys };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The markdown cell text of a part; key alternatives join with `/` as `formatKeyHints` does. */
|
|
49
|
+
function markdownPart(bindings: HotkeysMarkdownBindings, part: HotkeyPart): string {
|
|
50
|
+
if ("text" in part) return part.text;
|
|
51
|
+
if ("token" in part) return `\`${part.token}\``;
|
|
52
|
+
const label = part.action ? bindings.keybindings.getDisplayString(part.action) || "Disabled" : part.keys.join("/");
|
|
53
|
+
return `\`${label}\``;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The shortcut groups, built from the effective bindings. */
|
|
57
|
+
function hotkeyGroups(bindings: HotkeysMarkdownBindings): HotkeyGroup[] {
|
|
21
58
|
const isMac = keyHintPlatform() === "darwin";
|
|
59
|
+
// An action's effective keys, one keycap each; `Disabled` when unbound.
|
|
60
|
+
const act = (action: AppKeybinding): HotkeyPart => {
|
|
61
|
+
const keys = bindings.keybindings.getKeys(action);
|
|
62
|
+
if (keys.length > 0) return { keys: keys.map(formatKeyHint), ids: keys, action };
|
|
63
|
+
return { keys: [bindings.keybindings.getDisplayString(action) || "Disabled"], ids: [], action };
|
|
64
|
+
};
|
|
22
65
|
// CustomEditor tests the chord that was actually pressed, so exit keys split by role: a key
|
|
23
66
|
// that also carries tui.editor.deleteCharForward (the readline `^D` overlap) forward-deletes
|
|
24
67
|
// while the prompt holds a draft, any other exit key quits immediately. Mixed bindings such as
|
|
@@ -31,67 +74,206 @@ export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string
|
|
|
31
74
|
const quittingExitKeys = exitKeys.filter(
|
|
32
75
|
key => !bindings.keybindings.matchesCanonical(canonicalKeyId(key), "tui.editor.deleteCharForward"),
|
|
33
76
|
);
|
|
34
|
-
const exitRows:
|
|
77
|
+
const exitRows: HotkeyRow[] = [];
|
|
35
78
|
if (deletingExitKeys.length > 0) {
|
|
36
|
-
exitRows.push(
|
|
37
|
-
|
|
38
|
-
|
|
79
|
+
exitRows.push({
|
|
80
|
+
keys: [hints(deletingExitKeys)],
|
|
81
|
+
action: "Delete char forward (with draft) / exit (empty prompt)",
|
|
82
|
+
});
|
|
39
83
|
}
|
|
40
84
|
// An unbound exit action still gets its row, mirroring the `Disabled` hint every other row uses.
|
|
41
85
|
if (quittingExitKeys.length > 0 || deletingExitKeys.length === 0) {
|
|
42
|
-
exitRows.push(
|
|
86
|
+
exitRows.push({
|
|
87
|
+
keys: [quittingExitKeys.length > 0 ? hints(quittingExitKeys) : { keys: ["Disabled"], ids: [] }],
|
|
88
|
+
action: "Exit",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const groups: HotkeyGroup[] = [
|
|
92
|
+
{
|
|
93
|
+
title: "Navigation",
|
|
94
|
+
rows: [
|
|
95
|
+
{
|
|
96
|
+
keys: [hints(["up", "down", "left", "right"])],
|
|
97
|
+
action: `Move cursor / browse history (${formatKeyHint("up")} when empty)`,
|
|
98
|
+
},
|
|
99
|
+
{ keys: [hints(["alt+left", "alt+right"])], action: "Move by word" },
|
|
100
|
+
{
|
|
101
|
+
keys: [hints(isMac ? ["ctrl+a", "home", "super+left"] : ["ctrl+a", "home"])],
|
|
102
|
+
action: "Start of line",
|
|
103
|
+
},
|
|
104
|
+
{ keys: [hints(isMac ? ["ctrl+e", "end", "super+right"] : ["ctrl+e", "end"])], action: "End of line" },
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
title: "Editing",
|
|
109
|
+
rows: [
|
|
110
|
+
{ keys: [hints(["enter"])], action: "Send message" },
|
|
111
|
+
{ keys: [hints(["shift+enter", "alt+enter"])], action: "New line" },
|
|
112
|
+
{ keys: [hints(["ctrl+w", "alt+backspace"])], action: "Delete word backwards" },
|
|
113
|
+
{ keys: [hints(["ctrl+u"])], action: "Delete to start of line" },
|
|
114
|
+
{ keys: [hints(["ctrl+k"])], action: "Delete to end of line" },
|
|
115
|
+
{ keys: [act("app.clipboard.copyLine")], action: "Copy current line" },
|
|
116
|
+
{ keys: [act("app.clipboard.copyPrompt")], action: "Copy whole prompt" },
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
title: "Other",
|
|
121
|
+
rows: [
|
|
122
|
+
{ keys: [hints(["tab"])], action: "Path completion / accept autocomplete" },
|
|
123
|
+
{ keys: [act("app.interrupt")], action: "Cancel autocomplete / interrupt active work" },
|
|
124
|
+
{ keys: [act("app.clear")], action: "Clear editor (first) / exit (second)" },
|
|
125
|
+
...exitRows,
|
|
126
|
+
{ keys: [act("app.suspend")], action: "Suspend to background" },
|
|
127
|
+
{ keys: [act("app.display.reset")], action: "Reset terminal display" },
|
|
128
|
+
{ keys: [act("app.thinking.cycle")], action: "Cycle thinking level" },
|
|
129
|
+
{ keys: [act("app.model.cycleForward")], action: "Cycle role models (slow/default/smol)" },
|
|
130
|
+
{ keys: [act("app.model.cycleBackward")], action: "Cycle role models (backward)" },
|
|
131
|
+
{ keys: [act("app.model.selectTemporary")], action: "Select model (temporary)" },
|
|
132
|
+
{ keys: [act("app.model.select")], action: "Select model (set roles)" },
|
|
133
|
+
{ keys: [act("app.plan.toggle")], action: "Toggle plan mode" },
|
|
134
|
+
{ keys: [act("app.history.search")], action: "Search prompt history" },
|
|
135
|
+
{ keys: [act("app.tools.expand")], action: "Toggle tool output expansion" },
|
|
136
|
+
{ keys: [act("app.tools.toggleVisibility")], action: "Toggle tool activity visibility" },
|
|
137
|
+
{ keys: [act("app.thinking.toggle")], action: "Toggle thinking block visibility" },
|
|
138
|
+
{ keys: [act("app.editor.external")], action: "Edit message in external editor" },
|
|
139
|
+
{ keys: [act("app.retry")], action: "Retry last failed assistant turn" },
|
|
140
|
+
{ keys: [act("app.clipboard.pasteImage")], action: "Paste image or text from clipboard" },
|
|
141
|
+
{
|
|
142
|
+
keys: [{ text: "Hold " }, hints(["space"])],
|
|
143
|
+
action: "Speech-to-text (push-to-talk): hold to record, release to transcribe",
|
|
144
|
+
},
|
|
145
|
+
{ keys: [act("app.live.toggle")], action: "Start/stop live voice mode (/live)" },
|
|
146
|
+
{
|
|
147
|
+
keys: [
|
|
148
|
+
act("app.agents.hub"),
|
|
149
|
+
{ text: " / " },
|
|
150
|
+
act("app.session.observe"),
|
|
151
|
+
{ text: " / double-tap " },
|
|
152
|
+
hints(["left"]),
|
|
153
|
+
{ text: " (empty editor)" },
|
|
154
|
+
],
|
|
155
|
+
action: "Open the agent hub",
|
|
156
|
+
},
|
|
157
|
+
{ keys: [{ token: "#<number>" }], action: "GitHub issue/PR reference (e.g. `#3164` → `pr://`/`issue://`)" },
|
|
158
|
+
{
|
|
159
|
+
keys: [{ token: "#" }, { text: " / " }, { token: "#<text>" }],
|
|
160
|
+
action: "Prompt actions (copy / undo / move cursor)",
|
|
161
|
+
},
|
|
162
|
+
{ keys: [{ token: "/" }], action: "Slash commands" },
|
|
163
|
+
{ keys: [{ token: "!" }], action: "Run bash command" },
|
|
164
|
+
{ keys: [{ token: "!!" }], action: "Run bash command (excluded from context)" },
|
|
165
|
+
{ keys: [{ token: "$" }], action: "Run Python in shared kernel" },
|
|
166
|
+
{ keys: [{ token: "$$" }], action: "Run Python (excluded from context)" },
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
return groups;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Build the platform-aware Markdown reference for effective application hotkeys. */
|
|
174
|
+
export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string {
|
|
175
|
+
const lines: string[] = [];
|
|
176
|
+
for (const [index, group] of hotkeyGroups(bindings).entries()) {
|
|
177
|
+
if (index > 0) lines.push("");
|
|
178
|
+
lines.push(`**${group.title}**`, "| Key | Action |", "|-----|--------|");
|
|
179
|
+
for (const row of group.rows) {
|
|
180
|
+
const keys = row.keys.map(part => markdownPart(bindings, part)).join("");
|
|
181
|
+
lines.push(`| ${keys} | ${row.action} |`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return lines.join("\n");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* A shortcut cell as spans: each key alternative a `key` span holding its key
|
|
189
|
+
* id (`ctrl+r`, drawn as a keycap like `kbd`), literal tokens as code, prose dim.
|
|
190
|
+
*/
|
|
191
|
+
function keySpans(parts: readonly HotkeyPart[]): TspSpan[] {
|
|
192
|
+
const spans: TspSpan[] = [];
|
|
193
|
+
for (const part of parts) {
|
|
194
|
+
if ("text" in part) spans.push(span(part.text, "dim"));
|
|
195
|
+
else if ("token" in part) spans.push(span(part.token, "code"));
|
|
196
|
+
else if (part.ids.length === 0) spans.push(span(part.keys.join("/"), "dim"));
|
|
197
|
+
else {
|
|
198
|
+
for (const [index, id] of part.ids.entries()) {
|
|
199
|
+
if (index > 0) spans.push(span(" ", "dim"));
|
|
200
|
+
spans.push(span(id, "key"));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return spans;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Inline markdown (backticks) of an action description as spans: code runs mono, the rest plain. */
|
|
208
|
+
function actionSpans(action: string): TspSpan[] {
|
|
209
|
+
return action.split(/(`[^`]+`)/).flatMap(piece => {
|
|
210
|
+
if (piece === "") return [];
|
|
211
|
+
return piece.startsWith("`") && piece.endsWith("`") ? [span(piece.slice(1, -1), "code")] : [span(piece)];
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* `/hotkeys` under a native terminal: a large sheet "Keyboard shortcuts" with
|
|
217
|
+
* one section per group, each a two-column table whose key cells carry `key`
|
|
218
|
+
* spans (Tern draws them as keycaps). Esc (or Close) dismisses it. Terminals
|
|
219
|
+
* without the native surface get the transcript markdown panel instead.
|
|
220
|
+
*/
|
|
221
|
+
export class HotkeysSheetComponent implements Component {
|
|
222
|
+
readonly nativeOverlay = { role: "omp.overlay.hotkeys", size: "lg", head: "Keyboard shortcuts" } as const;
|
|
223
|
+
readonly #bindings: HotkeysMarkdownBindings;
|
|
224
|
+
readonly #onClose: () => void;
|
|
225
|
+
#native: NativeNode | undefined;
|
|
226
|
+
#markdown: Markdown | undefined;
|
|
227
|
+
|
|
228
|
+
constructor(bindings: HotkeysMarkdownBindings, onClose: () => void) {
|
|
229
|
+
this.#bindings = bindings;
|
|
230
|
+
this.#onClose = onClose;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
describe(): NativeNode {
|
|
234
|
+
if (this.#native) return this.#native;
|
|
235
|
+
const sections = hotkeyGroups(this.#bindings).map((group, index) =>
|
|
236
|
+
node(
|
|
237
|
+
"section",
|
|
238
|
+
{ head: group.title, role: "omp.hotkeys.group" },
|
|
239
|
+
[
|
|
240
|
+
node("table", {
|
|
241
|
+
role: "omp.hotkeys.table",
|
|
242
|
+
cols: [
|
|
243
|
+
{ id: "keys", head: "Key" },
|
|
244
|
+
{ id: "action", head: "Action", grow: 1 },
|
|
245
|
+
],
|
|
246
|
+
rows: group.rows.map((row, rowIndex) => ({
|
|
247
|
+
id: String(rowIndex),
|
|
248
|
+
cells: { keys: keySpans(row.keys), action: actionSpans(row.action) },
|
|
249
|
+
})),
|
|
250
|
+
}),
|
|
251
|
+
],
|
|
252
|
+
`g${index}`,
|
|
253
|
+
),
|
|
254
|
+
);
|
|
255
|
+
const close = actionButton("Close", "close", { keys: "escape" });
|
|
256
|
+
this.#native = col([...sections, actionBar([null, close])], { gap: "lg" });
|
|
257
|
+
return this.#native;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** The markdown reference, for a terminal that falls back to rows. */
|
|
261
|
+
render(width: number): readonly string[] {
|
|
262
|
+
this.#markdown ??= new Markdown(buildHotkeysMarkdown(this.#bindings), 1, 1, getMarkdownTheme());
|
|
263
|
+
return this.#markdown.render(width);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
invalidate(): void {
|
|
267
|
+
this.#native = undefined;
|
|
268
|
+
this.#markdown = undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
handleInput(data: string): void {
|
|
272
|
+
if (matchesSelectCancel(data)) this.#onClose();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Close runs what Esc runs. */
|
|
276
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
277
|
+
if (event.type === "action" && event.act === "close") this.#onClose();
|
|
43
278
|
}
|
|
44
|
-
return [
|
|
45
|
-
"**Navigation**",
|
|
46
|
-
"| Key | Action |",
|
|
47
|
-
"|-----|--------|",
|
|
48
|
-
`| \`${formatKeyHints(["up", "down", "left", "right"])}\` | Move cursor / browse history (${formatKeyHint("up")} when empty) |`,
|
|
49
|
-
`| \`${formatKeyHints(["alt+left", "alt+right"])}\` | Move by word |`,
|
|
50
|
-
`| \`${formatKeyHints(isMac ? ["ctrl+a", "home", "super+left"] : ["ctrl+a", "home"])}\` | Start of line |`,
|
|
51
|
-
`| \`${formatKeyHints(isMac ? ["ctrl+e", "end", "super+right"] : ["ctrl+e", "end"])}\` | End of line |`,
|
|
52
|
-
"",
|
|
53
|
-
"**Editing**",
|
|
54
|
-
"| Key | Action |",
|
|
55
|
-
"|-----|--------|",
|
|
56
|
-
`| \`${formatKeyHint("enter")}\` | Send message |`,
|
|
57
|
-
`| \`${formatKeyHints(["shift+enter", "alt+enter"])}\` | New line |`,
|
|
58
|
-
`| \`${formatKeyHints(["ctrl+w", "alt+backspace"])}\` | Delete word backwards |`,
|
|
59
|
-
`| \`${formatKeyHint("ctrl+u")}\` | Delete to start of line |`,
|
|
60
|
-
`| \`${formatKeyHint("ctrl+k")}\` | Delete to end of line |`,
|
|
61
|
-
`| \`${hotkeyLabel(bindings, "app.clipboard.copyLine")}\` | Copy current line |`,
|
|
62
|
-
`| \`${hotkeyLabel(bindings, "app.clipboard.copyPrompt")}\` | Copy whole prompt |`,
|
|
63
|
-
"",
|
|
64
|
-
"**Other**",
|
|
65
|
-
"| Key | Action |",
|
|
66
|
-
"|-----|--------|",
|
|
67
|
-
`| \`${formatKeyHint("tab")}\` | Path completion / accept autocomplete |`,
|
|
68
|
-
`| \`${hotkeyLabel(bindings, "app.interrupt")}\` | Cancel autocomplete / interrupt active work |`,
|
|
69
|
-
`| \`${hotkeyLabel(bindings, "app.clear")}\` | Clear editor (first) / exit (second) |`,
|
|
70
|
-
...exitRows,
|
|
71
|
-
`| \`${hotkeyLabel(bindings, "app.suspend")}\` | Suspend to background |`,
|
|
72
|
-
`| \`${hotkeyLabel(bindings, "app.display.reset")}\` | Reset terminal display |`,
|
|
73
|
-
`| \`${hotkeyLabel(bindings, "app.thinking.cycle")}\` | Cycle thinking level |`,
|
|
74
|
-
`| \`${hotkeyLabel(bindings, "app.model.cycleForward")}\` | Cycle role models (slow/default/smol) |`,
|
|
75
|
-
`| \`${hotkeyLabel(bindings, "app.model.cycleBackward")}\` | Cycle role models (backward) |`,
|
|
76
|
-
`| \`${hotkeyLabel(bindings, "app.model.selectTemporary")}\` | Select model (temporary) |`,
|
|
77
|
-
`| \`${hotkeyLabel(bindings, "app.model.select")}\` | Select model (set roles) |`,
|
|
78
|
-
`| \`${hotkeyLabel(bindings, "app.plan.toggle")}\` | Toggle plan mode |`,
|
|
79
|
-
`| \`${hotkeyLabel(bindings, "app.history.search")}\` | Search prompt history |`,
|
|
80
|
-
`| \`${hotkeyLabel(bindings, "app.tools.expand")}\` | Toggle tool output expansion |`,
|
|
81
|
-
`| \`${hotkeyLabel(bindings, "app.tools.toggleVisibility")}\` | Toggle tool activity visibility |`,
|
|
82
|
-
`| \`${hotkeyLabel(bindings, "app.thinking.toggle")}\` | Toggle thinking block visibility |`,
|
|
83
|
-
`| \`${hotkeyLabel(bindings, "app.editor.external")}\` | Edit message in external editor |`,
|
|
84
|
-
`| \`${hotkeyLabel(bindings, "app.retry")}\` | Retry last failed assistant turn |`,
|
|
85
|
-
`| \`${hotkeyLabel(bindings, "app.clipboard.pasteImage")}\` | Paste image or text from clipboard |`,
|
|
86
|
-
`| Hold \`${formatKeyHint("space")}\` | Speech-to-text (push-to-talk): hold to record, release to transcribe |`,
|
|
87
|
-
`| \`${hotkeyLabel(bindings, "app.live.toggle")}\` | Start/stop live voice mode (/live) |`,
|
|
88
|
-
`| \`${hotkeyLabel(bindings, "app.agents.hub")}\` / \`${hotkeyLabel(bindings, "app.session.observe")}\` / double-tap \`${formatKeyHint("left")}\` (empty editor) | Open the agent hub |`,
|
|
89
|
-
"| `#<number>` | GitHub issue/PR reference (e.g. `#3164` → `pr://`/`issue://`) |",
|
|
90
|
-
"| `#` / `#<text>` | Prompt actions (copy / undo / move cursor) |",
|
|
91
|
-
"| `/` | Slash commands |",
|
|
92
|
-
"| `!` | Run bash command |",
|
|
93
|
-
"| `!!` | Run bash command (excluded from context) |",
|
|
94
|
-
"| `$` | Run Python in shared kernel |",
|
|
95
|
-
"| `$$` | Run Python (excluded from context) |",
|
|
96
|
-
].join("\n");
|
|
97
279
|
}
|
package/src/index.ts
CHANGED
|
@@ -57,6 +57,12 @@ export * from "./latex-block";
|
|
|
57
57
|
export * from "./latex-to-unicode";
|
|
58
58
|
// SGR mouse report parsing
|
|
59
59
|
export * from "./mouse";
|
|
60
|
+
// Tern Surface Protocol: describe contract, builders, blobs, settling, render state
|
|
61
|
+
export * from "./native/blobs";
|
|
62
|
+
export * from "./native/describe";
|
|
63
|
+
export type * from "./native/node";
|
|
64
|
+
export * from "./native/settle";
|
|
65
|
+
export * from "./native/state";
|
|
60
66
|
// Mermaid diagram support
|
|
61
67
|
// Input buffering for batch splitting
|
|
62
68
|
export * from "./stdin-buffer";
|
package/src/latex-block.ts
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
// scratch here on this module's ANSI-aware Box model.
|
|
24
24
|
|
|
25
25
|
import { latexColorScope, latexToUnicode, MATH_FONT_COMMANDS } from "./latex-to-unicode";
|
|
26
|
+
import { node } from "./native/describe";
|
|
27
|
+
import type { NativeNode } from "./native/node";
|
|
26
28
|
import { visibleWidth } from "./utils";
|
|
27
29
|
|
|
28
30
|
/**
|
|
@@ -1428,6 +1430,15 @@ function splitLines(src: string): string[] {
|
|
|
1428
1430
|
return lines;
|
|
1429
1431
|
}
|
|
1430
1432
|
|
|
1433
|
+
/**
|
|
1434
|
+
* The native form of {@link latexToBlock}: the TeX source as a `math` node
|
|
1435
|
+
* the terminal typesets (display style by default, `display: false` for
|
|
1436
|
+
* inline `$…$` math).
|
|
1437
|
+
*/
|
|
1438
|
+
export function describeLatex(src: string, display = true): NativeNode {
|
|
1439
|
+
return node("math", { text: src, display });
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1431
1442
|
/**
|
|
1432
1443
|
* Render a display LaTeX math fragment to lines with full 2-D layout: stacked
|
|
1433
1444
|
* fractions, stretchy delimiters, matrix grids, operator limits, drawn
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference document applier: applies TSP frames to a node tree the way the
|
|
3
|
+
* spec says the terminal does (§5.1). Ops are validated and applied one by
|
|
4
|
+
* one; a rejected op is reported and skipped without affecting the rest of
|
|
5
|
+
* the frame. `settle` is recorded as a hint and never restricts later ops.
|
|
6
|
+
*
|
|
7
|
+
* Used by tests, the debug server's `doc` op, and the TSP test harness.
|
|
8
|
+
*/
|
|
9
|
+
import { TSP_KINDS, TSP_TEXT_KINDS, type TspFrame, type TspKind, type TspNode, type TspOp } from "@oh-my-pi/pi-wire";
|
|
10
|
+
|
|
11
|
+
/** One rejected op. */
|
|
12
|
+
export interface TspApplyError {
|
|
13
|
+
/** Frame sequence number. */
|
|
14
|
+
s: number;
|
|
15
|
+
/** Op index inside the frame. */
|
|
16
|
+
op: number;
|
|
17
|
+
msg: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface DocNode {
|
|
21
|
+
id: string;
|
|
22
|
+
k: TspKind;
|
|
23
|
+
p: Record<string, unknown>;
|
|
24
|
+
c: DocNode[];
|
|
25
|
+
parent: DocNode | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const KINDS: ReadonlySet<string> = new Set(TSP_KINDS);
|
|
29
|
+
const TEXT_KINDS: ReadonlySet<string> = new Set(TSP_TEXT_KINDS);
|
|
30
|
+
|
|
31
|
+
class OpError extends Error {}
|
|
32
|
+
|
|
33
|
+
function fail(msg: string): never {
|
|
34
|
+
throw new OpError(msg);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A surface document: the root (id = surface id) plus an id index. */
|
|
38
|
+
export class TspDocument {
|
|
39
|
+
readonly surface: string;
|
|
40
|
+
#root: DocNode;
|
|
41
|
+
#index = new Map<string, DocNode>();
|
|
42
|
+
#settled = new Set<string>();
|
|
43
|
+
#focus: string | null = null;
|
|
44
|
+
#suspended = false;
|
|
45
|
+
|
|
46
|
+
constructor(surface: string) {
|
|
47
|
+
this.surface = surface;
|
|
48
|
+
this.#root = { id: surface, k: "col", p: {}, c: [], parent: null };
|
|
49
|
+
this.#index.set(surface, this.#root);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Currently focused node id. */
|
|
53
|
+
get focus(): string | null {
|
|
54
|
+
return this.#focus;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get suspended(): boolean {
|
|
58
|
+
return this.#suspended;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Ids that received a `settle` hint and no later op. */
|
|
62
|
+
get settled(): ReadonlySet<string> {
|
|
63
|
+
return this.#settled;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Number of nodes, including the root. */
|
|
67
|
+
get size(): number {
|
|
68
|
+
return this.#index.size;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
has(id: string): boolean {
|
|
72
|
+
return this.#index.has(id);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** `x keep:true`: drop the live-only regions (`dock`, `layer`) and focus; `main` stays. */
|
|
76
|
+
close(): void {
|
|
77
|
+
for (const region of ["dock", "layer"]) {
|
|
78
|
+
const node = this.#index.get(region);
|
|
79
|
+
if (!node || node.parent !== this.#root) continue;
|
|
80
|
+
this.#root.c.splice(this.#root.c.indexOf(node), 1);
|
|
81
|
+
this.#unregister(node);
|
|
82
|
+
}
|
|
83
|
+
this.#focus = null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Apply a frame op by op; returns the rejected ops. */
|
|
87
|
+
applyFrame(frame: TspFrame): TspApplyError[] {
|
|
88
|
+
const errors: TspApplyError[] = [];
|
|
89
|
+
for (let i = 0; i < frame.ops.length; i++) {
|
|
90
|
+
try {
|
|
91
|
+
this.#apply(frame.ops[i]!);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (!(error instanceof OpError)) throw error;
|
|
94
|
+
errors.push({ s: frame.s, op: i, msg: error.message });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return errors;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Snapshot of the whole document (root included) as wire nodes. */
|
|
101
|
+
snapshot(): TspNode {
|
|
102
|
+
return this.#export(this.#root);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Snapshot of one subtree, or undefined for an unknown id. */
|
|
106
|
+
get(id: string): TspNode | undefined {
|
|
107
|
+
const found = this.#index.get(id);
|
|
108
|
+
return found ? this.#export(found) : undefined;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#export(node: DocNode): TspNode {
|
|
112
|
+
const out: { id: string; k: TspKind; p?: Record<string, unknown>; c?: TspNode[] } = { id: node.id, k: node.k };
|
|
113
|
+
if (Object.keys(node.p).length > 0) out.p = { ...node.p };
|
|
114
|
+
if (node.c.length > 0) out.c = node.c.map(child => this.#export(child));
|
|
115
|
+
return out as TspNode;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#node(id: string): DocNode {
|
|
119
|
+
return this.#index.get(id) ?? fail(`unknown id ${id}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#unsettle(node: DocNode): void {
|
|
123
|
+
if (this.#settled.size === 0) return;
|
|
124
|
+
for (let at: DocNode | null = node; at; at = at.parent) this.#settled.delete(at.id);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#apply(op: TspOp): void {
|
|
128
|
+
switch (op[0]) {
|
|
129
|
+
case "add": {
|
|
130
|
+
const [, id, parentId, before, wire] = op;
|
|
131
|
+
if (wire.id !== id) fail(`add id ${id} does not match node id ${wire.id}`);
|
|
132
|
+
const parent = this.#node(parentId);
|
|
133
|
+
const index = this.#insertIndex(parent, before);
|
|
134
|
+
const built = this.#build(wire, parent, new Set());
|
|
135
|
+
parent.c.splice(index, 0, built);
|
|
136
|
+
this.#register(built);
|
|
137
|
+
this.#unsettle(parent);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
case "set": {
|
|
141
|
+
const [, id, props] = op;
|
|
142
|
+
const node = this.#node(id);
|
|
143
|
+
if (typeof props !== "object" || props === null || Array.isArray(props))
|
|
144
|
+
fail("set props must be an object");
|
|
145
|
+
for (const key in props) {
|
|
146
|
+
const value = props[key];
|
|
147
|
+
if (value === null) delete node.p[key];
|
|
148
|
+
else if (value !== undefined) node.p[key] = value;
|
|
149
|
+
}
|
|
150
|
+
this.#unsettle(node);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
case "text": {
|
|
154
|
+
const [, id, mode, text] = op;
|
|
155
|
+
const node = this.#textNode(id);
|
|
156
|
+
if (typeof text !== "string") fail("text must be a string");
|
|
157
|
+
if (mode === "append") node.p.text = this.#text(node) + text;
|
|
158
|
+
else if (mode === "replace") node.p.text = text;
|
|
159
|
+
else fail(`unknown text mode ${String(mode)}`);
|
|
160
|
+
this.#unsettle(node);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
case "splice": {
|
|
164
|
+
const [, id, at, del, text] = op;
|
|
165
|
+
const node = this.#textNode(id);
|
|
166
|
+
const current = this.#text(node);
|
|
167
|
+
if (!Number.isInteger(at) || !Number.isInteger(del) || at < 0 || del < 0 || at + del > current.length)
|
|
168
|
+
fail(`splice range ${at}+${del} outside text of length ${current.length}`);
|
|
169
|
+
node.p.text = current.slice(0, at) + text + current.slice(at + del);
|
|
170
|
+
this.#unsettle(node);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
case "move": {
|
|
174
|
+
const [, id, parentId, before] = op;
|
|
175
|
+
const node = this.#node(id);
|
|
176
|
+
if (node === this.#root) fail("cannot move the root");
|
|
177
|
+
const parent = this.#node(parentId);
|
|
178
|
+
for (let at: DocNode | null = parent; at; at = at.parent) {
|
|
179
|
+
if (at === node) fail(`cannot move ${id} into its own subtree`);
|
|
180
|
+
}
|
|
181
|
+
if (before === id) fail("move before itself");
|
|
182
|
+
const oldParent = node.parent!;
|
|
183
|
+
// Validate `before` before detaching so a rejected move leaves the tree intact.
|
|
184
|
+
if (before !== null && this.#index.get(before)?.parent !== parent)
|
|
185
|
+
fail(`${before} is not a child of ${parentId}`);
|
|
186
|
+
oldParent.c.splice(oldParent.c.indexOf(node), 1);
|
|
187
|
+
parent.c.splice(this.#insertIndex(parent, before), 0, node);
|
|
188
|
+
node.parent = parent;
|
|
189
|
+
this.#unsettle(oldParent);
|
|
190
|
+
this.#unsettle(node);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
case "del": {
|
|
194
|
+
const [, id] = op;
|
|
195
|
+
const node = this.#node(id);
|
|
196
|
+
if (node === this.#root) fail("cannot delete the root");
|
|
197
|
+
const parent = node.parent!;
|
|
198
|
+
parent.c.splice(parent.c.indexOf(node), 1);
|
|
199
|
+
this.#unregister(node);
|
|
200
|
+
this.#unsettle(parent);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
case "settle": {
|
|
204
|
+
const [, id] = op;
|
|
205
|
+
this.#node(id);
|
|
206
|
+
this.#settled.add(id);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
case "focus": {
|
|
210
|
+
const [, id] = op;
|
|
211
|
+
if (id !== null) this.#node(id);
|
|
212
|
+
this.#focus = id;
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
case "reveal": {
|
|
216
|
+
const [, id] = op;
|
|
217
|
+
this.#node(id);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
case "suspend":
|
|
221
|
+
this.#suspended = true;
|
|
222
|
+
return;
|
|
223
|
+
case "resume":
|
|
224
|
+
this.#suspended = false;
|
|
225
|
+
return;
|
|
226
|
+
default:
|
|
227
|
+
fail(`unknown op ${String((op as readonly unknown[])[0])}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#textNode(id: string): DocNode {
|
|
232
|
+
const node = this.#node(id);
|
|
233
|
+
if (!TEXT_KINDS.has(node.k)) fail(`${id} (${node.k}) has no primary text`);
|
|
234
|
+
return node;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
#text(node: DocNode): string {
|
|
238
|
+
return typeof node.p.text === "string" ? node.p.text : "";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
#insertIndex(parent: DocNode, before: string | null): number {
|
|
242
|
+
if (before === null) return parent.c.length;
|
|
243
|
+
const sibling = this.#index.get(before);
|
|
244
|
+
if (!sibling || sibling.parent !== parent) fail(`${before} is not a child of ${parent.id}`);
|
|
245
|
+
return parent.c.indexOf(sibling);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#build(wire: TspNode, parent: DocNode, seen: Set<string>): DocNode {
|
|
249
|
+
if (typeof wire.id !== "string" || wire.id.length === 0) fail("node without id");
|
|
250
|
+
if (!KINDS.has(wire.k)) fail(`unknown kind ${String(wire.k)}`);
|
|
251
|
+
if (this.#index.has(wire.id) || seen.has(wire.id)) fail(`duplicate id ${wire.id}`);
|
|
252
|
+
seen.add(wire.id);
|
|
253
|
+
const node: DocNode = { id: wire.id, k: wire.k, p: {}, c: [], parent };
|
|
254
|
+
if (wire.p) {
|
|
255
|
+
for (const key in wire.p) {
|
|
256
|
+
const value = (wire.p as Record<string, unknown>)[key];
|
|
257
|
+
if (value !== undefined && value !== null) node.p[key] = value;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (wire.c) for (const child of wire.c) node.c.push(this.#build(child, node, seen));
|
|
261
|
+
return node;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
#register(node: DocNode): void {
|
|
265
|
+
this.#index.set(node.id, node);
|
|
266
|
+
for (const child of node.c) this.#register(child);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
#unregister(node: DocNode): void {
|
|
270
|
+
this.#index.delete(node.id);
|
|
271
|
+
this.#settled.delete(node.id);
|
|
272
|
+
if (this.#focus === node.id) this.#focus = null;
|
|
273
|
+
for (const child of node.c) this.#unregister(child);
|
|
274
|
+
}
|
|
275
|
+
}
|