@oh-my-pi/pi-tui 18.4.2 → 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 +56 -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/thinking-display.d.ts +2 -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 +42 -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/loop-watchdog.d.ts +9 -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 +9 -1
- 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 +16 -9
- package/dist/types/setup/scenes/splash.d.ts +8 -0
- package/dist/types/setup/scenes/types.d.ts +6 -27
- 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/stdin-buffer.d.ts +10 -7
- package/dist/types/terminal-capabilities.d.ts +1 -1
- package/dist/types/terminal.d.ts +36 -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-types.d.ts +90 -0
- package/dist/types/tools/web-search.d.ts +9 -168
- 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 +538 -51
- 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/thinking-display.ts +73 -11
- 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 +139 -17
- 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 +239 -36
- 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 +131 -56
- 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/loop-watchdog.ts +38 -10
- 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 +184 -7
- 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 +585 -33
- 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 +138 -24
- package/src/setup/scenes/splash.ts +28 -1
- package/src/setup/scenes/theme.ts +88 -3
- package/src/setup/scenes/types.ts +7 -28
- package/src/setup/startup-splash.ts +46 -9
- package/src/setup/wizard-overlay.ts +140 -23
- package/src/setup/wizard.ts +1 -1
- package/src/status-line/component.ts +414 -18
- 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/stdin-buffer.ts +27 -21
- package/src/terminal-capabilities.ts +7 -0
- package/src/terminal.ts +153 -11
- 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/mermaid-cache.ts +10 -1
- 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/theme/tui-adapters.ts +14 -1
- 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 +233 -62
- 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 +357 -31
- 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/streaming-output.ts +79 -16
- 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-types.ts +99 -0
- package/src/tools/web-search.ts +111 -170
- package/src/tools/write.ts +144 -5
- package/src/tools/xdev.ts +64 -1
- package/src/tui.ts +295 -4
- package/dist/types/setup/scenes/providers.d.ts +0 -3
- package/dist/types/setup/scenes/web-search.d.ts +0 -22
- package/src/setup/scenes/providers.ts +0 -110
- package/src/setup/scenes/web-search.ts +0 -165
|
@@ -3,7 +3,10 @@ import { replaceTabs } from "../render/render-utils";
|
|
|
3
3
|
import { getMarkdownTheme, theme } from "../theme/theme";
|
|
4
4
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
5
5
|
import { StreamingPanelContent } from "../chrome/streaming-panel";
|
|
6
|
-
import { interruptKey } from "../chrome/keybinding-hints";
|
|
6
|
+
import { boundKeys, interruptKey } from "../chrome/keybinding-hints";
|
|
7
|
+
import type { NativeNode } from "../native/node";
|
|
8
|
+
import { col, md, node, span, text } from "../native/describe";
|
|
9
|
+
import { hintsRow, type NativeHint, statusHintsRow } from "../native/overlay";
|
|
7
10
|
|
|
8
11
|
export type OmfgPanelState =
|
|
9
12
|
| "generating"
|
|
@@ -15,6 +18,18 @@ export type OmfgPanelState =
|
|
|
15
18
|
| "aborted"
|
|
16
19
|
| "error";
|
|
17
20
|
|
|
21
|
+
/** States with work still in flight (the sheet head shows the live spinner). */
|
|
22
|
+
const LIVE_STATES: Record<OmfgPanelState, boolean> = {
|
|
23
|
+
generating: true,
|
|
24
|
+
validating: true,
|
|
25
|
+
confirming: true,
|
|
26
|
+
saving: true,
|
|
27
|
+
saved: false,
|
|
28
|
+
rejected: false,
|
|
29
|
+
aborted: false,
|
|
30
|
+
error: false,
|
|
31
|
+
};
|
|
32
|
+
|
|
18
33
|
interface OmfgPanelComponentOptions {
|
|
19
34
|
complaint: string;
|
|
20
35
|
tui: TUI;
|
|
@@ -28,11 +43,14 @@ export class OmfgPanelComponent extends OverlayPanel {
|
|
|
28
43
|
#savedPath: string | undefined;
|
|
29
44
|
#errorMessage: string | undefined;
|
|
30
45
|
#closed = false;
|
|
46
|
+
readonly #complaint: string;
|
|
31
47
|
readonly #content: StreamingPanelContent;
|
|
48
|
+
#native: NativeNode | undefined;
|
|
32
49
|
|
|
33
50
|
constructor(options: OmfgPanelComponentOptions) {
|
|
34
|
-
super(`/omfg ${replaceTabs(options.complaint)}
|
|
51
|
+
super(`/omfg ${replaceTabs(options.complaint)}`, "omp.overlay.omfg");
|
|
35
52
|
this.#tui = options.tui;
|
|
53
|
+
this.#complaint = replaceTabs(options.complaint);
|
|
36
54
|
this.#content = new StreamingPanelContent(() => ({
|
|
37
55
|
sections: [new Text(theme.fg("muted", replaceTabs(this.#status)), 0, 0), this.#contentComponent()],
|
|
38
56
|
footer: this.#footerLine(),
|
|
@@ -98,7 +116,73 @@ export class OmfgPanelComponent extends OverlayPanel {
|
|
|
98
116
|
this.#closed = true;
|
|
99
117
|
}
|
|
100
118
|
|
|
119
|
+
override invalidate(): void {
|
|
120
|
+
this.#native = undefined;
|
|
121
|
+
super.invalidate();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
override describe(): NativeNode {
|
|
125
|
+
if (this.#native) return this.#native;
|
|
126
|
+
const tone =
|
|
127
|
+
this.#state === "error"
|
|
128
|
+
? "error"
|
|
129
|
+
: this.#state === "rejected" || this.#state === "aborted"
|
|
130
|
+
? "warning"
|
|
131
|
+
: undefined;
|
|
132
|
+
// Inline in the dock, styled as a sheet by role: a borderless column headed by the complaint.
|
|
133
|
+
const head = node("row", { role: "omp.sheet.head", gap: "sm", align: "center" }, [
|
|
134
|
+
...(LIVE_STATES[this.#state] ? [node("spinner", {})] : []),
|
|
135
|
+
text([span("/omfg", "accent"), span(` ${this.#complaint}`)], { truncate: "end", lines: 1 }),
|
|
136
|
+
]);
|
|
137
|
+
this.#native = col(
|
|
138
|
+
[
|
|
139
|
+
head,
|
|
140
|
+
text([span(replaceTabs(this.#status), "muted")], { wrap: "word" }),
|
|
141
|
+
this.#describeBody(),
|
|
142
|
+
this.#describeFooter(),
|
|
143
|
+
],
|
|
144
|
+
{ role: this.nativeRole, gap: "sm", tone },
|
|
145
|
+
);
|
|
146
|
+
return this.#native;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
#describeBody(): NativeNode {
|
|
150
|
+
if (this.#state === "error") {
|
|
151
|
+
return text([span(replaceTabs(this.#errorMessage ?? "Unknown error"), "error")], { wrap: "word" });
|
|
152
|
+
}
|
|
153
|
+
const preview = replaceTabs(this.#preview).trim();
|
|
154
|
+
if (preview) return md(preview, { stream: this.#state === "generating" });
|
|
155
|
+
return text([span(`${theme.status.pending} Waiting for candidate rule…`, "dim")]);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
#describeFooter(): NativeNode {
|
|
159
|
+
const esc: NativeHint = { keys: boundKeys("app.interrupt", ["escape"]).slice(0, 1), label: "dismiss" };
|
|
160
|
+
switch (this.#state) {
|
|
161
|
+
case "generating":
|
|
162
|
+
case "validating":
|
|
163
|
+
case "confirming":
|
|
164
|
+
case "saving":
|
|
165
|
+
return hintsRow([{ ...esc, label: "cancel /omfg" }]);
|
|
166
|
+
case "saved":
|
|
167
|
+
return statusHintsRow(
|
|
168
|
+
[
|
|
169
|
+
span(`${theme.status.success} Registered live`, "success"),
|
|
170
|
+
span(" · ", "muted"),
|
|
171
|
+
span(replaceTabs(this.#savedPath ?? "saved"), "path"),
|
|
172
|
+
],
|
|
173
|
+
[esc],
|
|
174
|
+
);
|
|
175
|
+
case "rejected":
|
|
176
|
+
return statusHintsRow([span(`${theme.status.warning} Not saved`, "warning")], [esc]);
|
|
177
|
+
case "aborted":
|
|
178
|
+
return statusHintsRow([span(`${theme.status.warning} Cancelled`, "warning")], [esc]);
|
|
179
|
+
case "error":
|
|
180
|
+
return statusHintsRow([span(`${theme.status.error} Error`, "error")], [esc]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
101
184
|
#rebuild(): void {
|
|
185
|
+
this.#native = undefined;
|
|
102
186
|
this.#content.refresh();
|
|
103
187
|
this.#tui.requestRender();
|
|
104
188
|
}
|
|
@@ -18,7 +18,11 @@ import { centerLine } from "../utils";
|
|
|
18
18
|
import { theme } from "../theme/theme";
|
|
19
19
|
import { matchesAppInterrupt } from "../keybinding-matchers";
|
|
20
20
|
import { formatKeyHint } from "../app-keybindings";
|
|
21
|
-
import { interruptKey } from "../chrome/keybinding-hints";
|
|
21
|
+
import { boundKeys, interruptKey } from "../chrome/keybinding-hints";
|
|
22
|
+
import type { NativeNode, NativeUiEvent } from "../native/node";
|
|
23
|
+
import { col, node, row, span, text } from "../native/describe";
|
|
24
|
+
import { actionBar, actionButton } from "../native/overlay";
|
|
25
|
+
import { isNativeRendering } from "../native/state";
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* Slice of `InteractiveModeContext` the pause screen drives. Narrow so tests
|
|
@@ -120,15 +124,20 @@ export class PauseScreenComponent implements Component, OverlayFocusOwner {
|
|
|
120
124
|
#done = Promise.withResolvers<void>();
|
|
121
125
|
#disposed = false;
|
|
122
126
|
#startedAt = Date.now();
|
|
127
|
+
#native: NativeNode | undefined;
|
|
123
128
|
|
|
124
129
|
constructor(readonly host: PauseScreenHost) {}
|
|
125
130
|
|
|
126
131
|
/** Start the clock; resolves once the user asks to resume. */
|
|
127
132
|
run(): Promise<void> {
|
|
128
133
|
this.#startedAt = agentPauseGate.pausedAt ?? Date.now();
|
|
129
|
-
this.#
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
this.#native = undefined;
|
|
135
|
+
// The tick only repaints the hold clock; natively the `elapsed` node counts on its own.
|
|
136
|
+
if (!isNativeRendering()) {
|
|
137
|
+
this.#timer ??= setInterval(() => {
|
|
138
|
+
if (!this.#disposed) this.host.ui.requestRender();
|
|
139
|
+
}, TICK_MS);
|
|
140
|
+
}
|
|
132
141
|
this.host.ui.requestRender();
|
|
133
142
|
return this.#done.promise;
|
|
134
143
|
}
|
|
@@ -160,6 +169,48 @@ export class PauseScreenComponent implements Component, OverlayFocusOwner {
|
|
|
160
169
|
}
|
|
161
170
|
}
|
|
162
171
|
|
|
172
|
+
invalidate(): void {
|
|
173
|
+
this.#native = undefined;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** A glass sheet titled "Paused" (not the whole pane: the transcript stays visible, frozen). */
|
|
177
|
+
readonly nativeOverlay = { role: "omp.overlay.pause", size: "md", anchor: "center", head: "Paused" } as const;
|
|
178
|
+
|
|
179
|
+
describe(): NativeNode {
|
|
180
|
+
if (this.#native) return this.#native;
|
|
181
|
+
const children: NativeNode[] = [];
|
|
182
|
+
if (this.host.sessionName) children.push(text([span(this.host.sessionName, "strong")]));
|
|
183
|
+
const resumeKey = boundKeys("app.interrupt", ["escape"])[0] ?? "escape";
|
|
184
|
+
children.push(
|
|
185
|
+
text(
|
|
186
|
+
BODY_LINES.map((line, index) => span(index === 0 ? line : `\n${line}`, "muted")),
|
|
187
|
+
{ wrap: "word" },
|
|
188
|
+
),
|
|
189
|
+
row(
|
|
190
|
+
[
|
|
191
|
+
text([span("Paused for", "dim")]),
|
|
192
|
+
node("elapsed", { age: Date.now() - this.#startedAt, format: "clock" }),
|
|
193
|
+
],
|
|
194
|
+
{ gap: "xs", align: "baseline" },
|
|
195
|
+
),
|
|
196
|
+
actionBar([
|
|
197
|
+
null,
|
|
198
|
+
actionButton("Resume", "resume", {
|
|
199
|
+
keys: resumeKey,
|
|
200
|
+
tone: "accent",
|
|
201
|
+
title: `Resume ${resumeKey} · enter · space`,
|
|
202
|
+
}),
|
|
203
|
+
]),
|
|
204
|
+
);
|
|
205
|
+
this.#native = col(children, { gap: "md" });
|
|
206
|
+
return this.#native;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Resume runs what Esc/Enter/Space run. */
|
|
210
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
211
|
+
if (event.type === "action" && event.act === "resume" && !this.#disposed) this.#done.resolve();
|
|
212
|
+
}
|
|
213
|
+
|
|
163
214
|
render(width: number): readonly string[] {
|
|
164
215
|
const elapsed = Date.now() - this.#startedAt;
|
|
165
216
|
return renderPauseScreen(
|
|
@@ -54,9 +54,16 @@ import { padToWidth } from "../render/utils";
|
|
|
54
54
|
import { renderSegmentTrack } from "../chrome/segment-track";
|
|
55
55
|
import { formatKeyHint, formatKeyHints } from "../app-keybindings";
|
|
56
56
|
import { editorKey, editorKeys } from "../chrome/keybinding-hints";
|
|
57
|
+
import type { KeyName } from "../key-hint-format";
|
|
58
|
+
import { col, item, keyed, md, node, row as rowNode, span, text } from "../native/describe";
|
|
59
|
+
import { leafKey, type NativeChild, type NativeNode, type NativeUiEvent } from "../native/node";
|
|
60
|
+
import { actionButton, actionHint, hintsRow, itemIndex, type NativeHint, selectList } from "../native/overlay";
|
|
61
|
+
import { getKeybindings } from "../keybindings";
|
|
57
62
|
|
|
58
63
|
/** Title shown in the overlay's top border. */
|
|
59
64
|
const OVERLAY_TITLE = "Plan Review";
|
|
65
|
+
/** Native sheet title when the plan has no title heading of its own. */
|
|
66
|
+
const NATIVE_TITLE = "Plan review";
|
|
60
67
|
/** Minimum plan-body rows kept visible even on short terminals. */
|
|
61
68
|
const MIN_BODY_ROWS = 3;
|
|
62
69
|
/** Visible rows for the in-overlay annotation editor before it scrolls. */
|
|
@@ -107,6 +114,14 @@ interface AnnotationChooser {
|
|
|
107
114
|
selected: number;
|
|
108
115
|
}
|
|
109
116
|
|
|
117
|
+
/** Described plan body and Contents entries, rebuilt when sections or annotations change. */
|
|
118
|
+
interface NativePlanContent {
|
|
119
|
+
sections: OverlaySection[];
|
|
120
|
+
rev: number;
|
|
121
|
+
body: NativeNode[];
|
|
122
|
+
toc: NativeNode[];
|
|
123
|
+
}
|
|
124
|
+
|
|
110
125
|
/** Serializable annotations retained by the plan-review owner between overlays. */
|
|
111
126
|
export interface PlanReviewAnnotationState {
|
|
112
127
|
annotations: Array<{
|
|
@@ -173,6 +188,10 @@ export class PlanReviewOverlay implements Component {
|
|
|
173
188
|
#scrollView: ScrollView;
|
|
174
189
|
#sections: OverlaySection[] = [];
|
|
175
190
|
#toc: number[] = [];
|
|
191
|
+
/** Section holding the plan's title heading (dropped from the ToC; the native sheet title), or -1. */
|
|
192
|
+
#titleIndex = -1;
|
|
193
|
+
/** Memoized {@link nativeOverlay} for the current title. */
|
|
194
|
+
#nativeOverlay: { title: string; props: NonNullable<Component["nativeOverlay"]> } | undefined;
|
|
176
195
|
/** Shallowest level among ToC entries, used to flatten indentation. */
|
|
177
196
|
#tocBaseLevel = 1;
|
|
178
197
|
#sectionOffsets: number[] = [];
|
|
@@ -223,6 +242,14 @@ export class PlanReviewOverlay implements Component {
|
|
|
223
242
|
#editingAnnotation: AnnotationSelection | undefined;
|
|
224
243
|
#annotationChooser: AnnotationChooser | undefined;
|
|
225
244
|
|
|
245
|
+
/** Bumped on every section/annotation change (all of them funnel through {@link #recomputeFeedback}). */
|
|
246
|
+
#annotationRev = 0;
|
|
247
|
+
#nativeContent: NativePlanContent | undefined;
|
|
248
|
+
#nativeSig = "";
|
|
249
|
+
#nativeRoot: NativeNode | undefined;
|
|
250
|
+
/** Content the memoized root was built from. */
|
|
251
|
+
#nativeRootContent: NativePlanContent | undefined;
|
|
252
|
+
|
|
226
253
|
constructor(
|
|
227
254
|
planContent: string,
|
|
228
255
|
options: PlanReviewOverlayOptions,
|
|
@@ -443,6 +470,7 @@ export class PlanReviewOverlay implements Component {
|
|
|
443
470
|
for (const i of headings) minLevel = Math.min(minLevel, this.#sections[i]!.level);
|
|
444
471
|
const topLevel = headings.filter(i => this.#sections[i]!.level === minLevel);
|
|
445
472
|
const titleIndex = topLevel.length === 1 && headings[0] === topLevel[0] ? topLevel[0] : -1;
|
|
473
|
+
this.#titleIndex = titleIndex ?? -1;
|
|
446
474
|
this.#toc = headings.filter(i => i !== titleIndex);
|
|
447
475
|
this.#tocBaseLevel = this.#toc.length > 0 ? Math.min(...this.#toc.map(i => this.#sections[i]!.level)) : 1;
|
|
448
476
|
}
|
|
@@ -996,6 +1024,7 @@ export class PlanReviewOverlay implements Component {
|
|
|
996
1024
|
}
|
|
997
1025
|
|
|
998
1026
|
#recomputeFeedback(): void {
|
|
1027
|
+
this.#annotationRev++;
|
|
999
1028
|
this.callbacks.onAnnotationStateChange?.(this.#annotationState());
|
|
1000
1029
|
const annotated = this.#sections.filter(section => section.annotations.length > 0);
|
|
1001
1030
|
if (annotated.length === 0 && this.#deleted.length === 0) {
|
|
@@ -1351,6 +1380,329 @@ export class PlanReviewOverlay implements Component {
|
|
|
1351
1380
|
return [theme.fg("dim", this.#buildHelp())];
|
|
1352
1381
|
}
|
|
1353
1382
|
|
|
1383
|
+
/** The native sheet: large glass, titled by the plan's own title heading (the body never repeats it). */
|
|
1384
|
+
get nativeOverlay(): NonNullable<Component["nativeOverlay"]> {
|
|
1385
|
+
const heading = this.#sections[this.#titleIndex]?.title;
|
|
1386
|
+
const title = heading ? sanitizeStatusText(heading) : NATIVE_TITLE;
|
|
1387
|
+
if (this.#nativeOverlay?.title !== title) {
|
|
1388
|
+
this.#nativeOverlay = {
|
|
1389
|
+
title,
|
|
1390
|
+
props: { role: "omp.overlay.planReview", size: "lg", anchor: "center", head: title },
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
return this.#nativeOverlay.props;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
describe(): NativeNode {
|
|
1397
|
+
// The terminal lays out the sidebar; it is shown whenever the Contents has
|
|
1398
|
+
// enough entries, which is also what Tab cycling consults.
|
|
1399
|
+
this.#sidebarShown = this.#toc.length >= SIDEBAR_MIN_HEADINGS;
|
|
1400
|
+
if (this.#annotating) this.#editor.focused = true;
|
|
1401
|
+
const content = this.#describeContent();
|
|
1402
|
+
const chooser = this.#annotationChooser;
|
|
1403
|
+
const target = this.#annotationTarget;
|
|
1404
|
+
const sig = [
|
|
1405
|
+
this.#focus,
|
|
1406
|
+
this.#tocCursor,
|
|
1407
|
+
this.#selectedIndex,
|
|
1408
|
+
this.#sliderIndex,
|
|
1409
|
+
this.#committed ? `committed:${this.#committedLabel ?? ""}` : "",
|
|
1410
|
+
this.#annotating
|
|
1411
|
+
? `annotating:${target?.sectionIndex}:${target?.row}:${target?.context}:${this.#editingAnnotation !== undefined}`
|
|
1412
|
+
: "",
|
|
1413
|
+
chooser
|
|
1414
|
+
? `chooser:${chooser.selected}:${chooser.entries.map(e => `${e.sectionIndex}.${e.annotationIndex}`).join()}`
|
|
1415
|
+
: "",
|
|
1416
|
+
].join("|");
|
|
1417
|
+
if (this.#nativeRoot && sig === this.#nativeSig && content === this.#nativeRootContent) return this.#nativeRoot;
|
|
1418
|
+
|
|
1419
|
+
const children: NativeChild[] = [];
|
|
1420
|
+
const tools = this.#describeTools();
|
|
1421
|
+
if (tools) children.push(tools);
|
|
1422
|
+
const bodyCol = node(
|
|
1423
|
+
"col",
|
|
1424
|
+
{ role: "omp.plan.body", grow: 1, gap: "md", tone: this.#focus === "body" ? "accent" : undefined },
|
|
1425
|
+
content.body,
|
|
1426
|
+
"body",
|
|
1427
|
+
);
|
|
1428
|
+
if (this.#sidebarShown) {
|
|
1429
|
+
const tocSection = this.#toc[this.#tocCursor];
|
|
1430
|
+
const toc = selectList("toc", content.toc, {
|
|
1431
|
+
selected: tocSection === undefined ? null : `h${tocSection}`,
|
|
1432
|
+
role: "omp.plan.toc",
|
|
1433
|
+
tone: this.#focus === "toc" ? "accent" : undefined,
|
|
1434
|
+
});
|
|
1435
|
+
const sidebar = node("col", { max: { w: "32ch" }, shrink: 0 }, [toc], "sidebar");
|
|
1436
|
+
children.push(keyed(rowNode([sidebar, bodyCol], { gap: "lg", align: "start" }), "split"));
|
|
1437
|
+
} else {
|
|
1438
|
+
children.push(bodyCol);
|
|
1439
|
+
}
|
|
1440
|
+
if (this.#promptTitle) {
|
|
1441
|
+
children.push(keyed(text([span(this.#promptTitle, "muted")], { role: "omp.plan.prompt" }), "prompt"));
|
|
1442
|
+
}
|
|
1443
|
+
if (this.#committed) {
|
|
1444
|
+
const label = this.#committedLabel ? `${this.#committedLabel} — submitting…` : "Submitting…";
|
|
1445
|
+
children.push(node("spinner", { label: [span(label, "accent strong")] }, undefined, "options"));
|
|
1446
|
+
children.push(
|
|
1447
|
+
keyed(
|
|
1448
|
+
text([span("Applying your selection — this can take a moment while context is prepared.", "dim")], {
|
|
1449
|
+
wrap: "word",
|
|
1450
|
+
}),
|
|
1451
|
+
"footer",
|
|
1452
|
+
),
|
|
1453
|
+
);
|
|
1454
|
+
} else {
|
|
1455
|
+
children.push(...this.#describeSlider());
|
|
1456
|
+
// The decision bar: Tern lays the list out as buttons, the first one the hero.
|
|
1457
|
+
const optionItems = this.#options.map((label, i) =>
|
|
1458
|
+
item(`o${i}`, {
|
|
1459
|
+
label,
|
|
1460
|
+
disabled: this.#disabled.has(i) || undefined,
|
|
1461
|
+
hint: i === this.#selectedIndex ? ["enter"] : undefined,
|
|
1462
|
+
}),
|
|
1463
|
+
);
|
|
1464
|
+
children.push(
|
|
1465
|
+
selectList("options", optionItems, {
|
|
1466
|
+
selected: this.#selectedIndex >= 0 ? `o${this.#selectedIndex}` : null,
|
|
1467
|
+
role: "omp.plan.options",
|
|
1468
|
+
tone: this.#focus === "actions" ? "accent" : undefined,
|
|
1469
|
+
}),
|
|
1470
|
+
);
|
|
1471
|
+
children.push(...this.#describeFooter());
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
this.#nativeSig = sig;
|
|
1475
|
+
this.#nativeRootContent = content;
|
|
1476
|
+
// The sheet is the frame: a borderless column, titled by `nativeOverlay`.
|
|
1477
|
+
this.#nativeRoot = col(children, { gap: "md" });
|
|
1478
|
+
return this.#nativeRoot;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
/** Head tools: Copy `c` and the external editor, mirroring their keys. */
|
|
1482
|
+
#describeTools(): NativeNode | undefined {
|
|
1483
|
+
if (this.#committed) return undefined;
|
|
1484
|
+
const buttons: NativeNode[] = [];
|
|
1485
|
+
if (this.callbacks.onCopyPlan)
|
|
1486
|
+
buttons.push(actionButton("Copy", "copyPlan", { keys: "c", title: "Copy plan c" }));
|
|
1487
|
+
// Unbound: the button still mirrors the callback, without a keycap.
|
|
1488
|
+
const editorKeyId = getKeybindings().getKeys("app.editor.external")[0];
|
|
1489
|
+
if (this.callbacks.onExternalEditor) {
|
|
1490
|
+
buttons.push(actionButton("Edit in $EDITOR", "externalEditor", editorKeyId ? { keys: editorKeyId } : {}));
|
|
1491
|
+
}
|
|
1492
|
+
if (buttons.length === 0) return undefined;
|
|
1493
|
+
return node("row", { role: "omp.plan.tools", gap: "sm", align: "center", justify: "end" }, buttons, "tools");
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
1497
|
+
if (this.#committed) return;
|
|
1498
|
+
if (event.type === "action") {
|
|
1499
|
+
// Head tools run exactly what `c` and the external-editor key run.
|
|
1500
|
+
if (this.#annotating || this.#annotationChooser) return;
|
|
1501
|
+
if (event.act === "copyPlan" && this.callbacks.onCopyPlan) {
|
|
1502
|
+
void this.callbacks.onCopyPlan(joinPlanSections(this.#sections));
|
|
1503
|
+
} else if (event.act === "externalEditor") {
|
|
1504
|
+
this.callbacks.onExternalEditor?.();
|
|
1505
|
+
}
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
if (event.type !== "select" && event.type !== "activate") return;
|
|
1509
|
+
const activate = event.type === "activate";
|
|
1510
|
+
switch (leafKey(event.key)) {
|
|
1511
|
+
case "toc": {
|
|
1512
|
+
const pos = this.#toc.indexOf(itemIndex(event.item, "h"));
|
|
1513
|
+
if (pos < 0) return;
|
|
1514
|
+
this.#focus = "toc";
|
|
1515
|
+
this.#tocCursor = pos;
|
|
1516
|
+
this.#scrubBodyToToc();
|
|
1517
|
+
if (activate) this.#setFocus("body");
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
case "options": {
|
|
1521
|
+
const index = itemIndex(event.item, "o");
|
|
1522
|
+
if (index < 0 || index >= this.#options.length || this.#disabled.has(index)) return;
|
|
1523
|
+
this.#focus = "actions";
|
|
1524
|
+
this.#selectedIndex = index;
|
|
1525
|
+
if (activate) this.#confirmSelection();
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
case "tabs": {
|
|
1529
|
+
const index = itemIndex(event.item, "t");
|
|
1530
|
+
if (index >= 0) this.#moveSlider(index - this.#sliderIndex);
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
case "chooser": {
|
|
1534
|
+
const chooser = this.#annotationChooser;
|
|
1535
|
+
const index = itemIndex(event.item, "c");
|
|
1536
|
+
if (!chooser || index < 0 || index >= chooser.entries.length) return;
|
|
1537
|
+
chooser.selected = index;
|
|
1538
|
+
if (activate) {
|
|
1539
|
+
this.#annotationChooser = undefined;
|
|
1540
|
+
this.#startExistingAnnotation(chooser.entries[index]!);
|
|
1541
|
+
}
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
/** Plan body (one `md` per section, annotation callouts after it) and Contents items. */
|
|
1548
|
+
#describeContent(): NativePlanContent {
|
|
1549
|
+
const cached = this.#nativeContent;
|
|
1550
|
+
if (cached && cached.sections === this.#sections && cached.rev === this.#annotationRev) return cached;
|
|
1551
|
+
const body: NativeNode[] = [];
|
|
1552
|
+
for (const [sectionIndex, section] of this.#sections.entries()) {
|
|
1553
|
+
const key = `s${sectionIndex}`;
|
|
1554
|
+
// The title heading is the sheet's title; the body keeps only what follows it.
|
|
1555
|
+
const newline = section.raw.indexOf("\n");
|
|
1556
|
+
const source =
|
|
1557
|
+
sectionIndex !== this.#titleIndex ? section.raw : newline < 0 ? "" : section.raw.slice(newline + 1);
|
|
1558
|
+
const hasText = sectionIndex !== this.#titleIndex || source.trim() !== "";
|
|
1559
|
+
if (section.annotations.length === 0) {
|
|
1560
|
+
if (hasText) body.push(keyed(md(source), key));
|
|
1561
|
+
continue;
|
|
1562
|
+
}
|
|
1563
|
+
const children: NativeNode[] = hasText ? [keyed(md(source), "md")] : [];
|
|
1564
|
+
for (const [n, annotation] of section.annotations.entries()) {
|
|
1565
|
+
// A margin note: the anchored line quoted, then the note, on one ink-pen bar.
|
|
1566
|
+
const note: NativeNode[] = [];
|
|
1567
|
+
if (annotation.target.kind === "line") {
|
|
1568
|
+
note.push(text([span(annotation.target.context, "muted")], { truncate: "end", lines: 1 }));
|
|
1569
|
+
}
|
|
1570
|
+
note.push(text(sanitizeText(annotation.note), { wrap: "word" }));
|
|
1571
|
+
children.push(node("col", { role: "omp.plan.note", gap: "xs" }, note, `n${n}`));
|
|
1572
|
+
}
|
|
1573
|
+
body.push(keyed(col(children, { gap: "sm" }), key));
|
|
1574
|
+
}
|
|
1575
|
+
const toc = this.#toc.map(sectionIndex => {
|
|
1576
|
+
const section = this.#sections[sectionIndex]!;
|
|
1577
|
+
const count = section.annotations.length;
|
|
1578
|
+
return item(`h${sectionIndex}`, {
|
|
1579
|
+
label: section.title || "(untitled)",
|
|
1580
|
+
value: count > 0 ? [span(`✎${count}`, "warning")] : undefined,
|
|
1581
|
+
role: `omp.plan.toc.depth${section.level - this.#tocBaseLevel}`,
|
|
1582
|
+
});
|
|
1583
|
+
});
|
|
1584
|
+
this.#nativeContent = { sections: this.#sections, rev: this.#annotationRev, body, toc };
|
|
1585
|
+
return this.#nativeContent;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
#describeSlider(): NativeNode[] {
|
|
1589
|
+
const slider = this.#slider;
|
|
1590
|
+
if (!slider) return [];
|
|
1591
|
+
const tabs = node(
|
|
1592
|
+
"tabs",
|
|
1593
|
+
{
|
|
1594
|
+
items: slider.segments.map((segment, i) => ({ id: `t${i}`, label: segment.label })),
|
|
1595
|
+
active: `t${this.#sliderIndex}`,
|
|
1596
|
+
actions: { click: "select" },
|
|
1597
|
+
role: "omp.plan.strategy",
|
|
1598
|
+
},
|
|
1599
|
+
undefined,
|
|
1600
|
+
"tabs",
|
|
1601
|
+
);
|
|
1602
|
+
const track: NativeChild[] = slider.caption ? [text([span(slider.caption, "dim")]), tabs] : [tabs];
|
|
1603
|
+
const out = [keyed(rowNode(track, { gap: "sm", align: "center" }), "slider")];
|
|
1604
|
+
const detail = slider.segments[this.#sliderIndex]?.detail;
|
|
1605
|
+
if (detail) out.push(keyed(text([span("↳ ", "dim"), span(detail, "muted")], { wrap: "word" }), "sliderDetail"));
|
|
1606
|
+
return out;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
#describeFooter(): NativeChild[] {
|
|
1610
|
+
const chooser = this.#annotationChooser;
|
|
1611
|
+
if (chooser) {
|
|
1612
|
+
const entries = chooser.entries.map((selection, i) => {
|
|
1613
|
+
const section = this.#sections[selection.sectionIndex];
|
|
1614
|
+
const annotation = section?.annotations[selection.annotationIndex];
|
|
1615
|
+
const where = annotation?.target.kind === "line" ? `line ${annotation.target.context}` : "section";
|
|
1616
|
+
return item(`c${i}`, {
|
|
1617
|
+
label: sanitizeStatusText(annotation?.note ?? ""),
|
|
1618
|
+
detail: `${sanitizeStatusText(section?.title || "Plan preamble")} · ${where}`,
|
|
1619
|
+
});
|
|
1620
|
+
});
|
|
1621
|
+
return [
|
|
1622
|
+
keyed(text([span("Edit annotation", "accent strong")]), "chooserHead"),
|
|
1623
|
+
selectList("chooser", entries, { selected: `c${chooser.selected}` }),
|
|
1624
|
+
hintsRow(
|
|
1625
|
+
[
|
|
1626
|
+
actionHint(["tui.select.up", "tui.select.down"], "choose"),
|
|
1627
|
+
{ keys: ["enter"], label: "edit" },
|
|
1628
|
+
actionHint("tui.select.cancel", "cancel"),
|
|
1629
|
+
],
|
|
1630
|
+
"chooserHints",
|
|
1631
|
+
),
|
|
1632
|
+
];
|
|
1633
|
+
}
|
|
1634
|
+
if (this.#annotating) {
|
|
1635
|
+
const target = this.#annotationTarget;
|
|
1636
|
+
const title = sanitizeStatusText(this.#sections[target?.sectionIndex ?? -1]?.title || "Plan preamble");
|
|
1637
|
+
const location = target?.row === null ? `‹${title}›` : `‹${title}› · ${target?.context ?? ""}`;
|
|
1638
|
+
const hints: (NativeHint | undefined)[] = [
|
|
1639
|
+
actionHint("tui.input.submit", "save"),
|
|
1640
|
+
actionHint("tui.input.newLine", "newline"),
|
|
1641
|
+
actionHint("tui.select.cancel", "cancel"),
|
|
1642
|
+
];
|
|
1643
|
+
if (this.#editingAnnotation) hints.push({ keys: [], label: "empty deletes" });
|
|
1644
|
+
if (this.#externalEditorLabel) hints.push({ keys: [], label: `${this.#externalEditorLabel} editor` });
|
|
1645
|
+
// The feedback field, inline under the plan: its caption names the anchor, omp's editor holds the text.
|
|
1646
|
+
return [
|
|
1647
|
+
node(
|
|
1648
|
+
"col",
|
|
1649
|
+
{ role: "omp.plan.feedback", gap: "xs" },
|
|
1650
|
+
[
|
|
1651
|
+
keyed(
|
|
1652
|
+
text([span("Note on ", "muted"), span(location, "accent")], { truncate: "end" }),
|
|
1653
|
+
"annotateHead",
|
|
1654
|
+
),
|
|
1655
|
+
this.#editor,
|
|
1656
|
+
hintsRow(hints, "annotateHints"),
|
|
1657
|
+
],
|
|
1658
|
+
"feedback",
|
|
1659
|
+
),
|
|
1660
|
+
];
|
|
1661
|
+
}
|
|
1662
|
+
return [hintsRow(this.#nativeHelpHints())];
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
/** {@link #buildHelp} as keycap hints. */
|
|
1666
|
+
#nativeHelpHints(): (NativeHint | undefined)[] {
|
|
1667
|
+
const upDown = (label: string) => actionHint(["tui.select.up", "tui.select.down"], label);
|
|
1668
|
+
const key = (keys: KeyName | readonly KeyName[], label: string): NativeHint => ({
|
|
1669
|
+
keys: typeof keys === "string" ? [keys] : keys,
|
|
1670
|
+
label,
|
|
1671
|
+
});
|
|
1672
|
+
const hints: (NativeHint | undefined)[] = [];
|
|
1673
|
+
switch (this.#focus) {
|
|
1674
|
+
case "actions":
|
|
1675
|
+
hints.push(upDown("select"), key("enter", "confirm"));
|
|
1676
|
+
if (this.#slider) hints.push(key(["left", "right"], "model"));
|
|
1677
|
+
break;
|
|
1678
|
+
case "toc":
|
|
1679
|
+
hints.push(
|
|
1680
|
+
upDown("section"),
|
|
1681
|
+
key("enter", "open"),
|
|
1682
|
+
key("a", "annotate"),
|
|
1683
|
+
key("e", "edit"),
|
|
1684
|
+
key("d", "delete"),
|
|
1685
|
+
key("u", "undo"),
|
|
1686
|
+
);
|
|
1687
|
+
break;
|
|
1688
|
+
case "body":
|
|
1689
|
+
hints.push(
|
|
1690
|
+
upDown("scroll"),
|
|
1691
|
+
key("shift", "faster"),
|
|
1692
|
+
key(["pageUp", "pageDown"], "page"),
|
|
1693
|
+
key(["g", "shift+g"], "ends"),
|
|
1694
|
+
key("a", "annotate"),
|
|
1695
|
+
key("e", "edit"),
|
|
1696
|
+
key("u", "undo"),
|
|
1697
|
+
);
|
|
1698
|
+
break;
|
|
1699
|
+
}
|
|
1700
|
+
// Copy and the external editor are head buttons with their keycaps; the hints skip them.
|
|
1701
|
+
hints.push(key("tab", "regions"));
|
|
1702
|
+
hints.push(this.#helpSuffix ? { keys: [], label: this.#helpSuffix } : actionHint("tui.select.cancel", "cancel"));
|
|
1703
|
+
return hints;
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1354
1706
|
render(width: number): readonly string[] {
|
|
1355
1707
|
const termHeight = process.stdout.rows || 40;
|
|
1356
1708
|
const sidebarShown = this.#sidebarVisible(width);
|
|
@@ -2,6 +2,10 @@ import { type Component, CURSOR_MARKER, type Focusable, Input, truncateToWidth,
|
|
|
2
2
|
import { theme } from "../theme/theme";
|
|
3
3
|
import { OverlayPanel, PanelRows } from "../chrome/overlay-box";
|
|
4
4
|
import { editorKey } from "../chrome/keybinding-hints";
|
|
5
|
+
import { col, keyed, span, text } from "../native/describe";
|
|
6
|
+
import type { NativeChild, NativeNode, NativeUiEvent } from "../native/node";
|
|
7
|
+
import { actionBar, actionButton } from "../native/overlay";
|
|
8
|
+
import { getKeybindings } from "../keybindings";
|
|
5
9
|
|
|
6
10
|
/** A confirmed destination chosen from {@link PlanSaveOverlay}. */
|
|
7
11
|
export interface PlanSaveOverlayResult {
|
|
@@ -16,6 +20,8 @@ export class PlanSaveOverlay implements Component, Focusable {
|
|
|
16
20
|
#focused = false;
|
|
17
21
|
readonly #panel: OverlayPanel;
|
|
18
22
|
readonly #body: PanelRows;
|
|
23
|
+
#nativeSig = "";
|
|
24
|
+
#nativeRoot: NativeNode | undefined;
|
|
19
25
|
|
|
20
26
|
constructor(suggestedPath: string, done: (result: PlanSaveOverlayResult | undefined) => void) {
|
|
21
27
|
this.#suggestedPath = suggestedPath;
|
|
@@ -64,6 +70,45 @@ export class PlanSaveOverlay implements Component, Focusable {
|
|
|
64
70
|
return this.#panel.render(width);
|
|
65
71
|
}
|
|
66
72
|
|
|
73
|
+
/** A small glass sheet titled "Save and quit". */
|
|
74
|
+
readonly nativeOverlay = { role: "omp.overlay.planSave", size: "sm", head: "Save and quit" } as const;
|
|
75
|
+
|
|
76
|
+
describe(): NativeNode {
|
|
77
|
+
this.#input.focused = this.#focused;
|
|
78
|
+
const showDefault = this.#input.getValue().length === 0;
|
|
79
|
+
const bindings = getKeybindings();
|
|
80
|
+
const submitKey = bindings.getKeys("tui.input.submit")[0];
|
|
81
|
+
const cancelKey = bindings.getKeys("tui.select.cancel")[0];
|
|
82
|
+
const sig = `${showDefault}|${this.#suggestedPath}|${submitKey}|${cancelKey}`;
|
|
83
|
+
if (this.#nativeRoot && sig === this.#nativeSig) return this.#nativeRoot;
|
|
84
|
+
const children: NativeChild[] = [this.#input];
|
|
85
|
+
if (showDefault) {
|
|
86
|
+
children.push(
|
|
87
|
+
keyed(
|
|
88
|
+
text([span("Empty saves to ", "dim"), span(this.#suggestedPath, "path")], { truncate: "middle" }),
|
|
89
|
+
"default",
|
|
90
|
+
),
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
children.push(
|
|
94
|
+
actionBar([
|
|
95
|
+
null,
|
|
96
|
+
actionButton("Cancel", "cancel", cancelKey ? { keys: cancelKey } : {}),
|
|
97
|
+
actionButton("Save and quit", "save", { tone: "accent", ...(submitKey ? { keys: submitKey } : {}) }),
|
|
98
|
+
]),
|
|
99
|
+
);
|
|
100
|
+
this.#nativeSig = sig;
|
|
101
|
+
this.#nativeRoot = col(children, { gap: "md" });
|
|
102
|
+
return this.#nativeRoot;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Save and Cancel run what the submit and cancel keys run. */
|
|
106
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
107
|
+
if (event.type !== "action") return;
|
|
108
|
+
if (event.act === "save") this.#input.onSubmit?.(this.#input.getValue());
|
|
109
|
+
else if (event.act === "cancel") this.#input.onEscape?.();
|
|
110
|
+
}
|
|
111
|
+
|
|
67
112
|
#renderInput(width: number): string {
|
|
68
113
|
if (this.#input.getValue().length > 0) return this.#input.render(width)[0] ?? "";
|
|
69
114
|
const prompt = this.#input.prompt;
|