@oh-my-pi/pi-tui 18.2.4 → 18.2.6
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 +23 -0
- package/README.md +43 -0
- package/dist/types/app-keybindings.d.ts +395 -0
- package/dist/types/apps/autoresearch-dashboard.d.ts +43 -0
- package/dist/types/apps/autoresearch-data.d.ts +15 -0
- package/dist/types/apps/cleanse-board.d.ts +66 -0
- package/dist/types/apps/cleanse-picker.d.ts +23 -0
- package/dist/types/apps/debug/log-formatting.d.ts +6 -0
- package/dist/types/apps/debug/log-viewer.d.ts +81 -0
- package/dist/types/apps/debug/protocol-probe.d.ts +42 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +58 -0
- package/dist/types/apps/debug/raw-sse.d.ts +26 -0
- package/dist/types/apps/debug/terminal-info.d.ts +34 -0
- package/dist/types/apps/debug/viewer-frame.d.ts +52 -0
- package/dist/types/apps/git/avatar.d.ts +9 -0
- package/dist/types/apps/git/colors.d.ts +49 -0
- package/dist/types/apps/git/diff-pane.d.ts +188 -0
- package/dist/types/apps/git/git-tui.d.ts +66 -0
- package/dist/types/apps/git/sidebar.d.ts +149 -0
- package/dist/types/apps/git/state.d.ts +117 -0
- package/dist/types/apps/if-bench-board.d.ts +75 -0
- package/dist/types/apps/live-visualizer.d.ts +33 -0
- package/dist/types/apps/ps-data.d.ts +51 -0
- package/dist/types/apps/ps-top.d.ts +33 -0
- package/dist/types/apps/session-picker.d.ts +26 -0
- package/dist/types/apps/setup-model-picker.d.ts +13 -0
- package/dist/types/apps/standalone-picker.d.ts +42 -0
- package/dist/types/autocomplete.d.ts +4 -0
- package/dist/types/chat/advisor-message.d.ts +11 -0
- package/dist/types/chat/assistant-message.d.ts +106 -0
- package/dist/types/chat/background-tan-message.d.ts +9 -0
- package/dist/types/chat/bash-execution.d.ts +47 -0
- package/dist/types/chat/cache-invalidation-marker.d.ts +50 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +50 -0
- package/dist/types/chat/collab-prompt-message.d.ts +10 -0
- package/dist/types/chat/compaction-summary-message.d.ts +54 -0
- package/dist/types/chat/custom-message.d.ts +10 -0
- package/dist/types/chat/display-preferences.d.ts +13 -0
- package/dist/types/chat/eval-execution.d.ts +29 -0
- package/dist/types/chat/execution-shared.d.ts +51 -0
- package/dist/types/chat/extension-types.d.ts +28 -0
- package/dist/types/chat/hook-message.d.ts +10 -0
- package/dist/types/chat/image-loading.d.ts +46 -0
- package/dist/types/chat/late-diagnostics-message.d.ts +21 -0
- package/dist/types/chat/messages.d.ts +189 -0
- package/dist/types/chat/reaction.d.ts +30 -0
- package/dist/types/chat/read-target.d.ts +4 -0
- package/dist/types/chat/read-tool-group.d.ts +67 -0
- package/dist/types/chat/served-model-marker.d.ts +47 -0
- package/dist/types/chat/skill-message.d.ts +33 -0
- package/dist/types/chat/skill-title-input.d.ts +14 -0
- package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/chat/thinking-display.d.ts +12 -0
- package/dist/types/chat/todo-reminder.d.ts +13 -0
- package/dist/types/chat/tool-execution.d.ts +138 -0
- package/dist/types/chat/transcript-browser.d.ts +93 -0
- package/dist/types/chat/transcript-entry.d.ts +45 -0
- package/dist/types/chat/transcript-outline.d.ts +86 -0
- package/dist/types/chat/transcript-render-helpers.d.ts +92 -0
- package/dist/types/chat/ttsr-notification.d.ts +23 -0
- package/dist/types/chat/user-message.d.ts +52 -0
- package/dist/types/chrome/chat-block.d.ts +64 -0
- package/dist/types/chrome/collab-qrcode.d.ts +28 -0
- package/dist/types/chrome/context-thresholds.d.ts +10 -0
- package/dist/types/chrome/countdown-timer.d.ts +14 -0
- package/dist/types/chrome/diff.d.ts +14 -0
- package/dist/types/chrome/dynamic-border.d.ts +16 -0
- package/dist/types/chrome/error-block.d.ts +17 -0
- package/dist/types/chrome/form-theme.d.ts +3 -0
- package/dist/types/chrome/format.d.ts +12 -0
- package/dist/types/chrome/index.d.ts +20 -0
- package/dist/types/chrome/keybinding-hints.d.ts +40 -0
- package/dist/types/chrome/live-board.d.ts +23 -0
- package/dist/types/chrome/local-date.d.ts +4 -0
- package/dist/types/chrome/message-divider.d.ts +22 -0
- package/dist/types/chrome/message-frame.d.ts +52 -0
- package/dist/types/chrome/message-notice.d.ts +35 -0
- package/dist/types/chrome/overlay-box.d.ts +74 -0
- package/dist/types/chrome/qrcode.d.ts +48 -0
- package/dist/types/chrome/segment-track.d.ts +27 -0
- package/dist/types/chrome/select-list-mouse-routing.d.ts +4 -0
- package/dist/types/chrome/selector-helpers.d.ts +52 -0
- package/dist/types/chrome/shared.d.ts +5 -0
- package/dist/types/chrome/streaming-panel.d.ts +19 -0
- package/dist/types/chrome/tool-activity.d.ts +17 -0
- package/dist/types/chrome/transcript-container.d.ts +129 -0
- package/dist/types/chrome/transcript-status.d.ts +12 -0
- package/dist/types/chrome/visual-truncate.d.ts +19 -0
- package/dist/types/components/disclosure.d.ts +42 -0
- package/dist/types/components/form.d.ts +130 -0
- package/dist/types/components/key-value-list.d.ts +24 -0
- package/dist/types/components/layout/geometry.d.ts +73 -0
- package/dist/types/components/layout/row.d.ts +55 -0
- package/dist/types/components/layout/split-pane.d.ts +80 -0
- package/dist/types/components/layout/stack.d.ts +50 -0
- package/dist/types/components/menu-selection.d.ts +71 -0
- package/dist/types/components/metric.d.ts +44 -0
- package/dist/types/components/progress-bar.d.ts +36 -0
- package/dist/types/components/scroll-view.d.ts +53 -19
- package/dist/types/components/scroll-viewport.d.ts +46 -0
- package/dist/types/components/section.d.ts +19 -0
- package/dist/types/components/select-list.d.ts +46 -2
- package/dist/types/components/settings-list.d.ts +20 -0
- package/dist/types/components/table.d.ts +32 -0
- package/dist/types/components/tree-view.d.ts +130 -0
- package/dist/types/components/wizard-step.d.ts +60 -0
- package/dist/types/hotkeys-markdown.d.ts +7 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/keybinding-matchers.d.ts +35 -0
- package/dist/types/keys.d.ts +2 -2
- package/dist/types/lang-from-path.d.ts +9 -0
- package/dist/types/overlays/advisor-config.d.ts +114 -0
- package/dist/types/overlays/agent-activity.d.ts +41 -0
- package/dist/types/overlays/agent-hub-projection.d.ts +33 -0
- package/dist/types/overlays/agent-hub-renderer.d.ts +53 -0
- package/dist/types/overlays/agent-hub-types.d.ts +99 -0
- package/dist/types/overlays/agent-hub.d.ts +126 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +71 -0
- package/dist/types/overlays/agents-hub.d.ts +72 -0
- package/dist/types/overlays/ask-dialog.d.ts +88 -0
- package/dist/types/overlays/bordered-loader.d.ts +11 -0
- package/dist/types/overlays/btw-history-panel.d.ts +29 -0
- package/dist/types/overlays/btw-history.d.ts +17 -0
- package/dist/types/overlays/btw-panel.d.ts +26 -0
- package/dist/types/overlays/cleanse-panel.d.ts +36 -0
- package/dist/types/overlays/codex-reset-fireworks.d.ts +52 -0
- package/dist/types/overlays/composer-shape-preview.d.ts +47 -0
- package/dist/types/overlays/composer-shape-registry.d.ts +50 -0
- package/dist/types/overlays/copy-selector.d.ts +48 -0
- package/dist/types/overlays/copy-targets.d.ts +63 -0
- package/dist/types/overlays/error-banner.d.ts +13 -0
- package/dist/types/overlays/extensions/display-text.d.ts +10 -0
- package/dist/types/overlays/extensions/extension-dashboard.d.ts +63 -0
- package/dist/types/overlays/extensions/extension-list.d.ts +54 -0
- package/dist/types/overlays/extensions/inspector-model.d.ts +109 -0
- package/dist/types/overlays/extensions/inspector-panel.d.ts +17 -0
- package/dist/types/overlays/extensions/live-tool-session.d.ts +28 -0
- package/dist/types/overlays/extensions/mcp-runtime.d.ts +107 -0
- package/dist/types/overlays/extensions/state-manager.d.ts +42 -0
- package/dist/types/overlays/extensions/types.d.ts +165 -0
- package/dist/types/overlays/history-search.d.ts +16 -0
- package/dist/types/overlays/hook-editor.d.ts +44 -0
- package/dist/types/overlays/hook-input.d.ts +20 -0
- package/dist/types/overlays/hook-selector.d.ts +71 -0
- package/dist/types/overlays/hub-frame.d.ts +77 -0
- package/dist/types/overlays/login-dialog.d.ts +43 -0
- package/dist/types/overlays/logout-account-selector.d.ts +15 -0
- package/dist/types/overlays/mcp-add-wizard.d.ts +87 -0
- package/dist/types/overlays/model-browser.d.ts +213 -0
- package/dist/types/overlays/model-hub.d.ts +72 -0
- package/dist/types/overlays/model-picker.d.ts +74 -0
- package/dist/types/overlays/model-selector.d.ts +52 -0
- package/dist/types/overlays/move-overlay.d.ts +39 -0
- package/dist/types/overlays/oauth-selector.d.ts +41 -0
- package/dist/types/overlays/omfg-panel.d.ts +20 -0
- package/dist/types/overlays/pause-screen.d.ts +43 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +89 -0
- package/dist/types/overlays/plan-save-overlay.d.ts +19 -0
- package/dist/types/overlays/plan-toc.d.ts +41 -0
- package/dist/types/overlays/plugin-selector.d.ts +28 -0
- package/dist/types/overlays/plugin-settings.d.ts +180 -0
- package/dist/types/overlays/queue-mode-selector.d.ts +11 -0
- package/dist/types/overlays/reset-usage-selector.d.ts +23 -0
- package/dist/types/overlays/rewind-selector.d.ts +61 -0
- package/dist/types/overlays/running-subagent-badge.d.ts +6 -0
- package/dist/types/overlays/session-account-selector.d.ts +24 -0
- package/dist/types/overlays/session-info-overlay.d.ts +17 -0
- package/dist/types/overlays/session-observer-registry.d.ts +77 -0
- package/dist/types/overlays/session-selector.d.ts +131 -0
- package/dist/types/overlays/settings-defs.d.ts +119 -0
- package/dist/types/overlays/settings-selector.d.ts +73 -0
- package/dist/types/overlays/show-images-selector.d.ts +11 -0
- package/dist/types/overlays/snapcompact-shape-preview.d.ts +31 -0
- package/dist/types/overlays/theme-selector.d.ts +12 -0
- package/dist/types/overlays/thinking-selector.d.ts +12 -0
- package/dist/types/overlays/tiny-title-download-progress.d.ts +21 -0
- package/dist/types/overlays/tree-selector.d.ts +92 -0
- package/dist/types/overlays/usage-dashboard.d.ts +94 -0
- package/dist/types/overlays/usage-display.d.ts +5 -0
- package/dist/types/overlays/usage-row.d.ts +17 -0
- package/dist/types/prompt/attachment-chips.d.ts +19 -0
- package/dist/types/prompt/composer-attachments.d.ts +71 -0
- package/dist/types/prompt/composer-cache.d.ts +37 -0
- package/dist/types/prompt/composer.d.ts +159 -0
- package/dist/types/prompt/custom-editor.d.ts +261 -0
- package/dist/types/prompt/editor-top-gap.d.ts +18 -0
- package/dist/types/prompt/emoji-autocomplete.d.ts +16 -0
- package/dist/types/prompt/github-ref-autocomplete.d.ts +35 -0
- package/dist/types/prompt/gradient-highlight.d.ts +32 -0
- package/dist/types/prompt/image-format.d.ts +4 -0
- package/dist/types/prompt/image-references.d.ts +26 -0
- package/dist/types/prompt/interactive-context-helpers.d.ts +43 -0
- package/dist/types/prompt/internal-url-autocomplete.d.ts +56 -0
- package/dist/types/prompt/macos-spelling.d.ts +44 -0
- package/dist/types/prompt/magic-keyword-boundary.d.ts +9 -0
- package/dist/types/prompt/magic-keywords.d.ts +26 -0
- package/dist/types/prompt/markdown-prose.d.ts +15 -0
- package/dist/types/prompt/model-mention-autocomplete.d.ts +25 -0
- package/dist/types/prompt/model-mention-syntax.d.ts +24 -0
- package/dist/types/prompt/orchestrate.d.ts +13 -0
- package/dist/types/prompt/prompt-action-autocomplete.d.ts +56 -0
- package/dist/types/prompt/queue-input.d.ts +8 -0
- package/dist/types/prompt/skill-tokens.d.ts +13 -0
- package/dist/types/prompt/tools-markdown.d.ts +12 -0
- package/dist/types/prompt/ultrathink.d.ts +13 -0
- package/dist/types/prompt/usage-amounts.d.ts +26 -0
- package/dist/types/prompt/video.d.ts +18 -0
- package/dist/types/prompt/welcome.d.ts +83 -0
- package/dist/types/prompt/workflow.d.ts +13 -0
- package/dist/types/render/code-cell.d.ts +51 -0
- package/dist/types/render/file-list.d.ts +22 -0
- package/dist/types/render/hyperlink.d.ts +80 -0
- package/dist/types/render/index.d.ts +16 -0
- package/dist/types/render/output-block.d.ts +54 -0
- package/dist/types/render/output-pane.d.ts +80 -0
- package/dist/types/render/render-utils.d.ts +312 -0
- package/dist/types/render/sixel.d.ts +21 -0
- package/dist/types/render/status-line.d.ts +23 -0
- package/dist/types/render/tool-card.d.ts +71 -0
- package/dist/types/render/tree-list.d.ts +29 -0
- package/dist/types/render/types.d.ts +17 -0
- package/dist/types/render/utils.d.ts +43 -0
- package/dist/types/render/width-aware-text.d.ts +23 -0
- package/dist/types/setup/lazy.d.ts +3 -0
- package/dist/types/setup/scenes/composer.d.ts +3 -0
- package/dist/types/setup/scenes/glyph.d.ts +3 -0
- package/dist/types/setup/scenes/model.d.ts +3 -0
- package/dist/types/setup/scenes/outro.d.ts +2 -0
- package/dist/types/setup/scenes/providers.d.ts +3 -0
- package/dist/types/setup/scenes/sign-in.d.ts +21 -0
- package/dist/types/setup/scenes/splash.d.ts +11 -0
- package/dist/types/setup/scenes/theme.d.ts +3 -0
- package/dist/types/setup/scenes/types.d.ts +110 -0
- package/dist/types/setup/scenes/web-search.d.ts +22 -0
- package/dist/types/setup/setup-version.d.ts +11 -0
- package/dist/types/setup/startup-splash.d.ts +9 -0
- package/dist/types/setup/wizard-overlay.d.ts +16 -0
- package/dist/types/setup/wizard.d.ts +25 -0
- package/dist/types/status-line/component.d.ts +182 -0
- package/dist/types/status-line/context-usage.d.ts +156 -0
- package/dist/types/status-line/footer.d.ts +30 -0
- package/dist/types/status-line/git-utils.d.ts +22 -0
- package/dist/types/status-line/host.d.ts +129 -0
- package/dist/types/status-line/index.d.ts +6 -0
- package/dist/types/status-line/loop.d.ts +18 -0
- package/dist/types/status-line/metrics.d.ts +21 -0
- package/dist/types/status-line/presets.d.ts +3 -0
- package/dist/types/status-line/schema.d.ts +15 -0
- package/dist/types/status-line/segments.d.ts +5 -0
- package/dist/types/status-line/separators.d.ts +3 -0
- package/dist/types/status-line/types.d.ts +236 -0
- package/dist/types/stdin-buffer.d.ts +4 -0
- package/dist/types/theme/color.d.ts +24 -0
- package/dist/types/theme/defaults/index.d.ts +9489 -0
- package/dist/types/theme/index.d.ts +4 -0
- package/dist/types/theme/loader.d.ts +23 -0
- package/dist/types/theme/mermaid-cache.d.ts +26 -0
- package/dist/types/theme/schema-validation.d.ts +3 -0
- package/dist/types/theme/schema.d.ts +25 -0
- package/dist/types/theme/session-color.d.ts +43 -0
- package/dist/types/theme/shimmer.d.ts +44 -0
- package/dist/types/theme/symbols.d.ts +34 -0
- package/dist/types/theme/theme-class.d.ts +299 -0
- package/dist/types/theme/theme.d.ts +111 -0
- package/dist/types/theme/tui-adapters.d.ts +30 -0
- package/dist/types/thinking.d.ts +165 -0
- package/dist/types/tools/agent-tree.d.ts +36 -0
- package/dist/types/tools/ask.d.ts +67 -0
- package/dist/types/tools/ast-edit.d.ts +53 -0
- package/dist/types/tools/ast-grep.d.ts +52 -0
- package/dist/types/tools/autoresearch.d.ts +156 -0
- package/dist/types/tools/bash-interactive.d.ts +28 -0
- package/dist/types/tools/bash.d.ts +103 -0
- package/dist/types/tools/conflict-detect.d.ts +43 -0
- package/dist/types/tools/debug.d.ts +60 -0
- package/dist/types/tools/default-renderer.d.ts +24 -0
- package/dist/types/tools/edit.d.ts +158 -0
- package/dist/types/tools/eval-format/code-mode-declarations.d.ts +5 -0
- package/dist/types/tools/eval-format/index.d.ts +5 -0
- package/dist/types/tools/eval-format/javascript.d.ts +2 -0
- package/dist/types/tools/eval-format/python.d.ts +2 -0
- package/dist/types/tools/eval.d.ts +94 -0
- package/dist/types/tools/fetch.d.ts +42 -0
- package/dist/types/tools/gh-format.d.ts +8 -0
- package/dist/types/tools/github.d.ts +144 -0
- package/dist/types/tools/glob.d.ts +44 -0
- package/dist/types/tools/goal.d.ts +42 -0
- package/dist/types/tools/grep.d.ts +64 -0
- package/dist/types/tools/grouped-file-output.d.ts +71 -0
- package/dist/types/tools/hashline-format.d.ts +28 -0
- package/dist/types/tools/hub.d.ts +340 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/json-tree.d.ts +59 -0
- package/dist/types/tools/line-ranges.d.ts +29 -0
- package/dist/types/tools/list-limit.d.ts +15 -0
- package/dist/types/tools/lsp.d.ts +72 -0
- package/dist/types/tools/match-line-format.d.ts +11 -0
- package/dist/types/tools/mcp.d.ts +81 -0
- package/dist/types/tools/memory.d.ts +67 -0
- package/dist/types/tools/output-meta.d.ts +151 -0
- package/dist/types/tools/read.d.ts +139 -0
- package/dist/types/tools/renderer.d.ts +98 -0
- package/dist/types/tools/report-tool-issue.d.ts +8 -0
- package/dist/types/tools/resolve.d.ts +47 -0
- package/dist/types/tools/streaming-output.d.ts +282 -0
- package/dist/types/tools/subprocess.d.ts +24 -0
- package/dist/types/tools/task-repair-args.d.ts +53 -0
- package/dist/types/tools/task-yield-assembly.d.ts +20 -0
- package/dist/types/tools/task.d.ts +425 -0
- package/dist/types/tools/terminal-output.d.ts +8 -0
- package/dist/types/tools/think.d.ts +13 -0
- package/dist/types/tools/todo.d.ts +118 -0
- package/dist/types/tools/tool-errors.d.ts +7 -0
- package/dist/types/tools/vibe.d.ts +120 -0
- package/dist/types/tools/web-search.d.ts +195 -0
- package/dist/types/tools/write.d.ts +76 -0
- package/dist/types/tools/xd-url.d.ts +13 -0
- package/dist/types/tools/xdev.d.ts +52 -0
- package/dist/types/tui.d.ts +18 -0
- package/dist/types/utils.d.ts +2 -0
- package/package.json +37 -3
- package/src/app-keybindings.ts +760 -0
- package/src/apps/autoresearch-dashboard.ts +500 -0
- package/src/apps/autoresearch-data.ts +64 -0
- package/src/apps/cleanse-board.ts +341 -0
- package/src/apps/cleanse-picker.ts +57 -0
- package/src/apps/debug/log-formatting.ts +53 -0
- package/src/apps/debug/log-viewer.ts +868 -0
- package/src/apps/debug/protocol-probe.ts +267 -0
- package/src/apps/debug/raw-sse-buffer.ts +449 -0
- package/src/apps/debug/raw-sse.ts +282 -0
- package/src/apps/debug/terminal-info.ts +115 -0
- package/src/apps/debug/viewer-frame.ts +174 -0
- package/src/apps/git/avatar.ts +52 -0
- package/src/apps/git/colors.ts +109 -0
- package/src/apps/git/diff-pane.ts +1512 -0
- package/src/apps/git/git-tui.ts +889 -0
- package/src/apps/git/sidebar.ts +1204 -0
- package/src/apps/git/state.ts +113 -0
- package/src/apps/if-bench-board.ts +324 -0
- package/src/apps/live-visualizer.ts +238 -0
- package/src/apps/ps-data.ts +116 -0
- package/src/apps/ps-top.ts +422 -0
- package/src/apps/session-picker.ts +95 -0
- package/src/apps/setup-model-picker.ts +21 -0
- package/src/apps/standalone-picker.ts +111 -0
- package/src/autocomplete.ts +9 -13
- package/src/chat/advisor-message.ts +175 -0
- package/src/chat/assistant-message.ts +1214 -0
- package/src/chat/background-tan-message.ts +35 -0
- package/src/chat/bash-execution.ts +394 -0
- package/src/chat/cache-invalidation-marker.ts +94 -0
- package/src/chat/chat-transcript-builder.ts +593 -0
- package/src/chat/collab-prompt-message.ts +34 -0
- package/src/chat/compaction-summary-message.ts +261 -0
- package/src/chat/custom-message.ts +23 -0
- package/src/chat/display-preferences.ts +24 -0
- package/src/chat/eval-execution.ts +172 -0
- package/src/chat/execution-shared.ts +113 -0
- package/src/chat/extension-types.ts +46 -0
- package/src/chat/hook-message.ts +20 -0
- package/src/chat/image-loading.ts +122 -0
- package/src/chat/late-diagnostics-message.ts +92 -0
- package/src/chat/messages.ts +305 -0
- package/src/chat/reaction.ts +65 -0
- package/src/chat/read-target.ts +7 -0
- package/src/chat/read-tool-group.ts +873 -0
- package/src/chat/served-model-marker.ts +91 -0
- package/src/chat/skill-message.ts +220 -0
- package/src/chat/skill-title-input.ts +41 -0
- package/src/chat/stripped-tool-calls-placeholder.ts +35 -0
- package/src/chat/thinking-display.ts +312 -0
- package/src/chat/todo-reminder.ts +33 -0
- package/src/chat/tool-execution.ts +1395 -0
- package/src/chat/transcript-browser.ts +268 -0
- package/src/chat/transcript-entry.ts +96 -0
- package/src/chat/transcript-outline.ts +260 -0
- package/src/chat/transcript-render-helpers.ts +315 -0
- package/src/chat/ttsr-notification.ts +123 -0
- package/src/chat/user-message.ts +287 -0
- package/src/chrome/chat-block.ts +110 -0
- package/src/chrome/collab-qrcode.ts +74 -0
- package/src/chrome/context-thresholds.ts +85 -0
- package/src/chrome/countdown-timer.ts +74 -0
- package/src/chrome/diff.ts +266 -0
- package/src/chrome/dynamic-border.ts +36 -0
- package/src/chrome/error-block.ts +63 -0
- package/src/chrome/form-theme.ts +10 -0
- package/src/chrome/format.ts +66 -0
- package/src/chrome/index.ts +21 -0
- package/src/chrome/keybinding-hints.ts +55 -0
- package/src/chrome/live-board.ts +123 -0
- package/src/chrome/local-date.ts +20 -0
- package/src/chrome/message-divider.ts +51 -0
- package/src/chrome/message-frame.ts +164 -0
- package/src/chrome/message-notice.ts +103 -0
- package/src/chrome/overlay-box.ts +301 -0
- package/src/chrome/qrcode.ts +539 -0
- package/src/chrome/segment-track.ts +86 -0
- package/src/chrome/select-list-mouse-routing.ts +11 -0
- package/src/chrome/selector-helpers.ts +119 -0
- package/src/chrome/shared.ts +27 -0
- package/src/chrome/streaming-panel.ts +72 -0
- package/src/chrome/tool-activity.ts +44 -0
- package/src/chrome/transcript-container.ts +902 -0
- package/src/chrome/transcript-status.ts +27 -0
- package/src/chrome/visual-truncate.ts +70 -0
- package/src/components/disclosure.ts +235 -0
- package/src/components/editor.ts +10 -12
- package/src/components/form.ts +566 -0
- package/src/components/input.ts +6 -27
- package/src/components/key-value-list.ts +88 -0
- package/src/components/layout/geometry.ts +202 -0
- package/src/components/layout/row.ts +283 -0
- package/src/components/layout/split-pane.ts +349 -0
- package/src/components/layout/stack.ts +261 -0
- package/src/components/markdown.ts +16 -12
- package/src/components/menu-selection.ts +248 -0
- package/src/components/metric.ts +132 -0
- package/src/components/progress-bar.ts +140 -0
- package/src/components/scroll-view.ts +372 -70
- package/src/components/scroll-viewport.ts +154 -0
- package/src/components/section.ts +77 -0
- package/src/components/select-list.ts +238 -159
- package/src/components/settings-list.ts +103 -80
- package/src/components/table.ts +127 -0
- package/src/components/tree-view.ts +481 -0
- package/src/components/wizard-step.ts +229 -0
- package/src/deccara.ts +1 -3
- package/src/hotkeys-markdown.ts +100 -0
- package/src/index.ts +18 -0
- package/src/keybinding-matchers.ts +99 -0
- package/src/keys.ts +2 -2
- package/src/lang-from-path.ts +252 -0
- package/src/overlays/advisor-config.ts +761 -0
- package/src/overlays/agent-activity.ts +113 -0
- package/src/overlays/agent-hub-projection.ts +250 -0
- package/src/overlays/agent-hub-renderer.ts +281 -0
- package/src/overlays/agent-hub-types.ts +74 -0
- package/src/overlays/agent-hub.ts +1562 -0
- package/src/overlays/agent-transcript-viewer.ts +669 -0
- package/src/overlays/agents-hub.ts +1203 -0
- package/src/overlays/ask-dialog.ts +1202 -0
- package/src/overlays/bordered-loader.ts +41 -0
- package/src/overlays/btw-history-panel.ts +591 -0
- package/src/overlays/btw-history.ts +33 -0
- package/src/overlays/btw-panel.ts +167 -0
- package/src/overlays/cleanse-panel.ts +167 -0
- package/src/overlays/codex-reset-fireworks.ts +375 -0
- package/src/overlays/composer-shape-preview.ts +137 -0
- package/src/overlays/composer-shape-registry.ts +82 -0
- package/src/overlays/copy-selector.ts +618 -0
- package/src/overlays/copy-targets.ts +210 -0
- package/src/overlays/error-banner.ts +39 -0
- package/src/overlays/extensions/display-text.ts +39 -0
- package/src/overlays/extensions/extension-dashboard.ts +645 -0
- package/src/overlays/extensions/extension-list.ts +667 -0
- package/src/overlays/extensions/inspector-model.ts +484 -0
- package/src/overlays/extensions/inspector-panel.ts +669 -0
- package/src/overlays/extensions/live-tool-session.ts +67 -0
- package/src/overlays/extensions/mcp-runtime.ts +289 -0
- package/src/overlays/extensions/state-manager.ts +337 -0
- package/src/overlays/extensions/types.ts +208 -0
- package/src/overlays/history-search.ts +268 -0
- package/src/overlays/hook-editor.ts +272 -0
- package/src/overlays/hook-input.ts +84 -0
- package/src/overlays/hook-selector.ts +635 -0
- package/src/overlays/hub-frame.ts +262 -0
- package/src/overlays/login-dialog.ts +231 -0
- package/src/overlays/logout-account-selector.ts +115 -0
- package/src/overlays/mcp-add-wizard.ts +1436 -0
- package/src/overlays/model-browser.ts +1176 -0
- package/src/overlays/model-hub.ts +2279 -0
- package/src/overlays/model-picker.ts +285 -0
- package/src/overlays/model-selector.ts +107 -0
- package/src/overlays/move-overlay.ts +197 -0
- package/src/overlays/oauth-selector.ts +446 -0
- package/src/overlays/omfg-panel.ts +136 -0
- package/src/overlays/pause-screen.ts +198 -0
- package/src/overlays/plan-review-overlay.ts +1227 -0
- package/src/overlays/plan-save-overlay.ts +74 -0
- package/src/overlays/plan-toc.ts +139 -0
- package/src/overlays/plugin-selector.ts +97 -0
- package/src/overlays/plugin-settings.ts +839 -0
- package/src/overlays/queue-mode-selector.ts +55 -0
- package/src/overlays/reset-usage-selector.ts +170 -0
- package/src/overlays/rewind-selector.ts +499 -0
- package/src/overlays/running-subagent-badge.ts +19 -0
- package/src/overlays/session-account-selector.ts +68 -0
- package/src/overlays/session-info-overlay.ts +96 -0
- package/src/overlays/session-observer-registry.ts +289 -0
- package/src/overlays/session-selector.ts +1137 -0
- package/src/overlays/settings-defs.ts +315 -0
- package/src/overlays/settings-selector.ts +1415 -0
- package/src/overlays/show-images-selector.ts +44 -0
- package/src/overlays/snapcompact-shape-preview-doc.md +14 -0
- package/src/overlays/snapcompact-shape-preview.ts +192 -0
- package/src/overlays/theme-selector.ts +62 -0
- package/src/overlays/thinking-selector.ts +51 -0
- package/src/overlays/tiny-title-download-progress.ts +102 -0
- package/src/overlays/tree-selector.ts +1121 -0
- package/src/overlays/usage-dashboard.ts +629 -0
- package/src/overlays/usage-display.ts +45 -0
- package/src/overlays/usage-row.ts +118 -0
- package/src/prompt/attachment-chips.ts +201 -0
- package/src/prompt/composer-attachments.ts +280 -0
- package/src/prompt/composer-cache.ts +304 -0
- package/src/prompt/composer.ts +934 -0
- package/src/prompt/custom-editor.ts +1392 -0
- package/src/prompt/data/emojis.json +1 -0
- package/src/prompt/editor-top-gap.ts +28 -0
- package/src/prompt/emoji-autocomplete.ts +285 -0
- package/src/prompt/github-ref-autocomplete.ts +75 -0
- package/src/prompt/gradient-highlight.ts +101 -0
- package/src/prompt/image-format.ts +28 -0
- package/src/prompt/image-references.ts +102 -0
- package/src/prompt/interactive-context-helpers.ts +126 -0
- package/src/prompt/internal-url-autocomplete.ts +155 -0
- package/src/prompt/macos-spelling.ts +456 -0
- package/src/prompt/magic-keyword-boundary.ts +23 -0
- package/src/prompt/magic-keywords.ts +42 -0
- package/src/prompt/markdown-prose.ts +245 -0
- package/src/prompt/model-mention-autocomplete.ts +94 -0
- package/src/prompt/model-mention-syntax.ts +41 -0
- package/src/prompt/orchestrate.ts +26 -0
- package/src/prompt/prompt-action-autocomplete.ts +337 -0
- package/src/prompt/queue-input.ts +132 -0
- package/src/prompt/skill-tokens.ts +36 -0
- package/src/prompt/tips.txt +27 -0
- package/src/prompt/tools-markdown.ts +29 -0
- package/src/prompt/ultrathink.ts +26 -0
- package/src/prompt/usage-amounts.ts +99 -0
- package/src/prompt/video.ts +47 -0
- package/src/prompt/welcome.ts +605 -0
- package/src/prompt/workflow.ts +26 -0
- package/src/render/code-cell.ts +244 -0
- package/src/render/file-list.ts +58 -0
- package/src/render/hyperlink.ts +192 -0
- package/src/render/index.ts +17 -0
- package/src/render/output-block.ts +267 -0
- package/src/render/output-pane.ts +299 -0
- package/src/render/render-utils.ts +1182 -0
- package/src/render/sixel.ts +69 -0
- package/src/render/status-line.ts +55 -0
- package/src/render/tool-card.ts +272 -0
- package/src/render/tree-list.ts +188 -0
- package/src/render/types.ts +19 -0
- package/src/render/utils.ts +109 -0
- package/src/render/width-aware-text.ts +60 -0
- package/src/setup/lazy.ts +17 -0
- package/src/setup/scenes/composer.ts +127 -0
- package/src/setup/scenes/glyph.ts +120 -0
- package/src/setup/scenes/model.ts +138 -0
- package/src/setup/scenes/outro.ts +24 -0
- package/src/setup/scenes/providers.ts +107 -0
- package/src/setup/scenes/sign-in.ts +373 -0
- package/src/setup/scenes/splash.ts +192 -0
- package/src/setup/scenes/theme.ts +343 -0
- package/src/setup/scenes/types.ts +111 -0
- package/src/setup/scenes/web-search.ts +165 -0
- package/src/setup/setup-version.ts +11 -0
- package/src/setup/startup-splash.ts +107 -0
- package/src/setup/wizard-overlay.ts +319 -0
- package/src/setup/wizard.ts +101 -0
- package/src/status-line/component.ts +3003 -0
- package/src/status-line/context-usage.ts +688 -0
- package/src/status-line/footer.ts +323 -0
- package/src/status-line/git-utils.ts +42 -0
- package/src/status-line/host.ts +97 -0
- package/src/status-line/index.ts +6 -0
- package/src/status-line/loop.ts +28 -0
- package/src/status-line/metrics.ts +94 -0
- package/src/status-line/presets.ts +107 -0
- package/src/status-line/schema.ts +57 -0
- package/src/status-line/segments.ts +934 -0
- package/src/status-line/separators.ts +55 -0
- package/src/status-line/types.ts +227 -0
- package/src/stdin-buffer.ts +4 -2
- package/src/theme/color.ts +95 -0
- package/src/theme/dark.json +95 -0
- package/src/theme/defaults/alabaster.json +93 -0
- package/src/theme/defaults/amethyst.json +96 -0
- package/src/theme/defaults/anthracite.json +93 -0
- package/src/theme/defaults/basalt.json +91 -0
- package/src/theme/defaults/birch.json +95 -0
- package/src/theme/defaults/dark-abyss.json +91 -0
- package/src/theme/defaults/dark-arctic.json +104 -0
- package/src/theme/defaults/dark-aurora.json +95 -0
- package/src/theme/defaults/dark-catppuccin.json +107 -0
- package/src/theme/defaults/dark-cavern.json +91 -0
- package/src/theme/defaults/dark-celestial.json +106 -0
- package/src/theme/defaults/dark-copper.json +95 -0
- package/src/theme/defaults/dark-cosmos.json +90 -0
- package/src/theme/defaults/dark-cyberpunk.json +102 -0
- package/src/theme/defaults/dark-dracula.json +98 -0
- package/src/theme/defaults/dark-eclipse.json +91 -0
- package/src/theme/defaults/dark-ember.json +95 -0
- package/src/theme/defaults/dark-equinox.json +90 -0
- package/src/theme/defaults/dark-forest.json +96 -0
- package/src/theme/defaults/dark-github.json +105 -0
- package/src/theme/defaults/dark-gruvbox.json +112 -0
- package/src/theme/defaults/dark-lavender.json +95 -0
- package/src/theme/defaults/dark-lunar.json +89 -0
- package/src/theme/defaults/dark-midnight.json +95 -0
- package/src/theme/defaults/dark-monochrome.json +94 -0
- package/src/theme/defaults/dark-monokai.json +98 -0
- package/src/theme/defaults/dark-nebula.json +90 -0
- package/src/theme/defaults/dark-nord.json +98 -0
- package/src/theme/defaults/dark-ocean.json +101 -0
- package/src/theme/defaults/dark-one.json +100 -0
- package/src/theme/defaults/dark-poimandres.json +115 -0
- package/src/theme/defaults/dark-rainforest.json +91 -0
- package/src/theme/defaults/dark-reef.json +91 -0
- package/src/theme/defaults/dark-retro.json +92 -0
- package/src/theme/defaults/dark-rose-pine.json +96 -0
- package/src/theme/defaults/dark-sakura.json +95 -0
- package/src/theme/defaults/dark-slate.json +95 -0
- package/src/theme/defaults/dark-solarized.json +97 -0
- package/src/theme/defaults/dark-solstice.json +90 -0
- package/src/theme/defaults/dark-starfall.json +91 -0
- package/src/theme/defaults/dark-sunset.json +99 -0
- package/src/theme/defaults/dark-swamp.json +90 -0
- package/src/theme/defaults/dark-synthwave.json +103 -0
- package/src/theme/defaults/dark-taiga.json +91 -0
- package/src/theme/defaults/dark-terminal.json +95 -0
- package/src/theme/defaults/dark-tokyo-night.json +101 -0
- package/src/theme/defaults/dark-tundra.json +91 -0
- package/src/theme/defaults/dark-twilight.json +91 -0
- package/src/theme/defaults/dark-volcanic.json +91 -0
- package/src/theme/defaults/graphite.json +92 -0
- package/src/theme/defaults/index.ts +201 -0
- package/src/theme/defaults/light-arctic.json +107 -0
- package/src/theme/defaults/light-aurora-day.json +91 -0
- package/src/theme/defaults/light-canyon.json +91 -0
- package/src/theme/defaults/light-catppuccin.json +106 -0
- package/src/theme/defaults/light-cirrus.json +90 -0
- package/src/theme/defaults/light-coral.json +95 -0
- package/src/theme/defaults/light-cyberpunk.json +96 -0
- package/src/theme/defaults/light-dawn.json +90 -0
- package/src/theme/defaults/light-dunes.json +91 -0
- package/src/theme/defaults/light-eucalyptus.json +95 -0
- package/src/theme/defaults/light-forest.json +100 -0
- package/src/theme/defaults/light-frost.json +95 -0
- package/src/theme/defaults/light-github.json +115 -0
- package/src/theme/defaults/light-glacier.json +91 -0
- package/src/theme/defaults/light-gruvbox.json +108 -0
- package/src/theme/defaults/light-haze.json +90 -0
- package/src/theme/defaults/light-honeycomb.json +95 -0
- package/src/theme/defaults/light-lagoon.json +91 -0
- package/src/theme/defaults/light-lavender.json +95 -0
- package/src/theme/defaults/light-meadow.json +91 -0
- package/src/theme/defaults/light-mint.json +95 -0
- package/src/theme/defaults/light-monochrome.json +101 -0
- package/src/theme/defaults/light-ocean.json +99 -0
- package/src/theme/defaults/light-one.json +99 -0
- package/src/theme/defaults/light-opal.json +91 -0
- package/src/theme/defaults/light-orchard.json +91 -0
- package/src/theme/defaults/light-paper.json +95 -0
- package/src/theme/defaults/light-poimandres.json +115 -0
- package/src/theme/defaults/light-prism.json +90 -0
- package/src/theme/defaults/light-retro.json +98 -0
- package/src/theme/defaults/light-sand.json +95 -0
- package/src/theme/defaults/light-savanna.json +91 -0
- package/src/theme/defaults/light-solarized.json +102 -0
- package/src/theme/defaults/light-soleil.json +90 -0
- package/src/theme/defaults/light-sunset.json +99 -0
- package/src/theme/defaults/light-synthwave.json +98 -0
- package/src/theme/defaults/light-tokyo-night.json +111 -0
- package/src/theme/defaults/light-wetland.json +91 -0
- package/src/theme/defaults/light-zenith.json +89 -0
- package/src/theme/defaults/limestone.json +94 -0
- package/src/theme/defaults/mahogany.json +97 -0
- package/src/theme/defaults/marble.json +93 -0
- package/src/theme/defaults/obsidian.json +91 -0
- package/src/theme/defaults/onyx.json +91 -0
- package/src/theme/defaults/pearl.json +93 -0
- package/src/theme/defaults/porcelain.json +91 -0
- package/src/theme/defaults/quartz.json +96 -0
- package/src/theme/defaults/sandstone.json +95 -0
- package/src/theme/defaults/titanium.json +90 -0
- package/src/theme/index.ts +5 -0
- package/src/theme/light.json +93 -0
- package/src/theme/loader.ts +200 -0
- package/src/theme/mermaid-cache.ts +92 -0
- package/src/theme/schema-validation.ts +119 -0
- package/src/theme/schema.ts +168 -0
- package/src/theme/session-color.ts +253 -0
- package/src/theme/shimmer.ts +307 -0
- package/src/theme/symbols.ts +1433 -0
- package/src/theme/theme-class.ts +787 -0
- package/src/theme/theme-schema.json +463 -0
- package/src/theme/theme.ts +810 -0
- package/src/theme/tui-adapters.ts +339 -0
- package/src/thinking.ts +380 -0
- package/src/tools/agent-tree.ts +128 -0
- package/src/tools/ask.ts +482 -0
- package/src/tools/ast-edit.ts +210 -0
- package/src/tools/ast-grep.ts +171 -0
- package/src/tools/autoresearch.ts +287 -0
- package/src/tools/bash-interactive.ts +295 -0
- package/src/tools/bash.ts +468 -0
- package/src/tools/conflict-detect.ts +77 -0
- package/src/tools/debug.ts +167 -0
- package/src/tools/default-renderer.ts +172 -0
- package/src/tools/edit.ts +1258 -0
- package/src/tools/eval-format/code-mode-declarations.ts +61 -0
- package/src/tools/eval-format/index.ts +16 -0
- package/src/tools/eval-format/javascript.ts +952 -0
- package/src/tools/eval-format/python.ts +544 -0
- package/src/tools/eval.ts +835 -0
- package/src/tools/fetch.ts +226 -0
- package/src/tools/gh-format.ts +18 -0
- package/src/tools/github.ts +686 -0
- package/src/tools/glob.ts +213 -0
- package/src/tools/goal.ts +153 -0
- package/src/tools/grep.ts +385 -0
- package/src/tools/grouped-file-output.ts +211 -0
- package/src/tools/hashline-format.ts +59 -0
- package/src/tools/hub.ts +1488 -0
- package/src/tools/index.ts +71 -0
- package/src/tools/json-tree.ts +388 -0
- package/src/tools/line-ranges.ts +98 -0
- package/src/tools/list-limit.ts +43 -0
- package/src/tools/lsp.ts +702 -0
- package/src/tools/match-line-format.ts +20 -0
- package/src/tools/mcp.ts +309 -0
- package/src/tools/memory.ts +220 -0
- package/src/tools/output-meta.ts +367 -0
- package/src/tools/read.ts +628 -0
- package/src/tools/renderer.ts +107 -0
- package/src/tools/report-tool-issue.ts +13 -0
- package/src/tools/resolve.ts +139 -0
- package/src/tools/streaming-output.ts +1576 -0
- package/src/tools/subprocess.ts +39 -0
- package/src/tools/task-repair-args.ts +118 -0
- package/src/tools/task-yield-assembly.ts +147 -0
- package/src/tools/task.ts +2110 -0
- package/src/tools/terminal-output.ts +153 -0
- package/src/tools/think.ts +28 -0
- package/src/tools/todo.ts +580 -0
- package/src/tools/tool-errors.ts +15 -0
- package/src/tools/vibe.ts +420 -0
- package/src/tools/web-search.ts +409 -0
- package/src/tools/write.ts +511 -0
- package/src/tools/xd-url.ts +28 -0
- package/src/tools/xdev.ts +201 -0
- package/src/tui.ts +57 -4
- package/src/utils.ts +8 -0
|
@@ -0,0 +1,810 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { detectMacOSAppearance, MacAppearanceObserver } from "@oh-my-pi/pi-natives";
|
|
4
|
+
import type { Terminal, TerminalAppearance } from "../terminal";
|
|
5
|
+
import { colorLuma } from "@oh-my-pi/pi-utils/color";
|
|
6
|
+
import { getCustomThemesDir } from "@oh-my-pi/pi-utils/dirs";
|
|
7
|
+
import * as logger from "@oh-my-pi/pi-utils/logger";
|
|
8
|
+
import { ansi256ToHex, resolveThemeColors, resolveVarRefs } from "./color";
|
|
9
|
+
import { type CreateThemeOptions, getBuiltinThemes, loadTheme, loadThemeJson, loadThemeSync } from "./loader";
|
|
10
|
+
import type { ThemeColor, ThemeJson } from "./schema";
|
|
11
|
+
import type { SymbolPreset } from "./symbols";
|
|
12
|
+
import type { Theme } from "./theme-class";
|
|
13
|
+
|
|
14
|
+
export { getAvailableThemes, getAvailableThemesWithPaths, getThemeByName, type ThemeInfo } from "./loader";
|
|
15
|
+
export { isValidThemeColor, type ThemeBg, type ThemeColor } from "./schema";
|
|
16
|
+
export {
|
|
17
|
+
getAvailableSymbolPresets,
|
|
18
|
+
isValidSymbolPreset,
|
|
19
|
+
type SpinnerType,
|
|
20
|
+
type SymbolKey,
|
|
21
|
+
type SymbolPreset,
|
|
22
|
+
} from "./symbols";
|
|
23
|
+
export { Theme } from "./theme-class";
|
|
24
|
+
export {
|
|
25
|
+
createHighlightStream,
|
|
26
|
+
getEditorTheme,
|
|
27
|
+
getMarkdownTheme,
|
|
28
|
+
getSelectListTheme,
|
|
29
|
+
getSettingsListTheme,
|
|
30
|
+
getSymbolTheme,
|
|
31
|
+
highlightCode,
|
|
32
|
+
setMarkdownMermaidRendering,
|
|
33
|
+
warmHighlighter,
|
|
34
|
+
} from "./tui-adapters";
|
|
35
|
+
|
|
36
|
+
/** Appearance detected via OSC 11 background color query, or undefined if not yet available. */
|
|
37
|
+
var terminalReportedAppearance: "dark" | "light" | undefined;
|
|
38
|
+
|
|
39
|
+
/** Appearance reported by the macOS fallback observer, or undefined if not yet available. */
|
|
40
|
+
var macOSReportedAppearance: "dark" | "light" | undefined;
|
|
41
|
+
|
|
42
|
+
function shouldUseMacOSAppearanceFallback(): boolean {
|
|
43
|
+
// Zellij currently breaks OSC 11 passthrough on macOS, so terminal-derived
|
|
44
|
+
// appearance cannot be trusted there. Fall back to host macOS appearance
|
|
45
|
+
// without letting it override valid terminal signals elsewhere.
|
|
46
|
+
return process.platform === "darwin" && !!Bun.env.ZELLIJ;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function detectTerminalBackground(): "dark" | "light" {
|
|
50
|
+
// Tier 1: terminal-reported appearance from OSC 11 luminance.
|
|
51
|
+
if (!shouldUseMacOSAppearanceFallback() && terminalReportedAppearance) {
|
|
52
|
+
return terminalReportedAppearance;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Tier 2: COLORFGBG env var (static at process start, but still terminal-derived).
|
|
56
|
+
const colorfgbg = Bun.env.COLORFGBG || "";
|
|
57
|
+
if (colorfgbg) {
|
|
58
|
+
const parts = colorfgbg.split(";");
|
|
59
|
+
if (parts.length >= 2) {
|
|
60
|
+
const bg = parseInt(parts[1], 10);
|
|
61
|
+
if (!Number.isNaN(bg)) return bg < 8 ? "dark" : "light";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Tier 3: host macOS appearance for known-broken terminal paths only.
|
|
66
|
+
if (shouldUseMacOSAppearanceFallback()) {
|
|
67
|
+
const macAppearance = macOSReportedAppearance ?? detectMacOSAppearance();
|
|
68
|
+
if (macAppearance) return macAppearance;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return "dark";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getDefaultTheme(): string {
|
|
75
|
+
const bg = detectTerminalBackground();
|
|
76
|
+
return bg === "light" ? autoLightTheme : autoDarkTheme;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Global Theme Instance
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
/** Active theme; imports remain live across initialization, previews, and theme switches. */
|
|
84
|
+
export var theme: Theme;
|
|
85
|
+
var currentThemeName: string | undefined;
|
|
86
|
+
|
|
87
|
+
type ThemeBinding = (value: Theme) => void;
|
|
88
|
+
var themeBindings: Set<ThemeBinding> | undefined;
|
|
89
|
+
|
|
90
|
+
/** @internal Mirror assignments into bundled module bindings without replacing the UI change listener. */
|
|
91
|
+
export function bindTheme(binding: ThemeBinding): () => void {
|
|
92
|
+
const bindings = (themeBindings ??= new Set<ThemeBinding>());
|
|
93
|
+
bindings.add(binding);
|
|
94
|
+
binding(theme);
|
|
95
|
+
return () => {
|
|
96
|
+
bindings.delete(binding);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function assignTheme(value: Theme): void {
|
|
101
|
+
theme = value;
|
|
102
|
+
if (themeBindings) {
|
|
103
|
+
for (const binding of themeBindings) binding(value);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Get the name of the currently active theme. */
|
|
108
|
+
export function getCurrentThemeName(): string | undefined {
|
|
109
|
+
return currentThemeName;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Returns unstyled `text` before `initTheme()` assigns the global theme; use only for early-render paths. */
|
|
113
|
+
export function fgOrPlain(color: ThemeColor, text: string, styledText: string = text): string {
|
|
114
|
+
return typeof theme === "undefined" ? text : theme.fg(color, styledText);
|
|
115
|
+
}
|
|
116
|
+
export interface ThemeChangeEvent {
|
|
117
|
+
/** Preview/presentation-only changes should repaint live UI without replacing native scrollback. */
|
|
118
|
+
ephemeral?: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
var currentSymbolPresetOverride: SymbolPreset | undefined;
|
|
122
|
+
var currentColorBlindMode: boolean = false;
|
|
123
|
+
var themeWatcher: fs.FSWatcher | undefined;
|
|
124
|
+
var themeReloadTimer: NodeJS.Timeout | undefined;
|
|
125
|
+
var sigwinchHandler: (() => void) | undefined;
|
|
126
|
+
var autoDetectedTheme: boolean = false;
|
|
127
|
+
var autoDarkTheme: string = "dark";
|
|
128
|
+
var autoLightTheme: string = "light";
|
|
129
|
+
var onThemeChangeCallback: ((event: ThemeChangeEvent) => void) | undefined;
|
|
130
|
+
var themeLoadRequestId: number = 0;
|
|
131
|
+
let themeEpoch = 0;
|
|
132
|
+
|
|
133
|
+
function getCurrentThemeOptions(): CreateThemeOptions {
|
|
134
|
+
return {
|
|
135
|
+
symbolPresetOverride: currentSymbolPresetOverride,
|
|
136
|
+
colorBlindMode: currentColorBlindMode,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function configureTheme(
|
|
140
|
+
symbolPreset?: SymbolPreset,
|
|
141
|
+
colorBlindMode?: boolean,
|
|
142
|
+
darkTheme?: string,
|
|
143
|
+
lightTheme?: string,
|
|
144
|
+
): string {
|
|
145
|
+
autoDetectedTheme = true;
|
|
146
|
+
autoDarkTheme = darkTheme ?? "dark";
|
|
147
|
+
autoLightTheme = lightTheme ?? "light";
|
|
148
|
+
currentSymbolPresetOverride = symbolPreset;
|
|
149
|
+
currentColorBlindMode = colorBlindMode ?? false;
|
|
150
|
+
const name = getDefaultTheme();
|
|
151
|
+
currentThemeName = name;
|
|
152
|
+
return name;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Initialize the active theme synchronously before the first terminal paint. */
|
|
156
|
+
export function initThemeSync(
|
|
157
|
+
symbolPreset?: SymbolPreset,
|
|
158
|
+
colorBlindMode?: boolean,
|
|
159
|
+
darkTheme?: string,
|
|
160
|
+
lightTheme?: string,
|
|
161
|
+
): void {
|
|
162
|
+
const name = configureTheme(symbolPreset, colorBlindMode, darkTheme, lightTheme);
|
|
163
|
+
const options: CreateThemeOptions = {
|
|
164
|
+
symbolPresetOverride: currentSymbolPresetOverride,
|
|
165
|
+
colorBlindMode: currentColorBlindMode,
|
|
166
|
+
};
|
|
167
|
+
try {
|
|
168
|
+
assignTheme(loadThemeSync(name, options));
|
|
169
|
+
} catch (error) {
|
|
170
|
+
logger.debug("Theme loading failed, falling back to dark theme", { error: String(error) });
|
|
171
|
+
currentThemeName = "dark";
|
|
172
|
+
assignTheme(loadThemeSync("dark", options));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Ensure the module-local theme is initialized before synchronous component work. */
|
|
177
|
+
export function ensureThemeSync(): void {
|
|
178
|
+
if (typeof theme === "undefined") initThemeSync();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Initialize the default theme only when no earlier prepaint initialized one. */
|
|
182
|
+
export async function ensureTheme(): Promise<void> {
|
|
183
|
+
if (typeof theme !== "undefined") return;
|
|
184
|
+
await initTheme();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export async function initTheme(
|
|
188
|
+
enableWatcher: boolean = false,
|
|
189
|
+
symbolPreset?: SymbolPreset,
|
|
190
|
+
colorBlindMode?: boolean,
|
|
191
|
+
darkTheme?: string,
|
|
192
|
+
lightTheme?: string,
|
|
193
|
+
): Promise<void> {
|
|
194
|
+
const name = configureTheme(symbolPreset, colorBlindMode, darkTheme, lightTheme);
|
|
195
|
+
try {
|
|
196
|
+
assignTheme(await loadTheme(name, getCurrentThemeOptions()));
|
|
197
|
+
if (enableWatcher) {
|
|
198
|
+
await startThemeWatcher();
|
|
199
|
+
startSigwinchListener();
|
|
200
|
+
}
|
|
201
|
+
} catch (err) {
|
|
202
|
+
logger.debug("Theme loading failed, falling back to dark theme", { error: String(err) });
|
|
203
|
+
currentThemeName = "dark";
|
|
204
|
+
assignTheme(await loadTheme("dark", getCurrentThemeOptions()));
|
|
205
|
+
// Don't start watcher for fallback theme
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function setTheme(
|
|
210
|
+
name: string,
|
|
211
|
+
enableWatcher: boolean = false,
|
|
212
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
213
|
+
autoDetectedTheme = false;
|
|
214
|
+
currentThemeName = name;
|
|
215
|
+
const requestId = ++themeLoadRequestId;
|
|
216
|
+
try {
|
|
217
|
+
const loadedTheme = await loadTheme(name, getCurrentThemeOptions());
|
|
218
|
+
if (requestId !== themeLoadRequestId) {
|
|
219
|
+
return { success: false, error: "Theme change superseded by a newer request" };
|
|
220
|
+
}
|
|
221
|
+
assignTheme(loadedTheme);
|
|
222
|
+
if (enableWatcher) {
|
|
223
|
+
await startThemeWatcher();
|
|
224
|
+
}
|
|
225
|
+
notifyThemeChange();
|
|
226
|
+
return { success: true };
|
|
227
|
+
} catch (error) {
|
|
228
|
+
if (requestId !== themeLoadRequestId) {
|
|
229
|
+
return { success: false, error: "Theme change superseded by a newer request" };
|
|
230
|
+
}
|
|
231
|
+
// Theme is invalid - fall back to dark theme
|
|
232
|
+
currentThemeName = "dark";
|
|
233
|
+
assignTheme(await loadTheme("dark", getCurrentThemeOptions()));
|
|
234
|
+
// The active theme just changed to the fallback — bump the epoch so memoized
|
|
235
|
+
// renderers (e.g. ToolExecutionComponent) re-shape with the fallback colors
|
|
236
|
+
// instead of holding the failed theme's stale styling.
|
|
237
|
+
notifyThemeChange();
|
|
238
|
+
// Don't start watcher for fallback theme
|
|
239
|
+
return {
|
|
240
|
+
success: false,
|
|
241
|
+
error: error instanceof Error ? error.message : String(error),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export async function previewTheme(
|
|
247
|
+
name: string,
|
|
248
|
+
event: ThemeChangeEvent = { ephemeral: true },
|
|
249
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
250
|
+
const requestId = ++themeLoadRequestId;
|
|
251
|
+
try {
|
|
252
|
+
const loadedTheme = await loadTheme(name, getCurrentThemeOptions());
|
|
253
|
+
if (requestId !== themeLoadRequestId) {
|
|
254
|
+
return { success: false, error: "Theme preview superseded by a newer request" };
|
|
255
|
+
}
|
|
256
|
+
assignTheme(loadedTheme);
|
|
257
|
+
notifyThemeChange(event);
|
|
258
|
+
return { success: true };
|
|
259
|
+
} catch (error) {
|
|
260
|
+
if (requestId !== themeLoadRequestId) {
|
|
261
|
+
return { success: false, error: "Theme preview superseded by a newer request" };
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
success: false,
|
|
265
|
+
error: error instanceof Error ? error.message : String(error),
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Enable auto-detection mode, switching to the appropriate dark/light theme.
|
|
272
|
+
*/
|
|
273
|
+
export function enableAutoTheme(event: ThemeChangeEvent = {}): void {
|
|
274
|
+
autoDetectedTheme = true;
|
|
275
|
+
reevaluateAutoTheme("enableAutoTheme", event);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Update the theme mappings for auto-detection mode.
|
|
280
|
+
* When a dark/light mapping changes and auto-detection is active, re-evaluate the theme.
|
|
281
|
+
*/
|
|
282
|
+
export function setAutoThemeMapping(mode: "dark" | "light", themeName: string): void {
|
|
283
|
+
if (mode === "dark") autoDarkTheme = themeName;
|
|
284
|
+
else autoLightTheme = themeName;
|
|
285
|
+
reevaluateAutoTheme("setAutoThemeMapping");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Called when the terminal detects a dark/light appearance change.
|
|
290
|
+
* The terminal layer queries OSC 11 (background color) and computes luminance;
|
|
291
|
+
* Mode 2031 notifications trigger re-queries rather than providing the value directly.
|
|
292
|
+
*/
|
|
293
|
+
export function onTerminalAppearanceChange(
|
|
294
|
+
mode: "dark" | "light",
|
|
295
|
+
event: ThemeChangeEvent = { ephemeral: true },
|
|
296
|
+
): void {
|
|
297
|
+
if (terminalReportedAppearance === mode) return;
|
|
298
|
+
terminalReportedAppearance = mode;
|
|
299
|
+
reevaluateAutoTheme("terminal appearance", event);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export function setThemeInstance(themeInstance: Theme): void {
|
|
303
|
+
autoDetectedTheme = false;
|
|
304
|
+
assignTheme(themeInstance);
|
|
305
|
+
currentThemeName = "<in-memory>";
|
|
306
|
+
stopThemeWatcher();
|
|
307
|
+
notifyThemeChange({ ephemeral: true });
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Set the symbol preset override, recreating the theme with the new preset.
|
|
312
|
+
*/
|
|
313
|
+
export async function setSymbolPreset(preset: SymbolPreset): Promise<void> {
|
|
314
|
+
currentSymbolPresetOverride = preset;
|
|
315
|
+
if (!currentThemeName) return;
|
|
316
|
+
|
|
317
|
+
const requestId = ++themeLoadRequestId;
|
|
318
|
+
try {
|
|
319
|
+
const loadedTheme = await loadTheme(currentThemeName, getCurrentThemeOptions());
|
|
320
|
+
if (requestId !== themeLoadRequestId) return;
|
|
321
|
+
assignTheme(loadedTheme);
|
|
322
|
+
} catch {
|
|
323
|
+
if (requestId !== themeLoadRequestId) return;
|
|
324
|
+
// Fall back to dark theme with new preset
|
|
325
|
+
assignTheme(await loadTheme("dark", getCurrentThemeOptions()));
|
|
326
|
+
if (requestId !== themeLoadRequestId) return;
|
|
327
|
+
}
|
|
328
|
+
notifyThemeChange({ ephemeral: true });
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Get the current symbol preset override.
|
|
333
|
+
*/
|
|
334
|
+
export function getSymbolPresetOverride(): SymbolPreset | undefined {
|
|
335
|
+
return currentSymbolPresetOverride;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Set color blind mode, recreating the theme with the new setting.
|
|
340
|
+
* When enabled, uses blue instead of green for diff additions.
|
|
341
|
+
*/
|
|
342
|
+
export async function setColorBlindMode(enabled: boolean): Promise<void> {
|
|
343
|
+
currentColorBlindMode = enabled;
|
|
344
|
+
if (!currentThemeName) return;
|
|
345
|
+
|
|
346
|
+
const requestId = ++themeLoadRequestId;
|
|
347
|
+
try {
|
|
348
|
+
const loadedTheme = await loadTheme(currentThemeName, getCurrentThemeOptions());
|
|
349
|
+
if (requestId !== themeLoadRequestId) return;
|
|
350
|
+
assignTheme(loadedTheme);
|
|
351
|
+
} catch {
|
|
352
|
+
if (requestId !== themeLoadRequestId) return;
|
|
353
|
+
// Fall back to dark theme
|
|
354
|
+
assignTheme(await loadTheme("dark", getCurrentThemeOptions()));
|
|
355
|
+
if (requestId !== themeLoadRequestId) return;
|
|
356
|
+
}
|
|
357
|
+
notifyThemeChange({ ephemeral: true });
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Get the current color blind mode setting.
|
|
362
|
+
*/
|
|
363
|
+
export function getColorBlindMode(): boolean {
|
|
364
|
+
return currentColorBlindMode;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function onThemeChange(callback: (event: ThemeChangeEvent) => void): () => void {
|
|
368
|
+
onThemeChangeCallback = callback;
|
|
369
|
+
return () => {
|
|
370
|
+
if (onThemeChangeCallback === callback) {
|
|
371
|
+
onThemeChangeCallback = undefined;
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Monotonic counter bumped on any theme-affecting change that should invalidate
|
|
378
|
+
* cached renders: theme swaps and reloads (including the invalid-theme dark
|
|
379
|
+
* fallback), theme previews, symbol-preset changes, and color-blind-mode
|
|
380
|
+
* changes — everything that routes through {@link notifyThemeChange}. Consumers
|
|
381
|
+
* key cached renders on it so the next render re-shapes their output.
|
|
382
|
+
*/
|
|
383
|
+
export function getThemeEpoch(): number {
|
|
384
|
+
return themeEpoch;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Bump the theme epoch and notify the registered theme-change listener. */
|
|
388
|
+
function notifyThemeChange(event: ThemeChangeEvent = {}): void {
|
|
389
|
+
themeEpoch++;
|
|
390
|
+
onThemeChangeCallback?.(event);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async function startThemeWatcher(): Promise<void> {
|
|
394
|
+
stopThemeWatcher();
|
|
395
|
+
|
|
396
|
+
// Only watch if it's a custom theme (not built-in)
|
|
397
|
+
if (!currentThemeName || currentThemeName === "dark" || currentThemeName === "light") {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const customThemesDir = getCustomThemesDir();
|
|
402
|
+
const watchedThemeName = currentThemeName;
|
|
403
|
+
const watchedFileName = `${watchedThemeName}.json`;
|
|
404
|
+
const themeFile = path.join(customThemesDir, watchedFileName);
|
|
405
|
+
|
|
406
|
+
// Only watch if the file exists
|
|
407
|
+
if (!fs.existsSync(themeFile)) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const scheduleReload = () => {
|
|
412
|
+
if (themeReloadTimer) {
|
|
413
|
+
clearTimeout(themeReloadTimer);
|
|
414
|
+
}
|
|
415
|
+
themeReloadTimer = setTimeout(() => {
|
|
416
|
+
themeReloadTimer = undefined;
|
|
417
|
+
|
|
418
|
+
// Ignore stale timers after switching themes or stopping the watcher
|
|
419
|
+
if (currentThemeName !== watchedThemeName) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Keep the last successfully loaded theme active if the file is temporarily missing
|
|
424
|
+
if (!fs.existsSync(themeFile)) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
loadTheme(watchedThemeName, getCurrentThemeOptions())
|
|
429
|
+
.then(loadedTheme => {
|
|
430
|
+
assignTheme(loadedTheme);
|
|
431
|
+
notifyThemeChange({ ephemeral: true });
|
|
432
|
+
})
|
|
433
|
+
.catch(() => {
|
|
434
|
+
// Ignore errors (file might be in invalid state while being edited)
|
|
435
|
+
});
|
|
436
|
+
}, 100);
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
try {
|
|
440
|
+
themeWatcher = fs.watch(customThemesDir, (_eventType, filename) => {
|
|
441
|
+
if (currentThemeName !== watchedThemeName) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (!filename) {
|
|
445
|
+
scheduleReload();
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const changedFile = String(filename);
|
|
449
|
+
if (changedFile !== watchedFileName) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
scheduleReload();
|
|
453
|
+
});
|
|
454
|
+
} catch {
|
|
455
|
+
// Ignore errors starting watcher
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Load and apply an already-resolved auto-theme name.
|
|
461
|
+
*/
|
|
462
|
+
function applyResolvedAutoTheme(resolved: string, debugLabel: string, event: ThemeChangeEvent): void {
|
|
463
|
+
if (resolved === currentThemeName) return;
|
|
464
|
+
currentThemeName = resolved;
|
|
465
|
+
const requestId = ++themeLoadRequestId;
|
|
466
|
+
loadTheme(resolved, getCurrentThemeOptions())
|
|
467
|
+
.then(loadedTheme => {
|
|
468
|
+
if (requestId !== themeLoadRequestId) return;
|
|
469
|
+
assignTheme(loadedTheme);
|
|
470
|
+
notifyThemeChange(event);
|
|
471
|
+
})
|
|
472
|
+
.catch(err => {
|
|
473
|
+
if (requestId !== themeLoadRequestId) return;
|
|
474
|
+
logger.debug(`Theme switch on ${debugLabel} failed`, { error: String(err) });
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Shared logic for re-evaluating the auto-detected theme.
|
|
480
|
+
* An explicit appearance is provisional input and does not alter terminal-reported state.
|
|
481
|
+
*/
|
|
482
|
+
function reevaluateAutoTheme(debugLabel: string, event: ThemeChangeEvent = {}, appearance?: "dark" | "light"): void {
|
|
483
|
+
if (!autoDetectedTheme) return;
|
|
484
|
+
const resolved =
|
|
485
|
+
appearance === undefined ? getDefaultTheme() : appearance === "dark" ? autoDarkTheme : autoLightTheme;
|
|
486
|
+
applyResolvedAutoTheme(resolved, debugLabel, event);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function reevaluateAutoThemeForAppearance(debugLabel: string, appearance?: "dark" | "light"): void {
|
|
490
|
+
reevaluateAutoTheme(debugLabel, { ephemeral: true }, appearance);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// ============================================================================
|
|
494
|
+
// macOS Appearance Fallback Observer
|
|
495
|
+
// ============================================================================
|
|
496
|
+
|
|
497
|
+
type MacOSAppearanceReprobeTerminal = Pick<
|
|
498
|
+
Terminal,
|
|
499
|
+
"appearance" | "onAppearanceChange" | "onAppearanceReport" | "onPrivateModeReport" | "refreshAppearance"
|
|
500
|
+
>;
|
|
501
|
+
|
|
502
|
+
const MACOS_APPEARANCE_REPROBE_DELAYS_MS = [25, 50, 100, 250, 500, 1000] as const;
|
|
503
|
+
const MACOS_APPEARANCE_RECONCILE_DELAY_MS = 1100;
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Fall back to native macOS appearance notifications when the terminal
|
|
507
|
+
* explicitly confirms that Mode 2031 notifications are unsupported.
|
|
508
|
+
*
|
|
509
|
+
* Native notifications provisionally repaint from the host appearance and
|
|
510
|
+
* synchronously trigger an OSC 11 probe, followed by a bounded burst of six
|
|
511
|
+
* retries. A changed terminal classification cancels the sequence; otherwise
|
|
512
|
+
* a confirmed terminal classification is restored at the validation deadline.
|
|
513
|
+
*/
|
|
514
|
+
export function startMacOSAppearanceReprobeFallback(terminal: MacOSAppearanceReprobeTerminal): () => void {
|
|
515
|
+
let disposed = false;
|
|
516
|
+
let observerStartAttempted = false;
|
|
517
|
+
let observer: MacAppearanceObserver | undefined;
|
|
518
|
+
let probeGeneration = 0;
|
|
519
|
+
let probeSequenceActive = false;
|
|
520
|
+
let probeBaseline: TerminalAppearance | undefined;
|
|
521
|
+
let probeResponseConfirmed = false;
|
|
522
|
+
const probeTimers = new Set<Timer>();
|
|
523
|
+
let reconciliationTimer: Timer | undefined;
|
|
524
|
+
|
|
525
|
+
const cancelProbeSequence = (): void => {
|
|
526
|
+
probeGeneration++;
|
|
527
|
+
probeSequenceActive = false;
|
|
528
|
+
probeBaseline = undefined;
|
|
529
|
+
probeResponseConfirmed = false;
|
|
530
|
+
if (reconciliationTimer) {
|
|
531
|
+
clearTimeout(reconciliationTimer);
|
|
532
|
+
reconciliationTimer = undefined;
|
|
533
|
+
}
|
|
534
|
+
for (const timer of probeTimers) {
|
|
535
|
+
clearTimeout(timer);
|
|
536
|
+
}
|
|
537
|
+
probeTimers.clear();
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
const scheduleProbeSequence = (): void => {
|
|
541
|
+
cancelProbeSequence();
|
|
542
|
+
if (disposed || !autoDetectedTheme) return;
|
|
543
|
+
|
|
544
|
+
probeSequenceActive = true;
|
|
545
|
+
probeBaseline = terminal.appearance;
|
|
546
|
+
probeResponseConfirmed = false;
|
|
547
|
+
const generation = probeGeneration;
|
|
548
|
+
terminal.refreshAppearance?.();
|
|
549
|
+
if (disposed || generation !== probeGeneration || !autoDetectedTheme) return;
|
|
550
|
+
for (const delay of MACOS_APPEARANCE_REPROBE_DELAYS_MS) {
|
|
551
|
+
const timer = setTimeout(() => {
|
|
552
|
+
probeTimers.delete(timer);
|
|
553
|
+
if (disposed || generation !== probeGeneration) return;
|
|
554
|
+
if (!autoDetectedTheme) {
|
|
555
|
+
cancelProbeSequence();
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
terminal.refreshAppearance?.();
|
|
559
|
+
}, delay);
|
|
560
|
+
timer.unref?.();
|
|
561
|
+
probeTimers.add(timer);
|
|
562
|
+
}
|
|
563
|
+
reconciliationTimer = setTimeout(() => {
|
|
564
|
+
reconciliationTimer = undefined;
|
|
565
|
+
if (disposed || generation !== probeGeneration) return;
|
|
566
|
+
const appearance = probeResponseConfirmed ? terminal.appearance : undefined;
|
|
567
|
+
cancelProbeSequence();
|
|
568
|
+
if (!autoDetectedTheme || !appearance) return;
|
|
569
|
+
reevaluateAutoThemeForAppearance("macOS appearance reconciliation", appearance);
|
|
570
|
+
}, MACOS_APPEARANCE_RECONCILE_DELAY_MS);
|
|
571
|
+
reconciliationTimer.unref?.();
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
const unsubscribeAppearanceReport = terminal.onAppearanceReport?.(() => {
|
|
575
|
+
if (disposed || !probeSequenceActive) return;
|
|
576
|
+
probeResponseConfirmed = true;
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
terminal.onAppearanceChange(appearance => {
|
|
580
|
+
if (disposed || !probeSequenceActive || appearance === probeBaseline) return;
|
|
581
|
+
cancelProbeSequence();
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
terminal.onPrivateModeReport?.((mode, supported, confirmed) => {
|
|
585
|
+
if (disposed || observerStartAttempted || mode !== 2031 || supported || confirmed !== true) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
observerStartAttempted = true;
|
|
590
|
+
try {
|
|
591
|
+
observer = MacAppearanceObserver.start((err, appearance) => {
|
|
592
|
+
if (disposed) return;
|
|
593
|
+
if (err) {
|
|
594
|
+
cancelProbeSequence();
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
if (appearance === "dark" || appearance === "light") {
|
|
598
|
+
reevaluateAutoThemeForAppearance("macOS provisional appearance", appearance);
|
|
599
|
+
}
|
|
600
|
+
scheduleProbeSequence();
|
|
601
|
+
});
|
|
602
|
+
} catch (err) {
|
|
603
|
+
logger.warn("Failed to start macOS appearance reprobe observer", { err });
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
return () => {
|
|
608
|
+
if (disposed) return;
|
|
609
|
+
disposed = true;
|
|
610
|
+
cancelProbeSequence();
|
|
611
|
+
if (unsubscribeAppearanceReport) unsubscribeAppearanceReport();
|
|
612
|
+
const activeObserver = observer;
|
|
613
|
+
observer = undefined;
|
|
614
|
+
if (!activeObserver) return;
|
|
615
|
+
try {
|
|
616
|
+
activeObserver.stop();
|
|
617
|
+
} catch (err) {
|
|
618
|
+
logger.debug("Failed to stop macOS appearance reprobe observer", { err });
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
var macObserver: { stop(): void } | undefined;
|
|
624
|
+
|
|
625
|
+
function startMacAppearanceObserver(): void {
|
|
626
|
+
stopMacAppearanceObserver();
|
|
627
|
+
if (!shouldUseMacOSAppearanceFallback()) return;
|
|
628
|
+
try {
|
|
629
|
+
macOSReportedAppearance = detectMacOSAppearance() ?? undefined;
|
|
630
|
+
macObserver = MacAppearanceObserver.start((err, appearance) => {
|
|
631
|
+
if (!err && (appearance === "dark" || appearance === "light")) {
|
|
632
|
+
macOSReportedAppearance = appearance;
|
|
633
|
+
reevaluateAutoThemeForAppearance("macOS fallback");
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
} catch (err) {
|
|
637
|
+
logger.warn("Failed to start macOS appearance observer", { err });
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function stopMacAppearanceObserver(): void {
|
|
642
|
+
if (macObserver) {
|
|
643
|
+
macObserver.stop();
|
|
644
|
+
macObserver = undefined;
|
|
645
|
+
}
|
|
646
|
+
macOSReportedAppearance = undefined;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// ============================================================================
|
|
650
|
+
// SIGWINCH Listener
|
|
651
|
+
// ============================================================================
|
|
652
|
+
|
|
653
|
+
/** Re-check appearance on SIGWINCH and switch dark/light when using auto-detected theme. */
|
|
654
|
+
function startSigwinchListener(): void {
|
|
655
|
+
stopSigwinchListener();
|
|
656
|
+
sigwinchHandler = () => {
|
|
657
|
+
reevaluateAutoThemeForAppearance("SIGWINCH");
|
|
658
|
+
};
|
|
659
|
+
process.on("SIGWINCH", sigwinchHandler);
|
|
660
|
+
startMacAppearanceObserver();
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function stopSigwinchListener(): void {
|
|
664
|
+
if (sigwinchHandler) {
|
|
665
|
+
process.removeListener("SIGWINCH", sigwinchHandler);
|
|
666
|
+
sigwinchHandler = undefined;
|
|
667
|
+
}
|
|
668
|
+
stopMacAppearanceObserver();
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
export function stopThemeWatcher(): void {
|
|
672
|
+
if (themeReloadTimer) {
|
|
673
|
+
clearTimeout(themeReloadTimer);
|
|
674
|
+
themeReloadTimer = undefined;
|
|
675
|
+
}
|
|
676
|
+
if (themeWatcher) {
|
|
677
|
+
themeWatcher.close();
|
|
678
|
+
themeWatcher = undefined;
|
|
679
|
+
}
|
|
680
|
+
stopSigwinchListener();
|
|
681
|
+
terminalReportedAppearance = undefined;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// ============================================================================
|
|
685
|
+
// HTML Export Helpers
|
|
686
|
+
// ============================================================================
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Classify a parsed theme JSON as light/dark by the perceived luminance of its
|
|
690
|
+
* status-line background. Mirrors {@link Theme.isLight} so the synchronous
|
|
691
|
+
* helpers below stay in lockstep with the runtime classifier — see the comment
|
|
692
|
+
* on `Theme.statusLineLuminance` for why `statusLineBg` is the source of truth
|
|
693
|
+
* (themes like `porcelain` style a dark chat bubble on an otherwise-light
|
|
694
|
+
* theme, so `userMessageBg` is unreliable).
|
|
695
|
+
*/
|
|
696
|
+
function isLightThemeJson(themeJson: ThemeJson): boolean {
|
|
697
|
+
try {
|
|
698
|
+
const resolved = resolveVarRefs(themeJson.colors.statusLineBg, themeJson.vars ?? {});
|
|
699
|
+
const luminance = colorLuma(resolved);
|
|
700
|
+
return luminance !== undefined && luminance > 0.5;
|
|
701
|
+
} catch {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function getHtmlDefaultTextForSurface(surface: string | number | undefined): string {
|
|
707
|
+
const luminance = surface === undefined ? undefined : colorLuma(surface);
|
|
708
|
+
return luminance !== undefined && luminance > 0.5 ? "#000000" : "#e5e5e7";
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function resolveThemeExportColors(themeJson: ThemeJson): {
|
|
712
|
+
pageBg?: string;
|
|
713
|
+
cardBg?: string;
|
|
714
|
+
infoBg?: string;
|
|
715
|
+
} {
|
|
716
|
+
const exportSection = themeJson.export;
|
|
717
|
+
if (!exportSection) return {};
|
|
718
|
+
|
|
719
|
+
const vars = themeJson.vars ?? {};
|
|
720
|
+
const resolve = (value: string | number | undefined): string | undefined => {
|
|
721
|
+
if (value === undefined) return undefined;
|
|
722
|
+
if (typeof value === "number") return ansi256ToHex(value);
|
|
723
|
+
if (value === "" || value.startsWith("#")) return value;
|
|
724
|
+
const varName = value.startsWith("$") ? value.slice(1) : value;
|
|
725
|
+
if (varName in vars) {
|
|
726
|
+
const resolved = resolveVarRefs(varName, vars);
|
|
727
|
+
return typeof resolved === "number" ? ansi256ToHex(resolved) : resolved;
|
|
728
|
+
}
|
|
729
|
+
return value;
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
return {
|
|
733
|
+
pageBg: resolve(exportSection.pageBg),
|
|
734
|
+
cardBg: resolve(exportSection.cardBg),
|
|
735
|
+
infoBg: resolve(exportSection.infoBg),
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Get resolved theme colors as CSS-compatible hex strings.
|
|
741
|
+
* Used by HTML export to generate CSS custom properties.
|
|
742
|
+
*/
|
|
743
|
+
export async function getResolvedThemeColors(themeName?: string): Promise<Record<string, string>> {
|
|
744
|
+
const name = themeName ?? getDefaultTheme();
|
|
745
|
+
const themeJson = await loadThemeJson(name);
|
|
746
|
+
const exportColors = resolveThemeExportColors(themeJson);
|
|
747
|
+
const resolved = resolveThemeColors(themeJson.colors, themeJson.vars);
|
|
748
|
+
|
|
749
|
+
// Empty foreground tokens use the terminal default color. In HTML export,
|
|
750
|
+
// that default must contrast the export surface, not the TUI status line:
|
|
751
|
+
// custom light themes can still export dark transcript cards when they omit
|
|
752
|
+
// `export`, because generateThemeVars derives those cards from userMessageBg.
|
|
753
|
+
const defaultText = getHtmlDefaultTextForSurface(
|
|
754
|
+
exportColors.cardBg ?? exportColors.pageBg ?? resolved.userMessageBg,
|
|
755
|
+
);
|
|
756
|
+
|
|
757
|
+
const cssColors: Record<string, string> = {};
|
|
758
|
+
for (const [key, value] of Object.entries(resolved)) {
|
|
759
|
+
if (typeof value === "number") {
|
|
760
|
+
cssColors[key] = ansi256ToHex(value);
|
|
761
|
+
} else if (value === "") {
|
|
762
|
+
// Empty means default terminal color - use sensible fallback for HTML
|
|
763
|
+
cssColors[key] = defaultText;
|
|
764
|
+
} else {
|
|
765
|
+
cssColors[key] = value;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return cssColors;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Check if a theme is a "light" theme by analyzing its status-line background
|
|
773
|
+
* luminance. Loads theme JSON synchronously (built-in or custom file on disk)
|
|
774
|
+
* for callers in synchronous flows (settings migration, setup wizard).
|
|
775
|
+
*/
|
|
776
|
+
export function isLightTheme(themeName?: string): boolean {
|
|
777
|
+
const name = themeName ?? "dark";
|
|
778
|
+
const builtinThemes = getBuiltinThemes();
|
|
779
|
+
let themeJson: ThemeJson | undefined;
|
|
780
|
+
if (name in builtinThemes) {
|
|
781
|
+
themeJson = builtinThemes[name];
|
|
782
|
+
} else {
|
|
783
|
+
try {
|
|
784
|
+
const customPath = path.join(getCustomThemesDir(), `${name}.json`);
|
|
785
|
+
const content = fs.readFileSync(customPath, "utf-8");
|
|
786
|
+
themeJson = JSON.parse(content) as ThemeJson;
|
|
787
|
+
} catch {
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
return isLightThemeJson(themeJson);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* Get explicit export colors from theme JSON, if specified.
|
|
796
|
+
* Returns undefined for each color that isn't explicitly set.
|
|
797
|
+
*/
|
|
798
|
+
export async function getThemeExportColors(themeName?: string): Promise<{
|
|
799
|
+
pageBg?: string;
|
|
800
|
+
cardBg?: string;
|
|
801
|
+
infoBg?: string;
|
|
802
|
+
}> {
|
|
803
|
+
const name = themeName ?? getDefaultTheme();
|
|
804
|
+
try {
|
|
805
|
+
const themeJson = await loadThemeJson(name);
|
|
806
|
+
return resolveThemeExportColors(themeJson);
|
|
807
|
+
} catch {
|
|
808
|
+
return {};
|
|
809
|
+
}
|
|
810
|
+
}
|