@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
|
@@ -9,7 +9,13 @@ import { addKeyAliases, canonicalKeyId } from "../keybindings";
|
|
|
9
9
|
import { type KeyId, parseKey } from "../keys";
|
|
10
10
|
import type { Component, TUI } from "../tui";
|
|
11
11
|
import { type ThemeColor, theme } from "../theme/theme";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
buildSessionModelScope,
|
|
14
|
+
MODEL_PICKER_COLUMNS,
|
|
15
|
+
ModelBrowser,
|
|
16
|
+
type ModelBrowserItem,
|
|
17
|
+
type ModelPickerCatalogue,
|
|
18
|
+
} from "./model-browser";
|
|
13
19
|
import type { ModelBrowserRegistry, ModelBrowserSource } from "./model-browser";
|
|
14
20
|
import type { ConfiguredThinkingLevel } from "../thinking";
|
|
15
21
|
import type { ScopedModelItem } from "./model-hub";
|
|
@@ -17,6 +23,11 @@ import { bottomBorder, row, topBorder } from "../chrome/overlay-box";
|
|
|
17
23
|
import { resolveSegmentPalette } from "../chrome/segment-track";
|
|
18
24
|
import { formatKeyHint } from "../app-keybindings";
|
|
19
25
|
import { editorKey, editorKeys } from "../chrome/keybinding-hints";
|
|
26
|
+
import { card, compact, span, text } from "../native/describe";
|
|
27
|
+
import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../native/node";
|
|
28
|
+
import { CLOSE_ACTION, picker, pickerAction, pickerEvent } from "../native/picker";
|
|
29
|
+
import type { TspPickerProps } from "@oh-my-pi/pi-wire";
|
|
30
|
+
import { actionHint, hintsRow, type NativeHint } from "../native/overlay";
|
|
20
31
|
|
|
21
32
|
/** Configured role resolved to a concrete model. */
|
|
22
33
|
export interface ResolvedRoleModel {
|
|
@@ -28,7 +39,8 @@ export interface ResolvedRoleModel {
|
|
|
28
39
|
|
|
29
40
|
/** Catalog refresh capability used by the session picker. */
|
|
30
41
|
export interface ModelPickerRegistry extends ModelBrowserRegistry {
|
|
31
|
-
|
|
42
|
+
/** Bring the catalog up to date without rebuilding a current one; `true` when the picker must re-read it. */
|
|
43
|
+
refreshIfStale(): Promise<boolean>;
|
|
32
44
|
}
|
|
33
45
|
|
|
34
46
|
export interface ModelPickerCallbacks {
|
|
@@ -116,6 +128,16 @@ export class ModelPickerComponent implements Component {
|
|
|
116
128
|
#taskMatchKeys = new Set<string>();
|
|
117
129
|
#taskModeKey: KeyId | undefined;
|
|
118
130
|
#taskSelector: string | undefined;
|
|
131
|
+
#nativeRoot: { memo: string; node: NativeNode } | undefined;
|
|
132
|
+
#pickerRoot:
|
|
133
|
+
| {
|
|
134
|
+
memo: string;
|
|
135
|
+
catalogue: ModelPickerCatalogue;
|
|
136
|
+
order: object;
|
|
137
|
+
preview: readonly NativeChild[];
|
|
138
|
+
node: NativeNode;
|
|
139
|
+
}
|
|
140
|
+
| undefined;
|
|
119
141
|
|
|
120
142
|
constructor(
|
|
121
143
|
tui: TUI,
|
|
@@ -172,13 +194,15 @@ export class ModelPickerComponent implements Component {
|
|
|
172
194
|
this.#browser.selectSelector(options.currentSelector);
|
|
173
195
|
}
|
|
174
196
|
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
// the
|
|
197
|
+
// Re-read only if the catalog moves (startup discovery landing, a
|
|
198
|
+
// models.yml edit): rebuilding a current catalog on every open blocks
|
|
199
|
+
// the first paint for seconds. A --models scope is registry-independent.
|
|
178
200
|
if (this.#scopedModels.length === 0) {
|
|
179
201
|
this.#registry
|
|
180
|
-
.
|
|
181
|
-
.then(
|
|
202
|
+
.refreshIfStale()
|
|
203
|
+
.then(changed => {
|
|
204
|
+
if (changed) this.#syncFromRegistryState();
|
|
205
|
+
})
|
|
182
206
|
.catch(error => {
|
|
183
207
|
this.#configError = error instanceof Error ? error.message : String(error);
|
|
184
208
|
})
|
|
@@ -297,4 +321,157 @@ export class ModelPickerComponent implements Component {
|
|
|
297
321
|
out.push(bottomBorder(width, borderColor));
|
|
298
322
|
return out;
|
|
299
323
|
}
|
|
324
|
+
|
|
325
|
+
/** A `picker` is its own sheet: the backend mounts it in `layer` without an `overlay` wrapper. */
|
|
326
|
+
nativeSheet(cx: DescribeContext): boolean {
|
|
327
|
+
return cx.supports("picker");
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Picker pointer events, each on the path of the key it stands for. */
|
|
331
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
332
|
+
const picked = pickerEvent(event);
|
|
333
|
+
if (!picked) return;
|
|
334
|
+
if (picked.kind !== "action") {
|
|
335
|
+
this.#browser.routePickerItem(picked.item, picked.kind === "activate");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
switch (picked.act) {
|
|
339
|
+
case CLOSE_ACTION.id:
|
|
340
|
+
this.#browser.handleCancel();
|
|
341
|
+
return;
|
|
342
|
+
case "clear":
|
|
343
|
+
if (this.#browser.query.length > 0) this.#browser.handleCancel();
|
|
344
|
+
return;
|
|
345
|
+
case "use": {
|
|
346
|
+
const selected = this.#browser.pickerSelected;
|
|
347
|
+
if (selected) this.#browser.routePickerItem(selected, true);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
case "task":
|
|
351
|
+
if (this.#taskModeKey !== undefined && !this.#roleMode) this.#toggleTaskMode();
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** The `md` picker sheet, or the fallback card when the terminal lacks the kind. */
|
|
357
|
+
describe(cx?: DescribeContext): NativeNode {
|
|
358
|
+
return cx?.supports("picker") ? this.#describePicker() : this.#describeCard();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
#describePicker(): NativeNode {
|
|
362
|
+
const mode = this.#taskMode ? "task" : this.#roleMode ? "role" : "session";
|
|
363
|
+
const query = this.#browser.query;
|
|
364
|
+
const view = this.#browser.pickerOrder({
|
|
365
|
+
providers: false,
|
|
366
|
+
rest: mode === "role" ? null : query.trim() ? "Matches" : "All",
|
|
367
|
+
});
|
|
368
|
+
const catalogue = this.#browser.pickerItems(this.#roleMode ? this.#quickRoleItems : this.#modelItems);
|
|
369
|
+
const current =
|
|
370
|
+
mode === "role"
|
|
371
|
+
? this.#currentQuickRoleSelector
|
|
372
|
+
: mode === "task"
|
|
373
|
+
? this.#taskSelector
|
|
374
|
+
: this.#currentSelector;
|
|
375
|
+
const preview = this.#browser.pickerPreview("compact", current);
|
|
376
|
+
const selected = this.#browser.pickerSelected;
|
|
377
|
+
const cursor = this.#browser.cursor;
|
|
378
|
+
const memo = `${mode}\0${this.#configError ?? ""}\0${query}\0${cursor}\0${selected ?? ""}`;
|
|
379
|
+
const cached = this.#pickerRoot;
|
|
380
|
+
if (
|
|
381
|
+
cached !== undefined &&
|
|
382
|
+
cached.memo === memo &&
|
|
383
|
+
cached.catalogue === catalogue &&
|
|
384
|
+
cached.order === view &&
|
|
385
|
+
cached.preview === preview
|
|
386
|
+
) {
|
|
387
|
+
return cached.node;
|
|
388
|
+
}
|
|
389
|
+
const subtitle: TspPickerProps["subtitle"] = this.#configError
|
|
390
|
+
? [span(this.#configError, "error")]
|
|
391
|
+
: mode === "task"
|
|
392
|
+
? [span(TASK_STATUS_HINT, "warning")]
|
|
393
|
+
: mode === "role"
|
|
394
|
+
? QUICK_ROLE_STATUS_HINT
|
|
395
|
+
: STATUS_HINT;
|
|
396
|
+
const cycleKey = editorKey("app.model.cycleForward") || formatKeyHint("ctrl+p");
|
|
397
|
+
const node = picker(
|
|
398
|
+
{
|
|
399
|
+
title: mode === "task" ? "Switch task model" : "Switch model",
|
|
400
|
+
subtitle,
|
|
401
|
+
icon: "cpu",
|
|
402
|
+
noun: mode === "role" ? "roles" : "models",
|
|
403
|
+
size: "md",
|
|
404
|
+
layout: "rows",
|
|
405
|
+
preview: "below",
|
|
406
|
+
query,
|
|
407
|
+
cursor,
|
|
408
|
+
placeholder: mode === "task" ? "Search models…" : "Search models, @ for quick roles…",
|
|
409
|
+
columns: MODEL_PICKER_COLUMNS,
|
|
410
|
+
...catalogue,
|
|
411
|
+
order: view.order,
|
|
412
|
+
...(view.hits ? { hits: view.hits } : {}),
|
|
413
|
+
selected,
|
|
414
|
+
...(current ? { current: [current] } : {}),
|
|
415
|
+
total: this.#browser.baseCount,
|
|
416
|
+
empty: mode === "role" ? `No quick roles in the ${cycleKey} cycle` : "No models available",
|
|
417
|
+
actions: compact([
|
|
418
|
+
pickerAction(
|
|
419
|
+
"use",
|
|
420
|
+
mode === "role" ? "Apply role" : mode === "task" ? "Use for Task subagents" : "Use for session",
|
|
421
|
+
"enter",
|
|
422
|
+
{ primary: true },
|
|
423
|
+
),
|
|
424
|
+
this.#taskModeKey !== undefined && mode !== "role"
|
|
425
|
+
? pickerAction("task", "Task model", this.#taskModeKey, { on: mode === "task" })
|
|
426
|
+
: undefined,
|
|
427
|
+
query.length > 0 ? { ...CLOSE_ACTION, label: "Clear search" } : CLOSE_ACTION,
|
|
428
|
+
]),
|
|
429
|
+
},
|
|
430
|
+
preview,
|
|
431
|
+
);
|
|
432
|
+
this.#pickerRoot = { memo, catalogue, order: view, preview, node };
|
|
433
|
+
return node;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** Root card over the status line, the embedded browser, and the mode's key hints. */
|
|
437
|
+
#describeCard(): NativeNode {
|
|
438
|
+
const mode = this.#taskMode ? "task" : this.#roleMode ? "role" : "session";
|
|
439
|
+
const memo = `${mode}\0${this.#configError ?? ""}\0${this.#taskModeKey ?? ""}`;
|
|
440
|
+
if (this.#nativeRoot?.memo === memo) return this.#nativeRoot.node;
|
|
441
|
+
|
|
442
|
+
const status = this.#configError
|
|
443
|
+
? span(this.#configError, "error")
|
|
444
|
+
: this.#taskMode
|
|
445
|
+
? span(TASK_STATUS_HINT, "error")
|
|
446
|
+
: span(this.#roleMode ? QUICK_ROLE_STATUS_HINT : STATUS_HINT, "muted");
|
|
447
|
+
const hints: (NativeHint | undefined)[] = [
|
|
448
|
+
actionHint(["tui.select.up", "tui.select.down"], mode === "role" ? "roles" : "models"),
|
|
449
|
+
{
|
|
450
|
+
keys: ["enter"],
|
|
451
|
+
label:
|
|
452
|
+
mode === "role"
|
|
453
|
+
? "apply role model"
|
|
454
|
+
: mode === "task"
|
|
455
|
+
? "use for Task subagents"
|
|
456
|
+
: "use for this session",
|
|
457
|
+
},
|
|
458
|
+
{ keys: [], label: "type to search" },
|
|
459
|
+
];
|
|
460
|
+
if (mode === "session") hints.push({ keys: ["@"], label: "quick roles" });
|
|
461
|
+
hints.push(actionHint("tui.select.cancel", "close"));
|
|
462
|
+
if (this.#taskModeKey !== undefined && !this.#roleMode) {
|
|
463
|
+
hints.push({ keys: [this.#taskModeKey], label: this.#taskMode ? "session model" : "task model" });
|
|
464
|
+
}
|
|
465
|
+
// `card` directly: the task-mode tone is a common prop `overlayCard` doesn't take.
|
|
466
|
+
const node = card(
|
|
467
|
+
{
|
|
468
|
+
role: "omp.overlay.model-picker",
|
|
469
|
+
head: this.#taskMode ? "Switch Task Model" : "Switch Model",
|
|
470
|
+
tone: this.#taskMode ? "error" : undefined,
|
|
471
|
+
},
|
|
472
|
+
[text([status], { wrap: "word" }), this.#browser, hintsRow(hints)],
|
|
473
|
+
);
|
|
474
|
+
this.#nativeRoot = { memo, node };
|
|
475
|
+
return node;
|
|
476
|
+
}
|
|
300
477
|
}
|
|
@@ -13,6 +13,9 @@ import { bottomBorder, row, topBorder } from "../chrome/overlay-box";
|
|
|
13
13
|
import { TextFormField } from "../components/form";
|
|
14
14
|
import { formatKeyHint } from "../app-keybindings";
|
|
15
15
|
import { editorKey, editorKeys } from "../chrome/keybinding-hints";
|
|
16
|
+
import type { NativeNode, NativeUiEvent } from "../native/node";
|
|
17
|
+
import { node, span } from "../native/describe";
|
|
18
|
+
import { actionHint, overlayCard, statusHintsRow } from "../native/overlay";
|
|
16
19
|
|
|
17
20
|
export interface MoveOverlayResult {
|
|
18
21
|
directory: string;
|
|
@@ -51,6 +54,7 @@ export class MoveOverlay implements Component, Focusable {
|
|
|
51
54
|
#renderMemo:
|
|
52
55
|
| { width: number; fieldLines: readonly string[]; revision: number; lines: readonly string[] }
|
|
53
56
|
| undefined;
|
|
57
|
+
#native: { revision: number; node: NativeNode } | undefined;
|
|
54
58
|
|
|
55
59
|
constructor(cwd: string, done: (result: MoveOverlayResult | undefined) => void, source: MoveDirectorySource) {
|
|
56
60
|
this.#cwd = cwd;
|
|
@@ -171,6 +175,47 @@ export class MoveOverlay implements Component, Focusable {
|
|
|
171
175
|
return lines;
|
|
172
176
|
}
|
|
173
177
|
|
|
178
|
+
describe(): NativeNode {
|
|
179
|
+
const memo = this.#native;
|
|
180
|
+
if (memo?.revision === this.#revision) return memo.node;
|
|
181
|
+
const items = this.#results
|
|
182
|
+
.slice(0, MAX_RESULTS)
|
|
183
|
+
.map(item => node("item", { label: item.label, detail: [span(item.value, "path")] }, undefined, item.value));
|
|
184
|
+
const list = node(
|
|
185
|
+
"list",
|
|
186
|
+
{
|
|
187
|
+
selected: this.#results[this.#selectedIndex]?.value ?? null,
|
|
188
|
+
empty: this.#field.getValue().length > 0 ? [span("No matching directories", "dim")] : undefined,
|
|
189
|
+
},
|
|
190
|
+
items,
|
|
191
|
+
"results",
|
|
192
|
+
);
|
|
193
|
+
const hints = statusHintsRow(
|
|
194
|
+
[span("Type to filter", "dim")],
|
|
195
|
+
[
|
|
196
|
+
actionHint(["tui.select.up", "tui.select.down"], "navigate"),
|
|
197
|
+
{ keys: ["tab"], label: "accept" },
|
|
198
|
+
{ keys: ["enter"], label: "confirm" },
|
|
199
|
+
actionHint("tui.select.cancel", "cancel"),
|
|
200
|
+
],
|
|
201
|
+
);
|
|
202
|
+
const described = overlayCard("omp.dialog.move", "Move to directory", [this.#field, list, hints]);
|
|
203
|
+
this.#native = { revision: this.#revision, node: described };
|
|
204
|
+
return described;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
208
|
+
if (event.type !== "select" && event.type !== "activate") return;
|
|
209
|
+
const index = this.#results.findIndex(result => result.value === event.item);
|
|
210
|
+
if (index === -1) return;
|
|
211
|
+
if (index !== this.#selectedIndex) {
|
|
212
|
+
this.#selectedIndex = index;
|
|
213
|
+
this.#revision++;
|
|
214
|
+
}
|
|
215
|
+
// Enter submits the field, which confirms the highlighted suggestion.
|
|
216
|
+
if (event.type === "activate") this.#field.submit();
|
|
217
|
+
}
|
|
218
|
+
|
|
174
219
|
invalidate(): void {
|
|
175
220
|
this.#field.input.prompt = theme.fg("dim", "Path: ");
|
|
176
221
|
this.#field.invalidate();
|
|
@@ -9,12 +9,20 @@ import {
|
|
|
9
9
|
type SgrMouseEvent,
|
|
10
10
|
Spacer,
|
|
11
11
|
TruncatedText,
|
|
12
|
+
visibleWidth,
|
|
12
13
|
} from "../index";
|
|
13
14
|
import { theme } from "../theme/theme";
|
|
14
15
|
import { matchesSelectCancel, matchesSelectDown, matchesSelectUp } from "../keybinding-matchers";
|
|
15
16
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
17
|
+
import { Input } from "../components/input";
|
|
16
18
|
import { MenuSelection } from "../components/menu-selection";
|
|
17
19
|
import { centeredViewportRange } from "../components/scroll-viewport";
|
|
20
|
+
import type { TspPickerItem, TspSpan, TspTone } from "@oh-my-pi/pi-wire";
|
|
21
|
+
import { node, span, text } from "../native/describe";
|
|
22
|
+
import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node";
|
|
23
|
+
import { CLOSE_ACTION, dockedPicker, PICKER_KEY, pickerAction, pickerEvent, pickerQuery } from "../native/picker";
|
|
24
|
+
import { overlayCard } from "../native/overlay";
|
|
25
|
+
import { isNativeRendering } from "../native/state";
|
|
18
26
|
|
|
19
27
|
const OAUTH_SELECTOR_MAX_VISIBLE = 10;
|
|
20
28
|
|
|
@@ -44,6 +52,8 @@ const ORIGIN_LABELS = {
|
|
|
44
52
|
export class OAuthSelectorComponent extends OverlayPanel {
|
|
45
53
|
#listContainer: Container;
|
|
46
54
|
#menu: MenuSelection<OAuthProviderInfo>;
|
|
55
|
+
/** The provider search field; its value drives `#menu`'s query. */
|
|
56
|
+
#search = Object.assign(new Input(), { prompt: "" });
|
|
47
57
|
#hoveredIndex: number | null = null;
|
|
48
58
|
/** First provider index of the visible ScrollView window (last #updateList). */
|
|
49
59
|
#scrollStart = 0;
|
|
@@ -61,6 +71,13 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
61
71
|
#spinnerFrame: number = 0;
|
|
62
72
|
#spinnerInterval?: NodeJS.Timeout;
|
|
63
73
|
#validationGeneration: number = 0;
|
|
74
|
+
#nativeItems: readonly NativeNode[] | undefined;
|
|
75
|
+
/** The `visibleItems` array {@link #nativeItems} was built from. */
|
|
76
|
+
#nativeItemsSource: readonly OAuthProviderInfo[] | undefined;
|
|
77
|
+
#nativeRoot: NativeNode | undefined;
|
|
78
|
+
/** Picker rows for the whole catalogue; dropped when an auth state changes. */
|
|
79
|
+
#pickerItems: readonly TspPickerItem[] | undefined;
|
|
80
|
+
#pickerRoot: NativeNode | undefined;
|
|
64
81
|
constructor(
|
|
65
82
|
mode: "login" | "logout",
|
|
66
83
|
authStorage: OAuthSelectorAuthSource,
|
|
@@ -72,7 +89,7 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
72
89
|
requestRender?: () => void;
|
|
73
90
|
},
|
|
74
91
|
) {
|
|
75
|
-
super(mode === "login" ? "Select provider to login" : "Select provider to logout");
|
|
92
|
+
super(mode === "login" ? "Select provider to login" : "Select provider to logout", "omp.overlay.oauth");
|
|
76
93
|
this.#mode = mode;
|
|
77
94
|
this.#authStorage = authStorage;
|
|
78
95
|
this.#onSelectCallback = onSelect;
|
|
@@ -155,6 +172,8 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
155
172
|
continue;
|
|
156
173
|
}
|
|
157
174
|
this.#authState.set(provider.id, "checking");
|
|
175
|
+
this.#nativeItems = undefined;
|
|
176
|
+
this.#pickerItems = undefined;
|
|
158
177
|
pending += 1;
|
|
159
178
|
void this.#validateProvider(provider.id, generation);
|
|
160
179
|
}
|
|
@@ -177,6 +196,8 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
177
196
|
|
|
178
197
|
if (generation !== this.#validationGeneration) return;
|
|
179
198
|
this.#authState.set(providerId, isValid ? "valid" : "invalid");
|
|
199
|
+
this.#nativeItems = undefined;
|
|
200
|
+
this.#pickerItems = undefined;
|
|
180
201
|
if (![...this.#authState.values()].includes("checking")) {
|
|
181
202
|
this.#stopSpinner();
|
|
182
203
|
}
|
|
@@ -185,7 +206,8 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
185
206
|
}
|
|
186
207
|
|
|
187
208
|
#startSpinner(): void {
|
|
188
|
-
|
|
209
|
+
// Natively the "checking" status pulses on the terminal's clock.
|
|
210
|
+
if (this.#spinnerInterval || isNativeRendering()) return;
|
|
189
211
|
this.#spinnerInterval = setInterval(() => {
|
|
190
212
|
const frameCount = theme.spinnerFrames.length;
|
|
191
213
|
if (frameCount > 0) {
|
|
@@ -243,8 +265,9 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
243
265
|
|
|
244
266
|
#renderStatusLine(_total: number): string {
|
|
245
267
|
const query = this.#menu.query.trim();
|
|
246
|
-
|
|
247
|
-
|
|
268
|
+
if (!query) return theme.fg("muted", "Type to search");
|
|
269
|
+
const width = visibleWidth(this.#search.getValue()) + 1;
|
|
270
|
+
return theme.fg("muted", "Search: ") + (this.#search.render(width)[0] ?? "");
|
|
248
271
|
}
|
|
249
272
|
|
|
250
273
|
#getProviderSearchText(provider: OAuthProviderInfo): string {
|
|
@@ -260,32 +283,32 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
260
283
|
return text;
|
|
261
284
|
}
|
|
262
285
|
|
|
263
|
-
|
|
264
|
-
|
|
286
|
+
/** Applies the search field's value to the filter; clears any stale status. */
|
|
287
|
+
#syncSearchQuery(): void {
|
|
288
|
+
this.#menu.setQuery(this.#search.getValue(), false);
|
|
265
289
|
this.#statusMessage = undefined;
|
|
266
290
|
this.#updateList();
|
|
267
291
|
}
|
|
268
292
|
|
|
293
|
+
/** Feeds keys the selector does not bind to the search field. Backspace on an empty query and a leading space bubble. */
|
|
269
294
|
#handleSearchInput(keyData: string): boolean {
|
|
270
295
|
if (!this.#isSearchEnabled()) return false;
|
|
271
|
-
|
|
272
|
-
if (
|
|
273
|
-
if (
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
this.#setSearchQuery(chars.join(""));
|
|
277
|
-
return true;
|
|
296
|
+
const before = this.#search.getValue();
|
|
297
|
+
if (before.length === 0) {
|
|
298
|
+
if (matchesKey(keyData, "backspace")) return false;
|
|
299
|
+
const printableText = extractPrintableText(keyData);
|
|
300
|
+
if (printableText !== undefined && printableText.trim().length === 0) return false;
|
|
278
301
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (
|
|
282
|
-
if (this.#
|
|
283
|
-
|
|
284
|
-
this.#setSearchQuery(this.#menu.query + printableText);
|
|
302
|
+
const cursorBefore = this.#search.getCursor();
|
|
303
|
+
if (!this.#search.handleInput(keyData)) return false;
|
|
304
|
+
if (this.#search.getValue() !== before) this.#syncSearchQuery();
|
|
305
|
+
else if (this.#search.getCursor() !== cursorBefore) this.#updateList();
|
|
285
306
|
return true;
|
|
286
307
|
}
|
|
287
308
|
|
|
288
309
|
#updateList(): void {
|
|
310
|
+
this.#nativeRoot = undefined;
|
|
311
|
+
this.#pickerRoot = undefined;
|
|
289
312
|
this.#listContainer.clear();
|
|
290
313
|
|
|
291
314
|
const items = this.#menu.visibleItems;
|
|
@@ -356,10 +379,6 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
356
379
|
return;
|
|
357
380
|
}
|
|
358
381
|
|
|
359
|
-
if (this.#handleSearchInput(keyData)) {
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
382
|
// Up arrow
|
|
364
383
|
if (matchesSelectUp(keyData)) {
|
|
365
384
|
this.#menu.move(-1, true);
|
|
@@ -388,6 +407,8 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
388
407
|
else if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
|
|
389
408
|
this.#confirmSelection();
|
|
390
409
|
}
|
|
410
|
+
// Everything else edits the search field
|
|
411
|
+
else this.#handleSearchInput(keyData);
|
|
391
412
|
}
|
|
392
413
|
|
|
393
414
|
/** Confirm the selected provider (Enter or mouse click). */
|
|
@@ -403,6 +424,189 @@ export class OAuthSelectorComponent extends OverlayPanel {
|
|
|
403
424
|
}
|
|
404
425
|
}
|
|
405
426
|
|
|
427
|
+
/** Credential status of a provider row: `value` (state) and `detail` (origin) spans. */
|
|
428
|
+
#describeStatus(providerId: string): { value?: readonly TspSpan[]; detail?: readonly TspSpan[] } {
|
|
429
|
+
const origin = this.#authStorage.keys.source(providerId);
|
|
430
|
+
const detail = origin
|
|
431
|
+
? [
|
|
432
|
+
span(
|
|
433
|
+
origin.kind === "env" && origin.envVar ? `env: ${origin.envVar}` : ORIGIN_LABELS[origin.kind],
|
|
434
|
+
"muted",
|
|
435
|
+
),
|
|
436
|
+
]
|
|
437
|
+
: undefined;
|
|
438
|
+
const state = this.#authState.get(providerId);
|
|
439
|
+
if (state === "checking") return { value: [span("checking", "warning", { fx: "pulse" })], detail };
|
|
440
|
+
if (state === "invalid") return { value: [span("invalid", "error")], detail };
|
|
441
|
+
if (state === "valid" || this.#hasSelectableAuth(providerId)) {
|
|
442
|
+
return { value: [span("logged in", "success")], detail };
|
|
443
|
+
}
|
|
444
|
+
return { detail };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** One provider card: initials mark, origin detail, auth-state dot, disabled reason. */
|
|
448
|
+
#pickerItem(provider: OAuthProviderInfo): TspPickerItem {
|
|
449
|
+
const origin = this.#authStorage.keys.source(provider.id);
|
|
450
|
+
const state = this.#authState.get(provider.id);
|
|
451
|
+
const dot: TspTone =
|
|
452
|
+
state === "checking"
|
|
453
|
+
? "pending"
|
|
454
|
+
: state === "invalid"
|
|
455
|
+
? "error"
|
|
456
|
+
: state === "valid" || this.#hasSelectableAuth(provider.id)
|
|
457
|
+
? "success"
|
|
458
|
+
: "muted";
|
|
459
|
+
const source = origin
|
|
460
|
+
? origin.kind === "env" && origin.envVar
|
|
461
|
+
? `env: ${origin.envVar}`
|
|
462
|
+
: ORIGIN_LABELS[origin.kind]
|
|
463
|
+
: undefined;
|
|
464
|
+
const detail = !source
|
|
465
|
+
? "Not configured"
|
|
466
|
+
: origin?.kind === "oauth"
|
|
467
|
+
? `Signed in · ${source}`
|
|
468
|
+
: `API key · ${source}`;
|
|
469
|
+
const initials = provider.name
|
|
470
|
+
.split(/[^\p{L}\p{N}]+/u)
|
|
471
|
+
.filter(word => word.length > 0)
|
|
472
|
+
.slice(0, 2)
|
|
473
|
+
.map(word => word[0]!.toUpperCase())
|
|
474
|
+
.join("");
|
|
475
|
+
return {
|
|
476
|
+
id: provider.id,
|
|
477
|
+
label: provider.name,
|
|
478
|
+
detail,
|
|
479
|
+
mark: { text: initials, seed: provider.id },
|
|
480
|
+
dot,
|
|
481
|
+
...(provider.available ? {} : { disabled: "Provider unavailable in this environment" }),
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
#describePicker(): NativeNode {
|
|
486
|
+
if (this.#pickerRoot) return this.#pickerRoot;
|
|
487
|
+
const all = this.#menu.items;
|
|
488
|
+
this.#pickerItems ??= all.map(provider => this.#pickerItem(provider));
|
|
489
|
+
const query = this.#menu.query;
|
|
490
|
+
const login = this.#mode === "login";
|
|
491
|
+
const search = this.#shouldRenderSearchStatus() ? pickerQuery(this.#search) : pickerQuery(null);
|
|
492
|
+
this.#pickerRoot = dockedPicker({
|
|
493
|
+
title: login ? "Sign in" : "Sign out",
|
|
494
|
+
subtitle: login ? "Pick a provider" : "Remove stored credentials",
|
|
495
|
+
icon: "key-round",
|
|
496
|
+
noun: "providers",
|
|
497
|
+
size: "md",
|
|
498
|
+
layout: "cards",
|
|
499
|
+
preview: "none",
|
|
500
|
+
...search,
|
|
501
|
+
placeholder: "Search providers…",
|
|
502
|
+
items: this.#pickerItems,
|
|
503
|
+
...(query.length > 0 ? { order: this.#menu.visibleItems.map(provider => provider.id) } : {}),
|
|
504
|
+
selected: this.#menu.selectedKey ?? null,
|
|
505
|
+
total: all.length,
|
|
506
|
+
empty: login ? "No OAuth providers available" : "No stored provider credentials to log out",
|
|
507
|
+
...(this.#statusMessage ? { message: this.#statusMessage } : {}),
|
|
508
|
+
actions: [
|
|
509
|
+
pickerAction(
|
|
510
|
+
"confirm",
|
|
511
|
+
login ? "Sign in" : "Sign out",
|
|
512
|
+
"enter",
|
|
513
|
+
login ? { primary: true } : { primary: true, danger: true },
|
|
514
|
+
),
|
|
515
|
+
CLOSE_ACTION,
|
|
516
|
+
],
|
|
517
|
+
});
|
|
518
|
+
return this.#pickerRoot;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
override describe(cx: DescribeContext): NativeNode {
|
|
522
|
+
if (cx.supports("picker")) return this.#describePicker();
|
|
523
|
+
if (this.#nativeRoot) return this.#nativeRoot;
|
|
524
|
+
const items = this.#menu.visibleItems;
|
|
525
|
+
if (!this.#nativeItems || this.#nativeItemsSource !== items) {
|
|
526
|
+
this.#nativeItemsSource = items;
|
|
527
|
+
this.#nativeItems = items.map(provider =>
|
|
528
|
+
node(
|
|
529
|
+
"item",
|
|
530
|
+
{
|
|
531
|
+
label: provider.name,
|
|
532
|
+
tone: provider.available ? undefined : "muted",
|
|
533
|
+
...this.#describeStatus(provider.id),
|
|
534
|
+
},
|
|
535
|
+
undefined,
|
|
536
|
+
provider.id,
|
|
537
|
+
),
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
const query = this.#menu.query;
|
|
541
|
+
const children: NativeNode[] = [];
|
|
542
|
+
if (this.#shouldRenderSearchStatus()) {
|
|
543
|
+
children.push(
|
|
544
|
+
node(
|
|
545
|
+
"input",
|
|
546
|
+
{ text: this.#search.getValue(), cursor: this.#search.getCursor(), placeholder: "Type to search" },
|
|
547
|
+
undefined,
|
|
548
|
+
"search",
|
|
549
|
+
),
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
const empty =
|
|
553
|
+
this.#menu.items.length === 0
|
|
554
|
+
? this.#mode === "login"
|
|
555
|
+
? "No OAuth providers available"
|
|
556
|
+
: "No stored provider credentials to log out"
|
|
557
|
+
: "No matching providers";
|
|
558
|
+
children.push(
|
|
559
|
+
node(
|
|
560
|
+
"list",
|
|
561
|
+
{
|
|
562
|
+
selected: this.#menu.selectedKey ?? null,
|
|
563
|
+
filter: query.trim() || undefined,
|
|
564
|
+
empty: [span(empty, "muted")],
|
|
565
|
+
max: { lines: OAUTH_SELECTOR_MAX_VISIBLE },
|
|
566
|
+
},
|
|
567
|
+
this.#nativeItems,
|
|
568
|
+
"list",
|
|
569
|
+
),
|
|
570
|
+
);
|
|
571
|
+
if (this.#statusMessage) children.push(text([span(this.#statusMessage, "warning")]));
|
|
572
|
+
this.#nativeRoot = overlayCard(this.nativeRole, this.title, children);
|
|
573
|
+
return this.#nativeRoot;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/** A click (or double-click) on a provider selects and confirms it, like the SGR click in {@link routeMouse}. */
|
|
577
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
578
|
+
const ev = pickerEvent(event, PICKER_KEY);
|
|
579
|
+
if (ev?.kind === "action") {
|
|
580
|
+
if (ev.act === "confirm") this.#confirmSelection();
|
|
581
|
+
else if (ev.act === "clear") {
|
|
582
|
+
this.#search.setValue("");
|
|
583
|
+
this.#syncSearchQuery();
|
|
584
|
+
} else if (ev.act === "close" || ev.act === "cancel") {
|
|
585
|
+
this.stopValidation();
|
|
586
|
+
this.#onCancelCallback();
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
if (ev?.kind === "select") {
|
|
591
|
+
const index = this.#menu.visibleItems.findIndex(provider => provider.id === ev.item);
|
|
592
|
+
if (index < 0 || index === this.#menu.selectedIndex) return;
|
|
593
|
+
this.#menu.setSelectedIndex(index);
|
|
594
|
+
this.#statusMessage = undefined;
|
|
595
|
+
this.#updateList();
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if ((event.type !== "select" && event.type !== "activate") || (event.key !== "list" && ev?.kind !== "activate"))
|
|
599
|
+
return;
|
|
600
|
+
const index = this.#menu.visibleItems.findIndex(provider => provider.id === event.item);
|
|
601
|
+
if (index < 0) return;
|
|
602
|
+
if (index !== this.#menu.selectedIndex) {
|
|
603
|
+
this.#menu.setSelectedIndex(index);
|
|
604
|
+
this.#statusMessage = undefined;
|
|
605
|
+
this.#updateList();
|
|
606
|
+
}
|
|
607
|
+
this.#confirmSelection();
|
|
608
|
+
}
|
|
609
|
+
|
|
406
610
|
/** Move the selection one step for a wheel notch (clamped, no wrap). */
|
|
407
611
|
handleWheel(delta: -1 | 1): void {
|
|
408
612
|
if (this.#menu.visibleItems.length === 0) return;
|