@oh-my-pi/pi-tui 18.2.4 → 18.2.5
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,118 @@
|
|
|
1
|
+
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import { Container, Spacer } from "../index";
|
|
3
|
+
import { formatDuration, formatNumber } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { theme } from "../theme/theme";
|
|
5
|
+
import { formatMetricRow, MetricRow, type MetricSpec } from "../components/metric";
|
|
6
|
+
|
|
7
|
+
/** Below this the rate is nonsense (cached/instant responses yield absurd tok/s). */
|
|
8
|
+
const MIN_DURATION_MS = 100;
|
|
9
|
+
|
|
10
|
+
/** Local `YYYY-MM-DD HH:mm:ss` stamp for the per-turn usage row. */
|
|
11
|
+
function formatUsageTimestamp(ms: number): string {
|
|
12
|
+
const d = new Date(ms);
|
|
13
|
+
const pad = (n: number): string => String(n).padStart(2, "0");
|
|
14
|
+
const date = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
15
|
+
const time = `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
16
|
+
return `${date} ${time}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Prompt→yield wall time for a turn, from pure local timestamps: the user
|
|
21
|
+
* prompt's timestamp to the response's completion time (`completedAt`, stamped
|
|
22
|
+
* by the session at `message_end`). No provider-reported duration is involved —
|
|
23
|
+
* messages persisted before the stamp existed simply have no span.
|
|
24
|
+
* Undefined when either end is unknown (mid-attach or unstamped message).
|
|
25
|
+
*/
|
|
26
|
+
export function turnElapsedMs(
|
|
27
|
+
turnStartedAt: number | undefined,
|
|
28
|
+
message: { completedAt?: number },
|
|
29
|
+
): number | undefined {
|
|
30
|
+
if (turnStartedAt === undefined || message.completedAt === undefined) return undefined;
|
|
31
|
+
const elapsed = message.completedAt - turnStartedAt;
|
|
32
|
+
return elapsed > 0 ? Math.round(elapsed) : undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function usageRowSpecs(
|
|
36
|
+
usage: Usage,
|
|
37
|
+
durationMs?: number,
|
|
38
|
+
ttftMs?: number,
|
|
39
|
+
timestamp?: number,
|
|
40
|
+
turnElapsedMs?: number,
|
|
41
|
+
): MetricSpec[] {
|
|
42
|
+
const totalInput = usage.input + usage.cacheWrite;
|
|
43
|
+
const specs: MetricSpec[] = [];
|
|
44
|
+
// Lead with the turn's local wall-clock time (down to the second), log-line style.
|
|
45
|
+
if (timestamp !== undefined && Number.isFinite(timestamp) && timestamp > 0) {
|
|
46
|
+
specs.push({ value: formatUsageTimestamp(timestamp) });
|
|
47
|
+
}
|
|
48
|
+
// The delta the operator actually waited, bare with a space so it scans
|
|
49
|
+
// apart from the TTFT figure below (which keeps the clock icon).
|
|
50
|
+
// `message.duration` comes from performance.now(), so the combined value is
|
|
51
|
+
// fractional; round before formatDuration so the label never prints a raw
|
|
52
|
+
// float (e.g. `347.28381699998863ms`).
|
|
53
|
+
if (turnElapsedMs !== undefined && turnElapsedMs > 0) {
|
|
54
|
+
specs.push({ value: `Δ ${formatDuration(Math.round(turnElapsedMs))}` });
|
|
55
|
+
}
|
|
56
|
+
specs.push({ leading: theme.icon.input, value: formatNumber(totalInput) });
|
|
57
|
+
specs.push({ leading: theme.icon.output, value: formatNumber(usage.output) });
|
|
58
|
+
if (usage.cacheRead > 0) {
|
|
59
|
+
specs.push({ leading: theme.icon.cache, value: formatNumber(usage.cacheRead) });
|
|
60
|
+
}
|
|
61
|
+
if (ttftMs && ttftMs > 0) {
|
|
62
|
+
specs.push({ leading: theme.icon.time, value: `${(ttftMs / 1000).toFixed(1)}s` });
|
|
63
|
+
}
|
|
64
|
+
if (durationMs && durationMs > MIN_DURATION_MS && usage.output > 0) {
|
|
65
|
+
// TPS over the total request duration — the post-TTFT window undercounts
|
|
66
|
+
// generation time when reasoning tokens are hidden before the first
|
|
67
|
+
// visible byte, inflating the rate.
|
|
68
|
+
const tokPerSec = (usage.output / durationMs) * 1000;
|
|
69
|
+
specs.push({ leading: theme.icon.throughput, value: `${tokPerSec.toFixed(1)}/s` });
|
|
70
|
+
}
|
|
71
|
+
return specs;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Format the metrics shared by standalone usage blocks and compact tool groups. */
|
|
75
|
+
export function formatUsageRow(
|
|
76
|
+
usage: Usage,
|
|
77
|
+
durationMs?: number,
|
|
78
|
+
ttftMs?: number,
|
|
79
|
+
timestamp?: number,
|
|
80
|
+
turnElapsedMs?: number,
|
|
81
|
+
): string {
|
|
82
|
+
return formatMetricRow(usageRowSpecs(usage, durationMs, ttftMs, timestamp, turnElapsedMs), {
|
|
83
|
+
separator: " ",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Blocks minted by {@link createUsageRowBlock}, so transcript walkers can attribute them to the turn above. */
|
|
88
|
+
const usageRowBlocks = new WeakSet<Container>();
|
|
89
|
+
|
|
90
|
+
/** Whether `component` is a per-turn usage/metrics row from {@link createUsageRowBlock}. */
|
|
91
|
+
export function isUsageRowBlock(component: object): boolean {
|
|
92
|
+
return usageRowBlocks.has(component as Container);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// `timestamp` and `turnElapsedMs` are optional and trail the throughput args to
|
|
96
|
+
// preserve the existing (usage, durationMs, ttftMs) call contract — this
|
|
97
|
+
// function is part of the package's public export surface (./modes/components/*).
|
|
98
|
+
export function createUsageRowBlock(
|
|
99
|
+
usage: Usage,
|
|
100
|
+
durationMs?: number,
|
|
101
|
+
ttftMs?: number,
|
|
102
|
+
timestamp?: number,
|
|
103
|
+
turnElapsedMs?: number,
|
|
104
|
+
): Container {
|
|
105
|
+
const block = new Container();
|
|
106
|
+
block.addChild(new Spacer(1));
|
|
107
|
+
block.addChild(
|
|
108
|
+
new MetricRow(usageRowSpecs(usage, durationMs, ttftMs, timestamp, turnElapsedMs), {
|
|
109
|
+
separator: " ",
|
|
110
|
+
overflow: "wrap",
|
|
111
|
+
paddingX: 1,
|
|
112
|
+
paddingY: 0,
|
|
113
|
+
style: text => theme.fg("dim", text),
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
usageRowBlocks.add(block);
|
|
117
|
+
return block;
|
|
118
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import {
|
|
3
|
+
type Component,
|
|
4
|
+
getImageDimensions,
|
|
5
|
+
getKittyGraphics,
|
|
6
|
+
type ImageBudget,
|
|
7
|
+
ImageProtocol,
|
|
8
|
+
renderImage,
|
|
9
|
+
replaceTabs,
|
|
10
|
+
TERMINAL,
|
|
11
|
+
truncateToWidth,
|
|
12
|
+
visibleWidth,
|
|
13
|
+
} from "../index";
|
|
14
|
+
import { fileHyperlink } from "../render/hyperlink";
|
|
15
|
+
import { convertImageToPng } from "../chat/image-loading";
|
|
16
|
+
import { attachmentSgr } from "./composer-attachments";
|
|
17
|
+
import { cachedImageDimensions, setCachedImageDimensions } from "./image-references";
|
|
18
|
+
import { theme } from "../theme/theme";
|
|
19
|
+
import type { ComposerChipDescriptor, CustomEditor, TextAttachment } from "./custom-editor";
|
|
20
|
+
|
|
21
|
+
/** Chip card geometry (mirrors omp2): a 12x4 content area inside a 1-cell rounded border. */
|
|
22
|
+
const INNER_COLS = 12;
|
|
23
|
+
const INNER_ROWS = 4;
|
|
24
|
+
const CARD_COLS = INNER_COLS + 2;
|
|
25
|
+
const CARD_GAP = 2;
|
|
26
|
+
const RESET_FG = "\x1b[39m";
|
|
27
|
+
/** Symbol-keyed PNG conversion cache on the draft image (same pattern as the dimension
|
|
28
|
+
* probe cache): Kitty's `f=100` transmit accepts only PNG, so non-PNG attachments
|
|
29
|
+
* (pastes are usually re-encoded JPEG/WebP) convert before transmit — the same pipeline
|
|
30
|
+
* the transcript uses. `null` = conversion in flight or failed. */
|
|
31
|
+
const kImagePng = Symbol("omp.imagePng");
|
|
32
|
+
|
|
33
|
+
interface ImageContentWithPng extends ImageContent {
|
|
34
|
+
[kImagePng]?: ImageContent | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The composer attachment band: one rounded card per staged attachment, rendered directly above
|
|
39
|
+
* the prompt box. Image and video cards show a live thumbnail (Kitty Unicode placeholders — the only
|
|
40
|
+
* protocol whose output is plain text cells and therefore composable inside a border row) with
|
|
41
|
+
* the pixel dimensions as the bottom caption; text-paste cards show the leading snippet with a
|
|
42
|
+
* `+N lines` / `N chars` caption. The top caption is the same `<icon> #N` token that sits in
|
|
43
|
+
* the editor buffer, in the same identity color. Cards that no longer fit the terminal width
|
|
44
|
+
* are omitted rather than wrapped. Renders to nothing while no attachment is staged.
|
|
45
|
+
*/
|
|
46
|
+
export class AttachmentChipsBand implements Component {
|
|
47
|
+
constructor(
|
|
48
|
+
private readonly editor: CustomEditor,
|
|
49
|
+
private readonly budget: ImageBudget,
|
|
50
|
+
private readonly requestRender: () => void,
|
|
51
|
+
) {}
|
|
52
|
+
|
|
53
|
+
render(width: number): readonly string[] {
|
|
54
|
+
const chips = this.editor.composerChips();
|
|
55
|
+
if (chips.length === 0) return [];
|
|
56
|
+
const rows = ["", "", "", "", "", ""];
|
|
57
|
+
const gap = " ".repeat(CARD_GAP);
|
|
58
|
+
let x = 0;
|
|
59
|
+
for (const chip of chips) {
|
|
60
|
+
if (x + CARD_COLS > width) break;
|
|
61
|
+
const card = this.#card(chip);
|
|
62
|
+
for (let r = 0; r < rows.length; r++) rows[r] += (x > 0 ? gap : "") + card[r];
|
|
63
|
+
x += (x > 0 ? CARD_GAP : 0) + CARD_COLS;
|
|
64
|
+
}
|
|
65
|
+
return rows;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#card(chip: ComposerChipDescriptor): string[] {
|
|
69
|
+
const sgr = attachmentSgr(chip.kind, chip.n);
|
|
70
|
+
const icon = theme.symbol(
|
|
71
|
+
chip.kind === "paste" ? "chip.paste" : chip.kind === "video" ? "chip.video" : "chip.image",
|
|
72
|
+
);
|
|
73
|
+
let bottomCaption: string;
|
|
74
|
+
let interior: string[];
|
|
75
|
+
if (chip.kind !== "paste") {
|
|
76
|
+
const dims = this.#imageDims(chip.image);
|
|
77
|
+
bottomCaption = dims ? `${dims.width}x${dims.height}` : "";
|
|
78
|
+
interior = this.#imageInterior(chip.image, dims, chip.kind);
|
|
79
|
+
} else {
|
|
80
|
+
bottomCaption = chip.text.lineCount > 1 ? `+${chip.text.lineCount} lines` : `${chip.text.charCount} chars`;
|
|
81
|
+
interior = this.#textInterior(chip.text);
|
|
82
|
+
}
|
|
83
|
+
const vertical = `${sgr}${theme.symbol("boxRound.vertical")}${RESET_FG}`;
|
|
84
|
+
const title =
|
|
85
|
+
chip.kind === "paste" || !chip.link ? `${icon} #${chip.n}` : fileHyperlink(chip.link, `${icon} #${chip.n}`);
|
|
86
|
+
return [
|
|
87
|
+
this.#borderRow(sgr, title, "top"),
|
|
88
|
+
...interior.map(row => vertical + row + vertical),
|
|
89
|
+
this.#borderRow(sgr, bottomCaption, "bottom"),
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Horizontal border with an optional centered, bold caption padded by one space per side. */
|
|
94
|
+
#borderRow(sgr: string, caption: string, edge: "top" | "bottom"): string {
|
|
95
|
+
const left = theme.symbol(edge === "top" ? "boxRound.topLeft" : "boxRound.bottomLeft");
|
|
96
|
+
const right = theme.symbol(edge === "top" ? "boxRound.topRight" : "boxRound.bottomRight");
|
|
97
|
+
const horizontal = theme.symbol("boxRound.horizontal");
|
|
98
|
+
if (!caption) return `${sgr}${left}${horizontal.repeat(INNER_COLS)}${right}${RESET_FG}`;
|
|
99
|
+
const cut = truncateToWidth(caption, INNER_COLS - 2);
|
|
100
|
+
const fill = INNER_COLS - visibleWidth(cut) - 2;
|
|
101
|
+
const leftFill = Math.max(0, Math.floor(fill / 2));
|
|
102
|
+
const rightFill = Math.max(0, fill - leftFill);
|
|
103
|
+
return `${sgr}${left}${horizontal.repeat(leftFill)} \x1b[1m${cut}\x1b[22m ${horizontal.repeat(rightFill)}${right}${RESET_FG}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Pixel dimensions for the caption/thumbnail fit, probed once from the header bytes and
|
|
107
|
+
* cached on the image object (`null` = undecodable header, never re-probed). */
|
|
108
|
+
#imageDims(image: ImageContent): { width: number; height: number } | null {
|
|
109
|
+
let dims = cachedImageDimensions(image);
|
|
110
|
+
if (dims === undefined) {
|
|
111
|
+
const probed = getImageDimensions(image.data, image.mimeType);
|
|
112
|
+
dims = probed ? { width: probed.widthPx, height: probed.heightPx } : null;
|
|
113
|
+
setCachedImageDimensions(image, dims);
|
|
114
|
+
}
|
|
115
|
+
return dims;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** 12x4 thumbnail as Kitty Unicode-placeholder cell rows, centered; any other protocol (or a
|
|
119
|
+
* budget-suppressed image) falls back to a centered icon — direct placements, SIXEL, and
|
|
120
|
+
* iTerm2 output cursor-addressed sequences that cannot be composed into a border row. */
|
|
121
|
+
#imageInterior(
|
|
122
|
+
image: ImageContent,
|
|
123
|
+
dims: { width: number; height: number } | null,
|
|
124
|
+
kind: "image" | "video",
|
|
125
|
+
): string[] {
|
|
126
|
+
if (dims && TERMINAL.imageProtocol === ImageProtocol.Kitty && getKittyGraphics().unicodePlaceholders) {
|
|
127
|
+
const display = this.#kittyDisplayImage(image);
|
|
128
|
+
if (display) {
|
|
129
|
+
const budget = this.budget;
|
|
130
|
+
const imageId = budget.acquireId(
|
|
131
|
+
`chip:${display.mimeType}:${display.data.length}:${display.data.slice(0, 32)}`,
|
|
132
|
+
);
|
|
133
|
+
// observe() keeps chip thumbnails inside the shared live-graphics budget so a
|
|
134
|
+
// paste-heavy session cannot pile up placements the way unbudgeted images would.
|
|
135
|
+
if (!budget.observe(imageId)) {
|
|
136
|
+
const result = renderImage(
|
|
137
|
+
display.data,
|
|
138
|
+
{ widthPx: dims.width, heightPx: dims.height },
|
|
139
|
+
{
|
|
140
|
+
maxWidthCells: INNER_COLS,
|
|
141
|
+
maxHeightCells: INNER_ROWS,
|
|
142
|
+
imageId,
|
|
143
|
+
includeTransmit: budget.shouldTransmit(imageId),
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
if (result?.transmit) budget.enqueueTransmit(imageId, result.transmit);
|
|
147
|
+
if (result?.lines) return this.#centerGrid(result.lines);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const icon = theme.symbol(kind === "video" ? "chip.video" : "chip.image");
|
|
152
|
+
const pad = INNER_COLS - visibleWidth(icon);
|
|
153
|
+
const iconRow = " ".repeat(Math.floor(pad / 2)) + theme.fg("muted", icon) + " ".repeat(Math.ceil(pad / 2));
|
|
154
|
+
return [" ".repeat(INNER_COLS), iconRow, " ".repeat(INNER_COLS), " ".repeat(INNER_COLS)];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** PNG form of `image` for the Kitty transmit; non-PNG sources convert asynchronously.
|
|
158
|
+
* Returns undefined while the conversion is pending (or after it failed), letting the
|
|
159
|
+
* caller fall back to the icon; a finished conversion triggers a repaint. */
|
|
160
|
+
#kittyDisplayImage(image: ImageContent): ImageContent | undefined {
|
|
161
|
+
if (image.mimeType === "image/png") return image;
|
|
162
|
+
const cached = (image as ImageContentWithPng)[kImagePng];
|
|
163
|
+
if (cached !== undefined) return cached ?? undefined;
|
|
164
|
+
(image as ImageContentWithPng)[kImagePng] = null;
|
|
165
|
+
convertImageToPng(image)
|
|
166
|
+
.then(converted => {
|
|
167
|
+
(image as ImageContentWithPng)[kImagePng] = converted;
|
|
168
|
+
this.requestRender();
|
|
169
|
+
})
|
|
170
|
+
.catch(() => {});
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Center a placeholder cell grid (≤ 12 columns, ≤ 4 rows) inside the content area. */
|
|
175
|
+
#centerGrid(lines: string[]): string[] {
|
|
176
|
+
const rows: string[] = [];
|
|
177
|
+
const topPad = Math.floor((INNER_ROWS - lines.length) / 2);
|
|
178
|
+
for (let r = 0; r < INNER_ROWS; r++) {
|
|
179
|
+
const line = lines[r - topPad];
|
|
180
|
+
if (line === undefined) {
|
|
181
|
+
rows.push(" ".repeat(INNER_COLS));
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const pad = Math.max(0, INNER_COLS - visibleWidth(line));
|
|
185
|
+
rows.push(" ".repeat(Math.floor(pad / 2)) + line + " ".repeat(Math.ceil(pad / 2)));
|
|
186
|
+
}
|
|
187
|
+
return rows;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Leading 4 rows x 12 cols of the pasted text, muted. */
|
|
191
|
+
#textInterior(entry: TextAttachment): string[] {
|
|
192
|
+
const lines = entry.content.split("\n");
|
|
193
|
+
const rows: string[] = [];
|
|
194
|
+
for (let r = 0; r < INNER_ROWS; r++) {
|
|
195
|
+
const cut = truncateToWidth(replaceTabs(lines[r] ?? ""), INNER_COLS);
|
|
196
|
+
const pad = INNER_COLS - visibleWidth(cut);
|
|
197
|
+
rows.push(theme.fg("muted", cut) + " ".repeat(Math.max(0, pad)));
|
|
198
|
+
}
|
|
199
|
+
return rows;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { allowsModelMentions, allowsSkillTokens, SKILL_TOKEN_RE } from "./skill-tokens";
|
|
2
|
+
import { MODEL_MENTION_RE, modelMentionToken } from "./model-mention-syntax";
|
|
3
|
+
import { SYMBOL_PRESETS } from "../theme/symbols";
|
|
4
|
+
import { type ThemeColor, theme } from "../theme/theme";
|
|
5
|
+
|
|
6
|
+
/** Attachment chip kinds staged in the composer: images, video previews, and large text pastes. */
|
|
7
|
+
export type ChipKind = "image" | "video" | "paste";
|
|
8
|
+
|
|
9
|
+
/** Compact atomic composer token for an invoked skill in the active symbol preset. */
|
|
10
|
+
export function skillChipLabel(name: string): string {
|
|
11
|
+
const icon =
|
|
12
|
+
typeof theme === "undefined"
|
|
13
|
+
? SYMBOL_PRESETS.unicode["icon.extensionSkill"]
|
|
14
|
+
: theme.symbol("icon.extensionSkill");
|
|
15
|
+
return `${icon} ${name}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Compact atomic composer token for a model mention in the active symbol preset. */
|
|
19
|
+
export function modelMentionChipLabel(name: string): string {
|
|
20
|
+
const icon = typeof theme === "undefined" ? SYMBOL_PRESETS.unicode["icon.model"] : theme.symbol("icon.model");
|
|
21
|
+
return `${icon} ${name}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Canonical `/skill:<name>` token a skill chip expands to on submit. */
|
|
25
|
+
export function skillToken(name: string): string {
|
|
26
|
+
return `/skill:${name}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function chipPillStyle(label: string, color: ThemeColor, restore: string): string {
|
|
30
|
+
if (typeof theme === "undefined") return label;
|
|
31
|
+
return `${theme.getBgAnsi("customMessageBg")}${theme.getFgAnsi(color)}\x1b[1m${label}\x1b[22m${restore}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Soft-pill styling for a skill chip: bold skill label color over the custom-message
|
|
36
|
+
* tint. `restore` re-arms the surrounding foreground/background after the chip.
|
|
37
|
+
*/
|
|
38
|
+
export function skillChipStyle(label: string, restore = "\x1b[39m\x1b[49m"): string {
|
|
39
|
+
return chipPillStyle(label, "customMessageLabel", restore);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Soft-pill styling for a model mention, restoring the surrounding colors afterward. */
|
|
43
|
+
export function modelChipStyle(label: string, restore = "\x1b[39m\x1b[49m"): string {
|
|
44
|
+
return chipPillStyle(label, "statusLineModel", restore);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Every glyph a skill chip may start with, across all symbol presets. */
|
|
48
|
+
const SKILL_ICONS = [...new Set(Object.values(SYMBOL_PRESETS).map(m => m["icon.extensionSkill"]))];
|
|
49
|
+
|
|
50
|
+
/** Skill names as they appear in chips: word characters and dashes, dots only between segments. */
|
|
51
|
+
const SKILL_NAME_SOURCE = "[\\w-]+(?:\\.[\\w-]+)*";
|
|
52
|
+
|
|
53
|
+
const SKILL_CHIP_SOURCE = `(?:${SKILL_ICONS.map(icon =>
|
|
54
|
+
/^[a-z]+$/i.test(icon) ? `(?<![A-Za-z])${RegExp.escape(icon)}` : RegExp.escape(icon),
|
|
55
|
+
).join("|")}) (${SKILL_NAME_SOURCE})(?![\\w-])`;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Replaces `/skill:<name>` tokens for known skills with compact chip labels and
|
|
59
|
+
* registers each label's token as its atomic editor expansion. Leaves the text
|
|
60
|
+
* untouched when skill tokens are not invocations in this draft (see
|
|
61
|
+
* {@link allowsSkillTokens}).
|
|
62
|
+
*/
|
|
63
|
+
export function collapseSkillTokens(
|
|
64
|
+
text: string,
|
|
65
|
+
isKnown: (name: string) => boolean,
|
|
66
|
+
register: (label: string, expansion: string) => void,
|
|
67
|
+
): string {
|
|
68
|
+
if (!text.includes("/skill:") || !allowsSkillTokens(text)) return text;
|
|
69
|
+
SKILL_TOKEN_RE.lastIndex = 0;
|
|
70
|
+
return text.replace(SKILL_TOKEN_RE, (match, delimiter: string, name: string) => {
|
|
71
|
+
if (!isKnown(name)) return match;
|
|
72
|
+
const label = skillChipLabel(name);
|
|
73
|
+
register(label, skillToken(name));
|
|
74
|
+
return `${delimiter}${label}`;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Replaces mentionable model selectors with their display chips and registers
|
|
80
|
+
* each chip's canonical selector as its atomic editor expansion.
|
|
81
|
+
*/
|
|
82
|
+
export function collapseModelMentions(
|
|
83
|
+
text: string,
|
|
84
|
+
labelFor: (selector: string) => string | undefined,
|
|
85
|
+
register: (label: string, expansion: string) => void,
|
|
86
|
+
): string {
|
|
87
|
+
if (!text.includes("^") || !allowsModelMentions(text)) return text;
|
|
88
|
+
MODEL_MENTION_RE.lastIndex = 0;
|
|
89
|
+
return text.replace(MODEL_MENTION_RE, (match, delimiter: string, selector: string) => {
|
|
90
|
+
const label = labelFor(selector);
|
|
91
|
+
if (label === undefined) return match;
|
|
92
|
+
register(label, modelMentionToken(selector));
|
|
93
|
+
return `${delimiter}${label}`;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const CHIP_ICON_KEY = { image: "chip.image", video: "chip.video", paste: "chip.paste" } as const;
|
|
98
|
+
|
|
99
|
+
/** Compact atomic composer token for attachment `n` in the active symbol preset. */
|
|
100
|
+
export function chipLabel(kind: ChipKind, n: number): string {
|
|
101
|
+
const icon =
|
|
102
|
+
typeof theme === "undefined" ? SYMBOL_PRESETS.unicode[CHIP_ICON_KEY[kind]] : theme.symbol(CHIP_ICON_KEY[kind]);
|
|
103
|
+
return `${icon} #${n}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Every glyph a chip token may start with, across all symbol presets. */
|
|
107
|
+
const CHIP_ICONS: Record<ChipKind, readonly string[]> = {
|
|
108
|
+
image: [...new Set(Object.values(SYMBOL_PRESETS).map(m => m[CHIP_ICON_KEY.image]))],
|
|
109
|
+
video: [...new Set(Object.values(SYMBOL_PRESETS).map(m => m[CHIP_ICON_KEY.video]))],
|
|
110
|
+
paste: [...new Set(Object.values(SYMBOL_PRESETS).map(m => m[CHIP_ICON_KEY.paste]))],
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const CHIP_TOKEN_SOURCE = `(?:${[...CHIP_ICONS.image, ...CHIP_ICONS.video, ...CHIP_ICONS.paste]
|
|
114
|
+
.map(icon => (/^[a-z]+$/i.test(icon) ? `(?<![A-Za-z])${RegExp.escape(icon)}` : RegExp.escape(icon)))
|
|
115
|
+
.join("|")}) #[1-9]\\d*`;
|
|
116
|
+
|
|
117
|
+
/** Infers an attachment kind from a chip label emitted by any configured symbol preset. */
|
|
118
|
+
export function chipLabelKind(label: string): ChipKind {
|
|
119
|
+
if (CHIP_ICONS.image.some(icon => label.startsWith(icon))) return "image";
|
|
120
|
+
if (CHIP_ICONS.video.some(icon => label.startsWith(icon))) return "video";
|
|
121
|
+
return "paste";
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const ATTACHMENT_PALETTE: readonly [number, number, number][] = [
|
|
125
|
+
[255, 179, 102],
|
|
126
|
+
[125, 207, 255],
|
|
127
|
+
[189, 147, 249],
|
|
128
|
+
[105, 220, 158],
|
|
129
|
+
[255, 141, 188],
|
|
130
|
+
[240, 223, 120],
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
/** Stable RGB color assigned to attachment `n`; each attachment type uses a distinct palette offset. */
|
|
134
|
+
export function attachmentRgb(kind: ChipKind, n: number): readonly [number, number, number] {
|
|
135
|
+
const index =
|
|
136
|
+
kind === "image"
|
|
137
|
+
? (n - 1) % ATTACHMENT_PALETTE.length
|
|
138
|
+
: kind === "video"
|
|
139
|
+
? (n + 1) % ATTACHMENT_PALETTE.length
|
|
140
|
+
: (n + 2) % ATTACHMENT_PALETTE.length;
|
|
141
|
+
return ATTACHMENT_PALETTE[index];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** ANSI truecolor foreground sequence for the color assigned by {@link attachmentRgb}. */
|
|
145
|
+
export function attachmentSgr(kind: ChipKind, n: number): string {
|
|
146
|
+
const [r, g, b] = attachmentRgb(kind, n);
|
|
147
|
+
return `\x1b[38;2;${r};${g};${b}m`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Matches expanded image, video, and paste markers, including optional marker metadata. */
|
|
151
|
+
export const PLACEHOLDER_REGEX = /\[(Image|Video|Paste) #([1-9]\d*)(?:,[^\]\n]*)?\]/g;
|
|
152
|
+
/** Matches an expanded attachment marker, a compact attachment chip, or a skill chip. */
|
|
153
|
+
export const COMPOSER_TOKEN_REGEX = new RegExp(
|
|
154
|
+
`${PLACEHOLDER_REGEX.source}|${CHIP_TOKEN_SOURCE}|${SKILL_CHIP_SOURCE}`,
|
|
155
|
+
"gu",
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
/** Add the registered model-chip labels to the composer placeholder matcher. */
|
|
159
|
+
export function composerTokenRegex(mentionLabels: Iterable<string>): RegExp {
|
|
160
|
+
const labels = [...new Set(mentionLabels)].sort((a, b) => b.length - a.length);
|
|
161
|
+
if (labels.length === 0) return COMPOSER_TOKEN_REGEX;
|
|
162
|
+
return new RegExp(
|
|
163
|
+
`${COMPOSER_TOKEN_REGEX.source}|(?<mention>${labels.map(label => RegExp.escape(label)).join("|")})`,
|
|
164
|
+
"gu",
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const VISION_MARKER_REGEX = /\[(Image|Video) #([1-9]\d*)((?:,[^\]\n]*)?)\](?: attachment:\/\/(\2))?/g;
|
|
169
|
+
|
|
170
|
+
/** Offsets image marker indices, including matching `attachment://` references. */
|
|
171
|
+
export function shiftImageMarkers(text: string, offset: number): string {
|
|
172
|
+
if (offset === 0) return text;
|
|
173
|
+
return text.replace(
|
|
174
|
+
VISION_MARKER_REGEX,
|
|
175
|
+
(_match, kind: string, idx: string, tail: string, attachmentIdx: string | undefined) => {
|
|
176
|
+
const marker = `[${kind} #${Number(idx) + offset}${tail}]`;
|
|
177
|
+
return attachmentIdx === undefined ? marker : `${marker} attachment://${Number(attachmentIdx) + offset}`;
|
|
178
|
+
},
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Replaces valid expanded image markers with compact tokens and registers each
|
|
184
|
+
* token's original marker as its atomic editor expansion.
|
|
185
|
+
*/
|
|
186
|
+
export function collapseImageMarkers(
|
|
187
|
+
text: string,
|
|
188
|
+
imageCount: number,
|
|
189
|
+
register: (label: string, expansion: string) => void,
|
|
190
|
+
): string {
|
|
191
|
+
if (imageCount === 0) return text;
|
|
192
|
+
return text.replace(VISION_MARKER_REGEX, (match, kind: string, idx: string, tail: string) => {
|
|
193
|
+
const n = Number(idx);
|
|
194
|
+
if (n > imageCount) return match;
|
|
195
|
+
const chipKind = kind === "Video" ? "video" : "image";
|
|
196
|
+
const label = chipLabel(chipKind, n);
|
|
197
|
+
register(label, `[${kind} #${n}${tail}]`);
|
|
198
|
+
return label;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Drops unreferenced vision attachments from a submission and densely remaps
|
|
204
|
+
* retained image/video markers. Returns `null` when no compaction is needed.
|
|
205
|
+
*/
|
|
206
|
+
export function compactImageMarkers(text: string, imageCount: number): { text: string; keep: number[] } | null {
|
|
207
|
+
if (imageCount === 0) return null;
|
|
208
|
+
const referenced = new Set<number>();
|
|
209
|
+
const scanner = new RegExp(VISION_MARKER_REGEX.source, "g");
|
|
210
|
+
for (;;) {
|
|
211
|
+
const match = scanner.exec(text);
|
|
212
|
+
if (match === null) break;
|
|
213
|
+
const n = Number(match[2]);
|
|
214
|
+
if (n <= imageCount) referenced.add(n);
|
|
215
|
+
}
|
|
216
|
+
if (referenced.size === imageCount) return null;
|
|
217
|
+
const keep = [...referenced].sort((a, b) => a - b);
|
|
218
|
+
const remap = new Map<number, number>(keep.map((n, i) => [n, i + 1]));
|
|
219
|
+
const rewritten = text.replace(
|
|
220
|
+
VISION_MARKER_REGEX,
|
|
221
|
+
(match, kind: string, idx: string, tail: string, attachmentIdx: string | undefined) => {
|
|
222
|
+
const mapped = remap.get(Number(idx));
|
|
223
|
+
if (mapped === undefined) return match;
|
|
224
|
+
const marker = `[${kind} #${mapped}${tail}]`;
|
|
225
|
+
return attachmentIdx === undefined ? marker : `${marker} attachment://${mapped}`;
|
|
226
|
+
},
|
|
227
|
+
);
|
|
228
|
+
return { text: rewritten, keep: keep.map(n => n - 1) };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Attachment kinds understood by placeholder renderers. */
|
|
232
|
+
export type PlaceholderKind = "image" | "video" | "paste";
|
|
233
|
+
|
|
234
|
+
/** Rendering callbacks for plain text and parsed attachment references. */
|
|
235
|
+
export interface PlaceholderRenderers {
|
|
236
|
+
/** Renders text outside attachment references. */
|
|
237
|
+
renderText: (text: string) => string;
|
|
238
|
+
/** Renders one parsed marker or compact chip token. */
|
|
239
|
+
renderReference: (label: string, kind: PlaceholderKind, index: number, form: "marker" | "chip") => string;
|
|
240
|
+
/** Renders one skill chip (`<icon> <name>`). */
|
|
241
|
+
renderSkill: (label: string, name: string) => string;
|
|
242
|
+
/** Renders one registered model mention chip. */
|
|
243
|
+
renderMention: (label: string) => string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Renders text while treating expanded markers, attachment chips, skill chips, and model mentions as distinct references. */
|
|
247
|
+
export function renderPlaceholders(
|
|
248
|
+
text: string,
|
|
249
|
+
renderers: PlaceholderRenderers,
|
|
250
|
+
tokenRegex: RegExp = COMPOSER_TOKEN_REGEX,
|
|
251
|
+
): string {
|
|
252
|
+
tokenRegex.lastIndex = 0;
|
|
253
|
+
let result = "";
|
|
254
|
+
let last = 0;
|
|
255
|
+
let matched = false;
|
|
256
|
+
|
|
257
|
+
for (;;) {
|
|
258
|
+
const match = tokenRegex.exec(text);
|
|
259
|
+
if (match === null) break;
|
|
260
|
+
matched = true;
|
|
261
|
+
if (match.index > last) result += renderers.renderText(text.slice(last, match.index));
|
|
262
|
+
const label = match[0];
|
|
263
|
+
if (match.groups?.mention !== undefined) {
|
|
264
|
+
result += renderers.renderMention(label);
|
|
265
|
+
} else if (label.startsWith("[")) {
|
|
266
|
+
const kind: PlaceholderKind = match[1] === "Paste" ? "paste" : match[1] === "Video" ? "video" : "image";
|
|
267
|
+
result += renderers.renderReference(label, kind, Number(match[2]), "marker");
|
|
268
|
+
} else if (match[3] !== undefined) {
|
|
269
|
+
result += renderers.renderSkill(label, match[3]);
|
|
270
|
+
} else {
|
|
271
|
+
const index = Number(label.slice(label.lastIndexOf("#") + 1));
|
|
272
|
+
result += renderers.renderReference(label, chipLabelKind(label), index, "chip");
|
|
273
|
+
}
|
|
274
|
+
last = match.index + match[0].length;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!matched) return renderers.renderText(text);
|
|
278
|
+
if (last < text.length) result += renderers.renderText(text.slice(last));
|
|
279
|
+
return result;
|
|
280
|
+
}
|