@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
|
@@ -30,12 +30,18 @@ import type {
|
|
|
30
30
|
StatusLineSeparatorStyle,
|
|
31
31
|
} from "../status-line/schema";
|
|
32
32
|
import {
|
|
33
|
+
numberSteps,
|
|
34
|
+
numericOption,
|
|
33
35
|
SETTING_TABS,
|
|
36
|
+
type SubmenuOption,
|
|
37
|
+
TAB_LEADS,
|
|
34
38
|
TAB_METADATA,
|
|
35
39
|
type SettingTab,
|
|
36
40
|
type SettingsHost,
|
|
37
41
|
type SettingsDisplayEntry,
|
|
38
42
|
} from "./settings-defs";
|
|
43
|
+
import type { TspPrefsControl, TspPrefsProps } from "@oh-my-pi/pi-wire";
|
|
44
|
+
import { prefsSectionId } from "../components/settings-list";
|
|
39
45
|
import { getCurrentThemeName, getSelectListTheme, getSettingsListTheme, theme } from "../theme/theme";
|
|
40
46
|
import { AUTO_THINKING, type ConfiguredThinkingLevel } from "../thinking";
|
|
41
47
|
import { getTabBarTheme } from "../chrome/shared";
|
|
@@ -45,11 +51,108 @@ import { bottomBorder, divider, row, topBorder } from "../chrome/overlay-box";
|
|
|
45
51
|
import { PluginSettingsComponent, type PluginSettingsHost } from "./plugin-settings";
|
|
46
52
|
import { getSettingDef, getSettingsForTab, type SettingDef } from "./settings-defs";
|
|
47
53
|
import { SnapcompactShapePreview } from "./snapcompact-shape-preview";
|
|
54
|
+
import { themePickerOptions } from "./theme-selector";
|
|
55
|
+
import type { SelectPickerOptions } from "../native/picker";
|
|
48
56
|
import { getPreset } from "../status-line/presets";
|
|
49
57
|
import { FormField, SelectFormField, TextFormField } from "../components/form";
|
|
50
58
|
import { formTheme } from "../chrome/form-theme";
|
|
51
59
|
import { formatKeyHint, formatKeyHints } from "../app-keybindings";
|
|
52
60
|
import { editorKey, editorKeys } from "../chrome/keybinding-hints";
|
|
61
|
+
import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../native/node";
|
|
62
|
+
import { col, node, span, text } from "../native/describe";
|
|
63
|
+
import { actionHint, hintsRow, type NativeHint, overlayCard } from "../native/overlay";
|
|
64
|
+
import { styledSpans } from "../native/spans";
|
|
65
|
+
import { sameItems } from "../native/memo";
|
|
66
|
+
import type { KeyName } from "../key-hint-format";
|
|
67
|
+
|
|
68
|
+
/** The native page id of the plugins tab. */
|
|
69
|
+
const PLUGINS_PAGE = "plugins";
|
|
70
|
+
/** Role of the status-line preview child: the page places it after the status-line section. */
|
|
71
|
+
const PREFS_STATUS_ROLE = "omp.prefs.preview.status";
|
|
72
|
+
/** Role of a sub-editor child without a native control: the page shows it in a card over itself. */
|
|
73
|
+
const PREFS_EDITOR_ROLE = "omp.prefs.editor";
|
|
74
|
+
/** Most choices a native popup menu lists; larger submenus open as a picker over the page. */
|
|
75
|
+
const PREFS_MENU_MAX = 12;
|
|
76
|
+
/** Text settings whose values are paths, ids or commands (drawn in mono). */
|
|
77
|
+
const MONO_TEXT_SETTING = /(path|dir|url|endpoint|host|command|model|id)$/i;
|
|
78
|
+
/** Submenus whose choices preview live while highlighted (the branches of `#createSubmenu`). */
|
|
79
|
+
const PREVIEWED_SETTINGS = new Set([
|
|
80
|
+
"theme.dark",
|
|
81
|
+
"theme.light",
|
|
82
|
+
"statusLine.preset",
|
|
83
|
+
"statusLine.separator",
|
|
84
|
+
"statusLine.contextLine",
|
|
85
|
+
"snapcompact.shape",
|
|
86
|
+
"composer.shape",
|
|
87
|
+
]);
|
|
88
|
+
/** The byte a cancel key sends: native menu closes go through the same cancel handling as the key. */
|
|
89
|
+
const ESCAPE = "\x1b";
|
|
90
|
+
|
|
91
|
+
/** Footer hint set of the settings overlay, by what currently owns the keys. */
|
|
92
|
+
type SettingsHintMode = "search" | "plugins" | "sections" | "rows" | "rows-sections";
|
|
93
|
+
|
|
94
|
+
/** The settings tab strip; muted tabs (no search matches) keep their place, dimmed. */
|
|
95
|
+
function settingsTabsNode(tabs: readonly Tab[], active: string | undefined): NativeNode {
|
|
96
|
+
return node(
|
|
97
|
+
"tabs",
|
|
98
|
+
{
|
|
99
|
+
items: tabs.map(tab => ({ id: tab.id, label: tab.muted ? [span(tab.label, "muted")] : tab.label })),
|
|
100
|
+
active,
|
|
101
|
+
},
|
|
102
|
+
undefined,
|
|
103
|
+
"tabs",
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Footer hints for `mode`, mirroring the ANSI footer line. */
|
|
108
|
+
function settingsHintsNode(mode: SettingsHintMode): NativeNode {
|
|
109
|
+
const confirmKeys: readonly KeyName[] = actionHint("tui.select.confirm", "")?.keys ?? [];
|
|
110
|
+
const close = actionHint("tui.select.cancel", "close");
|
|
111
|
+
const switchTabs: NativeHint = { keys: ["left", "right"], label: "switch tabs" };
|
|
112
|
+
let hints: (NativeHint | undefined)[];
|
|
113
|
+
switch (mode) {
|
|
114
|
+
case "search":
|
|
115
|
+
hints = [
|
|
116
|
+
actionHint("tui.select.confirm", "change"),
|
|
117
|
+
{ keys: ["tab"], label: "jump tabs" },
|
|
118
|
+
actionHint("tui.select.cancel", "exit search"),
|
|
119
|
+
];
|
|
120
|
+
break;
|
|
121
|
+
case "plugins":
|
|
122
|
+
hints = [{ keys: ["tab"], label: "switch tabs" }, close];
|
|
123
|
+
break;
|
|
124
|
+
case "sections":
|
|
125
|
+
hints = [
|
|
126
|
+
actionHint(["tui.select.up", "tui.select.down"], "jump sections"),
|
|
127
|
+
{ keys: ["tab", ...confirmKeys], label: "to settings" },
|
|
128
|
+
switchTabs,
|
|
129
|
+
close,
|
|
130
|
+
];
|
|
131
|
+
break;
|
|
132
|
+
case "rows":
|
|
133
|
+
case "rows-sections":
|
|
134
|
+
hints = [
|
|
135
|
+
{ keys: [...confirmKeys, "space"], label: "change" },
|
|
136
|
+
...(mode === "rows-sections"
|
|
137
|
+
? [{ keys: ["tab"], label: "jump sections" } satisfies NativeHint, switchTabs]
|
|
138
|
+
: [{ keys: ["tab"], label: "switch tabs" } satisfies NativeHint]),
|
|
139
|
+
{ keys: [], label: "type to search" },
|
|
140
|
+
close,
|
|
141
|
+
];
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
return hintsRow(hints);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface SettingsNativeMemo {
|
|
148
|
+
prefs?: { signature: string; children: readonly NativeChild[]; node: NativeNode };
|
|
149
|
+
prefsPreview?: { source: string; node: NativeNode };
|
|
150
|
+
tabs?: { tabs: readonly Tab[]; active: string | undefined; node: NativeNode };
|
|
151
|
+
search?: { input: Input; count: number; node: NativeNode };
|
|
152
|
+
preview?: { source: string; node: NativeNode };
|
|
153
|
+
hints: Partial<Record<SettingsHintMode, NativeNode>>;
|
|
154
|
+
root?: { children: readonly NativeChild[]; node: NativeNode };
|
|
155
|
+
}
|
|
53
156
|
|
|
54
157
|
/**
|
|
55
158
|
* Free-text string setting field backed by the shared text form field.
|
|
@@ -95,6 +198,7 @@ function createSettingsSelectField(
|
|
|
95
198
|
getPreview?: () => string,
|
|
96
199
|
footer?: Component,
|
|
97
200
|
requestRender?: () => void,
|
|
201
|
+
picker?: SelectPickerOptions,
|
|
98
202
|
): SelectFormField {
|
|
99
203
|
return new SelectFormField({
|
|
100
204
|
theme: formTheme,
|
|
@@ -111,6 +215,7 @@ function createSettingsSelectField(
|
|
|
111
215
|
hint: ` ${editorKey("tui.select.confirm")} to select · ${editorKey("tui.select.cancel")} to go back`,
|
|
112
216
|
footer,
|
|
113
217
|
requestRender,
|
|
218
|
+
picker,
|
|
114
219
|
});
|
|
115
220
|
}
|
|
116
221
|
|
|
@@ -187,6 +292,16 @@ class MultiSelectSubmenu extends Container {
|
|
|
187
292
|
this.addChild(this.#field);
|
|
188
293
|
}
|
|
189
294
|
|
|
295
|
+
/** The highlighted option (a native settings page rings it). */
|
|
296
|
+
get prefsOption(): string | undefined {
|
|
297
|
+
return this.#options[this.#cursor]?.value;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Applies a whole new selection (a native page's chip toggle or drag), as a key toggle or move does. */
|
|
301
|
+
setValues(next: readonly string[]): void {
|
|
302
|
+
this.#apply(next.filter(id => this.#options.some(option => option.value === id)));
|
|
303
|
+
}
|
|
304
|
+
|
|
190
305
|
#apply(next: string[]): void {
|
|
191
306
|
this.#value = next;
|
|
192
307
|
this.#onApply([...next]);
|
|
@@ -485,6 +600,8 @@ export interface SettingsCallbacks {
|
|
|
485
600
|
onStatusLinePreview?: (settings: StatusLinePreviewSettings) => void;
|
|
486
601
|
/** Get current rendered status line for inline preview */
|
|
487
602
|
getStatusLinePreview?: () => string;
|
|
603
|
+
/** Native status bar for the inline preview (TSP terminals dock the bar; its ANSI border geometry doesn't apply) */
|
|
604
|
+
describeStatusLinePreview?: () => NativeNode;
|
|
488
605
|
/** Called when plugins change */
|
|
489
606
|
onPluginsChanged?: () => void | Promise<void>;
|
|
490
607
|
/** Called when settings panel is closed */
|
|
@@ -497,6 +614,11 @@ export interface SettingsCallbacks {
|
|
|
497
614
|
*/
|
|
498
615
|
export class SettingsSelectorComponent implements Component {
|
|
499
616
|
#tabBar: TabBar;
|
|
617
|
+
/** The tab bar's current tab list (the bar keeps no public getter). */
|
|
618
|
+
#tabs: Tab[];
|
|
619
|
+
readonly #native: SettingsNativeMemo = { hints: {} };
|
|
620
|
+
/** Changed-setting counts per tab for the native page nav, cleared whenever the items rebuild. */
|
|
621
|
+
readonly #changedCounts = new Map<SettingTab, number>();
|
|
500
622
|
#currentList: SettingsList | null = null;
|
|
501
623
|
#searchList: SettingsList | null = null;
|
|
502
624
|
#pluginComponent: PluginSettingsComponent | null = null;
|
|
@@ -526,7 +648,9 @@ export class SettingsSelectorComponent implements Component {
|
|
|
526
648
|
this.#sidebarWidth = settingsSidebarWidth(context.settings.entries);
|
|
527
649
|
// No label prefix (the frame title already says Settings) and no
|
|
528
650
|
// "(tab to cycle)" hint (folded into the footer hint line).
|
|
529
|
-
|
|
651
|
+
const tabs = getSettingsTabs();
|
|
652
|
+
this.#tabs = tabs;
|
|
653
|
+
this.#tabBar = new TabBar("", tabs, getTabBarTheme());
|
|
530
654
|
this.#tabBar.showHint = false;
|
|
531
655
|
this.#tabBar.onTabChange = () => {
|
|
532
656
|
const tabId = this.#tabBar.getActiveTab().id as SettingTab | "plugins";
|
|
@@ -655,6 +779,437 @@ export class SettingsSelectorComponent implements Component {
|
|
|
655
779
|
return out;
|
|
656
780
|
}
|
|
657
781
|
|
|
782
|
+
/**
|
|
783
|
+
* Over a live session the native page is its own sheet: the backend puts
|
|
784
|
+
* it in `layer`, where a terminal with the `aside` feature docks it at the
|
|
785
|
+
* pane's right edge with the transcript beside it. Without `aside` it
|
|
786
|
+
* fills a screen surface instead.
|
|
787
|
+
*/
|
|
788
|
+
nativeSheet(cx: DescribeContext): boolean {
|
|
789
|
+
return cx.supports("prefs") && cx.feature("aside");
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* The native settings page (`prefs`) when the terminal draws it, else the
|
|
794
|
+
* root card of today's generic composition.
|
|
795
|
+
*/
|
|
796
|
+
describe(cx: DescribeContext): NativeNode {
|
|
797
|
+
return cx.supports("prefs") ? this.#describePrefs() : this.#describeCard();
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* The settings as a native page: every tab (and the plugins page) in the
|
|
802
|
+
* nav with its changed count, the current tab's sections (or the search
|
|
803
|
+
* results grouped by tab), the keyboard focus and open editor, the
|
|
804
|
+
* status-line preview on Appearance, and editors without a native control
|
|
805
|
+
* (large choice pickers, provider limits) as children over the page.
|
|
806
|
+
*/
|
|
807
|
+
#describePrefs(): NativeNode {
|
|
808
|
+
const memo = this.#native;
|
|
809
|
+
const searching = this.#searchList !== null;
|
|
810
|
+
const list = this.#searchList ?? this.#currentList;
|
|
811
|
+
const entries = this.#context.settings.entries;
|
|
812
|
+
const plugins = this.#currentTabId === "plugins" ? this.#pluginComponent : null;
|
|
813
|
+
const pluginPage = plugins?.prefsPage();
|
|
814
|
+
const tab = this.#currentTabId === "plugins" ? undefined : this.#currentTabId;
|
|
815
|
+
|
|
816
|
+
const pages: TspPrefsProps["pages"][number][] = SETTING_TABS.map(id => {
|
|
817
|
+
const changed = this.#changedCount(id);
|
|
818
|
+
return { id, label: TAB_METADATA[id].label, icon: id, changed: changed > 0 ? changed : undefined };
|
|
819
|
+
});
|
|
820
|
+
pages.push({ id: PLUGINS_PAGE, label: "Installed", icon: "plugins", group: "Plugins" });
|
|
821
|
+
|
|
822
|
+
let sections: TspPrefsProps["sections"] = [];
|
|
823
|
+
let focus: string | null = null;
|
|
824
|
+
let editing: TspPrefsProps["editing"] = null;
|
|
825
|
+
const children: NativeChild[] = [];
|
|
826
|
+
if (pluginPage) {
|
|
827
|
+
sections = pluginPage.sections;
|
|
828
|
+
focus = pluginPage.focus;
|
|
829
|
+
editing = pluginPage.editing;
|
|
830
|
+
if (pluginPage.editor) children.push(pluginPage.editor);
|
|
831
|
+
} else if (list) {
|
|
832
|
+
sections = list.prefsSections(
|
|
833
|
+
item => {
|
|
834
|
+
const def = getSettingDef(entries, item.id);
|
|
835
|
+
const group = def?.group ?? "General";
|
|
836
|
+
const id = prefsSectionId(group);
|
|
837
|
+
return searching && def ? { id: `${def.tab}/${id}`, title: group, page: def.tab } : { id, title: group };
|
|
838
|
+
},
|
|
839
|
+
item => this.#prefsControl(item.id, item.currentValue),
|
|
840
|
+
);
|
|
841
|
+
const at = list.prefsFocus();
|
|
842
|
+
focus = at.row ?? (at.section ? prefsSectionId(at.section) : null);
|
|
843
|
+
editing = list.prefsEditing(id => this.#inlineMenu(id));
|
|
844
|
+
const open = list.openSubmenu;
|
|
845
|
+
if (open && !editing) {
|
|
846
|
+
// Pickers describe themselves as a sheet; anything else sits in a card over the page.
|
|
847
|
+
children.push(
|
|
848
|
+
open.component instanceof SelectFormField
|
|
849
|
+
? open.component
|
|
850
|
+
: col([open.component], { role: PREFS_EDITOR_ROLE }),
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (tab === "appearance" && !searching) {
|
|
856
|
+
const source = this.#getStatusPreviewString();
|
|
857
|
+
if (memo.prefsPreview?.source !== source) {
|
|
858
|
+
memo.prefsPreview = {
|
|
859
|
+
source,
|
|
860
|
+
node: node(
|
|
861
|
+
"col",
|
|
862
|
+
{ role: PREFS_STATUS_ROLE },
|
|
863
|
+
[
|
|
864
|
+
this.#callbacks.describeStatusLinePreview?.() ??
|
|
865
|
+
text(styledSpans(source), { wrap: "none", truncate: "end" }),
|
|
866
|
+
],
|
|
867
|
+
"status-preview",
|
|
868
|
+
),
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
children.push(memo.prefsPreview.node);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
const props: TspPrefsProps = {
|
|
875
|
+
title: "omp settings",
|
|
876
|
+
pages,
|
|
877
|
+
page: searching ? this.#preSearchTabId : this.#currentTabId,
|
|
878
|
+
lead: searching ? undefined : (pluginPage?.lead ?? (tab ? TAB_LEADS[tab] : undefined)),
|
|
879
|
+
query: searching ? this.#searchQuery : undefined,
|
|
880
|
+
cursor: searching ? this.#searchInput.getCursor() : undefined,
|
|
881
|
+
sections,
|
|
882
|
+
focus,
|
|
883
|
+
editing,
|
|
884
|
+
};
|
|
885
|
+
const signature = JSON.stringify(props);
|
|
886
|
+
if (memo.prefs && memo.prefs.signature === signature && sameItems(memo.prefs.children, children)) {
|
|
887
|
+
return memo.prefs.node;
|
|
888
|
+
}
|
|
889
|
+
const root = node("prefs", props, children);
|
|
890
|
+
memo.prefs = { signature, children, node: root };
|
|
891
|
+
return root;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/** Settings changed from their default on `tab` (visible ones only); cached until the items rebuild. */
|
|
895
|
+
#changedCount(tab: SettingTab): number {
|
|
896
|
+
const cached = this.#changedCounts.get(tab);
|
|
897
|
+
if (cached !== undefined) return cached;
|
|
898
|
+
let count = 0;
|
|
899
|
+
for (const def of getSettingsForTab(this.#context.settings.entries, tab)) {
|
|
900
|
+
if (def.condition && !def.condition()) continue;
|
|
901
|
+
if (this.#isChanged(def, this.#getCurrentValue(def))) count++;
|
|
902
|
+
}
|
|
903
|
+
this.#changedCounts.set(tab, count);
|
|
904
|
+
return count;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/** Whether row `id`'s choices fit its popup menu (else the submenu opens as a picker over the page). */
|
|
908
|
+
#inlineMenu(id: string): boolean {
|
|
909
|
+
const def = getSettingDef(this.#context.settings.entries, id);
|
|
910
|
+
return def?.type !== "submenu" || this.#submenuOptions(def).length <= PREFS_MENU_MAX;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/** Setting `id`'s typed control for the native page; `shown` is the list's display value. */
|
|
914
|
+
#prefsControl(id: string, shown: string): TspPrefsControl | undefined {
|
|
915
|
+
const def = getSettingDef(this.#context.settings.entries, id);
|
|
916
|
+
if (!def) return undefined;
|
|
917
|
+
const value = this.#getCurrentValue(def);
|
|
918
|
+
switch (def.type) {
|
|
919
|
+
case "boolean":
|
|
920
|
+
return { k: "switch", on: value === true };
|
|
921
|
+
case "enum":
|
|
922
|
+
return { k: "choice", value: shown, options: def.values.map(v => ({ value: v, label: v })) };
|
|
923
|
+
case "submenu": {
|
|
924
|
+
const labels = numberSteps(def);
|
|
925
|
+
if (labels) {
|
|
926
|
+
const n = Number(value);
|
|
927
|
+
return { k: "number", value: Number.isFinite(n) ? n : -1, labels };
|
|
928
|
+
}
|
|
929
|
+
const options = this.#submenuOptions(def).map(o => ({
|
|
930
|
+
value: o.value,
|
|
931
|
+
label: o.label,
|
|
932
|
+
detail: o.description,
|
|
933
|
+
}));
|
|
934
|
+
// Few short plain choices segment; described ones and live-previewed ones
|
|
935
|
+
// (hovering the menu previews, see #createSubmenu) keep the menu.
|
|
936
|
+
return {
|
|
937
|
+
k: "choice",
|
|
938
|
+
value: shown,
|
|
939
|
+
options,
|
|
940
|
+
style: PREVIEWED_SETTINGS.has(def.path) || options.some(o => o.detail) ? "menu" : "auto",
|
|
941
|
+
mono: options.every(o => o.label === o.value),
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
case "text":
|
|
945
|
+
return {
|
|
946
|
+
k: "text",
|
|
947
|
+
value: shown,
|
|
948
|
+
secret: def.secret || undefined,
|
|
949
|
+
mono: !def.secret && MONO_TEXT_SETTING.test(def.path) ? true : undefined,
|
|
950
|
+
};
|
|
951
|
+
case "providerLimits":
|
|
952
|
+
return { k: "action", label: "Edit…", act: "edit" };
|
|
953
|
+
case "multiselect":
|
|
954
|
+
return {
|
|
955
|
+
k: "multi",
|
|
956
|
+
values: Array.isArray(value) ? value.filter((v): v is string => typeof v === "string") : [],
|
|
957
|
+
options: def.options.map(o => ({ value: o.value, label: o.label, detail: o.description })),
|
|
958
|
+
ordered: def.ordered || undefined,
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/** The default of `def` as its control names it (the changed dot's title). */
|
|
964
|
+
#defaultLabel(def: SettingDef): string {
|
|
965
|
+
const value: unknown = def.defaultValue;
|
|
966
|
+
switch (def.type) {
|
|
967
|
+
case "boolean":
|
|
968
|
+
return value ? "On" : "Off";
|
|
969
|
+
case "submenu": {
|
|
970
|
+
const raw = this.#getSubmenuCurrentValue(def.path, value);
|
|
971
|
+
return this.#submenuOptions(def).find(o => o.value === raw)?.label ?? raw;
|
|
972
|
+
}
|
|
973
|
+
case "multiselect":
|
|
974
|
+
return this.#formatMultiSelectValue(def, value);
|
|
975
|
+
case "text":
|
|
976
|
+
return def.secret ? "" : this.#formatTextInputEditValue(def.path, value);
|
|
977
|
+
default:
|
|
978
|
+
return value === undefined || value === null ? "" : String(value);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Pointer actions on the native page, each through the code the keys use:
|
|
984
|
+
* a page click switches tabs (leaving a search), a row click moves the
|
|
985
|
+
* selection, a value change goes through the row's cycle, submenu or text
|
|
986
|
+
* field (`null` unsets the setting), menu hovers preview, and closing an
|
|
987
|
+
* open menu cancels it (reverting its preview).
|
|
988
|
+
*/
|
|
989
|
+
#handlePrefsEvent(event: NativeUiEvent): void {
|
|
990
|
+
if (this.#currentTabId === "plugins" && this.#pluginComponent) {
|
|
991
|
+
if (event.type === "action" && event.act === "page" && event.value === PLUGINS_PAGE) {
|
|
992
|
+
this.#switchToTab("plugins");
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
if (
|
|
996
|
+
!(event.type === "action" && (event.act === "page" || (event.act === "close" && event.value === undefined)))
|
|
997
|
+
) {
|
|
998
|
+
this.#pluginComponent.handlePrefsEvent(event);
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
const list = this.#searchList ?? this.#currentList;
|
|
1003
|
+
switch (event.type) {
|
|
1004
|
+
case "action":
|
|
1005
|
+
if (event.act === "page" && event.value) {
|
|
1006
|
+
this.#showPage(event.value);
|
|
1007
|
+
} else if (event.act === "close") {
|
|
1008
|
+
if (event.value === undefined) this.#callbacks.onCancel();
|
|
1009
|
+
else if (list?.openSubmenu?.id === event.value) list.handleInput(ESCAPE);
|
|
1010
|
+
} else if (event.act === "edit" && event.value) {
|
|
1011
|
+
list?.openSubmenuFor(event.value);
|
|
1012
|
+
}
|
|
1013
|
+
return;
|
|
1014
|
+
case "select": {
|
|
1015
|
+
if (!list) return;
|
|
1016
|
+
const eq = event.item.indexOf("=");
|
|
1017
|
+
if (eq >= 0) {
|
|
1018
|
+
const open = list.openSubmenu;
|
|
1019
|
+
if (open?.id !== event.item.slice(0, eq) || !(open.component instanceof SelectFormField)) return;
|
|
1020
|
+
const select = open.component.selectList;
|
|
1021
|
+
select.setSelectedValue(event.item.slice(eq + 1));
|
|
1022
|
+
const item = select.getSelectedItem();
|
|
1023
|
+
if (item) select.onSelectionChange?.(item);
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
if (list.openSubmenu) list.handleInput(ESCAPE);
|
|
1027
|
+
list.selectItem(event.item);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
case "activate":
|
|
1031
|
+
list?.openSubmenuFor(event.item);
|
|
1032
|
+
return;
|
|
1033
|
+
case "change":
|
|
1034
|
+
if (list) this.#applyPrefsChange(list, event.item, event.value);
|
|
1035
|
+
return;
|
|
1036
|
+
case "toggle":
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/** Shows page `id` (a tab or the plugins page), leaving a search. */
|
|
1042
|
+
#showPage(id: string): void {
|
|
1043
|
+
if (this.#searchList) this.#endSearch(false);
|
|
1044
|
+
if (id !== this.#currentTabId) this.#tabBar.selectTab(id);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
/** A pointer value change on row `id`, through the path its keys take (see {@link #handlePrefsEvent}). */
|
|
1048
|
+
#applyPrefsChange(
|
|
1049
|
+
list: SettingsList,
|
|
1050
|
+
id: string,
|
|
1051
|
+
value: boolean | number | string | readonly string[] | null,
|
|
1052
|
+
): void {
|
|
1053
|
+
const def = getSettingDef(this.#context.settings.entries, id);
|
|
1054
|
+
if (!def) return;
|
|
1055
|
+
if (value === null) {
|
|
1056
|
+
if (list.openSubmenu) list.handleInput(ESCAPE);
|
|
1057
|
+
this.#context.settings.unset(def.path);
|
|
1058
|
+
this.#callbacks.onChange(def.path, this.#context.settings.get(def.path));
|
|
1059
|
+
if (def.tab === "appearance") this.#triggerStatusLinePreview();
|
|
1060
|
+
this.#refreshItems();
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
switch (def.type) {
|
|
1064
|
+
case "boolean":
|
|
1065
|
+
if (typeof value === "boolean") list.applyValue(id, String(value));
|
|
1066
|
+
return;
|
|
1067
|
+
case "enum":
|
|
1068
|
+
if (typeof value === "string") list.applyValue(id, value);
|
|
1069
|
+
return;
|
|
1070
|
+
case "submenu": {
|
|
1071
|
+
const choice =
|
|
1072
|
+
typeof value === "number"
|
|
1073
|
+
? this.#submenuOptions(def).find(o => numericOption(o.value) === value)?.value
|
|
1074
|
+
: typeof value === "string"
|
|
1075
|
+
? value
|
|
1076
|
+
: undefined;
|
|
1077
|
+
if (choice === undefined) return;
|
|
1078
|
+
const field = list.openSubmenuFor(id);
|
|
1079
|
+
if (field instanceof SelectFormField) {
|
|
1080
|
+
field.selectList.handleNativeEvent({ type: "activate", key: "", item: choice });
|
|
1081
|
+
}
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
case "text": {
|
|
1085
|
+
if (typeof value !== "string") return;
|
|
1086
|
+
const field = list.openSubmenuFor(id);
|
|
1087
|
+
if (field instanceof TextFormField) {
|
|
1088
|
+
field.setValue(value);
|
|
1089
|
+
field.submit();
|
|
1090
|
+
}
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
case "multiselect": {
|
|
1094
|
+
if (!Array.isArray(value)) return;
|
|
1095
|
+
const open = list.openSubmenu;
|
|
1096
|
+
if (open?.id === id && open.component instanceof MultiSelectSubmenu) {
|
|
1097
|
+
open.component.setValues(value);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
const next = [...value];
|
|
1101
|
+
this.#context.settings.set(def.path, next);
|
|
1102
|
+
this.#callbacks.onChange(def.path, next);
|
|
1103
|
+
list.updateValue(id, this.#formatMultiSelectValue(def, next));
|
|
1104
|
+
this.#refreshItems();
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
case "providerLimits":
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/** Rebuilds the visible items after a change made outside a list's own `onChange` (changed flags, conditions). */
|
|
1113
|
+
#refreshItems(): void {
|
|
1114
|
+
if (this.#searchList) this.#setSearchQuery(this.#searchQuery);
|
|
1115
|
+
else if (this.#currentTabId !== "plugins")
|
|
1116
|
+
this.#refreshCurrentTabItems(getSettingsForTab(this.#context.settings.entries, this.#currentTabId));
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Root card: tab strip, search field while searching, the active content
|
|
1121
|
+
* component (settings list, search results, or plugins), the appearance
|
|
1122
|
+
* status-line preview, and the footer hints.
|
|
1123
|
+
*/
|
|
1124
|
+
#describeCard(): NativeNode {
|
|
1125
|
+
const memo = this.#native;
|
|
1126
|
+
const searching = this.#searchList !== null;
|
|
1127
|
+
const children: NativeChild[] = [];
|
|
1128
|
+
|
|
1129
|
+
const active = this.#tabBar.getActiveTab()?.id;
|
|
1130
|
+
if (memo.tabs?.tabs !== this.#tabs || memo.tabs.active !== active) {
|
|
1131
|
+
memo.tabs = { tabs: this.#tabs, active, node: settingsTabsNode(this.#tabs, active) };
|
|
1132
|
+
}
|
|
1133
|
+
children.push(memo.tabs.node);
|
|
1134
|
+
|
|
1135
|
+
if (searching) {
|
|
1136
|
+
const count = this.#searchMatchCount;
|
|
1137
|
+
if (memo.search?.input !== this.#searchInput || memo.search.count !== count) {
|
|
1138
|
+
const countText = count === 1 ? "1 match" : `${count} matches`;
|
|
1139
|
+
memo.search = {
|
|
1140
|
+
input: this.#searchInput,
|
|
1141
|
+
count,
|
|
1142
|
+
node: node(
|
|
1143
|
+
"row",
|
|
1144
|
+
{ gap: "xs", align: "center", role: "omp.settings.search" },
|
|
1145
|
+
[
|
|
1146
|
+
text([span(theme.symbol("icon.search"), "accent")]),
|
|
1147
|
+
col([this.#searchInput], { grow: 1 }),
|
|
1148
|
+
text([span(countText, count > 0 ? "dim" : "warning")], { wrap: "none" }),
|
|
1149
|
+
],
|
|
1150
|
+
"search",
|
|
1151
|
+
),
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
children.push(memo.search.node);
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
const content = this.#searchList ?? this.#currentList ?? this.#pluginComponent;
|
|
1158
|
+
if (content) children.push(content);
|
|
1159
|
+
|
|
1160
|
+
if (!searching && this.#currentTabId === "appearance") {
|
|
1161
|
+
const source = this.#getStatusPreviewString();
|
|
1162
|
+
if (memo.preview?.source !== source) {
|
|
1163
|
+
memo.preview = {
|
|
1164
|
+
source,
|
|
1165
|
+
node: node(
|
|
1166
|
+
"col",
|
|
1167
|
+
{ gap: "xs" },
|
|
1168
|
+
[
|
|
1169
|
+
text([span("Preview:", "muted")]),
|
|
1170
|
+
this.#callbacks.describeStatusLinePreview?.() ??
|
|
1171
|
+
text(styledSpans(source), { wrap: "none", truncate: "end" }),
|
|
1172
|
+
],
|
|
1173
|
+
"preview",
|
|
1174
|
+
),
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
children.push(memo.preview.node);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
const mode: SettingsHintMode = searching
|
|
1181
|
+
? "search"
|
|
1182
|
+
: this.#currentTabId === "plugins"
|
|
1183
|
+
? "plugins"
|
|
1184
|
+
: this.#currentList?.sectionFocused
|
|
1185
|
+
? "sections"
|
|
1186
|
+
: this.#hasSectionJump
|
|
1187
|
+
? "rows-sections"
|
|
1188
|
+
: "rows";
|
|
1189
|
+
memo.hints[mode] ??= settingsHintsNode(mode);
|
|
1190
|
+
children.push(memo.hints[mode]);
|
|
1191
|
+
|
|
1192
|
+
if (memo.root && sameItems(memo.root.children, children)) return memo.root.node;
|
|
1193
|
+
const root = overlayCard("omp.overlay.settings", "Settings", children);
|
|
1194
|
+
memo.root = { children, node: root };
|
|
1195
|
+
return root;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Native page events (the root node, see {@link #handlePrefsEvent}); in the
|
|
1200
|
+
* generic composition a tab pick does what a tab click does: switch tabs (or
|
|
1201
|
+
* jump, while searching), unless an open submenu owns the pointer.
|
|
1202
|
+
*/
|
|
1203
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
1204
|
+
if (event.key === "") {
|
|
1205
|
+
this.#handlePrefsEvent(event);
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
if ((event.type !== "select" && event.type !== "activate") || event.key !== "tabs") return;
|
|
1209
|
+
if ((this.#searchList ?? this.#currentList)?.hasOpenSubmenu()) return;
|
|
1210
|
+
this.#tabBar.selectTab(event.item);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
658
1213
|
/**
|
|
659
1214
|
* Route an SGR mouse report against the frame geometry of the last render.
|
|
660
1215
|
* Wheel scrolls the focused list, motion drives the hover highlights (tabs
|
|
@@ -762,6 +1317,7 @@ export class SettingsSelectorComponent implements Component {
|
|
|
762
1317
|
return;
|
|
763
1318
|
}
|
|
764
1319
|
this.#searchQuery = query;
|
|
1320
|
+
this.#changedCounts.clear();
|
|
765
1321
|
|
|
766
1322
|
const counts = new Map<SettingTab, number>();
|
|
767
1323
|
const items: SettingItem[] = [];
|
|
@@ -802,12 +1358,11 @@ export class SettingsSelectorComponent implements Component {
|
|
|
802
1358
|
|
|
803
1359
|
this.#searchList.setItems(items);
|
|
804
1360
|
this.#searchMatchCount = total;
|
|
805
|
-
this.#
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
tabResults.map(result => result.tab),
|
|
809
|
-
),
|
|
1361
|
+
this.#tabs = this.#buildSearchTabs(
|
|
1362
|
+
counts,
|
|
1363
|
+
tabResults.map(result => result.tab),
|
|
810
1364
|
);
|
|
1365
|
+
this.#tabBar.setTabs(this.#tabs);
|
|
811
1366
|
this.#syncTabBarToSelection(this.#searchList.getSelectedItem());
|
|
812
1367
|
}
|
|
813
1368
|
|
|
@@ -825,7 +1380,8 @@ export class SettingsSelectorComponent implements Component {
|
|
|
825
1380
|
this.#searchQuery = "";
|
|
826
1381
|
this.#searchFirstMatch.clear();
|
|
827
1382
|
this.#searchMatchCount = 0;
|
|
828
|
-
this.#
|
|
1383
|
+
this.#tabs = getSettingsTabs();
|
|
1384
|
+
this.#tabBar.setTabs(this.#tabs, targetTab);
|
|
829
1385
|
this.#switchToTab(targetTab);
|
|
830
1386
|
if (selectedDef) {
|
|
831
1387
|
this.#currentList?.selectItem(selectedDef.path);
|
|
@@ -898,12 +1454,14 @@ export class SettingsSelectorComponent implements Component {
|
|
|
898
1454
|
}
|
|
899
1455
|
|
|
900
1456
|
const currentValue = this.#getCurrentValue(def);
|
|
1457
|
+
const changed = this.#isChanged(def, currentValue);
|
|
901
1458
|
const item = {
|
|
902
1459
|
id: def.path,
|
|
903
1460
|
label: def.label,
|
|
904
1461
|
description: def.description,
|
|
905
1462
|
warning: def.warning,
|
|
906
|
-
changed
|
|
1463
|
+
changed,
|
|
1464
|
+
defaultLabel: changed ? this.#defaultLabel(def) : undefined,
|
|
907
1465
|
};
|
|
908
1466
|
|
|
909
1467
|
switch (def.type) {
|
|
@@ -972,6 +1530,20 @@ export class SettingsSelectorComponent implements Component {
|
|
|
972
1530
|
return rawValue;
|
|
973
1531
|
}
|
|
974
1532
|
|
|
1533
|
+
/** A submenu's choices: the declared ones, or the runtime ones (thinking levels, themes, composer shapes). */
|
|
1534
|
+
#submenuOptions(def: SettingDef & { type: "submenu" }): readonly SubmenuOption[] {
|
|
1535
|
+
if (def.path === "defaultThinkingLevel") {
|
|
1536
|
+
// Prepend `auto`; the rest are the model's runtime-supported efforts.
|
|
1537
|
+
const levels: ConfiguredThinkingLevel[] = [AUTO_THINKING, ...this.#context.availableThinkingLevels];
|
|
1538
|
+
return levels.map(level => def.options.find(o => o.value === level) ?? { value: level, label: level });
|
|
1539
|
+
}
|
|
1540
|
+
if (def.path === "theme.dark" || def.path === "theme.light") {
|
|
1541
|
+
return this.#context.availableThemes.map(t => ({ value: t, label: t }));
|
|
1542
|
+
}
|
|
1543
|
+
if (def.path === "composer.shape") return getComposerShapeOptions();
|
|
1544
|
+
return def.options;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
975
1547
|
/**
|
|
976
1548
|
* Create a submenu for a submenu-type setting.
|
|
977
1549
|
*/
|
|
@@ -980,21 +1552,7 @@ export class SettingsSelectorComponent implements Component {
|
|
|
980
1552
|
currentValue: string,
|
|
981
1553
|
done: (value?: string) => void,
|
|
982
1554
|
): Component {
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
// Special case: inject runtime options for thinking level
|
|
986
|
-
if (def.path === "defaultThinkingLevel") {
|
|
987
|
-
// Prepend `auto`; the rest are the model's runtime-supported efforts.
|
|
988
|
-
const levels: ConfiguredThinkingLevel[] = [AUTO_THINKING, ...this.#context.availableThinkingLevels];
|
|
989
|
-
options = levels.map(level => {
|
|
990
|
-
const baseOpt = options.find(o => o.value === level);
|
|
991
|
-
return baseOpt || { value: level, label: level };
|
|
992
|
-
});
|
|
993
|
-
} else if (def.path === "theme.dark" || def.path === "theme.light") {
|
|
994
|
-
options = this.#context.availableThemes.map(t => ({ value: t, label: t }));
|
|
995
|
-
} else if (def.path === "composer.shape") {
|
|
996
|
-
options = getComposerShapeOptions();
|
|
997
|
-
}
|
|
1555
|
+
const options = this.#submenuOptions(def);
|
|
998
1556
|
// Preview handlers
|
|
999
1557
|
let onPreview: ((value: string) => void | Promise<void>) | undefined;
|
|
1000
1558
|
let onPreviewCancel: (() => void) | undefined;
|
|
@@ -1085,6 +1643,7 @@ export class SettingsSelectorComponent implements Component {
|
|
|
1085
1643
|
getPreview,
|
|
1086
1644
|
footer,
|
|
1087
1645
|
this.#context.requestRender,
|
|
1646
|
+
isThemeSetting ? themePickerOptions(def.label, String(currentValue)) : undefined,
|
|
1088
1647
|
);
|
|
1089
1648
|
}
|
|
1090
1649
|
|
|
@@ -1139,15 +1698,7 @@ export class SettingsSelectorComponent implements Component {
|
|
|
1139
1698
|
return entries.map(([provider, limit]) => `${provider}: ${limit}`).join(", ");
|
|
1140
1699
|
}
|
|
1141
1700
|
|
|
1142
|
-
#getMultiSelectOptions(def: SettingDef & { type: "multiselect" }) {
|
|
1143
|
-
if (def.path !== "providers.webSearchOrder") return def.options;
|
|
1144
|
-
const excluded: unknown = this.#context.settings.get("providers.webSearchExclude");
|
|
1145
|
-
if (!Array.isArray(excluded)) return def.options;
|
|
1146
|
-
return def.options.filter(option => !excluded.includes(option.value));
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
1701
|
#createMultiSelect(def: SettingDef & { type: "multiselect" }, done: (value?: string) => void): Container {
|
|
1150
|
-
const options = this.#getMultiSelectOptions(def);
|
|
1151
1702
|
const current: unknown = this.#context.settings.get(def.path);
|
|
1152
1703
|
const initial = Array.isArray(current)
|
|
1153
1704
|
? current.filter((entry): entry is string => typeof entry === "string")
|
|
@@ -1155,7 +1706,7 @@ export class SettingsSelectorComponent implements Component {
|
|
|
1155
1706
|
return new MultiSelectSubmenu(
|
|
1156
1707
|
def.label,
|
|
1157
1708
|
def.description,
|
|
1158
|
-
options,
|
|
1709
|
+
def.options,
|
|
1159
1710
|
initial,
|
|
1160
1711
|
def.ordered,
|
|
1161
1712
|
value => {
|
|
@@ -1167,7 +1718,7 @@ export class SettingsSelectorComponent implements Component {
|
|
|
1167
1718
|
}
|
|
1168
1719
|
|
|
1169
1720
|
#formatMultiSelectValue(def: SettingDef & { type: "multiselect" }, value: unknown): string {
|
|
1170
|
-
const options =
|
|
1721
|
+
const { options } = def;
|
|
1171
1722
|
const labels = Array.isArray(value)
|
|
1172
1723
|
? value.flatMap(entry => {
|
|
1173
1724
|
if (typeof entry !== "string") return [];
|
|
@@ -1278,6 +1829,7 @@ export class SettingsSelectorComponent implements Component {
|
|
|
1278
1829
|
* into a new group; groups whose items are all condition-hidden emit none.
|
|
1279
1830
|
*/
|
|
1280
1831
|
#buildItemsForDefs(defs: SettingDef[]): SettingItem[] {
|
|
1832
|
+
this.#changedCounts.clear();
|
|
1281
1833
|
const items: SettingItem[] = [];
|
|
1282
1834
|
let lastGroup: string | undefined;
|
|
1283
1835
|
for (const def of defs) {
|