@oh-my-pi/pi-tui 18.4.2 → 18.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/dist/types/apps/cleanse-board.d.ts +17 -0
- package/dist/types/apps/git/help.d.ts +16 -0
- package/dist/types/apps/git/sidebar.d.ts +18 -0
- package/dist/types/apps/live-visualizer.d.ts +10 -0
- package/dist/types/apps/ps-top.d.ts +15 -0
- package/dist/types/apps/standalone-picker.d.ts +3 -0
- package/dist/types/autocomplete.d.ts +8 -0
- package/dist/types/chat/advisor-message.d.ts +12 -2
- package/dist/types/chat/assistant-message.d.ts +20 -0
- package/dist/types/chat/bash-execution.d.ts +9 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +6 -1
- package/dist/types/chat/collab-prompt-message.d.ts +4 -0
- package/dist/types/chat/compaction-summary-message.d.ts +15 -0
- package/dist/types/chat/eval-execution.d.ts +8 -0
- package/dist/types/chat/execution-shared.d.ts +58 -0
- package/dist/types/chat/late-diagnostics-message.d.ts +15 -1
- package/dist/types/chat/read-tool-group.d.ts +15 -0
- package/dist/types/chat/skill-message.d.ts +9 -0
- package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +3 -0
- package/dist/types/chat/thinking-display.d.ts +2 -0
- package/dist/types/chat/todo-reminder.d.ts +4 -1
- package/dist/types/chat/tool-execution.d.ts +25 -1
- package/dist/types/chat/transcript-actions.d.ts +37 -0
- package/dist/types/chat/transcript-entry.d.ts +3 -1
- package/dist/types/chat/user-message.d.ts +25 -0
- package/dist/types/chrome/collab-qrcode.d.ts +7 -0
- package/dist/types/chrome/context-thresholds.d.ts +11 -0
- package/dist/types/chrome/countdown-timer.d.ts +9 -3
- package/dist/types/chrome/diff.d.ts +12 -0
- package/dist/types/chrome/dynamic-border.d.ts +3 -0
- package/dist/types/chrome/format.d.ts +6 -0
- package/dist/types/chrome/message-divider.d.ts +13 -0
- package/dist/types/chrome/message-frame.d.ts +10 -0
- package/dist/types/chrome/message-notice.d.ts +23 -0
- package/dist/types/chrome/overlay-box.d.ts +11 -2
- package/dist/types/chrome/qrcode.d.ts +7 -0
- package/dist/types/chrome/segment-track.d.ts +7 -0
- package/dist/types/chrome/selector-helpers.d.ts +0 -6
- package/dist/types/chrome/status-notice.d.ts +14 -0
- package/dist/types/chrome/streaming-panel.d.ts +3 -0
- package/dist/types/chrome/tool-activity.d.ts +3 -0
- package/dist/types/chrome/transcript-container.d.ts +13 -0
- package/dist/types/chrome/transcript-status.d.ts +15 -3
- package/dist/types/components/box.d.ts +7 -0
- package/dist/types/components/disclosure.d.ts +9 -0
- package/dist/types/components/editor.d.ts +42 -0
- package/dist/types/components/form.d.ts +14 -0
- package/dist/types/components/image.d.ts +7 -0
- package/dist/types/components/input.d.ts +20 -1
- package/dist/types/components/key-value-list.d.ts +3 -0
- package/dist/types/components/layout/geometry.d.ts +16 -0
- package/dist/types/components/layout/row.d.ts +7 -0
- package/dist/types/components/layout/split-pane.d.ts +8 -0
- package/dist/types/components/layout/stack.d.ts +6 -0
- package/dist/types/components/loader.d.ts +48 -0
- package/dist/types/components/markdown.d.ts +8 -0
- package/dist/types/components/metric.d.ts +7 -0
- package/dist/types/components/progress-bar.d.ts +3 -0
- package/dist/types/components/scroll-view.d.ts +6 -0
- package/dist/types/components/section.d.ts +3 -0
- package/dist/types/components/select-list.d.ts +33 -0
- package/dist/types/components/settings-list.d.ts +68 -0
- package/dist/types/components/spacer.d.ts +4 -0
- package/dist/types/components/tab-bar.d.ts +9 -0
- package/dist/types/components/table.d.ts +7 -0
- package/dist/types/components/text.d.ts +6 -0
- package/dist/types/components/tree-view.d.ts +9 -0
- package/dist/types/components/truncated-text.d.ts +3 -0
- package/dist/types/components/wizard-step.d.ts +6 -0
- package/dist/types/hotkeys-markdown.d.ts +24 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/latex-block.d.ts +7 -0
- package/dist/types/loop-watchdog.d.ts +9 -0
- package/dist/types/native/apply.d.ts +39 -0
- package/dist/types/native/backend.d.ts +94 -0
- package/dist/types/native/blobs.d.ts +29 -0
- package/dist/types/native/describe.d.ts +56 -0
- package/dist/types/native/encode.d.ts +50 -0
- package/dist/types/native/icons.d.ts +18 -0
- package/dist/types/native/memo.d.ts +27 -0
- package/dist/types/native/node.d.ts +107 -0
- package/dist/types/native/overlay.d.ts +64 -0
- package/dist/types/native/picker.d.ts +124 -0
- package/dist/types/native/reconcile.d.ts +41 -0
- package/dist/types/native/settle.d.ts +11 -0
- package/dist/types/native/spans.d.ts +21 -0
- package/dist/types/native/state.d.ts +6 -0
- package/dist/types/native/tone.d.ts +24 -0
- package/dist/types/overlays/advisor-config.d.ts +20 -0
- package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
- package/dist/types/overlays/agent-hub.d.ts +10 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
- package/dist/types/overlays/agents-hub.d.ts +8 -0
- package/dist/types/overlays/annotation-overlay.d.ts +3 -0
- package/dist/types/overlays/ask-dialog.d.ts +23 -0
- package/dist/types/overlays/bordered-loader.d.ts +3 -0
- package/dist/types/overlays/btw-history-panel.d.ts +9 -0
- package/dist/types/overlays/btw-panel.d.ts +3 -0
- package/dist/types/overlays/cleanse-panel.d.ts +5 -2
- package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
- package/dist/types/overlays/copy-selector.d.ts +38 -0
- package/dist/types/overlays/error-banner.d.ts +9 -0
- package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
- package/dist/types/overlays/history-search.d.ts +18 -0
- package/dist/types/overlays/hook-editor.d.ts +28 -1
- package/dist/types/overlays/hook-input.d.ts +3 -0
- package/dist/types/overlays/hook-selector.d.ts +10 -0
- package/dist/types/overlays/hub-frame.d.ts +18 -0
- package/dist/types/overlays/jobs-panel.d.ts +24 -0
- package/dist/types/overlays/login-dialog.d.ts +10 -0
- package/dist/types/overlays/logout-account-selector.d.ts +4 -0
- package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
- package/dist/types/overlays/model-browser.d.ts +69 -0
- package/dist/types/overlays/model-hub.d.ts +7 -0
- package/dist/types/overlays/model-picker.d.ts +9 -1
- package/dist/types/overlays/move-overlay.d.ts +3 -0
- package/dist/types/overlays/oauth-selector.d.ts +4 -0
- package/dist/types/overlays/omfg-panel.d.ts +3 -0
- package/dist/types/overlays/pause-screen.d.ts +12 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
- package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
- package/dist/types/overlays/plugin-selector.d.ts +4 -0
- package/dist/types/overlays/plugin-settings.d.ts +30 -0
- package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
- package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
- package/dist/types/overlays/rewind-selector.d.ts +5 -0
- package/dist/types/overlays/session-info-overlay.d.ts +19 -1
- package/dist/types/overlays/session-selector.d.ts +64 -1
- package/dist/types/overlays/settings-defs.d.ts +14 -0
- package/dist/types/overlays/settings-selector.d.ts +21 -0
- package/dist/types/overlays/show-images-selector.d.ts +4 -0
- package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
- package/dist/types/overlays/stats-notice.d.ts +8 -0
- package/dist/types/overlays/theme-selector.d.ts +11 -0
- package/dist/types/overlays/thinking-selector.d.ts +4 -0
- package/dist/types/overlays/tree-selector.d.ts +60 -2
- package/dist/types/overlays/usage-dashboard.d.ts +26 -3
- package/dist/types/overlays/usage-row.d.ts +36 -2
- package/dist/types/prompt/attachment-chips.d.ts +8 -0
- package/dist/types/prompt/composer-attachments.d.ts +15 -3
- package/dist/types/prompt/composer.d.ts +18 -1
- package/dist/types/prompt/custom-editor.d.ts +48 -2
- package/dist/types/prompt/editor-top-gap.d.ts +2 -0
- package/dist/types/prompt/macos-spelling.d.ts +6 -0
- package/dist/types/prompt/magic-keywords.d.ts +9 -0
- package/dist/types/prompt/queued-messages.d.ts +23 -0
- package/dist/types/prompt/skill-tokens.d.ts +4 -2
- package/dist/types/prompt/welcome.d.ts +16 -0
- package/dist/types/render/code-cell.d.ts +10 -0
- package/dist/types/render/file-list.d.ts +8 -0
- package/dist/types/render/hyperlink.d.ts +14 -0
- package/dist/types/render/output-block.d.ts +43 -0
- package/dist/types/render/output-pane.d.ts +17 -0
- package/dist/types/render/tool-card.d.ts +8 -0
- package/dist/types/render/tree-list.d.ts +8 -0
- package/dist/types/render/width-aware-text.d.ts +7 -0
- package/dist/types/setup/scenes/outro.d.ts +7 -0
- package/dist/types/setup/scenes/sign-in.d.ts +16 -9
- package/dist/types/setup/scenes/splash.d.ts +8 -0
- package/dist/types/setup/scenes/types.d.ts +6 -27
- package/dist/types/setup/wizard-overlay.d.ts +9 -0
- package/dist/types/status-line/component.d.ts +49 -5
- package/dist/types/status-line/context-usage.d.ts +20 -0
- package/dist/types/status-line/footer.d.ts +8 -0
- package/dist/types/status-line/metrics.d.ts +1 -2
- package/dist/types/status-line/segments.d.ts +10 -1
- package/dist/types/status-line/types.d.ts +40 -1
- package/dist/types/stdin-buffer.d.ts +10 -7
- package/dist/types/terminal-capabilities.d.ts +1 -1
- package/dist/types/terminal.d.ts +36 -0
- package/dist/types/theme/defaults/index.d.ts +100 -0
- package/dist/types/theme/schema.d.ts +2 -0
- package/dist/types/theme/shimmer.d.ts +8 -0
- package/dist/types/theme/theme-class.d.ts +2 -0
- package/dist/types/theme/theme.d.ts +33 -1
- package/dist/types/tools/ask.d.ts +3 -0
- package/dist/types/tools/ast-edit.d.ts +10 -1
- package/dist/types/tools/ast-grep.d.ts +10 -1
- package/dist/types/tools/autoresearch.d.ts +21 -4
- package/dist/types/tools/bash.d.ts +30 -1
- package/dist/types/tools/cfg-render.d.ts +5 -1
- package/dist/types/tools/debug.d.ts +3 -1
- package/dist/types/tools/default-renderer.d.ts +6 -1
- package/dist/types/tools/edit.d.ts +14 -1
- package/dist/types/tools/eval.d.ts +12 -1
- package/dist/types/tools/fetch.d.ts +16 -1
- package/dist/types/tools/find.d.ts +15 -1
- package/dist/types/tools/github.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +14 -1
- package/dist/types/tools/goal.d.ts +3 -1
- package/dist/types/tools/grep.d.ts +14 -1
- package/dist/types/tools/grouped-file-output.d.ts +58 -0
- package/dist/types/tools/json-tree.d.ts +20 -0
- package/dist/types/tools/lsp.d.ts +3 -10
- package/dist/types/tools/mcp.d.ts +16 -1
- package/dist/types/tools/memory.d.ts +26 -0
- package/dist/types/tools/native-view.d.ts +90 -0
- package/dist/types/tools/proc-render.d.ts +7 -1
- package/dist/types/tools/read.d.ts +23 -1
- package/dist/types/tools/renderer.d.ts +57 -0
- package/dist/types/tools/report-tool-issue.d.ts +3 -0
- package/dist/types/tools/resolve.d.ts +14 -1
- package/dist/types/tools/task.d.ts +3 -0
- package/dist/types/tools/think.d.ts +3 -0
- package/dist/types/tools/todo.d.ts +12 -0
- package/dist/types/tools/vibe.d.ts +3 -1
- package/dist/types/tools/wait.d.ts +3 -0
- package/dist/types/tools/web-search-types.d.ts +90 -0
- package/dist/types/tools/web-search.d.ts +9 -168
- package/dist/types/tools/write.d.ts +14 -1
- package/dist/types/tools/xdev.d.ts +13 -0
- package/dist/types/tui.d.ts +49 -0
- package/package.json +9 -9
- package/src/apps/autoresearch-dashboard.ts +362 -4
- package/src/apps/cleanse-board.ts +219 -1
- package/src/apps/cleanse-picker.ts +9 -1
- package/src/apps/debug/log-viewer.ts +15 -15
- package/src/apps/debug/protocol-probe.ts +2 -20
- package/src/apps/git/avatar.ts +2 -22
- package/src/apps/git/git-tui.ts +406 -59
- package/src/apps/git/help.ts +130 -0
- package/src/apps/git/sidebar.ts +491 -0
- package/src/apps/live-visualizer.ts +65 -0
- package/src/apps/ps-top.ts +448 -17
- package/src/apps/session-picker.ts +1 -0
- package/src/apps/setup-model-picker.ts +5 -1
- package/src/apps/standalone-picker.ts +55 -1
- package/src/autocomplete.ts +44 -1
- package/src/chat/advisor-message.ts +72 -3
- package/src/chat/assistant-message.ts +538 -51
- package/src/chat/background-tan-message.ts +4 -4
- package/src/chat/bash-execution.ts +81 -0
- package/src/chat/cache-invalidation-marker.ts +8 -0
- package/src/chat/chat-transcript-builder.ts +37 -6
- package/src/chat/collab-prompt-message.ts +15 -3
- package/src/chat/compaction-summary-message.ts +74 -1
- package/src/chat/custom-message.ts +3 -1
- package/src/chat/eval-execution.ts +57 -0
- package/src/chat/execution-shared.ts +153 -1
- package/src/chat/hook-message.ts +1 -0
- package/src/chat/late-diagnostics-message.ts +85 -2
- package/src/chat/read-tool-group.ts +341 -1
- package/src/chat/served-model-marker.ts +8 -0
- package/src/chat/skill-message.ts +63 -0
- package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
- package/src/chat/thinking-display.ts +73 -11
- package/src/chat/todo-reminder.ts +34 -4
- package/src/chat/tool-execution.ts +385 -10
- package/src/chat/transcript-actions.ts +38 -0
- package/src/chat/transcript-browser.ts +2 -9
- package/src/chat/transcript-entry.ts +10 -1
- package/src/chat/transcript-render-helpers.ts +16 -15
- package/src/chat/ttsr-notification.ts +38 -1
- package/src/chat/user-message.ts +167 -4
- package/src/chrome/collab-qrcode.ts +27 -2
- package/src/chrome/context-thresholds.ts +34 -0
- package/src/chrome/countdown-timer.ts +24 -1
- package/src/chrome/diff.ts +60 -1
- package/src/chrome/dynamic-border.ts +7 -0
- package/src/chrome/format.ts +12 -0
- package/src/chrome/message-divider.ts +33 -1
- package/src/chrome/message-frame.ts +53 -10
- package/src/chrome/message-notice.ts +71 -0
- package/src/chrome/overlay-box.ts +45 -2
- package/src/chrome/qrcode.ts +28 -0
- package/src/chrome/segment-track.ts +26 -0
- package/src/chrome/selector-helpers.ts +1 -17
- package/src/chrome/status-notice.ts +46 -0
- package/src/chrome/streaming-panel.ts +25 -1
- package/src/chrome/tool-activity.ts +20 -0
- package/src/chrome/transcript-container.ts +139 -17
- package/src/chrome/transcript-status.ts +40 -11
- package/src/components/box.ts +51 -0
- package/src/components/disclosure.ts +33 -0
- package/src/components/editor.ts +239 -36
- package/src/components/form.ts +93 -9
- package/src/components/image.ts +30 -0
- package/src/components/input.ts +77 -26
- package/src/components/key-value-list.ts +18 -0
- package/src/components/layout/geometry.ts +44 -0
- package/src/components/layout/row.ts +30 -0
- package/src/components/layout/split-pane.ts +65 -0
- package/src/components/layout/stack.ts +27 -0
- package/src/components/loader.ts +183 -1
- package/src/components/markdown.ts +131 -56
- package/src/components/metric.ts +39 -0
- package/src/components/progress-bar.ts +28 -0
- package/src/components/scroll-view.ts +23 -0
- package/src/components/section.ts +16 -0
- package/src/components/select-list.ts +174 -25
- package/src/components/settings-list.ts +264 -7
- package/src/components/spacer.ts +17 -0
- package/src/components/tab-bar.ts +42 -0
- package/src/components/table.ts +34 -0
- package/src/components/text.ts +23 -0
- package/src/components/tree-view.ts +65 -0
- package/src/components/truncated-text.ts +14 -0
- package/src/components/wizard-step.ts +18 -9
- package/src/debug-server.ts +14 -7
- package/src/hotkeys-markdown.ts +251 -69
- package/src/index.ts +6 -0
- package/src/latex-block.ts +11 -0
- package/src/loop-watchdog.ts +38 -10
- package/src/native/apply.ts +275 -0
- package/src/native/backend.ts +682 -0
- package/src/native/blobs.ts +70 -0
- package/src/native/describe.ts +124 -0
- package/src/native/encode.ts +233 -0
- package/src/native/icons.ts +184 -0
- package/src/native/memo.ts +64 -0
- package/src/native/node.ts +112 -0
- package/src/native/overlay.ts +131 -0
- package/src/native/picker.ts +333 -0
- package/src/native/reconcile.ts +1063 -0
- package/src/native/settle.ts +23 -0
- package/src/native/spans.ts +308 -0
- package/src/native/state.ts +28 -0
- package/src/native/tone.ts +79 -0
- package/src/overlays/advisor-config.ts +420 -0
- package/src/overlays/agent-hub-renderer.ts +155 -18
- package/src/overlays/agent-hub.ts +1037 -44
- package/src/overlays/agent-transcript-viewer.ts +129 -0
- package/src/overlays/agents-hub.ts +688 -53
- package/src/overlays/annotation-overlay.ts +391 -52
- package/src/overlays/ask-dialog.ts +435 -24
- package/src/overlays/bordered-loader.ts +17 -0
- package/src/overlays/btw-history-panel.ts +182 -0
- package/src/overlays/btw-panel.ts +68 -2
- package/src/overlays/cleanse-panel.ts +105 -15
- package/src/overlays/codex-reset-fireworks.ts +65 -5
- package/src/overlays/composer-shape-preview.ts +26 -1
- package/src/overlays/copy-selector.ts +545 -23
- package/src/overlays/error-banner.ts +44 -0
- package/src/overlays/extensions/extension-list.ts +23 -17
- package/src/overlays/history-search.ts +175 -33
- package/src/overlays/hook-editor.ts +113 -6
- package/src/overlays/hook-input.ts +22 -1
- package/src/overlays/hook-selector.ts +311 -22
- package/src/overlays/hub-frame.ts +80 -0
- package/src/overlays/jobs-panel.ts +112 -0
- package/src/overlays/login-dialog.ts +183 -1
- package/src/overlays/logout-account-selector.ts +102 -4
- package/src/overlays/mcp-add-wizard.ts +232 -53
- package/src/overlays/model-browser.ts +681 -22
- package/src/overlays/model-hub.ts +1402 -78
- package/src/overlays/model-picker.ts +184 -7
- package/src/overlays/move-overlay.ts +45 -0
- package/src/overlays/oauth-selector.ts +227 -23
- package/src/overlays/omfg-panel.ts +86 -2
- package/src/overlays/pause-screen.ts +55 -4
- package/src/overlays/plan-review-overlay.ts +352 -0
- package/src/overlays/plan-save-overlay.ts +45 -0
- package/src/overlays/plugin-selector.ts +21 -1
- package/src/overlays/plugin-settings.ts +195 -5
- package/src/overlays/queue-mode-selector.ts +19 -1
- package/src/overlays/reset-usage-selector.ts +110 -40
- package/src/overlays/rewind-selector.ts +458 -44
- package/src/overlays/session-account-selector.ts +1 -1
- package/src/overlays/session-info-overlay.ts +137 -1
- package/src/overlays/session-selector.ts +807 -46
- package/src/overlays/settings-defs.ts +41 -0
- package/src/overlays/settings-selector.ts +585 -33
- package/src/overlays/show-images-selector.ts +18 -1
- package/src/overlays/snapcompact-shape-preview.ts +48 -3
- package/src/overlays/stats-notice.ts +31 -0
- package/src/overlays/theme-selector.ts +31 -1
- package/src/overlays/thinking-selector.ts +22 -1
- package/src/overlays/tree-selector.ts +570 -110
- package/src/overlays/usage-dashboard.ts +587 -12
- package/src/overlays/usage-row.ts +161 -25
- package/src/prompt/attachment-chips.ts +60 -0
- package/src/prompt/composer-attachments.ts +31 -9
- package/src/prompt/composer.ts +55 -2
- package/src/prompt/custom-editor.ts +302 -4
- package/src/prompt/editor-top-gap.ts +8 -0
- package/src/prompt/macos-spelling.ts +24 -9
- package/src/prompt/magic-keywords.ts +22 -1
- package/src/prompt/model-mention-autocomplete.ts +1 -0
- package/src/prompt/queued-messages.ts +101 -0
- package/src/prompt/skill-tokens.ts +5 -3
- package/src/prompt/welcome.ts +213 -6
- package/src/render/code-cell.ts +103 -2
- package/src/render/file-list.ts +29 -0
- package/src/render/hyperlink.ts +32 -0
- package/src/render/output-block.ts +110 -0
- package/src/render/output-pane.ts +37 -0
- package/src/render/tool-card.ts +137 -0
- package/src/render/tree-list.ts +39 -0
- package/src/render/width-aware-text.ts +20 -0
- package/src/setup/scenes/composer.ts +29 -0
- package/src/setup/scenes/glyph.ts +15 -0
- package/src/setup/scenes/model.ts +36 -8
- package/src/setup/scenes/outro.ts +28 -1
- package/src/setup/scenes/sign-in.ts +138 -24
- package/src/setup/scenes/splash.ts +28 -1
- package/src/setup/scenes/theme.ts +88 -3
- package/src/setup/scenes/types.ts +7 -28
- package/src/setup/startup-splash.ts +46 -9
- package/src/setup/wizard-overlay.ts +140 -23
- package/src/setup/wizard.ts +1 -1
- package/src/status-line/component.ts +414 -18
- package/src/status-line/context-usage.ts +279 -50
- package/src/status-line/footer.ts +94 -1
- package/src/status-line/metrics.ts +3 -6
- package/src/status-line/segments.ts +463 -97
- package/src/status-line/separators.ts +3 -16
- package/src/status-line/types.ts +43 -1
- package/src/stdin-buffer.ts +27 -21
- package/src/terminal-capabilities.ts +7 -0
- package/src/terminal.ts +153 -11
- package/src/theme/defaults/dark-neon-noir.json +100 -0
- package/src/theme/defaults/index.ts +2 -0
- package/src/theme/defaults/light-prism.json +5 -5
- package/src/theme/defaults/onyx.json +62 -62
- package/src/theme/mermaid-cache.ts +10 -1
- package/src/theme/schema.ts +15 -0
- package/src/theme/shimmer.ts +33 -0
- package/src/theme/theme-class.ts +24 -19
- package/src/theme/theme.ts +111 -9
- package/src/theme/tui-adapters.ts +14 -1
- package/src/tools/ask.ts +157 -1
- package/src/tools/ast-edit.ts +174 -1
- package/src/tools/ast-grep.ts +82 -2
- package/src/tools/autoresearch.ts +149 -1
- package/src/tools/bash.ts +233 -62
- package/src/tools/cfg-render.ts +66 -1
- package/src/tools/debug.ts +78 -1
- package/src/tools/default-renderer.ts +35 -1
- package/src/tools/edit.ts +357 -31
- package/src/tools/eval.ts +257 -1
- package/src/tools/fetch.ts +102 -3
- package/src/tools/find.ts +127 -1
- package/src/tools/github.ts +119 -10
- package/src/tools/glob.ts +116 -1
- package/src/tools/goal.ts +56 -1
- package/src/tools/grep.ts +83 -2
- package/src/tools/grouped-file-output.ts +205 -0
- package/src/tools/json-tree.ts +116 -1
- package/src/tools/lsp.ts +318 -1
- package/src/tools/mcp.ts +80 -1
- package/src/tools/memory.ts +93 -11
- package/src/tools/native-view.ts +292 -0
- package/src/tools/proc-render.ts +221 -1
- package/src/tools/read.ts +199 -4
- package/src/tools/renderer.ts +61 -0
- package/src/tools/report-tool-issue.ts +7 -1
- package/src/tools/resolve.ts +63 -1
- package/src/tools/streaming-output.ts +79 -16
- package/src/tools/task.ts +406 -4
- package/src/tools/think.ts +19 -1
- package/src/tools/todo.ts +89 -0
- package/src/tools/vibe.ts +230 -2
- package/src/tools/wait.ts +181 -1
- package/src/tools/web-search-types.ts +99 -0
- package/src/tools/web-search.ts +111 -170
- package/src/tools/write.ts +144 -5
- package/src/tools/xdev.ts +64 -1
- package/src/tui.ts +295 -4
- package/dist/types/setup/scenes/providers.d.ts +0 -3
- package/dist/types/setup/scenes/web-search.d.ts +0 -22
- package/src/setup/scenes/providers.ts +0 -110
- package/src/setup/scenes/web-search.ts +0 -165
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { Text } from "../components/text";
|
|
2
2
|
import { type Component, Container } from "../tui";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
MessageNoticeComponent,
|
|
5
|
+
type MessageNoticeNativePresentation,
|
|
6
|
+
type MessageNoticePresentation,
|
|
7
|
+
} from "../chrome/message-notice";
|
|
4
8
|
import { theme } from "../theme";
|
|
5
9
|
import { expandKeyHint } from "../render/render-utils";
|
|
10
|
+
import { span, text } from "../native/describe";
|
|
11
|
+
import type { NativeNode } from "../native/node";
|
|
6
12
|
|
|
7
13
|
/** Rule fields shown in rewind notifications. */
|
|
8
14
|
export interface NotificationRule {
|
|
@@ -30,6 +36,8 @@ export class TtsrNotificationComponent extends Container {
|
|
|
30
36
|
this.#rules = [...rules];
|
|
31
37
|
this.#notice = new MessageNoticeComponent({
|
|
32
38
|
presentation: context => this.#presentation(context.expanded),
|
|
39
|
+
nativePresentation: () => this.#nativePresentation(),
|
|
40
|
+
role: "omp.notice.ttsr",
|
|
33
41
|
});
|
|
34
42
|
this.addChild(this.#notice);
|
|
35
43
|
}
|
|
@@ -57,6 +65,35 @@ export class TtsrNotificationComponent extends Container {
|
|
|
57
65
|
return this.#notice.isExpanded();
|
|
58
66
|
}
|
|
59
67
|
|
|
68
|
+
/**
|
|
69
|
+
* An inline warning notice, "Rule applied: no-unwrap", with every rule's
|
|
70
|
+
* full description as the disclosure below it.
|
|
71
|
+
*/
|
|
72
|
+
#nativePresentation(): MessageNoticeNativePresentation {
|
|
73
|
+
const single = this.#rules.length === 1 ? this.#rules[0] : undefined;
|
|
74
|
+
const head = single
|
|
75
|
+
? [span("Rule applied: ", "warning"), span(single.name, "mono strong")]
|
|
76
|
+
: [
|
|
77
|
+
span(`${this.#rules.length} rules applied: `, "warning"),
|
|
78
|
+
span(this.#rules.map(rule => rule.name).join(", "), "mono strong"),
|
|
79
|
+
];
|
|
80
|
+
const body: NativeNode[] = [];
|
|
81
|
+
for (const rule of this.#rules) {
|
|
82
|
+
const desc = (rule.description || rule.content)?.trim();
|
|
83
|
+
if (single) {
|
|
84
|
+
if (desc) body.push(text([span(desc, "em")], { wrap: "word", key: rule.name }));
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
body.push(
|
|
88
|
+
text(desc ? [span(rule.name, "strong"), span(": "), span(desc, "em")] : [span(rule.name, "strong")], {
|
|
89
|
+
wrap: "word",
|
|
90
|
+
key: rule.name,
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return { head, body, inline: { icon: "shield-alert" } };
|
|
95
|
+
}
|
|
96
|
+
|
|
60
97
|
#presentation(expanded: boolean): MessageNoticePresentation {
|
|
61
98
|
// fg colors conflict with inverse, so styling inside the block is limited
|
|
62
99
|
// to bold (names) and italic (descriptions).
|
package/src/chat/user-message.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { type Component, Container } from "../tui";
|
|
|
3
3
|
import { Disclosure } from "../components/disclosure";
|
|
4
4
|
import { Markdown } from "../components/markdown";
|
|
5
5
|
import { formatBytes } from "@oh-my-pi/pi-utils";
|
|
6
|
+
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
7
|
+
import type { TspSpan } from "@oh-my-pi/pi-wire";
|
|
6
8
|
import { ensureThemeSync, getMarkdownTheme, theme } from "../theme";
|
|
7
9
|
import {
|
|
8
10
|
attachmentSgr,
|
|
@@ -19,6 +21,11 @@ import { expandKeyHint, fileHyperlink } from "../render";
|
|
|
19
21
|
import { imageReferenceHyperlink } from "../prompt/image-references";
|
|
20
22
|
import { highlightMagicKeywords } from "../prompt/magic-keywords";
|
|
21
23
|
import type { ReactionTarget } from "./reaction";
|
|
24
|
+
import { card, md, node, row, span, text } from "../native/describe";
|
|
25
|
+
import { base64ImageNode } from "../native/blobs";
|
|
26
|
+
import { hasTranscriptActions, runTranscriptAction } from "./transcript-actions";
|
|
27
|
+
import { type NativeChild, type NativeNode, type NativeUiEvent, rootToggleExpanded } from "../native/node";
|
|
28
|
+
import { Memo } from "../native/memo";
|
|
22
29
|
|
|
23
30
|
// OSC 133 shell integration: marks prompt zones for terminal multiplexers.
|
|
24
31
|
//
|
|
@@ -46,12 +53,16 @@ const OSC133_ZONE_CLOSE = OSC133_ZONE_END + OSC133_COMMAND_START + OSC133_COMMAN
|
|
|
46
53
|
export interface UserBubbleOptions {
|
|
47
54
|
/** Materialized `file://` targets per attached image, indexed by chip number. */
|
|
48
55
|
imageLinks?: readonly (string | undefined)[];
|
|
56
|
+
/** The message's attached images in chip order (`#1` first); a native bubble shows them. */
|
|
57
|
+
images?: readonly ImageContent[];
|
|
49
58
|
/** Agent-attributed input: dim, flat prose. */
|
|
50
59
|
synthetic?: boolean;
|
|
51
60
|
/** Delivered into the response that was streaming; marked `*` at the bubble's top-left. */
|
|
52
61
|
liveSteered?: boolean;
|
|
53
62
|
/** SKILL.md path for a skill chip by name; `undefined` leaves the chip unlinked. */
|
|
54
63
|
skillPath?: (name: string) => string | undefined;
|
|
64
|
+
/** When the message was sent (ms); shown beside the native hover toolbar. */
|
|
65
|
+
timestamp?: number;
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
/**
|
|
@@ -116,7 +127,16 @@ export class UserMessageComponent extends Container implements ReactionTarget {
|
|
|
116
127
|
#zoneLines: string[] | undefined;
|
|
117
128
|
readonly #bgColor: (value: string) => string;
|
|
118
129
|
readonly #liveSteered: boolean;
|
|
130
|
+
readonly #synthetic: boolean;
|
|
131
|
+
readonly #timestamp: number | undefined;
|
|
132
|
+
readonly #images: readonly ImageContent[];
|
|
133
|
+
readonly #imageLinks: readonly (string | undefined)[] | undefined;
|
|
134
|
+
/** Display text: image markers collapsed to chips and model mentions to their labels. */
|
|
135
|
+
readonly #text: string;
|
|
136
|
+
/** Matches the composer tokens in {@link #text} (chips, skills, this message's mentions). */
|
|
137
|
+
readonly #tokens: RegExp;
|
|
119
138
|
#reaction: string | undefined;
|
|
139
|
+
#native: NativeNode | undefined;
|
|
120
140
|
|
|
121
141
|
constructor(text: string, options: UserBubbleOptions = {}) {
|
|
122
142
|
super();
|
|
@@ -135,18 +155,107 @@ export class UserMessageComponent extends Container implements ReactionTarget {
|
|
|
135
155
|
const bgColor = (value: string) => theme.bg("userMessageBg", value);
|
|
136
156
|
this.#bgColor = bgColor;
|
|
137
157
|
this.#liveSteered = options.liveSteered === true;
|
|
138
|
-
|
|
158
|
+
this.#synthetic = options.synthetic === true;
|
|
159
|
+
this.#timestamp = options.timestamp;
|
|
160
|
+
this.#images = options.images ?? [];
|
|
161
|
+
this.#imageLinks = options.imageLinks;
|
|
162
|
+
this.#text = text;
|
|
163
|
+
this.#tokens = composerTokenRegex(mentionLabels);
|
|
164
|
+
const markdown = new Markdown(text, 1, 1, getMarkdownTheme(), {
|
|
139
165
|
bgColor,
|
|
140
|
-
color: userBubbleColor(options,
|
|
166
|
+
color: userBubbleColor(options, this.#tokens),
|
|
141
167
|
});
|
|
142
|
-
|
|
143
|
-
this.addChild(
|
|
168
|
+
markdown.setIgnoreTight(true);
|
|
169
|
+
this.addChild(markdown);
|
|
144
170
|
}
|
|
145
171
|
|
|
146
172
|
setReaction(emoji: string): void {
|
|
147
173
|
if (this.#reaction === emoji) return;
|
|
148
174
|
this.#reaction = emoji;
|
|
149
175
|
this.#zoneLines = undefined;
|
|
176
|
+
this.#native = undefined;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* A head-less user-toned frame with the prompt as markdown under its
|
|
181
|
+
* attached images (titled `#N` like their chips, opening the materialized
|
|
182
|
+
* file on click): the fill says "you". A quiet toolbar (time, Copy, Rewind) fades in on hover when the
|
|
183
|
+
* host handles transcript actions. The live-steering marker and the
|
|
184
|
+
* agent's reaction are chips at the bottom-right, so a reaction landing
|
|
185
|
+
* later updates the frame in place, even deep in scrollback.
|
|
186
|
+
*/
|
|
187
|
+
override describe(): NativeNode {
|
|
188
|
+
if (this.#native) return this.#native;
|
|
189
|
+
const children: NativeChild[] = [];
|
|
190
|
+
if (!this.#synthetic && hasTranscriptActions()) {
|
|
191
|
+
const tools: NativeChild[] = [];
|
|
192
|
+
if (this.#timestamp !== undefined) {
|
|
193
|
+
const at = new Date(this.#timestamp);
|
|
194
|
+
tools.push(
|
|
195
|
+
text([span(at.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }), "dim mono")], {
|
|
196
|
+
role: "omp.user.time",
|
|
197
|
+
title: at.toLocaleString(),
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
tools.push(
|
|
202
|
+
// `copy-message`, not Tern's local `copy` (that would copy the label).
|
|
203
|
+
text("Copy", {
|
|
204
|
+
role: "omp.user.tool",
|
|
205
|
+
actions: { click: "copy-message" },
|
|
206
|
+
title: "Copy message",
|
|
207
|
+
key: "copy",
|
|
208
|
+
}),
|
|
209
|
+
text("Rewind", {
|
|
210
|
+
role: "omp.user.tool",
|
|
211
|
+
actions: { click: "rewind" },
|
|
212
|
+
title: "Rewind the conversation to an earlier message",
|
|
213
|
+
key: "rewind",
|
|
214
|
+
}),
|
|
215
|
+
);
|
|
216
|
+
children.push(node("row", { gap: "xs", role: "omp.user.tools" }, tools, "tools"));
|
|
217
|
+
}
|
|
218
|
+
// Videos keep their chip only: the native image node decodes stills.
|
|
219
|
+
const thumbs: NativeNode[] = [];
|
|
220
|
+
if (!this.#synthetic) {
|
|
221
|
+
this.#images.forEach((image, i) => {
|
|
222
|
+
if (!image.mimeType.startsWith("image/")) return;
|
|
223
|
+
const label = `#${i + 1}`;
|
|
224
|
+
const link = this.#imageLinks?.[i];
|
|
225
|
+
const open = link ? { href: link, actions: { click: "open" } } : {};
|
|
226
|
+
thumbs.push(base64ImageNode(image.data, image.mimeType, { alt: label, title: label, ...open }, label));
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
if (thumbs.length > 0) {
|
|
230
|
+
children.push(row(thumbs, { gap: "sm", wrap: true, align: "start", role: "omp.user.images" }));
|
|
231
|
+
}
|
|
232
|
+
const marks = this.#synthetic ? [] : tokenMarks(this.#text, this.#tokens);
|
|
233
|
+
children.push(md(this.#text, marks.length > 0 ? { marks } : undefined));
|
|
234
|
+
const badges: NativeChild[] = [];
|
|
235
|
+
if (this.#liveSteered) {
|
|
236
|
+
badges.push(
|
|
237
|
+
node("badge", {
|
|
238
|
+
text: "steered",
|
|
239
|
+
tone: "accent",
|
|
240
|
+
title: "Delivered into the response that was streaming",
|
|
241
|
+
}),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (this.#reaction !== undefined) badges.push(node("badge", { text: this.#reaction, role: "omp.reaction" }));
|
|
245
|
+
if (badges.length > 0)
|
|
246
|
+
children.push(node("row", { gap: "xs", justify: "end", role: "omp.user.badges" }, badges, "badges"));
|
|
247
|
+
this.#native = card(
|
|
248
|
+
{ role: this.#synthetic ? "omp.user.synthetic" : "omp.user", tone: this.#synthetic ? "muted" : "user" },
|
|
249
|
+
children,
|
|
250
|
+
);
|
|
251
|
+
return this.#native;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Hover toolbar clicks: omp's own copy and rewind commands. */
|
|
255
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
256
|
+
if (event.type !== "action") return;
|
|
257
|
+
if (event.act === "copy-message") runTranscriptAction({ act: "copy", text: this.#text });
|
|
258
|
+
else if (event.act === "rewind") runTranscriptAction({ act: "rewind" });
|
|
150
259
|
}
|
|
151
260
|
|
|
152
261
|
/**
|
|
@@ -178,6 +287,31 @@ export class UserMessageComponent extends Container implements ReactionTarget {
|
|
|
178
287
|
}
|
|
179
288
|
}
|
|
180
289
|
|
|
290
|
+
/**
|
|
291
|
+
* The composer tokens in `text` as `md` marks, styled as the composer
|
|
292
|
+
* decorates them (`CustomEditor.describeDecorations`), so a sent prompt keeps
|
|
293
|
+
* its chips highlighted.
|
|
294
|
+
*/
|
|
295
|
+
function tokenMarks(text: string, tokens: RegExp): TspSpan[] {
|
|
296
|
+
// One mark per distinct token: Tern styles every occurrence of its text.
|
|
297
|
+
const styles = new Map<string, string>();
|
|
298
|
+
const mark = (s: string) => (label: string) => {
|
|
299
|
+
styles.set(label, s);
|
|
300
|
+
return "";
|
|
301
|
+
};
|
|
302
|
+
renderPlaceholders(
|
|
303
|
+
text,
|
|
304
|
+
{
|
|
305
|
+
renderText: () => "",
|
|
306
|
+
renderSkill: mark("customMessageLabel strong"),
|
|
307
|
+
renderMention: mark("statusLineModel strong"),
|
|
308
|
+
renderReference: mark("accent strong"),
|
|
309
|
+
},
|
|
310
|
+
tokens,
|
|
311
|
+
);
|
|
312
|
+
return [...styles].map(([t, s]) => ({ t, s }));
|
|
313
|
+
}
|
|
314
|
+
|
|
181
315
|
/**
|
|
182
316
|
* Always-visible dim summary row for a collapsed synthetic input. Kept as a
|
|
183
317
|
* small domain renderer so the width-truncated label never pays Markdown
|
|
@@ -220,6 +354,8 @@ class SyntheticSummary implements Component {
|
|
|
220
354
|
*/
|
|
221
355
|
export class CollapsedSyntheticMessageComponent implements Component {
|
|
222
356
|
#disclosure: Disclosure;
|
|
357
|
+
#expanded = false;
|
|
358
|
+
readonly #native = new Memo();
|
|
223
359
|
|
|
224
360
|
readonly #text: string;
|
|
225
361
|
readonly #imageLinks?: readonly (string | undefined)[];
|
|
@@ -238,9 +374,36 @@ export class CollapsedSyntheticMessageComponent implements Component {
|
|
|
238
374
|
|
|
239
375
|
/** ctrl+o toggle: reveal/hide the full Markdown body. */
|
|
240
376
|
setExpanded(expanded: boolean): void {
|
|
377
|
+
this.#expanded = expanded;
|
|
241
378
|
this.#disclosure.setExpanded(expanded);
|
|
242
379
|
}
|
|
243
380
|
|
|
381
|
+
/**
|
|
382
|
+
* A muted collapsible card whose head is the one-line summary. The
|
|
383
|
+
* (potentially huge) markdown body is only described while expanded, so
|
|
384
|
+
* collapsed history costs no layout on either side; a native toggle
|
|
385
|
+
* expands it through {@link handleNativeEvent}.
|
|
386
|
+
*/
|
|
387
|
+
describe(): NativeNode {
|
|
388
|
+
return this.#native.get([this.#expanded], () =>
|
|
389
|
+
card(
|
|
390
|
+
{
|
|
391
|
+
role: "omp.user.synthetic",
|
|
392
|
+
tone: "muted",
|
|
393
|
+
head: [span(summarizeSyntheticInput(this.#text), "dim")],
|
|
394
|
+
collapsible: true,
|
|
395
|
+
collapsed: !this.#expanded,
|
|
396
|
+
},
|
|
397
|
+
this.#expanded ? [md(this.#text)] : [],
|
|
398
|
+
),
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
403
|
+
const expanded = rootToggleExpanded(event);
|
|
404
|
+
if (expanded !== undefined) this.setExpanded(expanded);
|
|
405
|
+
}
|
|
406
|
+
|
|
244
407
|
setIgnoreTight(ignore: boolean): this {
|
|
245
408
|
this.#disclosure.setIgnoreTight(ignore);
|
|
246
409
|
return this;
|
|
@@ -3,7 +3,9 @@ import { Ellipsis, truncateToWidth, visibleWidth } from "../utils";
|
|
|
3
3
|
import type { AnimationFrame, TranscriptPresentationTarget } from "./transcript-container";
|
|
4
4
|
import { fgOrPlain } from "../theme/theme";
|
|
5
5
|
import { urlHyperlinkAlways } from "../render/index";
|
|
6
|
-
import { QrCode, renderQrHalfBlocks } from "./qrcode";
|
|
6
|
+
import { QrCode, renderQrHalfBlocks, renderQrText } from "./qrcode";
|
|
7
|
+
import type { DescribeContext, NativeNode } from "../native/node";
|
|
8
|
+
import { code, col, text } from "../native/describe";
|
|
7
9
|
|
|
8
10
|
/** Scheme-less display form of a collab browser deep link, OSC-8 linked. */
|
|
9
11
|
export function collabBrowserLink(webLink: string, label?: string): string {
|
|
@@ -30,12 +32,16 @@ export function collabBrowserLink(webLink: string, label?: string): string {
|
|
|
30
32
|
* URL above" is not reachable.
|
|
31
33
|
*/
|
|
32
34
|
export class CollabQrCodeComponent implements Component, TranscriptPresentationTarget {
|
|
35
|
+
readonly #qr: QrCode;
|
|
33
36
|
readonly #lines: readonly string[];
|
|
34
37
|
readonly #minWidth: number;
|
|
35
38
|
#allocatedRows = Number.POSITIVE_INFINITY;
|
|
39
|
+
/** Native description per appearance: the polarity follows the terminal's foreground. */
|
|
40
|
+
#native: { dark: boolean; node: NativeNode } | undefined;
|
|
36
41
|
|
|
37
42
|
constructor(readonly url: string) {
|
|
38
|
-
|
|
43
|
+
this.#qr = QrCode.encodeText(url, "M");
|
|
44
|
+
const rows = renderQrHalfBlocks(this.#qr);
|
|
39
45
|
this.#lines = rows.map(row => ` ${row}`);
|
|
40
46
|
this.#minWidth = rows.reduce((max, row) => Math.max(max, visibleWidth(row)), 0) + 1;
|
|
41
47
|
}
|
|
@@ -54,6 +60,25 @@ export class CollabQrCodeComponent implements Component, TranscriptPresentationT
|
|
|
54
60
|
return this.#lines;
|
|
55
61
|
}
|
|
56
62
|
|
|
63
|
+
/**
|
|
64
|
+
* The symbol as an unwrapped monospace block plus the join link. Glyphs are
|
|
65
|
+
* drawn in the terminal's foreground, so on a dark appearance the light
|
|
66
|
+
* modules are inked to keep the dark-on-light symbol scanners expect.
|
|
67
|
+
*/
|
|
68
|
+
describe(cx: DescribeContext): NativeNode {
|
|
69
|
+
if (this.#native?.dark === cx.dark) return this.#native.node;
|
|
70
|
+
const qr = renderQrText(this.#qr, cx.dark).join("\n");
|
|
71
|
+
const node = col(
|
|
72
|
+
[
|
|
73
|
+
text([{ t: this.url.replace(/^https?:\/\//, ""), s: "accent link", href: this.url }], { wrap: "none" }),
|
|
74
|
+
code(qr, { lang: "text", wrap: false }),
|
|
75
|
+
],
|
|
76
|
+
{ role: "omp.collab.qrcode" },
|
|
77
|
+
);
|
|
78
|
+
this.#native = { dark: cx.dark, node };
|
|
79
|
+
return node;
|
|
80
|
+
}
|
|
81
|
+
|
|
57
82
|
/** Survives emergency 1-row transcript pressure when this block is otherwise hidden. */
|
|
58
83
|
renderTranscriptBlockEmergencyRow(width: number): string {
|
|
59
84
|
return this.#hiddenHint(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatNumber } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import type { TspTone } from "@oh-my-pi/pi-wire";
|
|
2
3
|
import type { ThemeColor } from "../theme/index";
|
|
3
4
|
export type ContextUsageLevel = "normal" | "warning" | "purple" | "error";
|
|
4
5
|
|
|
@@ -54,6 +55,26 @@ export function getContextUsageLevel(contextPercent: number, contextWindow: numb
|
|
|
54
55
|
return "normal";
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
/** Used share (0–1) where a level starts: the percent or token threshold, whichever comes first. */
|
|
59
|
+
function thresholdShare(contextWindow: number, percentThreshold: number, tokenThreshold: number): number {
|
|
60
|
+
const percent =
|
|
61
|
+
Number.isFinite(contextWindow) && contextWindow > 0
|
|
62
|
+
? Math.min(percentThreshold, (tokenThreshold / contextWindow) * 100)
|
|
63
|
+
: percentThreshold;
|
|
64
|
+
return percent / 100;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* `meter` tone switches matching {@link getContextUsageLevel}: warning from the
|
|
69
|
+
* warning level, error from the error level, as shares of `contextWindow`.
|
|
70
|
+
*/
|
|
71
|
+
export function getContextMeterThresholds(contextWindow: number): { warn: number; bad: number } {
|
|
72
|
+
return {
|
|
73
|
+
warn: thresholdShare(contextWindow, CONTEXT_WARNING_PERCENT_THRESHOLD, CONTEXT_WARNING_TOKEN_THRESHOLD),
|
|
74
|
+
bad: thresholdShare(contextWindow, CONTEXT_ERROR_PERCENT_THRESHOLD, CONTEXT_ERROR_TOKEN_THRESHOLD),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
57
78
|
/**
|
|
58
79
|
* Format context usage as `<percent>%/<window>` when the model window is known.
|
|
59
80
|
* Unknown windows render as `<tokens>/?`, because `0.0%/0` suggests a real
|
|
@@ -71,6 +92,19 @@ export function formatContextUsage(
|
|
|
71
92
|
return `${pct}/${formatNumber(contextWindow)}`;
|
|
72
93
|
}
|
|
73
94
|
|
|
95
|
+
/** Chrome tone for a context-usage level; undefined while usage is normal. */
|
|
96
|
+
export function getContextUsageTone(level: ContextUsageLevel): TspTone | undefined {
|
|
97
|
+
switch (level) {
|
|
98
|
+
case "error":
|
|
99
|
+
return "error";
|
|
100
|
+
case "purple":
|
|
101
|
+
case "warning":
|
|
102
|
+
return "warning";
|
|
103
|
+
case "normal":
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
74
108
|
export function getContextUsageThemeColor(level: ContextUsageLevel): ThemeColor {
|
|
75
109
|
switch (level) {
|
|
76
110
|
case "error":
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reusable countdown timer for dialog components.
|
|
3
3
|
*/
|
|
4
|
+
import { node } from "../native/describe";
|
|
5
|
+
import type { NativeNode } from "../native/node";
|
|
6
|
+
import { isNativeRendering } from "../native/state";
|
|
4
7
|
import type { TUI } from "../tui";
|
|
5
8
|
export class CountdownTimer {
|
|
6
9
|
#intervalId: NodeJS.Timeout | undefined;
|
|
7
10
|
#expireTimeoutId: NodeJS.Timeout | undefined;
|
|
8
11
|
#remainingSeconds: number;
|
|
9
12
|
#deadlineMs = 0;
|
|
13
|
+
#node: NativeNode | undefined;
|
|
10
14
|
readonly #initialMs: number;
|
|
11
15
|
|
|
12
16
|
constructor(
|
|
@@ -28,6 +32,7 @@ export class CountdownTimer {
|
|
|
28
32
|
#start(): void {
|
|
29
33
|
const now = Date.now();
|
|
30
34
|
this.#deadlineMs = now + this.#initialMs;
|
|
35
|
+
this.#node = undefined;
|
|
31
36
|
this.#remainingSeconds = this.#calculateRemainingSeconds(now);
|
|
32
37
|
this.onTick(this.#remainingSeconds);
|
|
33
38
|
this.tui?.requestRender();
|
|
@@ -37,7 +42,25 @@ export class CountdownTimer {
|
|
|
37
42
|
this.onExpire();
|
|
38
43
|
}, this.#initialMs);
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
// The per-second tick only repaints the remaining time; a TSP terminal
|
|
46
|
+
// counts down the described `elapsed` node itself.
|
|
47
|
+
if (!isNativeRendering()) this.#startInterval();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The remaining time as a terminal-clocked `elapsed` node: its age is the
|
|
52
|
+
* negative remaining time (the start lies in the future), so it counts up
|
|
53
|
+
* toward zero and freezes there at expiry. The age is taken on the first
|
|
54
|
+
* call after a (re)start, when the node is first written, and the node is
|
|
55
|
+
* reused until {@link reset}.
|
|
56
|
+
*/
|
|
57
|
+
describe(): NativeNode {
|
|
58
|
+
this.#node ??= node("elapsed", {
|
|
59
|
+
age: Math.min(0, Date.now() - this.#deadlineMs),
|
|
60
|
+
stopped: 0,
|
|
61
|
+
format: "short",
|
|
62
|
+
});
|
|
63
|
+
return this.#node;
|
|
41
64
|
}
|
|
42
65
|
|
|
43
66
|
#startInterval(): void {
|
package/src/chrome/diff.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { diffWords } from "@oh-my-pi/pi-natives";
|
|
2
2
|
import { DEFAULT_TAB_WIDTH, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import type { TspDiffHunk, TspProps } from "@oh-my-pi/pi-wire";
|
|
3
4
|
import { theme as activeTheme, getLanguageFromPath, highlightCode, type Theme } from "../theme/index";
|
|
4
|
-
import { type CodeFrameMarker, formatCodeFrameLine, replaceTabs } from "../render/render-utils";
|
|
5
|
+
import { type CodeFrameMarker, formatCodeFrameLine, replaceTabs, shortenPath } from "../render/render-utils";
|
|
6
|
+
import { node } from "../native/describe";
|
|
7
|
+
import type { NativeNode } from "../native/node";
|
|
5
8
|
/** SGR dim on / normal intensity — additive, preserves fg/bg colors. */
|
|
6
9
|
const DIM = "\x1b[2m";
|
|
7
10
|
const DIM_OFF = "\x1b[22m";
|
|
@@ -97,6 +100,62 @@ function renderIntraLineDiff(
|
|
|
97
100
|
return { removedLine, addedLine };
|
|
98
101
|
}
|
|
99
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Native `diff` node for omp's compact diff text (`+12|added`, `-12|removed`,
|
|
105
|
+
* ` 12|context`, blank or `…` rows between regions). Each contiguous region
|
|
106
|
+
* becomes one hunk; the terminal draws gutters, word emphasis and highlighting.
|
|
107
|
+
* Removed rows carry old line numbers, added rows new ones and context rows
|
|
108
|
+
* old ones, so the other side is derived from the running line delta.
|
|
109
|
+
*/
|
|
110
|
+
export function nativeDiff(diffText: string, options: { filePath?: string } & TspProps<"diff"> = {}): NativeNode {
|
|
111
|
+
const { filePath, ...props } = options;
|
|
112
|
+
const hunks: TspDiffHunk[] = [];
|
|
113
|
+
let lines: string[] = [];
|
|
114
|
+
let oldStart = 0;
|
|
115
|
+
let newStart = 0;
|
|
116
|
+
// New-minus-old line offset accumulated over the regions already closed.
|
|
117
|
+
let delta = 0;
|
|
118
|
+
let regionDelta = 0;
|
|
119
|
+
let nextOld = 1;
|
|
120
|
+
const close = (): void => {
|
|
121
|
+
if (lines.length > 0) hunks.push({ oldStart, newStart, lines });
|
|
122
|
+
lines = [];
|
|
123
|
+
delta += regionDelta;
|
|
124
|
+
regionDelta = 0;
|
|
125
|
+
};
|
|
126
|
+
for (const raw of sanitizeText(diffText).split("\n")) {
|
|
127
|
+
const parsed = parseDiffLine(raw);
|
|
128
|
+
const trimmed = raw.trim();
|
|
129
|
+
if (!parsed || (parsed.prefix === " " && (parsed.content === "..." || parsed.content === "…"))) {
|
|
130
|
+
if (trimmed.length === 0 || trimmed === "..." || trimmed === "…") close();
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const number = Number.parseInt(parsed.lineNum.trim(), 10);
|
|
134
|
+
if (lines.length === 0) {
|
|
135
|
+
if (Number.isFinite(number)) {
|
|
136
|
+
oldStart = parsed.prefix === "+" ? number - delta : number;
|
|
137
|
+
newStart = parsed.prefix === "+" ? number : number + delta;
|
|
138
|
+
} else {
|
|
139
|
+
oldStart = nextOld;
|
|
140
|
+
newStart = nextOld + delta;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (parsed.prefix === "+") regionDelta++;
|
|
144
|
+
else {
|
|
145
|
+
if (parsed.prefix === "-") regionDelta--;
|
|
146
|
+
nextOld = (Number.isFinite(number) ? number : nextOld) + 1;
|
|
147
|
+
}
|
|
148
|
+
lines.push(`${parsed.prefix}${parsed.content}`);
|
|
149
|
+
}
|
|
150
|
+
close();
|
|
151
|
+
return node("diff", {
|
|
152
|
+
...props,
|
|
153
|
+
hunks,
|
|
154
|
+
path: props.path ?? (filePath ? shortenPath(filePath) : undefined),
|
|
155
|
+
lang: props.lang ?? (filePath ? getLanguageFromPath(filePath) : undefined),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
100
159
|
export interface RenderDiffOptions {
|
|
101
160
|
/** File path used to resolve indentation (.editorconfig + defaults) */
|
|
102
161
|
filePath?: string;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Component } from "../tui";
|
|
2
2
|
import { fgOrPlain, theme } from "../theme/index";
|
|
3
|
+
import type { NativeNode } from "../native/node";
|
|
4
|
+
import { EMPTY_NODE } from "../native/describe";
|
|
3
5
|
/**
|
|
4
6
|
* Dynamic border component that adjusts to viewport width.
|
|
5
7
|
*
|
|
@@ -23,6 +25,11 @@ export class DynamicBorder implements Component {
|
|
|
23
25
|
this.#cachedLines = undefined;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
/** Native terminals draw their own chrome; a border rule describes nothing. */
|
|
29
|
+
describe(): NativeNode {
|
|
30
|
+
return EMPTY_NODE;
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
render(width: number): readonly string[] {
|
|
27
34
|
if (this.#cachedLines && this.#cachedWidth === width) {
|
|
28
35
|
return this.#cachedLines;
|
package/src/chrome/format.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { renderProgressBar } from "../components/progress-bar";
|
|
2
2
|
import { shimmerText } from "../theme/shimmer";
|
|
3
3
|
import { theme as currentTheme, type Theme } from "../theme/theme";
|
|
4
|
+
import type { NativeNode } from "../native/node";
|
|
5
|
+
import { node } from "../native/describe";
|
|
4
6
|
|
|
5
7
|
/** Title-case a provider id for display (`openai-codex` → `Openai Codex`). */
|
|
6
8
|
export function formatProviderName(provider: string): string {
|
|
@@ -40,6 +42,16 @@ function resolveProgressBarTheme(uiTheme: ProgressBarTheme | undefined): Progres
|
|
|
40
42
|
return uiTheme ?? currentTheme ?? unstyledProgressBarTheme;
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Native {@link renderAsciiBar}: a terminal-drawn progress bar with the same
|
|
47
|
+
* percent label; `undefined` is indeterminate.
|
|
48
|
+
*/
|
|
49
|
+
export function describeAsciiBar(fraction: number | undefined): NativeNode {
|
|
50
|
+
if (fraction === undefined) return node("progress", { value: null });
|
|
51
|
+
const value = Math.min(1, Math.max(0, fraction));
|
|
52
|
+
return node("progress", { value, label: `${Math.round(value * 100)}%` });
|
|
53
|
+
}
|
|
54
|
+
|
|
43
55
|
/**
|
|
44
56
|
* Render an ASCII progress bar with a trailing percent label.
|
|
45
57
|
* `fraction` is clamped to `[0, 1]`. `undefined` renders a dotted placeholder.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { Component } from "../tui";
|
|
2
|
-
import { type ThemeColor, theme } from "../theme";
|
|
2
|
+
import { getThemeEpoch, type ThemeColor, theme } from "../theme";
|
|
3
3
|
import { truncateToWidth } from "../utils";
|
|
4
|
+
import { node, span, text } from "../native/describe";
|
|
5
|
+
import type { NativeNode } from "../native/node";
|
|
6
|
+
import { plainText } from "../native/spans";
|
|
7
|
+
import { Memo } from "../native/memo";
|
|
4
8
|
|
|
5
9
|
/** Presentation policy for a compact message divider. */
|
|
6
10
|
export interface MessageDividerOptions {
|
|
@@ -11,6 +15,13 @@ export interface MessageDividerOptions {
|
|
|
11
15
|
readonly ruleWidth?: number;
|
|
12
16
|
/** Preserve an intentionally untruncated legacy label at very narrow widths. */
|
|
13
17
|
readonly truncateWhenNarrow?: boolean;
|
|
18
|
+
/** Semantic role of the native node. */
|
|
19
|
+
readonly role?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Draw as an inline notice (this named icon and a one-line label without
|
|
22
|
+
* the leading glyph) instead of a labelled rule.
|
|
23
|
+
*/
|
|
24
|
+
readonly native?: { readonly icon: string; readonly label: () => string };
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
/**
|
|
@@ -20,6 +31,7 @@ export interface MessageDividerOptions {
|
|
|
20
31
|
export class MessageDividerComponent implements Component {
|
|
21
32
|
readonly #options: MessageDividerOptions;
|
|
22
33
|
#cache: { width: number; lines: readonly string[] } | undefined;
|
|
34
|
+
readonly #native = new Memo();
|
|
23
35
|
|
|
24
36
|
constructor(options: MessageDividerOptions) {
|
|
25
37
|
this.#options = options;
|
|
@@ -27,6 +39,26 @@ export class MessageDividerComponent implements Component {
|
|
|
27
39
|
|
|
28
40
|
invalidate(): void {
|
|
29
41
|
this.#cache = undefined;
|
|
42
|
+
this.#native.clear();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** An inline notice, else a labelled `rule`; the label is theme-aware, so it rebuilds on theme changes. */
|
|
46
|
+
describe(): NativeNode {
|
|
47
|
+
const inline = this.#options.native;
|
|
48
|
+
if (inline) {
|
|
49
|
+
return this.#native.get([getThemeEpoch()], () =>
|
|
50
|
+
node("row", { gap: "sm", role: this.#options.role ?? "omp.divider" }, [
|
|
51
|
+
node("icon", { name: inline.icon }),
|
|
52
|
+
text([span(inline.label(), this.#options.labelColor)], { truncate: "end" }),
|
|
53
|
+
]),
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return this.#native.get([getThemeEpoch()], () =>
|
|
57
|
+
node("rule", {
|
|
58
|
+
role: this.#options.role ?? "omp.divider",
|
|
59
|
+
label: [span(plainText(this.#options.label()), this.#options.labelColor)],
|
|
60
|
+
}),
|
|
61
|
+
);
|
|
30
62
|
}
|
|
31
63
|
|
|
32
64
|
render(width: number): readonly string[] {
|