@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,266 @@
|
|
|
1
|
+
import { diffWords } from "@oh-my-pi/pi-natives";
|
|
2
|
+
import { DEFAULT_TAB_WIDTH, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import { theme as activeTheme, getLanguageFromPath, highlightCode, type Theme } from "../theme/index";
|
|
4
|
+
import { type CodeFrameMarker, formatCodeFrameLine, replaceTabs } from "../render/render-utils";
|
|
5
|
+
/** SGR dim on / normal intensity — additive, preserves fg/bg colors. */
|
|
6
|
+
const DIM = "\x1b[2m";
|
|
7
|
+
const DIM_OFF = "\x1b[22m";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Visualize leading whitespace (indentation) with dim glyphs.
|
|
11
|
+
* Tabs become ` → ` and spaces become `·`. Only affects whitespace
|
|
12
|
+
* before the first non-whitespace character; remaining tabs in code
|
|
13
|
+
* content are replaced with spaces (like replaceTabs).
|
|
14
|
+
*/
|
|
15
|
+
function visualizeIndent(text: string): string {
|
|
16
|
+
const match = text.match(/^([ \t]+)/);
|
|
17
|
+
if (!match) return replaceTabs(text);
|
|
18
|
+
const indent = match[1];
|
|
19
|
+
const rest = text.slice(indent.length);
|
|
20
|
+
const tabWidth = DEFAULT_TAB_WIDTH;
|
|
21
|
+
const leftPadding = Math.floor(tabWidth / 2);
|
|
22
|
+
const rightPadding = Math.max(0, tabWidth - leftPadding - 1);
|
|
23
|
+
const tabMarker = `${DIM}${" ".repeat(leftPadding)}→${" ".repeat(rightPadding)}${DIM_OFF}`;
|
|
24
|
+
let visible = "";
|
|
25
|
+
for (const ch of indent) {
|
|
26
|
+
if (ch === "\t") {
|
|
27
|
+
visible += tabMarker;
|
|
28
|
+
} else {
|
|
29
|
+
visible += `${DIM}·${DIM_OFF}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return `${visible}${replaceTabs(rest)}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Parse diff line to extract prefix, line number, and content.
|
|
37
|
+
* Supported formats: "+123|content" (canonical) and "+123 content" (legacy).
|
|
38
|
+
*/
|
|
39
|
+
function parseDiffLine(line: string): { prefix: CodeFrameMarker; lineNum: string; content: string } | null {
|
|
40
|
+
const canonical = line.match(/^([+-\s])(\s*\d+)\|(.*)$/);
|
|
41
|
+
if (canonical) {
|
|
42
|
+
return { prefix: canonical[1] as CodeFrameMarker, lineNum: canonical[2] ?? "", content: canonical[3] ?? "" };
|
|
43
|
+
}
|
|
44
|
+
const legacy = line.match(/^([+-\s])(?:(\s*\d+)\s)?(.*)$/);
|
|
45
|
+
if (!legacy) return null;
|
|
46
|
+
return { prefix: legacy[1] as CodeFrameMarker, lineNum: legacy[2] ?? "", content: legacy[3] ?? "" };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Compute word-level diff and render with inverse on changed parts.
|
|
51
|
+
* Uses diffWords which groups whitespace with adjacent words for cleaner highlighting.
|
|
52
|
+
* Strips leading whitespace from inverse to avoid highlighting indentation.
|
|
53
|
+
*/
|
|
54
|
+
function renderIntraLineDiff(
|
|
55
|
+
oldContent: string,
|
|
56
|
+
newContent: string,
|
|
57
|
+
renderTheme: Theme,
|
|
58
|
+
): { removedLine: string; addedLine: string } {
|
|
59
|
+
const wordDiff = diffWords(oldContent, newContent);
|
|
60
|
+
|
|
61
|
+
let removedLine = "";
|
|
62
|
+
let addedLine = "";
|
|
63
|
+
let isFirstRemoved = true;
|
|
64
|
+
let isFirstAdded = true;
|
|
65
|
+
|
|
66
|
+
for (const part of wordDiff) {
|
|
67
|
+
if (part.removed) {
|
|
68
|
+
let value = part.value;
|
|
69
|
+
// Strip leading whitespace from the first removed part
|
|
70
|
+
if (isFirstRemoved) {
|
|
71
|
+
const leadingWs = value.match(/^(\s*)/)?.[1] || "";
|
|
72
|
+
value = value.slice(leadingWs.length);
|
|
73
|
+
removedLine += leadingWs;
|
|
74
|
+
isFirstRemoved = false;
|
|
75
|
+
}
|
|
76
|
+
if (value) {
|
|
77
|
+
removedLine += renderTheme.inverse(value);
|
|
78
|
+
}
|
|
79
|
+
} else if (part.added) {
|
|
80
|
+
let value = part.value;
|
|
81
|
+
// Strip leading whitespace from the first added part
|
|
82
|
+
if (isFirstAdded) {
|
|
83
|
+
const leadingWs = value.match(/^(\s*)/)?.[1] || "";
|
|
84
|
+
value = value.slice(leadingWs.length);
|
|
85
|
+
addedLine += leadingWs;
|
|
86
|
+
isFirstAdded = false;
|
|
87
|
+
}
|
|
88
|
+
if (value) {
|
|
89
|
+
addedLine += renderTheme.inverse(value);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
removedLine += part.value;
|
|
93
|
+
addedLine += part.value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { removedLine, addedLine };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface RenderDiffOptions {
|
|
101
|
+
/** File path used to resolve indentation (.editorconfig + defaults) */
|
|
102
|
+
filePath?: string;
|
|
103
|
+
/** Theme used for diff colors and syntax highlighting; defaults to the active TUI theme. */
|
|
104
|
+
theme?: Theme;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Render a diff string with colored lines and intra-line change highlighting.
|
|
109
|
+
* - Context lines: dim/gray
|
|
110
|
+
* - Removed lines: red, with inverse on changed tokens
|
|
111
|
+
* - Added lines: green, with inverse on changed tokens
|
|
112
|
+
*/
|
|
113
|
+
export function renderDiff(diffText: string, options: RenderDiffOptions = {}): string {
|
|
114
|
+
const renderTheme = options.theme ?? activeTheme;
|
|
115
|
+
const lines = sanitizeText(diffText).split("\n");
|
|
116
|
+
const result: string[] = [];
|
|
117
|
+
const parsedLines = lines.map(parseDiffLine);
|
|
118
|
+
// Reserve 3 gutter digits: a streaming preview re-renders this diff as it
|
|
119
|
+
// grows, and a width derived purely from the current max line number widens
|
|
120
|
+
// at the 100-line crossing — re-padding every already-rendered row, which
|
|
121
|
+
// breaks the transcript's append-only commit detection and forces a full
|
|
122
|
+
// recommit of the block into native scrollback. A constant gutter through
|
|
123
|
+
// 999 lines keeps streamed rows byte-identical to the final result render.
|
|
124
|
+
const lineNumberWidth = parsedLines.reduce((width, parsed) => {
|
|
125
|
+
const lineNumber = parsed?.lineNum.trim() ?? "";
|
|
126
|
+
return Math.max(width, lineNumber.length);
|
|
127
|
+
}, 3);
|
|
128
|
+
|
|
129
|
+
// Batch-highlight context (unedited) lines so consecutive lines tokenize
|
|
130
|
+
// with full multi-line context. Highlighting is a no-op when no language
|
|
131
|
+
// can be detected from the file path.
|
|
132
|
+
const contextHighlights = highlightContextLines(parsedLines, options.filePath, renderTheme);
|
|
133
|
+
// Track the line number rendered on the previous emitted line so we can
|
|
134
|
+
// blank out duplicate gutters. Two cases trigger this:
|
|
135
|
+
// 1. Single-line replacement (`-N` followed by `+N`) — the `+N` repeats `N`.
|
|
136
|
+
// 2. Insertion followed by context (`+N` then ` N` if producer used oldLine).
|
|
137
|
+
let prevLineNum = "";
|
|
138
|
+
|
|
139
|
+
const formatLine = (prefix: CodeFrameMarker, lineNum: string, content: string): string => {
|
|
140
|
+
if (lineNum.trim().length === 0) {
|
|
141
|
+
prevLineNum = "";
|
|
142
|
+
return `${prefix}${content}`;
|
|
143
|
+
}
|
|
144
|
+
const trimmed = lineNum.trim();
|
|
145
|
+
const displayNum = trimmed === prevLineNum ? "" : trimmed;
|
|
146
|
+
prevLineNum = trimmed;
|
|
147
|
+
return formatCodeFrameLine(prefix, displayNum, content, lineNumberWidth);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
let i = 0;
|
|
151
|
+
while (i < lines.length) {
|
|
152
|
+
const line = lines[i];
|
|
153
|
+
const parsed = parseDiffLine(line);
|
|
154
|
+
|
|
155
|
+
if (!parsed) {
|
|
156
|
+
prevLineNum = "";
|
|
157
|
+
// Blank gap rows (and legacy "..." markers from older transcripts)
|
|
158
|
+
// mark non-contiguous diff regions; display them as a single dim
|
|
159
|
+
// unicode ellipsis.
|
|
160
|
+
const trimmed = line.trim();
|
|
161
|
+
const isGapRow = trimmed.length === 0 || trimmed === "..." || trimmed === "…";
|
|
162
|
+
result.push(renderTheme.fg("toolDiffContext", isGapRow ? "…" : replaceTabs(line)));
|
|
163
|
+
i++;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (parsed.prefix === "-") {
|
|
168
|
+
const removedLines: { lineNum: string; content: string }[] = [];
|
|
169
|
+
while (i < lines.length) {
|
|
170
|
+
const p = parseDiffLine(lines[i]);
|
|
171
|
+
if (p?.prefix !== "-") break;
|
|
172
|
+
removedLines.push({ lineNum: p.lineNum, content: p.content });
|
|
173
|
+
i++;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const addedLines: { lineNum: string; content: string }[] = [];
|
|
177
|
+
while (i < lines.length) {
|
|
178
|
+
const p = parseDiffLine(lines[i]);
|
|
179
|
+
if (p?.prefix !== "+") break;
|
|
180
|
+
addedLines.push({ lineNum: p.lineNum, content: p.content });
|
|
181
|
+
i++;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (removedLines.length === 1 && addedLines.length === 1) {
|
|
185
|
+
const removed = removedLines[0];
|
|
186
|
+
const added = addedLines[0];
|
|
187
|
+
|
|
188
|
+
const { removedLine, addedLine } = renderIntraLineDiff(
|
|
189
|
+
replaceTabs(removed.content),
|
|
190
|
+
replaceTabs(added.content),
|
|
191
|
+
renderTheme,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
result.push(
|
|
195
|
+
renderTheme.fg("toolDiffRemoved", formatLine("-", removed.lineNum, visualizeIndent(removedLine))),
|
|
196
|
+
);
|
|
197
|
+
result.push(renderTheme.fg("toolDiffAdded", formatLine("+", added.lineNum, visualizeIndent(addedLine))));
|
|
198
|
+
} else {
|
|
199
|
+
for (const removed of removedLines) {
|
|
200
|
+
result.push(
|
|
201
|
+
renderTheme.fg("toolDiffRemoved", formatLine("-", removed.lineNum, visualizeIndent(removed.content))),
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
for (const added of addedLines) {
|
|
205
|
+
result.push(
|
|
206
|
+
renderTheme.fg("toolDiffAdded", formatLine("+", added.lineNum, visualizeIndent(added.content))),
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} else if (parsed.prefix === "+") {
|
|
211
|
+
result.push(renderTheme.fg("toolDiffAdded", formatLine("+", parsed.lineNum, visualizeIndent(parsed.content))));
|
|
212
|
+
i++;
|
|
213
|
+
} else {
|
|
214
|
+
const highlighted = contextHighlights.get(i);
|
|
215
|
+
const content = highlighted !== undefined ? replaceTabs(highlighted) : visualizeIndent(parsed.content);
|
|
216
|
+
result.push(renderTheme.fg("toolDiffContext", formatLine(" ", parsed.lineNum, content)));
|
|
217
|
+
i++;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return result.join("\n");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Batch-highlight runs of consecutive context lines.
|
|
226
|
+
* Returns a map keyed by index in `parsedLines` to the highlighted content
|
|
227
|
+
* for that line. Lines whose language is unknown are not added to the map,
|
|
228
|
+
* letting callers fall back to the existing rendering path.
|
|
229
|
+
*/
|
|
230
|
+
function highlightContextLines(
|
|
231
|
+
parsedLines: Array<{ prefix: CodeFrameMarker; lineNum: string; content: string } | null>,
|
|
232
|
+
filePath: string | undefined,
|
|
233
|
+
renderTheme: Theme,
|
|
234
|
+
): Map<number, string> {
|
|
235
|
+
const map = new Map<number, string>();
|
|
236
|
+
const lang = filePath ? getLanguageFromPath(filePath) : undefined;
|
|
237
|
+
if (!lang) return map;
|
|
238
|
+
|
|
239
|
+
let runIndices: number[] = [];
|
|
240
|
+
let runContents: string[] = [];
|
|
241
|
+
const flush = () => {
|
|
242
|
+
if (runContents.length === 0) return;
|
|
243
|
+
const highlighted = highlightCode(runContents.join("\n"), lang, renderTheme);
|
|
244
|
+
for (let k = 0; k < runIndices.length; k++) {
|
|
245
|
+
map.set(runIndices[k], highlighted[k] ?? runContents[k]);
|
|
246
|
+
}
|
|
247
|
+
runIndices = [];
|
|
248
|
+
runContents = [];
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
for (let j = 0; j < parsedLines.length; j++) {
|
|
252
|
+
const p = parsedLines[j];
|
|
253
|
+
// Collapse markers ("...") are emitted as context lines but are not real
|
|
254
|
+
// code; highlighting them produces nonsense (e.g. "..." → spread operator)
|
|
255
|
+
// and would also stitch together unrelated context blocks across the gap.
|
|
256
|
+
const isCollapseMarker = p?.prefix === " " && (p.content === "..." || p.content === "…");
|
|
257
|
+
if (p && p.prefix === " " && !isCollapseMarker) {
|
|
258
|
+
runIndices.push(j);
|
|
259
|
+
runContents.push(p.content);
|
|
260
|
+
} else {
|
|
261
|
+
flush();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
flush();
|
|
265
|
+
return map;
|
|
266
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Component } from "../tui";
|
|
2
|
+
import { fgOrPlain, theme } from "../theme/index";
|
|
3
|
+
/**
|
|
4
|
+
* Dynamic border component that adjusts to viewport width.
|
|
5
|
+
*
|
|
6
|
+
* Note: the module-level `theme` may be `undefined` — when loaded through jiti
|
|
7
|
+
* (separate module cache) or from a second `src` module graph in npm-package
|
|
8
|
+
* installs, where the host bundle assigns `theme` but this copy never sees it
|
|
9
|
+
* (issue #5366). Both the default color and `render()` degrade to plain,
|
|
10
|
+
* unstyled output instead of crashing the TUI.
|
|
11
|
+
*/
|
|
12
|
+
export class DynamicBorder implements Component {
|
|
13
|
+
#color: (str: string) => string;
|
|
14
|
+
#cachedWidth = -1;
|
|
15
|
+
#cachedLines: string[] | undefined;
|
|
16
|
+
|
|
17
|
+
constructor(color: (str: string) => string = str => fgOrPlain("border", str)) {
|
|
18
|
+
this.#color = color;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
invalidate(): void {
|
|
22
|
+
this.#cachedWidth = -1;
|
|
23
|
+
this.#cachedLines = undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
render(width: number): readonly string[] {
|
|
27
|
+
if (this.#cachedLines && this.#cachedWidth === width) {
|
|
28
|
+
return this.#cachedLines;
|
|
29
|
+
}
|
|
30
|
+
const horizontal = typeof theme === "undefined" ? "─" : theme.boxRound.horizontal;
|
|
31
|
+
const lines = [this.#color(horizontal.repeat(Math.max(1, width)))];
|
|
32
|
+
this.#cachedWidth = width;
|
|
33
|
+
this.#cachedLines = lines;
|
|
34
|
+
return lines;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import { replaceTabs, truncateToWidth, wrapTextWithAnsi } from "../utils";
|
|
3
|
+
import { sanitizeText } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { expandKeyHint, shortenEmbeddedPaths, TRUNCATE_LENGTHS } from "../render/render-utils";
|
|
5
|
+
import { theme } from "../theme/index";
|
|
6
|
+
/** Indent for every row after the first, so continuations hang under the prefix. */
|
|
7
|
+
const CONTINUATION_INDENT = " ";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Plain, bounded error text to sanitize before applying terminal styles.
|
|
11
|
+
* Match embedded home paths (including quoted names with spaces), not URL
|
|
12
|
+
* paths or home-prefix siblings. Callers retain the original error for logs.
|
|
13
|
+
*/
|
|
14
|
+
export function sanitizeErrorLine(
|
|
15
|
+
error: unknown,
|
|
16
|
+
maxWidth: number = TRUNCATE_LENGTHS.LINE,
|
|
17
|
+
homeDir: string = os.homedir(),
|
|
18
|
+
): string {
|
|
19
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
20
|
+
const text = shortenEmbeddedPaths(replaceTabs(sanitizeText(message.replace(/\r\n?/g, "\n"))), homeDir, true);
|
|
21
|
+
return truncateToWidth(text.replace(/\s+/g, " ").trim() || "Unknown error", Math.max(0, maxWidth));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Format a provider error into at most `maxRows` wrapped rows for a
|
|
26
|
+
* `WidthAwareText` of `contentWidth` cells. Lines wrap to the render width
|
|
27
|
+
* instead of being cut at a fixed column, so a long single-line body — a raw
|
|
28
|
+
* 400 JSON envelope, a `raw-http-request=` dump path — stays readable. Blank
|
|
29
|
+
* lines are dropped. When rows are cut, a dim `… +N more lines (<key> to
|
|
30
|
+
* expand)` row follows; pass `Infinity` to keep every row. `styleLine` colors
|
|
31
|
+
* logical line `index` and supplies line 0's prefix (`Error: `, the banner
|
|
32
|
+
* glyph). Shared by the inline transcript error and the pinned banner.
|
|
33
|
+
*/
|
|
34
|
+
export function formatErrorBlock(
|
|
35
|
+
message: string,
|
|
36
|
+
contentWidth: number,
|
|
37
|
+
maxRows: number,
|
|
38
|
+
styleLine: (line: string, index: number) => string,
|
|
39
|
+
): string {
|
|
40
|
+
const lines = replaceTabs(message)
|
|
41
|
+
.split("\n")
|
|
42
|
+
.map(line => line.trim())
|
|
43
|
+
.filter(line => line.length > 0);
|
|
44
|
+
if (lines.length === 0) lines.push("Unknown error");
|
|
45
|
+
const wrapWidth = Math.max(1, contentWidth - CONTINUATION_INDENT.length);
|
|
46
|
+
const rows: string[] = [];
|
|
47
|
+
for (let index = 0; index < lines.length; index++) {
|
|
48
|
+
for (const row of wrapTextWithAnsi(styleLine(lines[index]!, index), wrapWidth)) {
|
|
49
|
+
rows.push(rows.length === 0 ? row : `${CONTINUATION_INDENT}${row}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (rows.length > maxRows) {
|
|
53
|
+
const hidden = rows.length - maxRows;
|
|
54
|
+
rows.length = maxRows;
|
|
55
|
+
rows.push(
|
|
56
|
+
theme.fg(
|
|
57
|
+
"dim",
|
|
58
|
+
`${CONTINUATION_INDENT}… +${hidden} more line${hidden === 1 ? "" : "s"} (${expandKeyHint()} to expand)`,
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return rows.join("\n");
|
|
63
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FormFieldTheme } from "../components/form";
|
|
2
|
+
import { theme } from "../theme/theme";
|
|
3
|
+
|
|
4
|
+
/** Shared accent form-field theme used by overlay dialogs. */
|
|
5
|
+
export const formTheme: FormFieldTheme = {
|
|
6
|
+
label: text => theme.bold(theme.fg("accent", text)),
|
|
7
|
+
description: text => theme.fg("muted", text),
|
|
8
|
+
error: text => theme.fg("error", text),
|
|
9
|
+
hint: text => theme.fg("dim", text),
|
|
10
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { renderProgressBar } from "../components/progress-bar";
|
|
2
|
+
import { shimmerText } from "../theme/shimmer";
|
|
3
|
+
import { theme as currentTheme, type Theme } from "../theme/theme";
|
|
4
|
+
|
|
5
|
+
/** Title-case a provider id for display (`openai-codex` → `Openai Codex`). */
|
|
6
|
+
export function formatProviderName(provider: string): string {
|
|
7
|
+
return provider
|
|
8
|
+
.split(/[-_]/g)
|
|
9
|
+
.map(part => (part ? part[0].toUpperCase() + part.slice(1) : ""))
|
|
10
|
+
.join(" ");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Format a millisecond duration as a coarse-grained human label. */
|
|
14
|
+
export function formatCoarseDuration(ms: number): string {
|
|
15
|
+
const seconds = Math.max(0, Math.round(ms / 1000));
|
|
16
|
+
if (seconds < 60) return `${seconds}s`;
|
|
17
|
+
const minutes = Math.round(seconds / 60);
|
|
18
|
+
if (minutes < 60) return `${minutes}m`;
|
|
19
|
+
const hours = Math.round(minutes / 60);
|
|
20
|
+
if (hours < 48) return `${hours}h`;
|
|
21
|
+
const days = Math.round(hours / 24);
|
|
22
|
+
return `${days}d`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type ProgressBarTheme = Pick<Theme, "bold" | "fg" | "getFgAnsi">;
|
|
26
|
+
|
|
27
|
+
const unstyledProgressBarTheme: ProgressBarTheme = {
|
|
28
|
+
fg(_color, text) {
|
|
29
|
+
return text;
|
|
30
|
+
},
|
|
31
|
+
bold(text) {
|
|
32
|
+
return text;
|
|
33
|
+
},
|
|
34
|
+
getFgAnsi() {
|
|
35
|
+
return "";
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function resolveProgressBarTheme(uiTheme: ProgressBarTheme | undefined): ProgressBarTheme {
|
|
40
|
+
return uiTheme ?? currentTheme ?? unstyledProgressBarTheme;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Render an ASCII progress bar with a trailing percent label.
|
|
45
|
+
* `fraction` is clamped to `[0, 1]`. `undefined` renders a dotted placeholder.
|
|
46
|
+
*/
|
|
47
|
+
export function renderAsciiBar(fraction: number | undefined, width = 24, uiTheme?: ProgressBarTheme): string {
|
|
48
|
+
const progressBarTheme = resolveProgressBarTheme(uiTheme);
|
|
49
|
+
const shimmer = (text: string): string => shimmerText(text, progressBarTheme);
|
|
50
|
+
if (fraction === undefined) {
|
|
51
|
+
return renderProgressBar(undefined, width, {
|
|
52
|
+
prefix: "[",
|
|
53
|
+
suffix: "]",
|
|
54
|
+
style: { filled: "·", empty: "·", indeterminate: "·", styleBar: shimmer },
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return renderProgressBar(fraction, width, {
|
|
58
|
+
min: 0,
|
|
59
|
+
max: 1,
|
|
60
|
+
prefix: "[",
|
|
61
|
+
suffix: "]",
|
|
62
|
+
showPercentage: true,
|
|
63
|
+
formatPercentage: value => `${Math.round(value * 100)}%`,
|
|
64
|
+
style: { filled: "█", empty: "░", styleBar: shimmer },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Shared chat/overlay chrome: borders, panels, transcript container, diff and error blocks.
|
|
2
|
+
export * from "./chat-block";
|
|
3
|
+
export * from "./context-thresholds";
|
|
4
|
+
export * from "./countdown-timer";
|
|
5
|
+
export * from "./diff";
|
|
6
|
+
export * from "./dynamic-border";
|
|
7
|
+
export * from "./error-block";
|
|
8
|
+
export * from "./keybinding-hints";
|
|
9
|
+
export * from "./message-divider";
|
|
10
|
+
export * from "./message-frame";
|
|
11
|
+
export * from "./message-notice";
|
|
12
|
+
export * from "./overlay-box";
|
|
13
|
+
export * from "./segment-track";
|
|
14
|
+
export * from "./select-list-mouse-routing";
|
|
15
|
+
export * from "./selector-helpers";
|
|
16
|
+
export * from "./shared";
|
|
17
|
+
export * from "./streaming-panel";
|
|
18
|
+
export * from "./tool-activity";
|
|
19
|
+
export * from "./transcript-container";
|
|
20
|
+
export * from "./transcript-status";
|
|
21
|
+
export * from "./visual-truncate";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for formatting keybinding hints in the UI.
|
|
3
|
+
*/
|
|
4
|
+
import { getKeybindings, type Keybinding } from "../keybindings";
|
|
5
|
+
import { type AppKeybinding, formatKeyHints, type KeybindingsManager } from "../app-keybindings";
|
|
6
|
+
import { theme } from "../theme/index";
|
|
7
|
+
/**
|
|
8
|
+
* Get display string for an editor action.
|
|
9
|
+
*/
|
|
10
|
+
export function editorKey(action: Keybinding): string {
|
|
11
|
+
return formatKeyHints(getKeybindings().getKeys(action));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get display string for an app action.
|
|
16
|
+
*/
|
|
17
|
+
export function appKey(keybindings: KeybindingsManager, action: AppKeybinding): string {
|
|
18
|
+
return formatKeyHints(keybindings.getKeys(action));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Format a keybinding hint with consistent styling: dim key, muted description.
|
|
23
|
+
* Looks up the key from editor keybindings automatically.
|
|
24
|
+
*
|
|
25
|
+
* @param action - Keybinding action name (e.g., "tui.select.confirm", "app.tools.expand")
|
|
26
|
+
* @param description - Description text (e.g., "to expand", "cancel")
|
|
27
|
+
* @returns Formatted string with dim key and muted description
|
|
28
|
+
*/
|
|
29
|
+
export function keyHint(action: Keybinding, description: string): string {
|
|
30
|
+
return theme.fg("dim", editorKey(action)) + theme.fg("muted", ` ${description}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Format a keybinding hint for app-level actions.
|
|
35
|
+
* Requires the KeybindingsManager instance.
|
|
36
|
+
*
|
|
37
|
+
* @param keybindings - KeybindingsManager instance
|
|
38
|
+
* @param action - App keybinding name (e.g., "app.interrupt", "app.editor.external")
|
|
39
|
+
* @param description - Description text
|
|
40
|
+
* @returns Formatted string with dim key and muted description
|
|
41
|
+
*/
|
|
42
|
+
export function appKeyHint(keybindings: KeybindingsManager, action: AppKeybinding, description: string): string {
|
|
43
|
+
return theme.fg("dim", appKey(keybindings, action)) + theme.fg("muted", ` ${description}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Format a raw key string with description (for non-configurable keys like ↑↓).
|
|
48
|
+
*
|
|
49
|
+
* @param key - Raw key string
|
|
50
|
+
* @param description - Description text
|
|
51
|
+
* @returns Formatted string with dim key and muted description
|
|
52
|
+
*/
|
|
53
|
+
export function rawKeyHint(key: string, description: string): string {
|
|
54
|
+
return theme.fg("dim", key) + theme.fg("muted", ` ${description}`);
|
|
55
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transient multi-line status board for standalone CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Repaints a caller-rendered block of lines in place at ~12.5fps while
|
|
5
|
+
* permanent output logged through {@link LiveBoard.log} scrolls above it.
|
|
6
|
+
* Non-TTY outputs disable rendering entirely and `log` degrades to plain
|
|
7
|
+
* writes, so callers keep one code path for both modes.
|
|
8
|
+
*/
|
|
9
|
+
import { replaceTabs, truncateToWidth } from "../utils";
|
|
10
|
+
import { ensureThemeSync, theme } from "../theme/theme";
|
|
11
|
+
|
|
12
|
+
const RENDER_INTERVAL_MS = 80;
|
|
13
|
+
|
|
14
|
+
/** Output contract for the live board (satisfied by `process.stdout`). */
|
|
15
|
+
export interface LiveBoardOutput {
|
|
16
|
+
isTTY?: boolean;
|
|
17
|
+
columns?: number;
|
|
18
|
+
rows?: number;
|
|
19
|
+
write(text: string): boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Live repaint handle returned by {@link createLiveBoard}. */
|
|
23
|
+
export interface LiveBoard {
|
|
24
|
+
readonly interactive: boolean;
|
|
25
|
+
/** Print a permanent line above the board; plain write when non-interactive. */
|
|
26
|
+
log(text: string): void;
|
|
27
|
+
/** Repaint immediately after a state change instead of waiting for the next tick. */
|
|
28
|
+
repaint(): void;
|
|
29
|
+
/** Clear the board, stop the timer, and restore the cursor. */
|
|
30
|
+
close(): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a live board whose content comes from `render(spinner, width)` on
|
|
35
|
+
* every tick. An empty render result paints nothing and releases the cursor,
|
|
36
|
+
* so an idle board never interferes with other terminal UI (e.g. pickers).
|
|
37
|
+
*/
|
|
38
|
+
export function createLiveBoard(
|
|
39
|
+
render: (spinner: string, width: number) => string[],
|
|
40
|
+
output: LiveBoardOutput = process.stdout,
|
|
41
|
+
): LiveBoard {
|
|
42
|
+
const interactive = output.isTTY === true;
|
|
43
|
+
let frame = 0;
|
|
44
|
+
let lineCount = 0;
|
|
45
|
+
let cursorHidden = false;
|
|
46
|
+
let closed = false;
|
|
47
|
+
let timer: NodeJS.Timeout | undefined;
|
|
48
|
+
|
|
49
|
+
const dimensions = (): { width: number; maxRows: number } => {
|
|
50
|
+
const columns = output.columns ?? 0;
|
|
51
|
+
const rows = output.rows ?? 0;
|
|
52
|
+
return {
|
|
53
|
+
width: Number.isFinite(columns) && columns > 0 ? Math.trunc(columns) : 80,
|
|
54
|
+
maxRows: Math.max(4, (Number.isFinite(rows) && rows > 0 ? Math.trunc(rows) : 24) - 2),
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const paint = (lines: string[]): void => {
|
|
59
|
+
// Erase each line explicitly and cap it to the terminal width so the
|
|
60
|
+
// `\x1b[<n>A` cursor-up always matches the logical line count, even in
|
|
61
|
+
// raw-mode terminals without ONLCR where wrapped rows would otherwise
|
|
62
|
+
// staircase into scrollback.
|
|
63
|
+
if (lines.length === 0 && lineCount === 0) return;
|
|
64
|
+
const { width } = dimensions();
|
|
65
|
+
let out = lineCount > 0 ? `\x1b[${lineCount}A` : "";
|
|
66
|
+
out += "\r";
|
|
67
|
+
if (lines.length > 0) {
|
|
68
|
+
out += `${lines.map(line => `\x1b[2K${truncateToWidth(replaceTabs(line), width)}`).join("\r\n")}\r\n`;
|
|
69
|
+
}
|
|
70
|
+
out += "\x1b[0J";
|
|
71
|
+
if (lines.length > 0 && !cursorHidden) {
|
|
72
|
+
out += "\x1b[?25l";
|
|
73
|
+
cursorHidden = true;
|
|
74
|
+
} else if (lines.length === 0 && cursorHidden) {
|
|
75
|
+
out += "\x1b[?25h";
|
|
76
|
+
cursorHidden = false;
|
|
77
|
+
}
|
|
78
|
+
output.write(out);
|
|
79
|
+
lineCount = lines.length;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const repaint = (): void => {
|
|
83
|
+
if (!interactive || closed) return;
|
|
84
|
+
const { width, maxRows } = dimensions();
|
|
85
|
+
ensureThemeSync();
|
|
86
|
+
const frames = theme.getSpinnerFrames("activity");
|
|
87
|
+
const spinner = frames[frame % frames.length] ?? "*";
|
|
88
|
+
let lines = render(spinner, width);
|
|
89
|
+
if (lines.length > maxRows) {
|
|
90
|
+
lines = [...lines.slice(0, maxRows - 1), `… +${lines.length - (maxRows - 1)} more`];
|
|
91
|
+
}
|
|
92
|
+
paint(lines);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
if (interactive) {
|
|
96
|
+
timer = setInterval(() => {
|
|
97
|
+
frame += 1;
|
|
98
|
+
repaint();
|
|
99
|
+
}, RENDER_INTERVAL_MS);
|
|
100
|
+
timer.unref?.();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
interactive,
|
|
105
|
+
log(text) {
|
|
106
|
+
if (closed || !interactive) {
|
|
107
|
+
output.write(`${text}\n`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
paint([]);
|
|
111
|
+
output.write(`${text}\n`);
|
|
112
|
+
repaint();
|
|
113
|
+
},
|
|
114
|
+
repaint,
|
|
115
|
+
close() {
|
|
116
|
+
if (closed) return;
|
|
117
|
+
closed = true;
|
|
118
|
+
if (!interactive) return;
|
|
119
|
+
clearInterval(timer);
|
|
120
|
+
paint([]);
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** formatLocalCalendarDate formats a Date as YYYY-MM-DD in the host local timezone. */
|
|
2
|
+
export function formatLocalCalendarDate(date: Date = new Date()): string {
|
|
3
|
+
const year = date.getFullYear();
|
|
4
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
5
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
6
|
+
return `${year}-${month}-${day}`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Format a local date and minute with a compact numeric UTC offset. */
|
|
10
|
+
export function formatLocalDateTimeWithOffset(date: Date): string {
|
|
11
|
+
const offsetMinutes = date.getTimezoneOffset();
|
|
12
|
+
const offsetSign = offsetMinutes <= 0 ? "+" : "-";
|
|
13
|
+
const absoluteOffset = Math.abs(offsetMinutes);
|
|
14
|
+
const offsetHours = Math.floor(absoluteOffset / 60);
|
|
15
|
+
const offsetRemainderMinutes = absoluteOffset % 60;
|
|
16
|
+
const pad2 = (value: number): string => String(value).padStart(2, "0");
|
|
17
|
+
return `${formatLocalCalendarDate(date)} ${pad2(date.getHours())}:${pad2(date.getMinutes())} ${offsetSign}${pad2(
|
|
18
|
+
offsetHours,
|
|
19
|
+
)}:${pad2(offsetRemainderMinutes)}`;
|
|
20
|
+
}
|