@oh-my-pi/pi-tui 18.2.4 → 18.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +43 -0
- package/dist/types/app-keybindings.d.ts +395 -0
- package/dist/types/apps/autoresearch-dashboard.d.ts +43 -0
- package/dist/types/apps/autoresearch-data.d.ts +15 -0
- package/dist/types/apps/cleanse-board.d.ts +66 -0
- package/dist/types/apps/cleanse-picker.d.ts +23 -0
- package/dist/types/apps/debug/log-formatting.d.ts +6 -0
- package/dist/types/apps/debug/log-viewer.d.ts +81 -0
- package/dist/types/apps/debug/protocol-probe.d.ts +42 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +58 -0
- package/dist/types/apps/debug/raw-sse.d.ts +26 -0
- package/dist/types/apps/debug/terminal-info.d.ts +34 -0
- package/dist/types/apps/debug/viewer-frame.d.ts +52 -0
- package/dist/types/apps/git/avatar.d.ts +9 -0
- package/dist/types/apps/git/colors.d.ts +49 -0
- package/dist/types/apps/git/diff-pane.d.ts +188 -0
- package/dist/types/apps/git/git-tui.d.ts +66 -0
- package/dist/types/apps/git/sidebar.d.ts +149 -0
- package/dist/types/apps/git/state.d.ts +117 -0
- package/dist/types/apps/if-bench-board.d.ts +75 -0
- package/dist/types/apps/live-visualizer.d.ts +33 -0
- package/dist/types/apps/ps-data.d.ts +51 -0
- package/dist/types/apps/ps-top.d.ts +33 -0
- package/dist/types/apps/session-picker.d.ts +26 -0
- package/dist/types/apps/setup-model-picker.d.ts +13 -0
- package/dist/types/apps/standalone-picker.d.ts +42 -0
- package/dist/types/autocomplete.d.ts +4 -0
- package/dist/types/chat/advisor-message.d.ts +11 -0
- package/dist/types/chat/assistant-message.d.ts +106 -0
- package/dist/types/chat/background-tan-message.d.ts +9 -0
- package/dist/types/chat/bash-execution.d.ts +47 -0
- package/dist/types/chat/cache-invalidation-marker.d.ts +50 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +50 -0
- package/dist/types/chat/collab-prompt-message.d.ts +10 -0
- package/dist/types/chat/compaction-summary-message.d.ts +54 -0
- package/dist/types/chat/custom-message.d.ts +10 -0
- package/dist/types/chat/display-preferences.d.ts +13 -0
- package/dist/types/chat/eval-execution.d.ts +29 -0
- package/dist/types/chat/execution-shared.d.ts +51 -0
- package/dist/types/chat/extension-types.d.ts +28 -0
- package/dist/types/chat/hook-message.d.ts +10 -0
- package/dist/types/chat/image-loading.d.ts +46 -0
- package/dist/types/chat/late-diagnostics-message.d.ts +21 -0
- package/dist/types/chat/messages.d.ts +189 -0
- package/dist/types/chat/reaction.d.ts +30 -0
- package/dist/types/chat/read-target.d.ts +4 -0
- package/dist/types/chat/read-tool-group.d.ts +67 -0
- package/dist/types/chat/served-model-marker.d.ts +47 -0
- package/dist/types/chat/skill-message.d.ts +33 -0
- package/dist/types/chat/skill-title-input.d.ts +14 -0
- package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/chat/thinking-display.d.ts +12 -0
- package/dist/types/chat/todo-reminder.d.ts +13 -0
- package/dist/types/chat/tool-execution.d.ts +138 -0
- package/dist/types/chat/transcript-browser.d.ts +93 -0
- package/dist/types/chat/transcript-entry.d.ts +45 -0
- package/dist/types/chat/transcript-outline.d.ts +86 -0
- package/dist/types/chat/transcript-render-helpers.d.ts +92 -0
- package/dist/types/chat/ttsr-notification.d.ts +23 -0
- package/dist/types/chat/user-message.d.ts +52 -0
- package/dist/types/chrome/chat-block.d.ts +64 -0
- package/dist/types/chrome/collab-qrcode.d.ts +28 -0
- package/dist/types/chrome/context-thresholds.d.ts +10 -0
- package/dist/types/chrome/countdown-timer.d.ts +14 -0
- package/dist/types/chrome/diff.d.ts +14 -0
- package/dist/types/chrome/dynamic-border.d.ts +16 -0
- package/dist/types/chrome/error-block.d.ts +17 -0
- package/dist/types/chrome/form-theme.d.ts +3 -0
- package/dist/types/chrome/format.d.ts +12 -0
- package/dist/types/chrome/index.d.ts +20 -0
- package/dist/types/chrome/keybinding-hints.d.ts +40 -0
- package/dist/types/chrome/live-board.d.ts +23 -0
- package/dist/types/chrome/local-date.d.ts +4 -0
- package/dist/types/chrome/message-divider.d.ts +22 -0
- package/dist/types/chrome/message-frame.d.ts +52 -0
- package/dist/types/chrome/message-notice.d.ts +35 -0
- package/dist/types/chrome/overlay-box.d.ts +74 -0
- package/dist/types/chrome/qrcode.d.ts +48 -0
- package/dist/types/chrome/segment-track.d.ts +27 -0
- package/dist/types/chrome/select-list-mouse-routing.d.ts +4 -0
- package/dist/types/chrome/selector-helpers.d.ts +52 -0
- package/dist/types/chrome/shared.d.ts +5 -0
- package/dist/types/chrome/streaming-panel.d.ts +19 -0
- package/dist/types/chrome/tool-activity.d.ts +17 -0
- package/dist/types/chrome/transcript-container.d.ts +129 -0
- package/dist/types/chrome/transcript-status.d.ts +12 -0
- package/dist/types/chrome/visual-truncate.d.ts +19 -0
- package/dist/types/components/disclosure.d.ts +42 -0
- package/dist/types/components/form.d.ts +130 -0
- package/dist/types/components/key-value-list.d.ts +24 -0
- package/dist/types/components/layout/geometry.d.ts +73 -0
- package/dist/types/components/layout/row.d.ts +55 -0
- package/dist/types/components/layout/split-pane.d.ts +80 -0
- package/dist/types/components/layout/stack.d.ts +50 -0
- package/dist/types/components/menu-selection.d.ts +71 -0
- package/dist/types/components/metric.d.ts +44 -0
- package/dist/types/components/progress-bar.d.ts +36 -0
- package/dist/types/components/scroll-view.d.ts +53 -19
- package/dist/types/components/scroll-viewport.d.ts +46 -0
- package/dist/types/components/section.d.ts +19 -0
- package/dist/types/components/select-list.d.ts +46 -2
- package/dist/types/components/settings-list.d.ts +20 -0
- package/dist/types/components/table.d.ts +32 -0
- package/dist/types/components/tree-view.d.ts +130 -0
- package/dist/types/components/wizard-step.d.ts +60 -0
- package/dist/types/hotkeys-markdown.d.ts +7 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/keybinding-matchers.d.ts +35 -0
- package/dist/types/keys.d.ts +2 -2
- package/dist/types/lang-from-path.d.ts +9 -0
- package/dist/types/overlays/advisor-config.d.ts +114 -0
- package/dist/types/overlays/agent-activity.d.ts +41 -0
- package/dist/types/overlays/agent-hub-projection.d.ts +33 -0
- package/dist/types/overlays/agent-hub-renderer.d.ts +53 -0
- package/dist/types/overlays/agent-hub-types.d.ts +99 -0
- package/dist/types/overlays/agent-hub.d.ts +126 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +71 -0
- package/dist/types/overlays/agents-hub.d.ts +72 -0
- package/dist/types/overlays/ask-dialog.d.ts +88 -0
- package/dist/types/overlays/bordered-loader.d.ts +11 -0
- package/dist/types/overlays/btw-history-panel.d.ts +29 -0
- package/dist/types/overlays/btw-history.d.ts +17 -0
- package/dist/types/overlays/btw-panel.d.ts +26 -0
- package/dist/types/overlays/cleanse-panel.d.ts +36 -0
- package/dist/types/overlays/codex-reset-fireworks.d.ts +52 -0
- package/dist/types/overlays/composer-shape-preview.d.ts +47 -0
- package/dist/types/overlays/composer-shape-registry.d.ts +50 -0
- package/dist/types/overlays/copy-selector.d.ts +48 -0
- package/dist/types/overlays/copy-targets.d.ts +63 -0
- package/dist/types/overlays/error-banner.d.ts +13 -0
- package/dist/types/overlays/extensions/display-text.d.ts +10 -0
- package/dist/types/overlays/extensions/extension-dashboard.d.ts +63 -0
- package/dist/types/overlays/extensions/extension-list.d.ts +54 -0
- package/dist/types/overlays/extensions/inspector-model.d.ts +109 -0
- package/dist/types/overlays/extensions/inspector-panel.d.ts +17 -0
- package/dist/types/overlays/extensions/live-tool-session.d.ts +28 -0
- package/dist/types/overlays/extensions/mcp-runtime.d.ts +107 -0
- package/dist/types/overlays/extensions/state-manager.d.ts +42 -0
- package/dist/types/overlays/extensions/types.d.ts +165 -0
- package/dist/types/overlays/history-search.d.ts +16 -0
- package/dist/types/overlays/hook-editor.d.ts +44 -0
- package/dist/types/overlays/hook-input.d.ts +20 -0
- package/dist/types/overlays/hook-selector.d.ts +71 -0
- package/dist/types/overlays/hub-frame.d.ts +77 -0
- package/dist/types/overlays/login-dialog.d.ts +43 -0
- package/dist/types/overlays/logout-account-selector.d.ts +15 -0
- package/dist/types/overlays/mcp-add-wizard.d.ts +87 -0
- package/dist/types/overlays/model-browser.d.ts +213 -0
- package/dist/types/overlays/model-hub.d.ts +72 -0
- package/dist/types/overlays/model-picker.d.ts +74 -0
- package/dist/types/overlays/model-selector.d.ts +52 -0
- package/dist/types/overlays/move-overlay.d.ts +39 -0
- package/dist/types/overlays/oauth-selector.d.ts +41 -0
- package/dist/types/overlays/omfg-panel.d.ts +20 -0
- package/dist/types/overlays/pause-screen.d.ts +43 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +89 -0
- package/dist/types/overlays/plan-save-overlay.d.ts +19 -0
- package/dist/types/overlays/plan-toc.d.ts +41 -0
- package/dist/types/overlays/plugin-selector.d.ts +28 -0
- package/dist/types/overlays/plugin-settings.d.ts +180 -0
- package/dist/types/overlays/queue-mode-selector.d.ts +11 -0
- package/dist/types/overlays/reset-usage-selector.d.ts +23 -0
- package/dist/types/overlays/rewind-selector.d.ts +61 -0
- package/dist/types/overlays/running-subagent-badge.d.ts +6 -0
- package/dist/types/overlays/session-account-selector.d.ts +24 -0
- package/dist/types/overlays/session-info-overlay.d.ts +17 -0
- package/dist/types/overlays/session-observer-registry.d.ts +77 -0
- package/dist/types/overlays/session-selector.d.ts +131 -0
- package/dist/types/overlays/settings-defs.d.ts +119 -0
- package/dist/types/overlays/settings-selector.d.ts +73 -0
- package/dist/types/overlays/show-images-selector.d.ts +11 -0
- package/dist/types/overlays/snapcompact-shape-preview.d.ts +31 -0
- package/dist/types/overlays/theme-selector.d.ts +12 -0
- package/dist/types/overlays/thinking-selector.d.ts +12 -0
- package/dist/types/overlays/tiny-title-download-progress.d.ts +21 -0
- package/dist/types/overlays/tree-selector.d.ts +92 -0
- package/dist/types/overlays/usage-dashboard.d.ts +94 -0
- package/dist/types/overlays/usage-display.d.ts +5 -0
- package/dist/types/overlays/usage-row.d.ts +17 -0
- package/dist/types/prompt/attachment-chips.d.ts +19 -0
- package/dist/types/prompt/composer-attachments.d.ts +71 -0
- package/dist/types/prompt/composer-cache.d.ts +37 -0
- package/dist/types/prompt/composer.d.ts +159 -0
- package/dist/types/prompt/custom-editor.d.ts +261 -0
- package/dist/types/prompt/editor-top-gap.d.ts +18 -0
- package/dist/types/prompt/emoji-autocomplete.d.ts +16 -0
- package/dist/types/prompt/github-ref-autocomplete.d.ts +35 -0
- package/dist/types/prompt/gradient-highlight.d.ts +32 -0
- package/dist/types/prompt/image-format.d.ts +4 -0
- package/dist/types/prompt/image-references.d.ts +26 -0
- package/dist/types/prompt/interactive-context-helpers.d.ts +43 -0
- package/dist/types/prompt/internal-url-autocomplete.d.ts +56 -0
- package/dist/types/prompt/macos-spelling.d.ts +44 -0
- package/dist/types/prompt/magic-keyword-boundary.d.ts +9 -0
- package/dist/types/prompt/magic-keywords.d.ts +26 -0
- package/dist/types/prompt/markdown-prose.d.ts +15 -0
- package/dist/types/prompt/model-mention-autocomplete.d.ts +25 -0
- package/dist/types/prompt/model-mention-syntax.d.ts +24 -0
- package/dist/types/prompt/orchestrate.d.ts +13 -0
- package/dist/types/prompt/prompt-action-autocomplete.d.ts +56 -0
- package/dist/types/prompt/queue-input.d.ts +8 -0
- package/dist/types/prompt/skill-tokens.d.ts +13 -0
- package/dist/types/prompt/tools-markdown.d.ts +12 -0
- package/dist/types/prompt/ultrathink.d.ts +13 -0
- package/dist/types/prompt/usage-amounts.d.ts +26 -0
- package/dist/types/prompt/video.d.ts +18 -0
- package/dist/types/prompt/welcome.d.ts +83 -0
- package/dist/types/prompt/workflow.d.ts +13 -0
- package/dist/types/render/code-cell.d.ts +51 -0
- package/dist/types/render/file-list.d.ts +22 -0
- package/dist/types/render/hyperlink.d.ts +80 -0
- package/dist/types/render/index.d.ts +16 -0
- package/dist/types/render/output-block.d.ts +54 -0
- package/dist/types/render/output-pane.d.ts +80 -0
- package/dist/types/render/render-utils.d.ts +312 -0
- package/dist/types/render/sixel.d.ts +21 -0
- package/dist/types/render/status-line.d.ts +23 -0
- package/dist/types/render/tool-card.d.ts +71 -0
- package/dist/types/render/tree-list.d.ts +29 -0
- package/dist/types/render/types.d.ts +17 -0
- package/dist/types/render/utils.d.ts +43 -0
- package/dist/types/render/width-aware-text.d.ts +23 -0
- package/dist/types/setup/lazy.d.ts +3 -0
- package/dist/types/setup/scenes/composer.d.ts +3 -0
- package/dist/types/setup/scenes/glyph.d.ts +3 -0
- package/dist/types/setup/scenes/model.d.ts +3 -0
- package/dist/types/setup/scenes/outro.d.ts +2 -0
- package/dist/types/setup/scenes/providers.d.ts +3 -0
- package/dist/types/setup/scenes/sign-in.d.ts +21 -0
- package/dist/types/setup/scenes/splash.d.ts +11 -0
- package/dist/types/setup/scenes/theme.d.ts +3 -0
- package/dist/types/setup/scenes/types.d.ts +110 -0
- package/dist/types/setup/scenes/web-search.d.ts +22 -0
- package/dist/types/setup/setup-version.d.ts +11 -0
- package/dist/types/setup/startup-splash.d.ts +9 -0
- package/dist/types/setup/wizard-overlay.d.ts +16 -0
- package/dist/types/setup/wizard.d.ts +25 -0
- package/dist/types/status-line/component.d.ts +182 -0
- package/dist/types/status-line/context-usage.d.ts +156 -0
- package/dist/types/status-line/footer.d.ts +30 -0
- package/dist/types/status-line/git-utils.d.ts +22 -0
- package/dist/types/status-line/host.d.ts +129 -0
- package/dist/types/status-line/index.d.ts +6 -0
- package/dist/types/status-line/loop.d.ts +18 -0
- package/dist/types/status-line/metrics.d.ts +21 -0
- package/dist/types/status-line/presets.d.ts +3 -0
- package/dist/types/status-line/schema.d.ts +15 -0
- package/dist/types/status-line/segments.d.ts +5 -0
- package/dist/types/status-line/separators.d.ts +3 -0
- package/dist/types/status-line/types.d.ts +236 -0
- package/dist/types/stdin-buffer.d.ts +4 -0
- package/dist/types/theme/color.d.ts +24 -0
- package/dist/types/theme/defaults/index.d.ts +9489 -0
- package/dist/types/theme/index.d.ts +4 -0
- package/dist/types/theme/loader.d.ts +23 -0
- package/dist/types/theme/mermaid-cache.d.ts +26 -0
- package/dist/types/theme/schema-validation.d.ts +3 -0
- package/dist/types/theme/schema.d.ts +25 -0
- package/dist/types/theme/session-color.d.ts +43 -0
- package/dist/types/theme/shimmer.d.ts +44 -0
- package/dist/types/theme/symbols.d.ts +34 -0
- package/dist/types/theme/theme-class.d.ts +299 -0
- package/dist/types/theme/theme.d.ts +111 -0
- package/dist/types/theme/tui-adapters.d.ts +30 -0
- package/dist/types/thinking.d.ts +165 -0
- package/dist/types/tools/agent-tree.d.ts +36 -0
- package/dist/types/tools/ask.d.ts +67 -0
- package/dist/types/tools/ast-edit.d.ts +53 -0
- package/dist/types/tools/ast-grep.d.ts +52 -0
- package/dist/types/tools/autoresearch.d.ts +156 -0
- package/dist/types/tools/bash-interactive.d.ts +28 -0
- package/dist/types/tools/bash.d.ts +103 -0
- package/dist/types/tools/conflict-detect.d.ts +43 -0
- package/dist/types/tools/debug.d.ts +60 -0
- package/dist/types/tools/default-renderer.d.ts +24 -0
- package/dist/types/tools/edit.d.ts +158 -0
- package/dist/types/tools/eval-format/code-mode-declarations.d.ts +5 -0
- package/dist/types/tools/eval-format/index.d.ts +5 -0
- package/dist/types/tools/eval-format/javascript.d.ts +2 -0
- package/dist/types/tools/eval-format/python.d.ts +2 -0
- package/dist/types/tools/eval.d.ts +94 -0
- package/dist/types/tools/fetch.d.ts +42 -0
- package/dist/types/tools/gh-format.d.ts +8 -0
- package/dist/types/tools/github.d.ts +144 -0
- package/dist/types/tools/glob.d.ts +44 -0
- package/dist/types/tools/goal.d.ts +42 -0
- package/dist/types/tools/grep.d.ts +64 -0
- package/dist/types/tools/grouped-file-output.d.ts +71 -0
- package/dist/types/tools/hashline-format.d.ts +28 -0
- package/dist/types/tools/hub.d.ts +340 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/json-tree.d.ts +59 -0
- package/dist/types/tools/line-ranges.d.ts +29 -0
- package/dist/types/tools/list-limit.d.ts +15 -0
- package/dist/types/tools/lsp.d.ts +72 -0
- package/dist/types/tools/match-line-format.d.ts +11 -0
- package/dist/types/tools/mcp.d.ts +81 -0
- package/dist/types/tools/memory.d.ts +67 -0
- package/dist/types/tools/output-meta.d.ts +151 -0
- package/dist/types/tools/read.d.ts +139 -0
- package/dist/types/tools/renderer.d.ts +98 -0
- package/dist/types/tools/report-tool-issue.d.ts +8 -0
- package/dist/types/tools/resolve.d.ts +47 -0
- package/dist/types/tools/streaming-output.d.ts +282 -0
- package/dist/types/tools/subprocess.d.ts +24 -0
- package/dist/types/tools/task-repair-args.d.ts +53 -0
- package/dist/types/tools/task-yield-assembly.d.ts +20 -0
- package/dist/types/tools/task.d.ts +425 -0
- package/dist/types/tools/terminal-output.d.ts +8 -0
- package/dist/types/tools/think.d.ts +13 -0
- package/dist/types/tools/todo.d.ts +118 -0
- package/dist/types/tools/tool-errors.d.ts +7 -0
- package/dist/types/tools/vibe.d.ts +120 -0
- package/dist/types/tools/web-search.d.ts +195 -0
- package/dist/types/tools/write.d.ts +76 -0
- package/dist/types/tools/xd-url.d.ts +13 -0
- package/dist/types/tools/xdev.d.ts +52 -0
- package/dist/types/tui.d.ts +18 -0
- package/dist/types/utils.d.ts +2 -0
- package/package.json +37 -3
- package/src/app-keybindings.ts +760 -0
- package/src/apps/autoresearch-dashboard.ts +500 -0
- package/src/apps/autoresearch-data.ts +64 -0
- package/src/apps/cleanse-board.ts +341 -0
- package/src/apps/cleanse-picker.ts +57 -0
- package/src/apps/debug/log-formatting.ts +53 -0
- package/src/apps/debug/log-viewer.ts +868 -0
- package/src/apps/debug/protocol-probe.ts +267 -0
- package/src/apps/debug/raw-sse-buffer.ts +449 -0
- package/src/apps/debug/raw-sse.ts +282 -0
- package/src/apps/debug/terminal-info.ts +115 -0
- package/src/apps/debug/viewer-frame.ts +174 -0
- package/src/apps/git/avatar.ts +52 -0
- package/src/apps/git/colors.ts +109 -0
- package/src/apps/git/diff-pane.ts +1512 -0
- package/src/apps/git/git-tui.ts +889 -0
- package/src/apps/git/sidebar.ts +1204 -0
- package/src/apps/git/state.ts +113 -0
- package/src/apps/if-bench-board.ts +324 -0
- package/src/apps/live-visualizer.ts +238 -0
- package/src/apps/ps-data.ts +116 -0
- package/src/apps/ps-top.ts +422 -0
- package/src/apps/session-picker.ts +95 -0
- package/src/apps/setup-model-picker.ts +21 -0
- package/src/apps/standalone-picker.ts +111 -0
- package/src/autocomplete.ts +9 -13
- package/src/chat/advisor-message.ts +175 -0
- package/src/chat/assistant-message.ts +1214 -0
- package/src/chat/background-tan-message.ts +35 -0
- package/src/chat/bash-execution.ts +394 -0
- package/src/chat/cache-invalidation-marker.ts +94 -0
- package/src/chat/chat-transcript-builder.ts +593 -0
- package/src/chat/collab-prompt-message.ts +34 -0
- package/src/chat/compaction-summary-message.ts +261 -0
- package/src/chat/custom-message.ts +23 -0
- package/src/chat/display-preferences.ts +24 -0
- package/src/chat/eval-execution.ts +172 -0
- package/src/chat/execution-shared.ts +113 -0
- package/src/chat/extension-types.ts +46 -0
- package/src/chat/hook-message.ts +20 -0
- package/src/chat/image-loading.ts +122 -0
- package/src/chat/late-diagnostics-message.ts +92 -0
- package/src/chat/messages.ts +305 -0
- package/src/chat/reaction.ts +65 -0
- package/src/chat/read-target.ts +7 -0
- package/src/chat/read-tool-group.ts +873 -0
- package/src/chat/served-model-marker.ts +91 -0
- package/src/chat/skill-message.ts +220 -0
- package/src/chat/skill-title-input.ts +41 -0
- package/src/chat/stripped-tool-calls-placeholder.ts +35 -0
- package/src/chat/thinking-display.ts +312 -0
- package/src/chat/todo-reminder.ts +33 -0
- package/src/chat/tool-execution.ts +1395 -0
- package/src/chat/transcript-browser.ts +268 -0
- package/src/chat/transcript-entry.ts +96 -0
- package/src/chat/transcript-outline.ts +260 -0
- package/src/chat/transcript-render-helpers.ts +315 -0
- package/src/chat/ttsr-notification.ts +123 -0
- package/src/chat/user-message.ts +287 -0
- package/src/chrome/chat-block.ts +110 -0
- package/src/chrome/collab-qrcode.ts +74 -0
- package/src/chrome/context-thresholds.ts +85 -0
- package/src/chrome/countdown-timer.ts +74 -0
- package/src/chrome/diff.ts +266 -0
- package/src/chrome/dynamic-border.ts +36 -0
- package/src/chrome/error-block.ts +63 -0
- package/src/chrome/form-theme.ts +10 -0
- package/src/chrome/format.ts +66 -0
- package/src/chrome/index.ts +21 -0
- package/src/chrome/keybinding-hints.ts +55 -0
- package/src/chrome/live-board.ts +123 -0
- package/src/chrome/local-date.ts +20 -0
- package/src/chrome/message-divider.ts +51 -0
- package/src/chrome/message-frame.ts +164 -0
- package/src/chrome/message-notice.ts +103 -0
- package/src/chrome/overlay-box.ts +301 -0
- package/src/chrome/qrcode.ts +539 -0
- package/src/chrome/segment-track.ts +86 -0
- package/src/chrome/select-list-mouse-routing.ts +11 -0
- package/src/chrome/selector-helpers.ts +119 -0
- package/src/chrome/shared.ts +27 -0
- package/src/chrome/streaming-panel.ts +72 -0
- package/src/chrome/tool-activity.ts +44 -0
- package/src/chrome/transcript-container.ts +902 -0
- package/src/chrome/transcript-status.ts +27 -0
- package/src/chrome/visual-truncate.ts +70 -0
- package/src/components/disclosure.ts +235 -0
- package/src/components/editor.ts +10 -12
- package/src/components/form.ts +566 -0
- package/src/components/input.ts +6 -27
- package/src/components/key-value-list.ts +88 -0
- package/src/components/layout/geometry.ts +202 -0
- package/src/components/layout/row.ts +283 -0
- package/src/components/layout/split-pane.ts +349 -0
- package/src/components/layout/stack.ts +261 -0
- package/src/components/markdown.ts +16 -12
- package/src/components/menu-selection.ts +248 -0
- package/src/components/metric.ts +132 -0
- package/src/components/progress-bar.ts +140 -0
- package/src/components/scroll-view.ts +372 -70
- package/src/components/scroll-viewport.ts +154 -0
- package/src/components/section.ts +77 -0
- package/src/components/select-list.ts +238 -159
- package/src/components/settings-list.ts +103 -80
- package/src/components/table.ts +127 -0
- package/src/components/tree-view.ts +481 -0
- package/src/components/wizard-step.ts +229 -0
- package/src/deccara.ts +1 -3
- package/src/hotkeys-markdown.ts +100 -0
- package/src/index.ts +18 -0
- package/src/keybinding-matchers.ts +99 -0
- package/src/keys.ts +2 -2
- package/src/lang-from-path.ts +252 -0
- package/src/overlays/advisor-config.ts +761 -0
- package/src/overlays/agent-activity.ts +113 -0
- package/src/overlays/agent-hub-projection.ts +250 -0
- package/src/overlays/agent-hub-renderer.ts +281 -0
- package/src/overlays/agent-hub-types.ts +74 -0
- package/src/overlays/agent-hub.ts +1562 -0
- package/src/overlays/agent-transcript-viewer.ts +669 -0
- package/src/overlays/agents-hub.ts +1203 -0
- package/src/overlays/ask-dialog.ts +1202 -0
- package/src/overlays/bordered-loader.ts +41 -0
- package/src/overlays/btw-history-panel.ts +591 -0
- package/src/overlays/btw-history.ts +33 -0
- package/src/overlays/btw-panel.ts +167 -0
- package/src/overlays/cleanse-panel.ts +167 -0
- package/src/overlays/codex-reset-fireworks.ts +375 -0
- package/src/overlays/composer-shape-preview.ts +137 -0
- package/src/overlays/composer-shape-registry.ts +82 -0
- package/src/overlays/copy-selector.ts +618 -0
- package/src/overlays/copy-targets.ts +210 -0
- package/src/overlays/error-banner.ts +39 -0
- package/src/overlays/extensions/display-text.ts +39 -0
- package/src/overlays/extensions/extension-dashboard.ts +645 -0
- package/src/overlays/extensions/extension-list.ts +667 -0
- package/src/overlays/extensions/inspector-model.ts +484 -0
- package/src/overlays/extensions/inspector-panel.ts +669 -0
- package/src/overlays/extensions/live-tool-session.ts +67 -0
- package/src/overlays/extensions/mcp-runtime.ts +289 -0
- package/src/overlays/extensions/state-manager.ts +337 -0
- package/src/overlays/extensions/types.ts +208 -0
- package/src/overlays/history-search.ts +268 -0
- package/src/overlays/hook-editor.ts +272 -0
- package/src/overlays/hook-input.ts +84 -0
- package/src/overlays/hook-selector.ts +635 -0
- package/src/overlays/hub-frame.ts +262 -0
- package/src/overlays/login-dialog.ts +231 -0
- package/src/overlays/logout-account-selector.ts +115 -0
- package/src/overlays/mcp-add-wizard.ts +1436 -0
- package/src/overlays/model-browser.ts +1176 -0
- package/src/overlays/model-hub.ts +2279 -0
- package/src/overlays/model-picker.ts +285 -0
- package/src/overlays/model-selector.ts +107 -0
- package/src/overlays/move-overlay.ts +197 -0
- package/src/overlays/oauth-selector.ts +446 -0
- package/src/overlays/omfg-panel.ts +136 -0
- package/src/overlays/pause-screen.ts +198 -0
- package/src/overlays/plan-review-overlay.ts +1227 -0
- package/src/overlays/plan-save-overlay.ts +74 -0
- package/src/overlays/plan-toc.ts +139 -0
- package/src/overlays/plugin-selector.ts +97 -0
- package/src/overlays/plugin-settings.ts +839 -0
- package/src/overlays/queue-mode-selector.ts +55 -0
- package/src/overlays/reset-usage-selector.ts +170 -0
- package/src/overlays/rewind-selector.ts +499 -0
- package/src/overlays/running-subagent-badge.ts +19 -0
- package/src/overlays/session-account-selector.ts +68 -0
- package/src/overlays/session-info-overlay.ts +96 -0
- package/src/overlays/session-observer-registry.ts +289 -0
- package/src/overlays/session-selector.ts +1137 -0
- package/src/overlays/settings-defs.ts +315 -0
- package/src/overlays/settings-selector.ts +1415 -0
- package/src/overlays/show-images-selector.ts +44 -0
- package/src/overlays/snapcompact-shape-preview-doc.md +14 -0
- package/src/overlays/snapcompact-shape-preview.ts +192 -0
- package/src/overlays/theme-selector.ts +62 -0
- package/src/overlays/thinking-selector.ts +51 -0
- package/src/overlays/tiny-title-download-progress.ts +102 -0
- package/src/overlays/tree-selector.ts +1121 -0
- package/src/overlays/usage-dashboard.ts +629 -0
- package/src/overlays/usage-display.ts +45 -0
- package/src/overlays/usage-row.ts +118 -0
- package/src/prompt/attachment-chips.ts +201 -0
- package/src/prompt/composer-attachments.ts +280 -0
- package/src/prompt/composer-cache.ts +304 -0
- package/src/prompt/composer.ts +934 -0
- package/src/prompt/custom-editor.ts +1392 -0
- package/src/prompt/data/emojis.json +1 -0
- package/src/prompt/editor-top-gap.ts +28 -0
- package/src/prompt/emoji-autocomplete.ts +285 -0
- package/src/prompt/github-ref-autocomplete.ts +75 -0
- package/src/prompt/gradient-highlight.ts +101 -0
- package/src/prompt/image-format.ts +28 -0
- package/src/prompt/image-references.ts +102 -0
- package/src/prompt/interactive-context-helpers.ts +126 -0
- package/src/prompt/internal-url-autocomplete.ts +155 -0
- package/src/prompt/macos-spelling.ts +456 -0
- package/src/prompt/magic-keyword-boundary.ts +23 -0
- package/src/prompt/magic-keywords.ts +42 -0
- package/src/prompt/markdown-prose.ts +245 -0
- package/src/prompt/model-mention-autocomplete.ts +94 -0
- package/src/prompt/model-mention-syntax.ts +41 -0
- package/src/prompt/orchestrate.ts +26 -0
- package/src/prompt/prompt-action-autocomplete.ts +337 -0
- package/src/prompt/queue-input.ts +132 -0
- package/src/prompt/skill-tokens.ts +36 -0
- package/src/prompt/tips.txt +27 -0
- package/src/prompt/tools-markdown.ts +29 -0
- package/src/prompt/ultrathink.ts +26 -0
- package/src/prompt/usage-amounts.ts +99 -0
- package/src/prompt/video.ts +47 -0
- package/src/prompt/welcome.ts +605 -0
- package/src/prompt/workflow.ts +26 -0
- package/src/render/code-cell.ts +244 -0
- package/src/render/file-list.ts +58 -0
- package/src/render/hyperlink.ts +192 -0
- package/src/render/index.ts +17 -0
- package/src/render/output-block.ts +267 -0
- package/src/render/output-pane.ts +299 -0
- package/src/render/render-utils.ts +1182 -0
- package/src/render/sixel.ts +69 -0
- package/src/render/status-line.ts +55 -0
- package/src/render/tool-card.ts +272 -0
- package/src/render/tree-list.ts +188 -0
- package/src/render/types.ts +19 -0
- package/src/render/utils.ts +109 -0
- package/src/render/width-aware-text.ts +60 -0
- package/src/setup/lazy.ts +17 -0
- package/src/setup/scenes/composer.ts +127 -0
- package/src/setup/scenes/glyph.ts +120 -0
- package/src/setup/scenes/model.ts +138 -0
- package/src/setup/scenes/outro.ts +24 -0
- package/src/setup/scenes/providers.ts +107 -0
- package/src/setup/scenes/sign-in.ts +373 -0
- package/src/setup/scenes/splash.ts +192 -0
- package/src/setup/scenes/theme.ts +343 -0
- package/src/setup/scenes/types.ts +111 -0
- package/src/setup/scenes/web-search.ts +165 -0
- package/src/setup/setup-version.ts +11 -0
- package/src/setup/startup-splash.ts +107 -0
- package/src/setup/wizard-overlay.ts +319 -0
- package/src/setup/wizard.ts +101 -0
- package/src/status-line/component.ts +3003 -0
- package/src/status-line/context-usage.ts +688 -0
- package/src/status-line/footer.ts +323 -0
- package/src/status-line/git-utils.ts +42 -0
- package/src/status-line/host.ts +97 -0
- package/src/status-line/index.ts +6 -0
- package/src/status-line/loop.ts +28 -0
- package/src/status-line/metrics.ts +94 -0
- package/src/status-line/presets.ts +107 -0
- package/src/status-line/schema.ts +57 -0
- package/src/status-line/segments.ts +934 -0
- package/src/status-line/separators.ts +55 -0
- package/src/status-line/types.ts +227 -0
- package/src/stdin-buffer.ts +4 -2
- package/src/theme/color.ts +95 -0
- package/src/theme/dark.json +95 -0
- package/src/theme/defaults/alabaster.json +93 -0
- package/src/theme/defaults/amethyst.json +96 -0
- package/src/theme/defaults/anthracite.json +93 -0
- package/src/theme/defaults/basalt.json +91 -0
- package/src/theme/defaults/birch.json +95 -0
- package/src/theme/defaults/dark-abyss.json +91 -0
- package/src/theme/defaults/dark-arctic.json +104 -0
- package/src/theme/defaults/dark-aurora.json +95 -0
- package/src/theme/defaults/dark-catppuccin.json +107 -0
- package/src/theme/defaults/dark-cavern.json +91 -0
- package/src/theme/defaults/dark-celestial.json +106 -0
- package/src/theme/defaults/dark-copper.json +95 -0
- package/src/theme/defaults/dark-cosmos.json +90 -0
- package/src/theme/defaults/dark-cyberpunk.json +102 -0
- package/src/theme/defaults/dark-dracula.json +98 -0
- package/src/theme/defaults/dark-eclipse.json +91 -0
- package/src/theme/defaults/dark-ember.json +95 -0
- package/src/theme/defaults/dark-equinox.json +90 -0
- package/src/theme/defaults/dark-forest.json +96 -0
- package/src/theme/defaults/dark-github.json +105 -0
- package/src/theme/defaults/dark-gruvbox.json +112 -0
- package/src/theme/defaults/dark-lavender.json +95 -0
- package/src/theme/defaults/dark-lunar.json +89 -0
- package/src/theme/defaults/dark-midnight.json +95 -0
- package/src/theme/defaults/dark-monochrome.json +94 -0
- package/src/theme/defaults/dark-monokai.json +98 -0
- package/src/theme/defaults/dark-nebula.json +90 -0
- package/src/theme/defaults/dark-nord.json +98 -0
- package/src/theme/defaults/dark-ocean.json +101 -0
- package/src/theme/defaults/dark-one.json +100 -0
- package/src/theme/defaults/dark-poimandres.json +115 -0
- package/src/theme/defaults/dark-rainforest.json +91 -0
- package/src/theme/defaults/dark-reef.json +91 -0
- package/src/theme/defaults/dark-retro.json +92 -0
- package/src/theme/defaults/dark-rose-pine.json +96 -0
- package/src/theme/defaults/dark-sakura.json +95 -0
- package/src/theme/defaults/dark-slate.json +95 -0
- package/src/theme/defaults/dark-solarized.json +97 -0
- package/src/theme/defaults/dark-solstice.json +90 -0
- package/src/theme/defaults/dark-starfall.json +91 -0
- package/src/theme/defaults/dark-sunset.json +99 -0
- package/src/theme/defaults/dark-swamp.json +90 -0
- package/src/theme/defaults/dark-synthwave.json +103 -0
- package/src/theme/defaults/dark-taiga.json +91 -0
- package/src/theme/defaults/dark-terminal.json +95 -0
- package/src/theme/defaults/dark-tokyo-night.json +101 -0
- package/src/theme/defaults/dark-tundra.json +91 -0
- package/src/theme/defaults/dark-twilight.json +91 -0
- package/src/theme/defaults/dark-volcanic.json +91 -0
- package/src/theme/defaults/graphite.json +92 -0
- package/src/theme/defaults/index.ts +201 -0
- package/src/theme/defaults/light-arctic.json +107 -0
- package/src/theme/defaults/light-aurora-day.json +91 -0
- package/src/theme/defaults/light-canyon.json +91 -0
- package/src/theme/defaults/light-catppuccin.json +106 -0
- package/src/theme/defaults/light-cirrus.json +90 -0
- package/src/theme/defaults/light-coral.json +95 -0
- package/src/theme/defaults/light-cyberpunk.json +96 -0
- package/src/theme/defaults/light-dawn.json +90 -0
- package/src/theme/defaults/light-dunes.json +91 -0
- package/src/theme/defaults/light-eucalyptus.json +95 -0
- package/src/theme/defaults/light-forest.json +100 -0
- package/src/theme/defaults/light-frost.json +95 -0
- package/src/theme/defaults/light-github.json +115 -0
- package/src/theme/defaults/light-glacier.json +91 -0
- package/src/theme/defaults/light-gruvbox.json +108 -0
- package/src/theme/defaults/light-haze.json +90 -0
- package/src/theme/defaults/light-honeycomb.json +95 -0
- package/src/theme/defaults/light-lagoon.json +91 -0
- package/src/theme/defaults/light-lavender.json +95 -0
- package/src/theme/defaults/light-meadow.json +91 -0
- package/src/theme/defaults/light-mint.json +95 -0
- package/src/theme/defaults/light-monochrome.json +101 -0
- package/src/theme/defaults/light-ocean.json +99 -0
- package/src/theme/defaults/light-one.json +99 -0
- package/src/theme/defaults/light-opal.json +91 -0
- package/src/theme/defaults/light-orchard.json +91 -0
- package/src/theme/defaults/light-paper.json +95 -0
- package/src/theme/defaults/light-poimandres.json +115 -0
- package/src/theme/defaults/light-prism.json +90 -0
- package/src/theme/defaults/light-retro.json +98 -0
- package/src/theme/defaults/light-sand.json +95 -0
- package/src/theme/defaults/light-savanna.json +91 -0
- package/src/theme/defaults/light-solarized.json +102 -0
- package/src/theme/defaults/light-soleil.json +90 -0
- package/src/theme/defaults/light-sunset.json +99 -0
- package/src/theme/defaults/light-synthwave.json +98 -0
- package/src/theme/defaults/light-tokyo-night.json +111 -0
- package/src/theme/defaults/light-wetland.json +91 -0
- package/src/theme/defaults/light-zenith.json +89 -0
- package/src/theme/defaults/limestone.json +94 -0
- package/src/theme/defaults/mahogany.json +97 -0
- package/src/theme/defaults/marble.json +93 -0
- package/src/theme/defaults/obsidian.json +91 -0
- package/src/theme/defaults/onyx.json +91 -0
- package/src/theme/defaults/pearl.json +93 -0
- package/src/theme/defaults/porcelain.json +91 -0
- package/src/theme/defaults/quartz.json +96 -0
- package/src/theme/defaults/sandstone.json +95 -0
- package/src/theme/defaults/titanium.json +90 -0
- package/src/theme/index.ts +5 -0
- package/src/theme/light.json +93 -0
- package/src/theme/loader.ts +200 -0
- package/src/theme/mermaid-cache.ts +92 -0
- package/src/theme/schema-validation.ts +119 -0
- package/src/theme/schema.ts +168 -0
- package/src/theme/session-color.ts +253 -0
- package/src/theme/shimmer.ts +307 -0
- package/src/theme/symbols.ts +1433 -0
- package/src/theme/theme-class.ts +787 -0
- package/src/theme/theme-schema.json +463 -0
- package/src/theme/theme.ts +810 -0
- package/src/theme/tui-adapters.ts +339 -0
- package/src/thinking.ts +380 -0
- package/src/tools/agent-tree.ts +128 -0
- package/src/tools/ask.ts +482 -0
- package/src/tools/ast-edit.ts +210 -0
- package/src/tools/ast-grep.ts +171 -0
- package/src/tools/autoresearch.ts +287 -0
- package/src/tools/bash-interactive.ts +295 -0
- package/src/tools/bash.ts +468 -0
- package/src/tools/conflict-detect.ts +77 -0
- package/src/tools/debug.ts +167 -0
- package/src/tools/default-renderer.ts +172 -0
- package/src/tools/edit.ts +1258 -0
- package/src/tools/eval-format/code-mode-declarations.ts +61 -0
- package/src/tools/eval-format/index.ts +16 -0
- package/src/tools/eval-format/javascript.ts +952 -0
- package/src/tools/eval-format/python.ts +544 -0
- package/src/tools/eval.ts +835 -0
- package/src/tools/fetch.ts +226 -0
- package/src/tools/gh-format.ts +18 -0
- package/src/tools/github.ts +686 -0
- package/src/tools/glob.ts +213 -0
- package/src/tools/goal.ts +153 -0
- package/src/tools/grep.ts +385 -0
- package/src/tools/grouped-file-output.ts +211 -0
- package/src/tools/hashline-format.ts +59 -0
- package/src/tools/hub.ts +1488 -0
- package/src/tools/index.ts +71 -0
- package/src/tools/json-tree.ts +388 -0
- package/src/tools/line-ranges.ts +98 -0
- package/src/tools/list-limit.ts +43 -0
- package/src/tools/lsp.ts +702 -0
- package/src/tools/match-line-format.ts +20 -0
- package/src/tools/mcp.ts +309 -0
- package/src/tools/memory.ts +220 -0
- package/src/tools/output-meta.ts +367 -0
- package/src/tools/read.ts +628 -0
- package/src/tools/renderer.ts +107 -0
- package/src/tools/report-tool-issue.ts +13 -0
- package/src/tools/resolve.ts +139 -0
- package/src/tools/streaming-output.ts +1576 -0
- package/src/tools/subprocess.ts +39 -0
- package/src/tools/task-repair-args.ts +118 -0
- package/src/tools/task-yield-assembly.ts +147 -0
- package/src/tools/task.ts +2110 -0
- package/src/tools/terminal-output.ts +153 -0
- package/src/tools/think.ts +28 -0
- package/src/tools/todo.ts +580 -0
- package/src/tools/tool-errors.ts +15 -0
- package/src/tools/vibe.ts +420 -0
- package/src/tools/web-search.ts +409 -0
- package/src/tools/write.ts +511 -0
- package/src/tools/xd-url.ts +28 -0
- package/src/tools/xdev.ts +201 -0
- package/src/tui.ts +57 -4
- package/src/utils.ts +8 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fullscreen `/usage` dashboard (the /settings idiom): mounted as an overlay
|
|
3
|
+
* on the alternate screen so it takes no transcript space. Shows a compact
|
|
4
|
+
* subscriptions grid (one card per provider, worst window per quota bucket)
|
|
5
|
+
* above a GitHub-style daily activity heatmap fed by the local stats DB.
|
|
6
|
+
* Enter flips into the classic full per-account report, scrollable in place.
|
|
7
|
+
*/
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import { resolveUsedFraction, type UsageLimit, type UsageReport } from "@oh-my-pi/pi-ai";
|
|
10
|
+
import { type Component, matchesKey, replaceTabs, routeSgrMouseInput, truncateToWidth, visibleWidth } from "../index";
|
|
11
|
+
import { colorLuma, formatDuration, hexToRgb, rgbToHex, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
12
|
+
import { formatProviderName } from "../chrome/format";
|
|
13
|
+
import { collapseSharedUsageReports, formatLimitTitle } from "./usage-display";
|
|
14
|
+
import { colorToAnsi } from "../theme/color";
|
|
15
|
+
import { ensureThemeSync, theme } from "../theme/theme";
|
|
16
|
+
import { formatAbsoluteOnlyAmount } from "../prompt/usage-amounts";
|
|
17
|
+
import {
|
|
18
|
+
matchesSelectCancel,
|
|
19
|
+
matchesSelectDown,
|
|
20
|
+
matchesSelectPageDown,
|
|
21
|
+
matchesSelectPageUp,
|
|
22
|
+
matchesSelectUp,
|
|
23
|
+
} from "../keybinding-matchers";
|
|
24
|
+
import { OverlayPanel, PanelDivider, PanelRows } from "../chrome/overlay-box";
|
|
25
|
+
|
|
26
|
+
/** Local calendar-day activity consumed by the usage heatmap. */
|
|
27
|
+
export interface DailyActivityPoint {
|
|
28
|
+
day: string;
|
|
29
|
+
cost: number;
|
|
30
|
+
requests: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Subscriptions grid model
|
|
35
|
+
// =============================================================================
|
|
36
|
+
|
|
37
|
+
/** One quota bucket on a provider card: the account-aggregate of one window group. */
|
|
38
|
+
export interface CardWindowRow {
|
|
39
|
+
/** Display label (limit label with tier folded in). */
|
|
40
|
+
label: string;
|
|
41
|
+
/** Window label/id shown dim after the label when sibling rows share a label. */
|
|
42
|
+
windowTag?: string;
|
|
43
|
+
/** Mean used fraction across accounts (0..1, >1 = overage); undefined when unreported. */
|
|
44
|
+
fraction: number | undefined;
|
|
45
|
+
status: UsageLimit["status"];
|
|
46
|
+
/** Reset countdown of the worst account, ms from now, when in the future. */
|
|
47
|
+
resetMs?: number;
|
|
48
|
+
/** Absolute one-sided amount (e.g. `$12.34 used`, `100 credits left`) for limits without a fraction. */
|
|
49
|
+
usedText?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Compact per-provider summary backing one card in the subscriptions grid. */
|
|
53
|
+
export interface ProviderCard {
|
|
54
|
+
provider: string;
|
|
55
|
+
name: string;
|
|
56
|
+
/** Number of accounts reporting for this provider. */
|
|
57
|
+
accounts: number;
|
|
58
|
+
/** Window rows sorted most-pressing first. */
|
|
59
|
+
windows: CardWindowRow[];
|
|
60
|
+
/** True when every account reports no limits (e.g. enterprise plans). */
|
|
61
|
+
unlimited: boolean;
|
|
62
|
+
/** True when nothing is used anywhere (or there are no limits): collapses to a tick. */
|
|
63
|
+
idle: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Aggregate status across a bucket's limits, mirroring the classic report:
|
|
68
|
+
* a mix of healthy and pressured accounts reads as a warning, not as the
|
|
69
|
+
* worst account's status.
|
|
70
|
+
*/
|
|
71
|
+
function aggregateStatus(limits: readonly { status?: UsageLimit["status"] }[]): UsageLimit["status"] {
|
|
72
|
+
const hasOk = limits.some(limit => limit.status === "ok");
|
|
73
|
+
const hasWarning = limits.some(limit => limit.status === "warning");
|
|
74
|
+
const hasExhausted = limits.some(limit => limit.status === "exhausted");
|
|
75
|
+
if (hasOk) return hasWarning || hasExhausted ? "warning" : "ok";
|
|
76
|
+
if (hasWarning) return "warning";
|
|
77
|
+
if (hasExhausted) return "exhausted";
|
|
78
|
+
return "unknown";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Fraction below which a window counts as untouched (renders as 100% free). */
|
|
82
|
+
const IDLE_FRACTION = 0.005;
|
|
83
|
+
/**
|
|
84
|
+
* Compact duration tag for a window (`7d`, `1d`, `5h`, `mo`), preferring the
|
|
85
|
+
* declared duration and falling back to a short id. Kept terse because it
|
|
86
|
+
* shares the label column with the limit name.
|
|
87
|
+
*/
|
|
88
|
+
function compactWindowTag(window: NonNullable<UsageLimit["window"]>): string {
|
|
89
|
+
if (window.durationMs) {
|
|
90
|
+
const hours = window.durationMs / 3_600_000;
|
|
91
|
+
if (hours >= 28 * 24) return "mo";
|
|
92
|
+
if (hours >= 24) return `${Math.round(hours / 24)}d`;
|
|
93
|
+
return `${Math.round(hours)}h`;
|
|
94
|
+
}
|
|
95
|
+
const id = window.id.toLowerCase();
|
|
96
|
+
return id.length <= 3 ? id : id.slice(0, 1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Collapse usage reports into one compact card per provider: limits grouped by
|
|
101
|
+
* quota bucket (label + window), each bucket showing the mean used fraction
|
|
102
|
+
* across accounts (matching the classic report's aggregate "% free") with the
|
|
103
|
+
* most-used account's reset countdown. Cards sort most-pressing first so
|
|
104
|
+
* what's burning is on top-left; fully idle providers collapse into a tick.
|
|
105
|
+
*/
|
|
106
|
+
export function buildProviderCards(reports: UsageReport[], nowMs: number): ProviderCard[] {
|
|
107
|
+
const displayReports = collapseSharedUsageReports(reports);
|
|
108
|
+
const grouped = new Map<string, UsageReport[]>();
|
|
109
|
+
for (const report of displayReports) {
|
|
110
|
+
const list = grouped.get(report.provider) ?? [];
|
|
111
|
+
list.push(report);
|
|
112
|
+
grouped.set(report.provider, list);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const cards: ProviderCard[] = [];
|
|
116
|
+
for (const [provider, providerReports] of grouped) {
|
|
117
|
+
const buckets = new Map<string, { label: string; limits: UsageLimit[] }>();
|
|
118
|
+
for (const report of providerReports) {
|
|
119
|
+
for (const limit of report.limits) {
|
|
120
|
+
const label = formatLimitTitle(limit);
|
|
121
|
+
const key = `${label}|${limit.window?.id ?? limit.scope.windowId ?? "default"}`;
|
|
122
|
+
const entry = buckets.get(key) ?? { label, limits: [] };
|
|
123
|
+
entry.limits.push(limit);
|
|
124
|
+
buckets.set(key, entry);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const windows: CardWindowRow[] = [...buckets.values()].map(bucket => {
|
|
129
|
+
const fractions = bucket.limits
|
|
130
|
+
.map(limit => resolveUsedFraction(limit))
|
|
131
|
+
.filter((value): value is number => value !== undefined);
|
|
132
|
+
const fraction =
|
|
133
|
+
fractions.length > 0 ? fractions.reduce((sum, value) => sum + value, 0) / fractions.length : undefined;
|
|
134
|
+
const worst = bucket.limits.reduce((max, limit) =>
|
|
135
|
+
(resolveUsedFraction(limit) ?? -1) > (resolveUsedFraction(max) ?? -1) ? limit : max,
|
|
136
|
+
);
|
|
137
|
+
const resetsAt = worst.window?.resetsAt;
|
|
138
|
+
return {
|
|
139
|
+
label: bucket.label,
|
|
140
|
+
windowTag: worst.window ? compactWindowTag(worst.window) : undefined,
|
|
141
|
+
fraction,
|
|
142
|
+
status: aggregateStatus(bucket.limits),
|
|
143
|
+
resetMs: resetsAt !== undefined && resetsAt > nowMs ? resetsAt - nowMs : undefined,
|
|
144
|
+
usedText: fraction === undefined ? formatAbsoluteOnlyAmount(bucket.limits) : undefined,
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
windows.sort((a, b) => (b.fraction ?? -1) - (a.fraction ?? -1));
|
|
148
|
+
// The window tag earns its columns only when sibling rows would otherwise
|
|
149
|
+
// be indistinguishable (e.g. Antigravity's daily vs weekly "Usage (Google)").
|
|
150
|
+
for (const window of windows) {
|
|
151
|
+
const duplicated = windows.some(other => other !== window && other.label === window.label);
|
|
152
|
+
if (!duplicated) window.windowTag = undefined;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
cards.push({
|
|
156
|
+
provider,
|
|
157
|
+
name: formatProviderName(provider),
|
|
158
|
+
accounts: providerReports.length,
|
|
159
|
+
windows,
|
|
160
|
+
unlimited: windows.length === 0,
|
|
161
|
+
idle: windows.every(window => window.fraction !== undefined && window.fraction < IDLE_FRACTION),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
cards.sort((a, b) => {
|
|
166
|
+
const aWorst = a.windows[0]?.fraction ?? -1;
|
|
167
|
+
const bWorst = b.windows[0]?.fraction ?? -1;
|
|
168
|
+
if (aWorst !== bWorst) return bWorst - aWorst;
|
|
169
|
+
return a.name.localeCompare(b.name);
|
|
170
|
+
});
|
|
171
|
+
return cards;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// =============================================================================
|
|
175
|
+
// Activity heatmap model
|
|
176
|
+
// =============================================================================
|
|
177
|
+
|
|
178
|
+
/** GitHub-style week-per-column heatmap grid derived from daily activity. */
|
|
179
|
+
export interface HeatmapLayout {
|
|
180
|
+
/** Per week column: short month name when the column starts a new month. */
|
|
181
|
+
monthLabels: (string | undefined)[];
|
|
182
|
+
/** 7 rows (Mon..Sun) × N week columns; 0..4 intensity, null = future day. */
|
|
183
|
+
cells: (number | null)[][];
|
|
184
|
+
totalCost: number;
|
|
185
|
+
totalRequests: number;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
189
|
+
export const HEATMAP_DAY_LABELS = ["M", "T", "W", "T", "F", "S", "S"];
|
|
190
|
+
|
|
191
|
+
function localIso(date: Date): string {
|
|
192
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
193
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
194
|
+
return `${date.getFullYear()}-${month}-${day}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function addDays(date: Date, days: number): Date {
|
|
198
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Lay out daily activity into a Monday-first week grid ending at `today`'s
|
|
203
|
+
* week. Intensity levels are magnitude-scaled against the busiest day
|
|
204
|
+
* (square-root compressed so mid-size days stay distinguishable from
|
|
205
|
+
* outliers), over per-day cost — falling back to request counts when nothing
|
|
206
|
+
* in range has priced usage. Unlike GitHub's rank quartiles, intensity tracks
|
|
207
|
+
* *how much* work a day carried.
|
|
208
|
+
*/
|
|
209
|
+
export function buildHeatmapLayout(points: DailyActivityPoint[], weeks: number, today = new Date()): HeatmapLayout {
|
|
210
|
+
const byDay = new Map(points.map(point => [point.day, point]));
|
|
211
|
+
const anyCost = points.some(point => point.cost > 0);
|
|
212
|
+
const metric = (point: DailyActivityPoint): number => (anyCost ? point.cost : point.requests);
|
|
213
|
+
|
|
214
|
+
const today0 = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
|
215
|
+
const mondayOffset = (today0.getDay() + 6) % 7;
|
|
216
|
+
const currentMonday = addDays(today0, -mondayOffset);
|
|
217
|
+
const start = addDays(currentMonday, -(weeks - 1) * 7);
|
|
218
|
+
const startIso = localIso(start);
|
|
219
|
+
const todayIso = localIso(today0);
|
|
220
|
+
|
|
221
|
+
const inRange = points.filter(point => point.day >= startIso && point.day <= todayIso);
|
|
222
|
+
const max = inRange.reduce((acc, point) => Math.max(acc, metric(point)), 0);
|
|
223
|
+
const level = (value: number): number => {
|
|
224
|
+
if (value <= 0 || max <= 0) return 0;
|
|
225
|
+
return Math.min(4, Math.max(1, Math.ceil(Math.sqrt(value / max) * 4)));
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const monthLabels: (string | undefined)[] = [];
|
|
229
|
+
const cells: (number | null)[][] = Array.from({ length: 7 }, () =>
|
|
230
|
+
Array.from({ length: weeks }, (): number | null => null),
|
|
231
|
+
);
|
|
232
|
+
let previousMonth = -1;
|
|
233
|
+
for (let week = 0; week < weeks; week++) {
|
|
234
|
+
const weekStart = addDays(start, week * 7);
|
|
235
|
+
const month = weekStart.getMonth();
|
|
236
|
+
monthLabels.push(month !== previousMonth ? MONTH_NAMES[month] : undefined);
|
|
237
|
+
previousMonth = month;
|
|
238
|
+
for (let day = 0; day < 7; day++) {
|
|
239
|
+
const date = addDays(weekStart, day);
|
|
240
|
+
if (date > today0) continue;
|
|
241
|
+
const point = byDay.get(localIso(date));
|
|
242
|
+
cells[day][week] = level(point ? metric(point) : 0);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
monthLabels,
|
|
248
|
+
cells,
|
|
249
|
+
totalCost: inRange.reduce((sum, point) => sum + point.cost, 0),
|
|
250
|
+
totalRequests: inRange.reduce((sum, point) => sum + point.requests, 0),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// =============================================================================
|
|
255
|
+
// Component
|
|
256
|
+
// =============================================================================
|
|
257
|
+
|
|
258
|
+
/** Callbacks and data sources for {@link UsageDashboardComponent}. */
|
|
259
|
+
export interface UsageDashboardOptions {
|
|
260
|
+
reports: UsageReport[];
|
|
261
|
+
/**
|
|
262
|
+
* Full classic `/usage` report for the expanded detail view; re-invoked per
|
|
263
|
+
* terminal width.
|
|
264
|
+
*/
|
|
265
|
+
renderDetail: (width: number) => string;
|
|
266
|
+
/**
|
|
267
|
+
* Stream daily activity into the heatmap: push cached DB rows immediately,
|
|
268
|
+
* then push again after an incremental session sync. Resolves when the sync
|
|
269
|
+
* settles; rejection renders as a dim unavailable note. `signal` aborts when
|
|
270
|
+
* the dashboard closes so an in-flight sync can stop early.
|
|
271
|
+
*/
|
|
272
|
+
loadActivity: (push: (points: DailyActivityPoint[]) => void, signal: AbortSignal) => Promise<void>;
|
|
273
|
+
requestRender: () => void;
|
|
274
|
+
onClose: () => void;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Sanitize activity loading error text for safe single-line display in the TUI overlay.
|
|
279
|
+
* Strips ANSI/control sequences, expands tabs, collapses whitespace runs/newlines,
|
|
280
|
+
* shortens home directory paths to ~, and removes trailing dots.
|
|
281
|
+
*/
|
|
282
|
+
export function formatActivityErrorDetail(error: string, homeDir = os.homedir()): string {
|
|
283
|
+
let text = replaceTabs(sanitizeText(error)).replace(/\s+/g, " ").trim();
|
|
284
|
+
if (homeDir) {
|
|
285
|
+
const escaped = homeDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
286
|
+
const forward = homeDir.replaceAll("\\", "/").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
287
|
+
text = text.replace(new RegExp(`${escaped}|${forward}`, "gi"), "~");
|
|
288
|
+
}
|
|
289
|
+
return text.replace(/\.+$/, "");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const CARD_MIN_WIDTH = 32;
|
|
293
|
+
const CARD_GUTTER = 3;
|
|
294
|
+
const CARD_MAX_WINDOWS = 4;
|
|
295
|
+
|
|
296
|
+
export class UsageDashboardComponent implements Component {
|
|
297
|
+
#options: UsageDashboardOptions;
|
|
298
|
+
#cards: ProviderCard[];
|
|
299
|
+
#nowMs: number;
|
|
300
|
+
#view: "overview" | "detail" = "overview";
|
|
301
|
+
#scroll = 0;
|
|
302
|
+
#activity: DailyActivityPoint[] | null = null;
|
|
303
|
+
#activityError: string | null = null;
|
|
304
|
+
#syncing = true;
|
|
305
|
+
#detailCache: { width: number; lines: string[] } | null = null;
|
|
306
|
+
#lastViewportRows = 10;
|
|
307
|
+
#closed = false;
|
|
308
|
+
readonly #panel: OverlayPanel;
|
|
309
|
+
readonly #header: PanelRows;
|
|
310
|
+
readonly #body: PanelRows;
|
|
311
|
+
readonly #footer: PanelRows;
|
|
312
|
+
readonly #closeController = new AbortController();
|
|
313
|
+
|
|
314
|
+
constructor(options: UsageDashboardOptions) {
|
|
315
|
+
ensureThemeSync();
|
|
316
|
+
this.#options = options;
|
|
317
|
+
this.#nowMs = Date.now();
|
|
318
|
+
this.#cards = buildProviderCards(options.reports, this.#nowMs);
|
|
319
|
+
this.#panel = new OverlayPanel("Usage");
|
|
320
|
+
this.#header = new PanelRows();
|
|
321
|
+
this.#header.setHeight(1);
|
|
322
|
+
this.#body = new PanelRows();
|
|
323
|
+
this.#footer = new PanelRows();
|
|
324
|
+
this.#footer.setHeight(1);
|
|
325
|
+
this.#panel.addChild(this.#header);
|
|
326
|
+
this.#panel.addChild(this.#body);
|
|
327
|
+
this.#panel.addChild(new PanelDivider());
|
|
328
|
+
this.#panel.addChild(this.#footer);
|
|
329
|
+
void this.#loadActivity();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async #loadActivity(): Promise<void> {
|
|
333
|
+
try {
|
|
334
|
+
await this.#options.loadActivity(points => {
|
|
335
|
+
if (this.#closed) return;
|
|
336
|
+
this.#activity = points;
|
|
337
|
+
this.#options.requestRender();
|
|
338
|
+
}, this.#closeController.signal);
|
|
339
|
+
} catch (error) {
|
|
340
|
+
this.#activityError = error instanceof Error ? error.message : String(error);
|
|
341
|
+
} finally {
|
|
342
|
+
this.#syncing = false;
|
|
343
|
+
if (!this.#closed) this.#options.requestRender();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
invalidate(): void {
|
|
348
|
+
this.#detailCache = null;
|
|
349
|
+
this.#panel.invalidate();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
dispose(): void {
|
|
353
|
+
this.#closed = true;
|
|
354
|
+
this.#closeController.abort();
|
|
355
|
+
this.#panel.dispose();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// ---------------------------------------------------------------------------
|
|
359
|
+
// Subscriptions grid rendering
|
|
360
|
+
// ---------------------------------------------------------------------------
|
|
361
|
+
|
|
362
|
+
#statusIcon(status: UsageLimit["status"]): string {
|
|
363
|
+
if (status === "exhausted") return theme.fg("error", theme.status.error);
|
|
364
|
+
if (status === "warning") return theme.fg("warning", theme.status.warning);
|
|
365
|
+
if (status === "ok") return theme.fg("success", theme.status.success);
|
|
366
|
+
return theme.fg("dim", theme.status.info);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
#statusColor(status: UsageLimit["status"]): "success" | "warning" | "error" | "dim" {
|
|
370
|
+
if (status === "exhausted") return "error";
|
|
371
|
+
if (status === "warning") return "warning";
|
|
372
|
+
if (status === "ok") return "success";
|
|
373
|
+
return "dim";
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
#miniBar(fraction: number | undefined, status: UsageLimit["status"], width: number): string {
|
|
377
|
+
if (fraction === undefined) return theme.fg("dim", "·".repeat(width));
|
|
378
|
+
const clamped = Math.min(Math.max(fraction, 0), 1);
|
|
379
|
+
const filled = Math.round(clamped * width);
|
|
380
|
+
const bar = "█".repeat(filled);
|
|
381
|
+
const empty = "░".repeat(width - filled);
|
|
382
|
+
return `${theme.fg(this.#statusColor(status), bar)}${theme.fg("dim", empty)}`;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
#renderCardLines(card: ProviderCard, width: number): string[] {
|
|
386
|
+
const lines: string[] = [];
|
|
387
|
+
const cardStatus = card.unlimited ? "ok" : aggregateStatus(card.windows);
|
|
388
|
+
const accountsText = card.accounts > 1 ? theme.fg("dim", `${card.accounts} accts`) : "";
|
|
389
|
+
const titleBudget = width - 2 - visibleWidth(accountsText) - (accountsText ? 1 : 0);
|
|
390
|
+
const title = theme.bold(truncateToWidth(card.name, Math.max(4, titleBudget)));
|
|
391
|
+
const titlePad = Math.max(0, width - 2 - visibleWidth(title) - visibleWidth(accountsText));
|
|
392
|
+
lines.push(`${this.#statusIcon(cardStatus)} ${title}${" ".repeat(titlePad)}${accountsText}`);
|
|
393
|
+
|
|
394
|
+
if (card.unlimited) {
|
|
395
|
+
lines.push(` ${theme.fg("dim", "no limits")}`);
|
|
396
|
+
return lines;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const hidden = card.windows.length - CARD_MAX_WINDOWS;
|
|
400
|
+
const visibleWindows = card.windows.slice(0, CARD_MAX_WINDOWS);
|
|
401
|
+
// Fixed columns across every row of the card so bars all start and end
|
|
402
|
+
// at the same x: label | bar | pct | reset. The reset column sizes to
|
|
403
|
+
// the card's widest countdown instead of flexing per row.
|
|
404
|
+
const resetWidth = visibleWindows.reduce(
|
|
405
|
+
(max, window) => Math.max(max, window.resetMs !== undefined ? formatDuration(window.resetMs).length : 0),
|
|
406
|
+
0,
|
|
407
|
+
);
|
|
408
|
+
const labelWidth = Math.min(16, Math.max(6, width - 24));
|
|
409
|
+
const barWidth = Math.max(5, width - 2 - labelWidth - 1 - 5 - (resetWidth > 0 ? resetWidth + 1 : 0));
|
|
410
|
+
for (const window of visibleWindows) {
|
|
411
|
+
const tagPlain = window.windowTag
|
|
412
|
+
? truncateToWidth(window.windowTag, Math.max(2, Math.floor(labelWidth / 2) - 1))
|
|
413
|
+
: "";
|
|
414
|
+
const baseWidth = tagPlain ? labelWidth - visibleWidth(tagPlain) - 1 : labelWidth;
|
|
415
|
+
const basePlain = truncateToWidth(window.label, baseWidth).padEnd(baseWidth);
|
|
416
|
+
const label = tagPlain
|
|
417
|
+
? `${theme.fg("muted", basePlain)} ${theme.fg("dim", tagPlain)}`
|
|
418
|
+
: theme.fg("muted", basePlain);
|
|
419
|
+
if (window.fraction === undefined) {
|
|
420
|
+
const text = theme.fg("dim", window.usedText ?? "no data");
|
|
421
|
+
lines.push(truncateToWidth(` ${label} ${text}`, width));
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
const freePct = Math.max(0, Math.round((1 - window.fraction) * 100));
|
|
425
|
+
const pctText = theme.fg(this.#statusColor(window.status), `${freePct}%`.padStart(5));
|
|
426
|
+
const resetPlain = window.resetMs !== undefined ? formatDuration(window.resetMs) : "";
|
|
427
|
+
const resetText = resetWidth > 0 ? ` ${theme.fg("dim", resetPlain.padStart(resetWidth))}` : "";
|
|
428
|
+
lines.push(` ${label} ${this.#miniBar(window.fraction, window.status, barWidth)}${pctText}${resetText}`);
|
|
429
|
+
}
|
|
430
|
+
if (hidden > 0) lines.push(` ${theme.fg("dim", `+${hidden} more`)}`);
|
|
431
|
+
return lines;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
#renderCardsGrid(innerWidth: number): string[] {
|
|
435
|
+
if (this.#cards.length === 0) return [theme.fg("dim", "No usage data available.")];
|
|
436
|
+
const active = this.#cards.filter(card => !card.idle);
|
|
437
|
+
const idle = this.#cards.filter(card => card.idle);
|
|
438
|
+
const columns = Math.max(1, Math.floor((innerWidth + CARD_GUTTER) / (CARD_MIN_WIDTH + CARD_GUTTER)));
|
|
439
|
+
const cardWidth = Math.floor((innerWidth - (columns - 1) * CARD_GUTTER) / columns);
|
|
440
|
+
const lines: string[] = [];
|
|
441
|
+
for (let start = 0; start < active.length; start += columns) {
|
|
442
|
+
const rowCards = active.slice(start, start + columns).map(card => this.#renderCardLines(card, cardWidth));
|
|
443
|
+
const height = Math.max(...rowCards.map(card => card.length));
|
|
444
|
+
for (let lineIdx = 0; lineIdx < height; lineIdx++) {
|
|
445
|
+
const segments = rowCards.map(card => {
|
|
446
|
+
const line = card[lineIdx] ?? "";
|
|
447
|
+
return line + " ".repeat(Math.max(0, cardWidth - visibleWidth(line)));
|
|
448
|
+
});
|
|
449
|
+
lines.push(segments.join(" ".repeat(CARD_GUTTER)).trimEnd());
|
|
450
|
+
}
|
|
451
|
+
if (start + columns < active.length) lines.push("");
|
|
452
|
+
}
|
|
453
|
+
// Untouched providers collapse into a single tick line: their windows
|
|
454
|
+
// are all at 100% free (or have no limits), so per-window bars are noise.
|
|
455
|
+
if (idle.length > 0) {
|
|
456
|
+
if (active.length > 0) lines.push("");
|
|
457
|
+
const names = idle.map(card => card.name).join(" · ");
|
|
458
|
+
const prefix = `${theme.fg("success", theme.status.success)} `;
|
|
459
|
+
lines.push(truncateToWidth(`${prefix}${theme.fg("dim", `untouched: ${names}`)}`, innerWidth));
|
|
460
|
+
}
|
|
461
|
+
return lines;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// ---------------------------------------------------------------------------
|
|
465
|
+
// Heatmap rendering
|
|
466
|
+
// ---------------------------------------------------------------------------
|
|
467
|
+
|
|
468
|
+
/** Truecolor ramp from the theme's background side toward its accent: level 1
|
|
469
|
+
* sits near-invisible, level 4 is the full accent, so cell brightness reads
|
|
470
|
+
* as amount of work. Anchored to black or white by the text color's luma so
|
|
471
|
+
* the ramp keeps its direction on light themes. */
|
|
472
|
+
#heatRamp(): string[] {
|
|
473
|
+
const mode = theme.getColorMode();
|
|
474
|
+
const darkBackground = (colorLuma(theme.getColorHex("text")) ?? 1) > 0.5;
|
|
475
|
+
const from = darkBackground ? { r: 20, g: 20, b: 24 } : { r: 244, g: 244, b: 246 };
|
|
476
|
+
const to = hexToRgb(theme.getColorHex("accent"));
|
|
477
|
+
return [0.3, 0.5, 0.72, 1].map(t =>
|
|
478
|
+
colorToAnsi(
|
|
479
|
+
rgbToHex({
|
|
480
|
+
r: Math.round(from.r + (to.r - from.r) * t),
|
|
481
|
+
g: Math.round(from.g + (to.g - from.g) * t),
|
|
482
|
+
b: Math.round(from.b + (to.b - from.b) * t),
|
|
483
|
+
}),
|
|
484
|
+
mode,
|
|
485
|
+
),
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
#renderHeatmap(innerWidth: number): string[] {
|
|
490
|
+
const summary: string[] = [];
|
|
491
|
+
if (this.#activityError) {
|
|
492
|
+
const detail = formatActivityErrorDetail(this.#activityError);
|
|
493
|
+
return [theme.fg("dim", detail ? `Usage history unavailable (${detail}).` : "Usage history unavailable.")];
|
|
494
|
+
}
|
|
495
|
+
const points = this.#activity;
|
|
496
|
+
if (!points) return [theme.fg("dim", "Loading usage history…")];
|
|
497
|
+
|
|
498
|
+
const labelWidth = 2;
|
|
499
|
+
const weeks = Math.max(4, Math.min(53, Math.floor((innerWidth - labelWidth) / 2)));
|
|
500
|
+
const layout = buildHeatmapLayout(points, weeks);
|
|
501
|
+
const ramp = this.#heatRamp();
|
|
502
|
+
const reset = "\x1b[39m";
|
|
503
|
+
|
|
504
|
+
const cost =
|
|
505
|
+
layout.totalCost >= 1
|
|
506
|
+
? `$${new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 }).format(layout.totalCost)}`
|
|
507
|
+
: `$${layout.totalCost.toFixed(2)}`;
|
|
508
|
+
const requests = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 }).format(
|
|
509
|
+
layout.totalRequests,
|
|
510
|
+
);
|
|
511
|
+
summary.push(
|
|
512
|
+
`${theme.bold(theme.fg("accent", "Activity"))} ${theme.fg("dim", `${cost} · ${requests} requests · last ${weeks} weeks`)}${this.#syncing ? theme.fg("dim", " · syncing…") : ""}`,
|
|
513
|
+
);
|
|
514
|
+
summary.push("");
|
|
515
|
+
|
|
516
|
+
let monthLine = " ".repeat(labelWidth);
|
|
517
|
+
for (let week = 0; week < weeks; week++) {
|
|
518
|
+
const label = layout.monthLabels[week];
|
|
519
|
+
const targetCol = labelWidth + week * 2;
|
|
520
|
+
if (label && targetCol >= visibleWidth(monthLine)) {
|
|
521
|
+
monthLine = monthLine.padEnd(targetCol) + label;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
summary.push(theme.fg("dim", truncateToWidth(monthLine, innerWidth)));
|
|
525
|
+
|
|
526
|
+
for (let day = 0; day < 7; day++) {
|
|
527
|
+
let line = theme.fg("dim", HEATMAP_DAY_LABELS[day]) + " ";
|
|
528
|
+
for (let week = 0; week < weeks; week++) {
|
|
529
|
+
const cell = layout.cells[day][week];
|
|
530
|
+
if (cell === null) line += " ";
|
|
531
|
+
else if (cell === 0) line += `${theme.fg("dim", "·")} `;
|
|
532
|
+
else line += `${ramp[cell - 1]}■${reset} `;
|
|
533
|
+
}
|
|
534
|
+
summary.push(line.trimEnd());
|
|
535
|
+
}
|
|
536
|
+
return summary;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// ---------------------------------------------------------------------------
|
|
540
|
+
// Frame
|
|
541
|
+
// ---------------------------------------------------------------------------
|
|
542
|
+
|
|
543
|
+
#overviewLines(innerWidth: number): string[] {
|
|
544
|
+
const lines: string[] = [];
|
|
545
|
+
lines.push(...this.#renderCardsGrid(innerWidth));
|
|
546
|
+
lines.push("");
|
|
547
|
+
lines.push(...this.#renderHeatmap(innerWidth));
|
|
548
|
+
return lines;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
#detailLines(innerWidth: number): string[] {
|
|
552
|
+
if (this.#detailCache?.width !== innerWidth) {
|
|
553
|
+
this.#detailCache = { width: innerWidth, lines: this.#options.renderDetail(innerWidth).split("\n") };
|
|
554
|
+
}
|
|
555
|
+
return this.#detailCache.lines;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
render(width: number): readonly string[] {
|
|
559
|
+
const height = Math.max(14, process.stdout.rows || 40);
|
|
560
|
+
const innerWidth = Math.max(20, width - 4);
|
|
561
|
+
|
|
562
|
+
const contentSource = this.#view === "detail" ? this.#detailLines(innerWidth) : this.#overviewLines(innerWidth);
|
|
563
|
+
// Fixed chrome: top border, blank, content…, divider, hint, bottom border.
|
|
564
|
+
const contentRows = Math.max(5, height - 5);
|
|
565
|
+
this.#lastViewportRows = contentRows;
|
|
566
|
+
const maxScroll = Math.max(0, contentSource.length - contentRows);
|
|
567
|
+
if (this.#scroll > maxScroll) this.#scroll = maxScroll;
|
|
568
|
+
|
|
569
|
+
const latestFetchedAt = Math.max(0, ...this.#options.reports.map(report => report.fetchedAt ?? 0));
|
|
570
|
+
const checkedText = latestFetchedAt ? `checked ${formatDuration(this.#nowMs - latestFetchedAt)} ago` : "";
|
|
571
|
+
const title = this.#view === "detail" ? "Usage · Details" : "Usage";
|
|
572
|
+
|
|
573
|
+
const scrollHint = maxScroll > 0 ? "↑/↓ scroll · " : "";
|
|
574
|
+
const hint = this.#view === "detail" ? `${scrollHint}Esc back` : `${scrollHint}↵ details · Esc close`;
|
|
575
|
+
this.#panel.title = title;
|
|
576
|
+
this.#header.setLines([checkedText ? theme.fg("dim", checkedText) : ""]);
|
|
577
|
+
this.#body.setLines(contentSource.slice(this.#scroll, this.#scroll + contentRows));
|
|
578
|
+
this.#body.setHeight(contentRows);
|
|
579
|
+
this.#footer.setLines([theme.fg("dim", hint)]);
|
|
580
|
+
return this.#panel.render(width);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
#scrollBy(delta: number): void {
|
|
584
|
+
this.#scroll = Math.max(0, this.#scroll + delta);
|
|
585
|
+
this.#options.requestRender();
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
#setView(view: "overview" | "detail"): void {
|
|
589
|
+
this.#view = view;
|
|
590
|
+
this.#scroll = 0;
|
|
591
|
+
this.#options.requestRender();
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
handleInput(data: string): void {
|
|
595
|
+
if (
|
|
596
|
+
routeSgrMouseInput(data, event => {
|
|
597
|
+
if (event.wheel === null) return false;
|
|
598
|
+
this.#scrollBy(event.wheel * 2);
|
|
599
|
+
return true;
|
|
600
|
+
})
|
|
601
|
+
) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (matchesSelectCancel(data) || matchesKey(data, "q")) {
|
|
605
|
+
if (this.#view === "detail") {
|
|
606
|
+
this.#setView("overview");
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
this.dispose();
|
|
610
|
+
this.#options.onClose();
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
if (
|
|
614
|
+
this.#view === "overview" &&
|
|
615
|
+
(matchesKey(data, "return") || matchesKey(data, "tab") || matchesKey(data, "d"))
|
|
616
|
+
) {
|
|
617
|
+
this.#setView("detail");
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (matchesSelectUp(data)) this.#scrollBy(-1);
|
|
621
|
+
else if (matchesSelectDown(data)) this.#scrollBy(1);
|
|
622
|
+
else if (matchesSelectPageUp(data)) this.#scrollBy(-this.#lastViewportRows);
|
|
623
|
+
else if (matchesSelectPageDown(data)) this.#scrollBy(this.#lastViewportRows);
|
|
624
|
+
else if (matchesKey(data, "home")) {
|
|
625
|
+
this.#scroll = 0;
|
|
626
|
+
this.#options.requestRender();
|
|
627
|
+
} else if (matchesKey(data, "end")) this.#scrollBy(Number.MAX_SAFE_INTEGER);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { UsageLimit, UsageReport } from "@oh-my-pi/pi-ai";
|
|
2
|
+
|
|
3
|
+
/** Include the usage tier in a limit title unless its label already names it. */
|
|
4
|
+
export function formatLimitTitle(limit: UsageLimit): string {
|
|
5
|
+
const tier = limit.scope.tier;
|
|
6
|
+
if (tier && !limit.label.toLowerCase().includes(tier.toLowerCase())) {
|
|
7
|
+
return `${limit.label} (${tier})`;
|
|
8
|
+
}
|
|
9
|
+
return limit.label;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function collapseSharedLimits(limits: UsageLimit[]): UsageLimit[] {
|
|
13
|
+
const seenGroups = new Set<string>();
|
|
14
|
+
let collapsed: UsageLimit[] | undefined;
|
|
15
|
+
|
|
16
|
+
for (let index = 0; index < limits.length; index++) {
|
|
17
|
+
const limit = limits[index]!;
|
|
18
|
+
const group = limit.scope.sharedGroup;
|
|
19
|
+
if (group !== undefined && seenGroups.has(group)) {
|
|
20
|
+
collapsed ??= limits.slice(0, index);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (group !== undefined) seenGroups.add(group);
|
|
24
|
+
collapsed?.push(limit);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return collapsed ?? limits;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Collapse routing-specific copies of a shared quota for user-facing usage views. */
|
|
31
|
+
export function collapseSharedUsageReports(reports: UsageReport[]): UsageReport[] {
|
|
32
|
+
let collapsed: UsageReport[] | undefined;
|
|
33
|
+
|
|
34
|
+
for (let index = 0; index < reports.length; index++) {
|
|
35
|
+
const report = reports[index]!;
|
|
36
|
+
const limits = collapseSharedLimits(report.limits);
|
|
37
|
+
const displayReport = limits === report.limits ? report : { ...report, limits };
|
|
38
|
+
if (displayReport !== report) {
|
|
39
|
+
collapsed ??= reports.slice(0, index);
|
|
40
|
+
}
|
|
41
|
+
collapsed?.push(displayReport);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return collapsed ?? reports;
|
|
45
|
+
}
|