@oh-my-pi/pi-tui 18.4.2 → 18.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/dist/types/apps/cleanse-board.d.ts +17 -0
- package/dist/types/apps/git/help.d.ts +16 -0
- package/dist/types/apps/git/sidebar.d.ts +18 -0
- package/dist/types/apps/live-visualizer.d.ts +10 -0
- package/dist/types/apps/ps-top.d.ts +15 -0
- package/dist/types/apps/standalone-picker.d.ts +3 -0
- package/dist/types/autocomplete.d.ts +8 -0
- package/dist/types/chat/advisor-message.d.ts +12 -2
- package/dist/types/chat/assistant-message.d.ts +20 -0
- package/dist/types/chat/bash-execution.d.ts +9 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +6 -1
- package/dist/types/chat/collab-prompt-message.d.ts +4 -0
- package/dist/types/chat/compaction-summary-message.d.ts +15 -0
- package/dist/types/chat/eval-execution.d.ts +8 -0
- package/dist/types/chat/execution-shared.d.ts +58 -0
- package/dist/types/chat/late-diagnostics-message.d.ts +15 -1
- package/dist/types/chat/read-tool-group.d.ts +15 -0
- package/dist/types/chat/skill-message.d.ts +9 -0
- package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +3 -0
- package/dist/types/chat/thinking-display.d.ts +2 -0
- package/dist/types/chat/todo-reminder.d.ts +4 -1
- package/dist/types/chat/tool-execution.d.ts +25 -1
- package/dist/types/chat/transcript-actions.d.ts +37 -0
- package/dist/types/chat/transcript-entry.d.ts +3 -1
- package/dist/types/chat/user-message.d.ts +25 -0
- package/dist/types/chrome/collab-qrcode.d.ts +7 -0
- package/dist/types/chrome/context-thresholds.d.ts +11 -0
- package/dist/types/chrome/countdown-timer.d.ts +9 -3
- package/dist/types/chrome/diff.d.ts +12 -0
- package/dist/types/chrome/dynamic-border.d.ts +3 -0
- package/dist/types/chrome/format.d.ts +6 -0
- package/dist/types/chrome/message-divider.d.ts +13 -0
- package/dist/types/chrome/message-frame.d.ts +10 -0
- package/dist/types/chrome/message-notice.d.ts +23 -0
- package/dist/types/chrome/overlay-box.d.ts +11 -2
- package/dist/types/chrome/qrcode.d.ts +7 -0
- package/dist/types/chrome/segment-track.d.ts +7 -0
- package/dist/types/chrome/selector-helpers.d.ts +0 -6
- package/dist/types/chrome/status-notice.d.ts +14 -0
- package/dist/types/chrome/streaming-panel.d.ts +3 -0
- package/dist/types/chrome/tool-activity.d.ts +3 -0
- package/dist/types/chrome/transcript-container.d.ts +13 -0
- package/dist/types/chrome/transcript-status.d.ts +15 -3
- package/dist/types/components/box.d.ts +7 -0
- package/dist/types/components/disclosure.d.ts +9 -0
- package/dist/types/components/editor.d.ts +42 -0
- package/dist/types/components/form.d.ts +14 -0
- package/dist/types/components/image.d.ts +7 -0
- package/dist/types/components/input.d.ts +20 -1
- package/dist/types/components/key-value-list.d.ts +3 -0
- package/dist/types/components/layout/geometry.d.ts +16 -0
- package/dist/types/components/layout/row.d.ts +7 -0
- package/dist/types/components/layout/split-pane.d.ts +8 -0
- package/dist/types/components/layout/stack.d.ts +6 -0
- package/dist/types/components/loader.d.ts +48 -0
- package/dist/types/components/markdown.d.ts +8 -0
- package/dist/types/components/metric.d.ts +7 -0
- package/dist/types/components/progress-bar.d.ts +3 -0
- package/dist/types/components/scroll-view.d.ts +6 -0
- package/dist/types/components/section.d.ts +3 -0
- package/dist/types/components/select-list.d.ts +33 -0
- package/dist/types/components/settings-list.d.ts +68 -0
- package/dist/types/components/spacer.d.ts +4 -0
- package/dist/types/components/tab-bar.d.ts +9 -0
- package/dist/types/components/table.d.ts +7 -0
- package/dist/types/components/text.d.ts +6 -0
- package/dist/types/components/tree-view.d.ts +9 -0
- package/dist/types/components/truncated-text.d.ts +3 -0
- package/dist/types/components/wizard-step.d.ts +6 -0
- package/dist/types/hotkeys-markdown.d.ts +24 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/latex-block.d.ts +7 -0
- package/dist/types/loop-watchdog.d.ts +9 -0
- package/dist/types/native/apply.d.ts +39 -0
- package/dist/types/native/backend.d.ts +94 -0
- package/dist/types/native/blobs.d.ts +29 -0
- package/dist/types/native/describe.d.ts +56 -0
- package/dist/types/native/encode.d.ts +50 -0
- package/dist/types/native/icons.d.ts +18 -0
- package/dist/types/native/memo.d.ts +27 -0
- package/dist/types/native/node.d.ts +107 -0
- package/dist/types/native/overlay.d.ts +64 -0
- package/dist/types/native/picker.d.ts +124 -0
- package/dist/types/native/reconcile.d.ts +41 -0
- package/dist/types/native/settle.d.ts +11 -0
- package/dist/types/native/spans.d.ts +21 -0
- package/dist/types/native/state.d.ts +6 -0
- package/dist/types/native/tone.d.ts +24 -0
- package/dist/types/overlays/advisor-config.d.ts +20 -0
- package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
- package/dist/types/overlays/agent-hub.d.ts +10 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
- package/dist/types/overlays/agents-hub.d.ts +8 -0
- package/dist/types/overlays/annotation-overlay.d.ts +3 -0
- package/dist/types/overlays/ask-dialog.d.ts +23 -0
- package/dist/types/overlays/bordered-loader.d.ts +3 -0
- package/dist/types/overlays/btw-history-panel.d.ts +9 -0
- package/dist/types/overlays/btw-panel.d.ts +3 -0
- package/dist/types/overlays/cleanse-panel.d.ts +5 -2
- package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
- package/dist/types/overlays/copy-selector.d.ts +38 -0
- package/dist/types/overlays/error-banner.d.ts +9 -0
- package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
- package/dist/types/overlays/history-search.d.ts +18 -0
- package/dist/types/overlays/hook-editor.d.ts +28 -1
- package/dist/types/overlays/hook-input.d.ts +3 -0
- package/dist/types/overlays/hook-selector.d.ts +10 -0
- package/dist/types/overlays/hub-frame.d.ts +18 -0
- package/dist/types/overlays/jobs-panel.d.ts +24 -0
- package/dist/types/overlays/login-dialog.d.ts +10 -0
- package/dist/types/overlays/logout-account-selector.d.ts +4 -0
- package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
- package/dist/types/overlays/model-browser.d.ts +69 -0
- package/dist/types/overlays/model-hub.d.ts +7 -0
- package/dist/types/overlays/model-picker.d.ts +9 -1
- package/dist/types/overlays/move-overlay.d.ts +3 -0
- package/dist/types/overlays/oauth-selector.d.ts +4 -0
- package/dist/types/overlays/omfg-panel.d.ts +3 -0
- package/dist/types/overlays/pause-screen.d.ts +12 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
- package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
- package/dist/types/overlays/plugin-selector.d.ts +4 -0
- package/dist/types/overlays/plugin-settings.d.ts +30 -0
- package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
- package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
- package/dist/types/overlays/rewind-selector.d.ts +5 -0
- package/dist/types/overlays/session-info-overlay.d.ts +19 -1
- package/dist/types/overlays/session-selector.d.ts +64 -1
- package/dist/types/overlays/settings-defs.d.ts +14 -0
- package/dist/types/overlays/settings-selector.d.ts +21 -0
- package/dist/types/overlays/show-images-selector.d.ts +4 -0
- package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
- package/dist/types/overlays/stats-notice.d.ts +8 -0
- package/dist/types/overlays/theme-selector.d.ts +11 -0
- package/dist/types/overlays/thinking-selector.d.ts +4 -0
- package/dist/types/overlays/tree-selector.d.ts +60 -2
- package/dist/types/overlays/usage-dashboard.d.ts +26 -3
- package/dist/types/overlays/usage-row.d.ts +36 -2
- package/dist/types/prompt/attachment-chips.d.ts +8 -0
- package/dist/types/prompt/composer-attachments.d.ts +15 -3
- package/dist/types/prompt/composer.d.ts +18 -1
- package/dist/types/prompt/custom-editor.d.ts +48 -2
- package/dist/types/prompt/editor-top-gap.d.ts +2 -0
- package/dist/types/prompt/macos-spelling.d.ts +6 -0
- package/dist/types/prompt/magic-keywords.d.ts +9 -0
- package/dist/types/prompt/queued-messages.d.ts +23 -0
- package/dist/types/prompt/skill-tokens.d.ts +4 -2
- package/dist/types/prompt/welcome.d.ts +16 -0
- package/dist/types/render/code-cell.d.ts +10 -0
- package/dist/types/render/file-list.d.ts +8 -0
- package/dist/types/render/hyperlink.d.ts +14 -0
- package/dist/types/render/output-block.d.ts +43 -0
- package/dist/types/render/output-pane.d.ts +17 -0
- package/dist/types/render/tool-card.d.ts +8 -0
- package/dist/types/render/tree-list.d.ts +8 -0
- package/dist/types/render/width-aware-text.d.ts +7 -0
- package/dist/types/setup/scenes/outro.d.ts +7 -0
- package/dist/types/setup/scenes/sign-in.d.ts +16 -9
- package/dist/types/setup/scenes/splash.d.ts +8 -0
- package/dist/types/setup/scenes/types.d.ts +6 -27
- package/dist/types/setup/wizard-overlay.d.ts +9 -0
- package/dist/types/status-line/component.d.ts +49 -5
- package/dist/types/status-line/context-usage.d.ts +20 -0
- package/dist/types/status-line/footer.d.ts +8 -0
- package/dist/types/status-line/metrics.d.ts +1 -2
- package/dist/types/status-line/segments.d.ts +10 -1
- package/dist/types/status-line/types.d.ts +40 -1
- package/dist/types/stdin-buffer.d.ts +10 -7
- package/dist/types/terminal-capabilities.d.ts +1 -1
- package/dist/types/terminal.d.ts +36 -0
- package/dist/types/theme/defaults/index.d.ts +100 -0
- package/dist/types/theme/schema.d.ts +2 -0
- package/dist/types/theme/shimmer.d.ts +8 -0
- package/dist/types/theme/theme-class.d.ts +2 -0
- package/dist/types/theme/theme.d.ts +33 -1
- package/dist/types/tools/ask.d.ts +3 -0
- package/dist/types/tools/ast-edit.d.ts +10 -1
- package/dist/types/tools/ast-grep.d.ts +10 -1
- package/dist/types/tools/autoresearch.d.ts +21 -4
- package/dist/types/tools/bash.d.ts +30 -1
- package/dist/types/tools/cfg-render.d.ts +5 -1
- package/dist/types/tools/debug.d.ts +3 -1
- package/dist/types/tools/default-renderer.d.ts +6 -1
- package/dist/types/tools/edit.d.ts +14 -1
- package/dist/types/tools/eval.d.ts +12 -1
- package/dist/types/tools/fetch.d.ts +16 -1
- package/dist/types/tools/find.d.ts +15 -1
- package/dist/types/tools/github.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +14 -1
- package/dist/types/tools/goal.d.ts +3 -1
- package/dist/types/tools/grep.d.ts +14 -1
- package/dist/types/tools/grouped-file-output.d.ts +58 -0
- package/dist/types/tools/json-tree.d.ts +20 -0
- package/dist/types/tools/lsp.d.ts +3 -10
- package/dist/types/tools/mcp.d.ts +16 -1
- package/dist/types/tools/memory.d.ts +26 -0
- package/dist/types/tools/native-view.d.ts +90 -0
- package/dist/types/tools/proc-render.d.ts +7 -1
- package/dist/types/tools/read.d.ts +23 -1
- package/dist/types/tools/renderer.d.ts +57 -0
- package/dist/types/tools/report-tool-issue.d.ts +3 -0
- package/dist/types/tools/resolve.d.ts +14 -1
- package/dist/types/tools/task.d.ts +3 -0
- package/dist/types/tools/think.d.ts +3 -0
- package/dist/types/tools/todo.d.ts +12 -0
- package/dist/types/tools/vibe.d.ts +3 -1
- package/dist/types/tools/wait.d.ts +3 -0
- package/dist/types/tools/web-search-types.d.ts +90 -0
- package/dist/types/tools/web-search.d.ts +9 -168
- package/dist/types/tools/write.d.ts +14 -1
- package/dist/types/tools/xdev.d.ts +13 -0
- package/dist/types/tui.d.ts +49 -0
- package/package.json +9 -9
- package/src/apps/autoresearch-dashboard.ts +362 -4
- package/src/apps/cleanse-board.ts +219 -1
- package/src/apps/cleanse-picker.ts +9 -1
- package/src/apps/debug/log-viewer.ts +15 -15
- package/src/apps/debug/protocol-probe.ts +2 -20
- package/src/apps/git/avatar.ts +2 -22
- package/src/apps/git/git-tui.ts +406 -59
- package/src/apps/git/help.ts +130 -0
- package/src/apps/git/sidebar.ts +491 -0
- package/src/apps/live-visualizer.ts +65 -0
- package/src/apps/ps-top.ts +448 -17
- package/src/apps/session-picker.ts +1 -0
- package/src/apps/setup-model-picker.ts +5 -1
- package/src/apps/standalone-picker.ts +55 -1
- package/src/autocomplete.ts +44 -1
- package/src/chat/advisor-message.ts +72 -3
- package/src/chat/assistant-message.ts +538 -51
- package/src/chat/background-tan-message.ts +4 -4
- package/src/chat/bash-execution.ts +81 -0
- package/src/chat/cache-invalidation-marker.ts +8 -0
- package/src/chat/chat-transcript-builder.ts +37 -6
- package/src/chat/collab-prompt-message.ts +15 -3
- package/src/chat/compaction-summary-message.ts +74 -1
- package/src/chat/custom-message.ts +3 -1
- package/src/chat/eval-execution.ts +57 -0
- package/src/chat/execution-shared.ts +153 -1
- package/src/chat/hook-message.ts +1 -0
- package/src/chat/late-diagnostics-message.ts +85 -2
- package/src/chat/read-tool-group.ts +341 -1
- package/src/chat/served-model-marker.ts +8 -0
- package/src/chat/skill-message.ts +63 -0
- package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
- package/src/chat/thinking-display.ts +73 -11
- package/src/chat/todo-reminder.ts +34 -4
- package/src/chat/tool-execution.ts +385 -10
- package/src/chat/transcript-actions.ts +38 -0
- package/src/chat/transcript-browser.ts +2 -9
- package/src/chat/transcript-entry.ts +10 -1
- package/src/chat/transcript-render-helpers.ts +16 -15
- package/src/chat/ttsr-notification.ts +38 -1
- package/src/chat/user-message.ts +167 -4
- package/src/chrome/collab-qrcode.ts +27 -2
- package/src/chrome/context-thresholds.ts +34 -0
- package/src/chrome/countdown-timer.ts +24 -1
- package/src/chrome/diff.ts +60 -1
- package/src/chrome/dynamic-border.ts +7 -0
- package/src/chrome/format.ts +12 -0
- package/src/chrome/message-divider.ts +33 -1
- package/src/chrome/message-frame.ts +53 -10
- package/src/chrome/message-notice.ts +71 -0
- package/src/chrome/overlay-box.ts +45 -2
- package/src/chrome/qrcode.ts +28 -0
- package/src/chrome/segment-track.ts +26 -0
- package/src/chrome/selector-helpers.ts +1 -17
- package/src/chrome/status-notice.ts +46 -0
- package/src/chrome/streaming-panel.ts +25 -1
- package/src/chrome/tool-activity.ts +20 -0
- package/src/chrome/transcript-container.ts +139 -17
- package/src/chrome/transcript-status.ts +40 -11
- package/src/components/box.ts +51 -0
- package/src/components/disclosure.ts +33 -0
- package/src/components/editor.ts +239 -36
- package/src/components/form.ts +93 -9
- package/src/components/image.ts +30 -0
- package/src/components/input.ts +77 -26
- package/src/components/key-value-list.ts +18 -0
- package/src/components/layout/geometry.ts +44 -0
- package/src/components/layout/row.ts +30 -0
- package/src/components/layout/split-pane.ts +65 -0
- package/src/components/layout/stack.ts +27 -0
- package/src/components/loader.ts +183 -1
- package/src/components/markdown.ts +131 -56
- package/src/components/metric.ts +39 -0
- package/src/components/progress-bar.ts +28 -0
- package/src/components/scroll-view.ts +23 -0
- package/src/components/section.ts +16 -0
- package/src/components/select-list.ts +174 -25
- package/src/components/settings-list.ts +264 -7
- package/src/components/spacer.ts +17 -0
- package/src/components/tab-bar.ts +42 -0
- package/src/components/table.ts +34 -0
- package/src/components/text.ts +23 -0
- package/src/components/tree-view.ts +65 -0
- package/src/components/truncated-text.ts +14 -0
- package/src/components/wizard-step.ts +18 -9
- package/src/debug-server.ts +14 -7
- package/src/hotkeys-markdown.ts +251 -69
- package/src/index.ts +6 -0
- package/src/latex-block.ts +11 -0
- package/src/loop-watchdog.ts +38 -10
- package/src/native/apply.ts +275 -0
- package/src/native/backend.ts +682 -0
- package/src/native/blobs.ts +70 -0
- package/src/native/describe.ts +124 -0
- package/src/native/encode.ts +233 -0
- package/src/native/icons.ts +184 -0
- package/src/native/memo.ts +64 -0
- package/src/native/node.ts +112 -0
- package/src/native/overlay.ts +131 -0
- package/src/native/picker.ts +333 -0
- package/src/native/reconcile.ts +1063 -0
- package/src/native/settle.ts +23 -0
- package/src/native/spans.ts +308 -0
- package/src/native/state.ts +28 -0
- package/src/native/tone.ts +79 -0
- package/src/overlays/advisor-config.ts +420 -0
- package/src/overlays/agent-hub-renderer.ts +155 -18
- package/src/overlays/agent-hub.ts +1037 -44
- package/src/overlays/agent-transcript-viewer.ts +129 -0
- package/src/overlays/agents-hub.ts +688 -53
- package/src/overlays/annotation-overlay.ts +391 -52
- package/src/overlays/ask-dialog.ts +435 -24
- package/src/overlays/bordered-loader.ts +17 -0
- package/src/overlays/btw-history-panel.ts +182 -0
- package/src/overlays/btw-panel.ts +68 -2
- package/src/overlays/cleanse-panel.ts +105 -15
- package/src/overlays/codex-reset-fireworks.ts +65 -5
- package/src/overlays/composer-shape-preview.ts +26 -1
- package/src/overlays/copy-selector.ts +545 -23
- package/src/overlays/error-banner.ts +44 -0
- package/src/overlays/extensions/extension-list.ts +23 -17
- package/src/overlays/history-search.ts +175 -33
- package/src/overlays/hook-editor.ts +113 -6
- package/src/overlays/hook-input.ts +22 -1
- package/src/overlays/hook-selector.ts +311 -22
- package/src/overlays/hub-frame.ts +80 -0
- package/src/overlays/jobs-panel.ts +112 -0
- package/src/overlays/login-dialog.ts +183 -1
- package/src/overlays/logout-account-selector.ts +102 -4
- package/src/overlays/mcp-add-wizard.ts +232 -53
- package/src/overlays/model-browser.ts +681 -22
- package/src/overlays/model-hub.ts +1402 -78
- package/src/overlays/model-picker.ts +184 -7
- package/src/overlays/move-overlay.ts +45 -0
- package/src/overlays/oauth-selector.ts +227 -23
- package/src/overlays/omfg-panel.ts +86 -2
- package/src/overlays/pause-screen.ts +55 -4
- package/src/overlays/plan-review-overlay.ts +352 -0
- package/src/overlays/plan-save-overlay.ts +45 -0
- package/src/overlays/plugin-selector.ts +21 -1
- package/src/overlays/plugin-settings.ts +195 -5
- package/src/overlays/queue-mode-selector.ts +19 -1
- package/src/overlays/reset-usage-selector.ts +110 -40
- package/src/overlays/rewind-selector.ts +458 -44
- package/src/overlays/session-account-selector.ts +1 -1
- package/src/overlays/session-info-overlay.ts +137 -1
- package/src/overlays/session-selector.ts +807 -46
- package/src/overlays/settings-defs.ts +41 -0
- package/src/overlays/settings-selector.ts +585 -33
- package/src/overlays/show-images-selector.ts +18 -1
- package/src/overlays/snapcompact-shape-preview.ts +48 -3
- package/src/overlays/stats-notice.ts +31 -0
- package/src/overlays/theme-selector.ts +31 -1
- package/src/overlays/thinking-selector.ts +22 -1
- package/src/overlays/tree-selector.ts +570 -110
- package/src/overlays/usage-dashboard.ts +587 -12
- package/src/overlays/usage-row.ts +161 -25
- package/src/prompt/attachment-chips.ts +60 -0
- package/src/prompt/composer-attachments.ts +31 -9
- package/src/prompt/composer.ts +55 -2
- package/src/prompt/custom-editor.ts +302 -4
- package/src/prompt/editor-top-gap.ts +8 -0
- package/src/prompt/macos-spelling.ts +24 -9
- package/src/prompt/magic-keywords.ts +22 -1
- package/src/prompt/model-mention-autocomplete.ts +1 -0
- package/src/prompt/queued-messages.ts +101 -0
- package/src/prompt/skill-tokens.ts +5 -3
- package/src/prompt/welcome.ts +213 -6
- package/src/render/code-cell.ts +103 -2
- package/src/render/file-list.ts +29 -0
- package/src/render/hyperlink.ts +32 -0
- package/src/render/output-block.ts +110 -0
- package/src/render/output-pane.ts +37 -0
- package/src/render/tool-card.ts +137 -0
- package/src/render/tree-list.ts +39 -0
- package/src/render/width-aware-text.ts +20 -0
- package/src/setup/scenes/composer.ts +29 -0
- package/src/setup/scenes/glyph.ts +15 -0
- package/src/setup/scenes/model.ts +36 -8
- package/src/setup/scenes/outro.ts +28 -1
- package/src/setup/scenes/sign-in.ts +138 -24
- package/src/setup/scenes/splash.ts +28 -1
- package/src/setup/scenes/theme.ts +88 -3
- package/src/setup/scenes/types.ts +7 -28
- package/src/setup/startup-splash.ts +46 -9
- package/src/setup/wizard-overlay.ts +140 -23
- package/src/setup/wizard.ts +1 -1
- package/src/status-line/component.ts +414 -18
- package/src/status-line/context-usage.ts +279 -50
- package/src/status-line/footer.ts +94 -1
- package/src/status-line/metrics.ts +3 -6
- package/src/status-line/segments.ts +463 -97
- package/src/status-line/separators.ts +3 -16
- package/src/status-line/types.ts +43 -1
- package/src/stdin-buffer.ts +27 -21
- package/src/terminal-capabilities.ts +7 -0
- package/src/terminal.ts +153 -11
- package/src/theme/defaults/dark-neon-noir.json +100 -0
- package/src/theme/defaults/index.ts +2 -0
- package/src/theme/defaults/light-prism.json +5 -5
- package/src/theme/defaults/onyx.json +62 -62
- package/src/theme/mermaid-cache.ts +10 -1
- package/src/theme/schema.ts +15 -0
- package/src/theme/shimmer.ts +33 -0
- package/src/theme/theme-class.ts +24 -19
- package/src/theme/theme.ts +111 -9
- package/src/theme/tui-adapters.ts +14 -1
- package/src/tools/ask.ts +157 -1
- package/src/tools/ast-edit.ts +174 -1
- package/src/tools/ast-grep.ts +82 -2
- package/src/tools/autoresearch.ts +149 -1
- package/src/tools/bash.ts +233 -62
- package/src/tools/cfg-render.ts +66 -1
- package/src/tools/debug.ts +78 -1
- package/src/tools/default-renderer.ts +35 -1
- package/src/tools/edit.ts +357 -31
- package/src/tools/eval.ts +257 -1
- package/src/tools/fetch.ts +102 -3
- package/src/tools/find.ts +127 -1
- package/src/tools/github.ts +119 -10
- package/src/tools/glob.ts +116 -1
- package/src/tools/goal.ts +56 -1
- package/src/tools/grep.ts +83 -2
- package/src/tools/grouped-file-output.ts +205 -0
- package/src/tools/json-tree.ts +116 -1
- package/src/tools/lsp.ts +318 -1
- package/src/tools/mcp.ts +80 -1
- package/src/tools/memory.ts +93 -11
- package/src/tools/native-view.ts +292 -0
- package/src/tools/proc-render.ts +221 -1
- package/src/tools/read.ts +199 -4
- package/src/tools/renderer.ts +61 -0
- package/src/tools/report-tool-issue.ts +7 -1
- package/src/tools/resolve.ts +63 -1
- package/src/tools/streaming-output.ts +79 -16
- package/src/tools/task.ts +406 -4
- package/src/tools/think.ts +19 -1
- package/src/tools/todo.ts +89 -0
- package/src/tools/vibe.ts +230 -2
- package/src/tools/wait.ts +181 -1
- package/src/tools/web-search-types.ts +99 -0
- package/src/tools/web-search.ts +111 -170
- package/src/tools/write.ts +144 -5
- package/src/tools/xdev.ts +64 -1
- package/src/tui.ts +295 -4
- package/dist/types/setup/scenes/providers.d.ts +0 -3
- package/dist/types/setup/scenes/web-search.d.ts +0 -22
- package/src/setup/scenes/providers.ts +0 -110
- package/src/setup/scenes/web-search.ts +0 -165
package/src/apps/git/git-tui.ts
CHANGED
|
@@ -24,19 +24,25 @@
|
|
|
24
24
|
* every file underneath it.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
+
import type { TspSpan } from "@oh-my-pi/pi-wire";
|
|
27
28
|
import { formatKeyHint, formatKeyHints } from "../../app-keybindings";
|
|
28
29
|
import { SplitPane } from "../../components/layout/split-pane";
|
|
29
30
|
import { Stack } from "../../components/layout/stack";
|
|
30
31
|
import { matchesKey } from "../../keys";
|
|
31
32
|
import { ProcessTerminal } from "../../terminal";
|
|
32
33
|
import { routeSgrMouseInput } from "../../mouse";
|
|
33
|
-
import {
|
|
34
|
+
import { col, compact, keyed, node, row, span, text } from "../../native/describe";
|
|
35
|
+
import { Memo } from "../../native/memo";
|
|
36
|
+
import type { DescribeContext, NativeNode, NativeUiEvent } from "../../native/node";
|
|
37
|
+
import { actionButton } from "../../native/overlay";
|
|
38
|
+
import { type Component, type OverlayHandle, TUI } from "../../tui";
|
|
34
39
|
import { truncateToWidth, visibleWidth } from "../../utils";
|
|
35
40
|
import { theme, warmHighlighter } from "../../theme/theme";
|
|
36
41
|
import type { AvatarSource } from "./avatar";
|
|
37
42
|
import { pill, softPill, tintChip } from "./colors";
|
|
38
43
|
import {
|
|
39
44
|
buildDiffDocument,
|
|
45
|
+
type DiffDocument,
|
|
40
46
|
buildLineSelectionPatch,
|
|
41
47
|
DiffPane,
|
|
42
48
|
type HunkAction,
|
|
@@ -44,8 +50,9 @@ import {
|
|
|
44
50
|
type ViewMode,
|
|
45
51
|
type WhitespaceMode,
|
|
46
52
|
} from "./diff-pane";
|
|
53
|
+
import { GitHelpSheet } from "./help";
|
|
47
54
|
import { Sidebar, type SidebarAction, type GitCommitMessage } from "./sidebar";
|
|
48
|
-
import type { ChangedFile, FileContents, GitTuiModel } from "./state";
|
|
55
|
+
import type { AssetFileContents, ChangedFile, FileContents, GitTuiModel } from "./state";
|
|
49
56
|
|
|
50
57
|
/** AI staging counts displayed after filtering the working tree. */
|
|
51
58
|
export interface AiStageOutcome {
|
|
@@ -80,6 +87,20 @@ const STATUS_TTL_MS = 6_000;
|
|
|
80
87
|
|
|
81
88
|
type Focus = "diff" | "sidebar";
|
|
82
89
|
|
|
90
|
+
/** Tone of a status message: its colour in the header and its span token natively. */
|
|
91
|
+
type StatusTone = "success" | "warning" | "error" | "accent" | "dim";
|
|
92
|
+
|
|
93
|
+
/** Columns below which the native layout stacks the changes under the diff. */
|
|
94
|
+
const NARROW_COLS = 100;
|
|
95
|
+
|
|
96
|
+
/** The views of the native segmented control, in omp's `1`–`4` order. */
|
|
97
|
+
const VIEW_TABS: readonly { id: ViewMode; label: string }[] = [
|
|
98
|
+
{ id: "file", label: "File" },
|
|
99
|
+
{ id: "split", label: "Split" },
|
|
100
|
+
{ id: "inline", label: "Inline" },
|
|
101
|
+
{ id: "hunk", label: "Hunks" },
|
|
102
|
+
];
|
|
103
|
+
|
|
83
104
|
interface UiHit {
|
|
84
105
|
from: number;
|
|
85
106
|
to: number;
|
|
@@ -152,6 +173,7 @@ class GitTuiComponent implements Component {
|
|
|
152
173
|
#refreshTimer: NodeJS.Timeout | undefined;
|
|
153
174
|
#busy = false;
|
|
154
175
|
#status = "";
|
|
176
|
+
#statusTone: StatusTone = "dim";
|
|
155
177
|
#statusAt = 0;
|
|
156
178
|
#statusSticky = false;
|
|
157
179
|
#centerWidth = 0;
|
|
@@ -162,6 +184,10 @@ class GitTuiComponent implements Component {
|
|
|
162
184
|
/** After hopping files backwards, land on the last hunk once the diff loads. */
|
|
163
185
|
#pendingHunkEdge: "last" | null = null;
|
|
164
186
|
#disposed = false;
|
|
187
|
+
#help: OverlayHandle | null = null;
|
|
188
|
+
readonly #nativeBar = new Memo();
|
|
189
|
+
readonly #nativeBody = new Memo();
|
|
190
|
+
readonly #nativeRoot = new Memo();
|
|
165
191
|
|
|
166
192
|
constructor(ui: TUI, host: GitTuiHost) {
|
|
167
193
|
this.#ui = ui;
|
|
@@ -207,6 +233,7 @@ class GitTuiComponent implements Component {
|
|
|
207
233
|
this.#generationAbort?.abort();
|
|
208
234
|
this.#aiStageAbort?.abort();
|
|
209
235
|
clearInterval(this.#refreshTimer);
|
|
236
|
+
this.#help?.hide();
|
|
210
237
|
this.#sidebar.dispose();
|
|
211
238
|
this.#stack.dispose();
|
|
212
239
|
}
|
|
@@ -341,10 +368,8 @@ class GitTuiComponent implements Component {
|
|
|
341
368
|
if (this.#pendingDiscard !== key) {
|
|
342
369
|
this.#pendingDiscard = key;
|
|
343
370
|
this.#setStatus(
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
`Discard changes to ${action.selection.label}? Press ${formatKeyHint("delete")} again to confirm`,
|
|
347
|
-
),
|
|
371
|
+
"warning",
|
|
372
|
+
`Discard changes to ${action.selection.label}? Press ${formatKeyHint("delete")} again to confirm`,
|
|
348
373
|
);
|
|
349
374
|
return;
|
|
350
375
|
}
|
|
@@ -356,24 +381,23 @@ class GitTuiComponent implements Component {
|
|
|
356
381
|
switch (action.type) {
|
|
357
382
|
case "discard":
|
|
358
383
|
await this.#model.discard(action.selection.files);
|
|
359
|
-
this.#setStatus(
|
|
384
|
+
this.#setStatus("success", `Discarded ${action.selection.label}`);
|
|
360
385
|
break;
|
|
361
386
|
case "stage":
|
|
362
387
|
await this.#model.stage(action.selection?.files);
|
|
363
|
-
this.#setStatus(
|
|
364
|
-
theme.fg("success", action.selection ? `Staged ${action.selection.label}` : "Staged all changes"),
|
|
365
|
-
);
|
|
388
|
+
this.#setStatus("success", action.selection ? `Staged ${action.selection.label}` : "Staged all changes");
|
|
366
389
|
break;
|
|
367
390
|
case "unstage":
|
|
368
391
|
await this.#model.unstage(action.selection?.files);
|
|
369
392
|
this.#setStatus(
|
|
370
|
-
|
|
393
|
+
"success",
|
|
394
|
+
action.selection ? `Unstaged ${action.selection.label}` : "Unstaged all changes",
|
|
371
395
|
);
|
|
372
396
|
break;
|
|
373
397
|
case "stage-ai": {
|
|
374
398
|
const abort = new AbortController();
|
|
375
399
|
this.#aiStageAbort = abort;
|
|
376
|
-
this.#setStatus(
|
|
400
|
+
this.#setStatus("accent", `Filtering changes: ${action.prompt}`);
|
|
377
401
|
try {
|
|
378
402
|
const outcome = await this.#host.aiStage({
|
|
379
403
|
cwd: this.#model.cwd,
|
|
@@ -381,11 +405,11 @@ class GitTuiComponent implements Component {
|
|
|
381
405
|
files: this.#model.unstaged,
|
|
382
406
|
signal: abort.signal,
|
|
383
407
|
onProgress: message => {
|
|
384
|
-
if (!this.#disposed) this.#setStatus(
|
|
408
|
+
if (!this.#disposed) this.#setStatus("dim", message);
|
|
385
409
|
},
|
|
386
410
|
});
|
|
387
411
|
if (outcome.stagedHunks === 0 && outcome.wholeFiles === 0) {
|
|
388
|
-
this.#setStatus(
|
|
412
|
+
this.#setStatus("warning", `No changes matched "${action.prompt}"`);
|
|
389
413
|
} else {
|
|
390
414
|
const parts: string[] = [];
|
|
391
415
|
if (outcome.stagedHunks > 0) parts.push(`${outcome.stagedHunks} of ${outcome.totalHunks} hunks`);
|
|
@@ -393,10 +417,8 @@ class GitTuiComponent implements Component {
|
|
|
393
417
|
parts.push(`${outcome.wholeFiles} whole file${outcome.wholeFiles === 1 ? "" : "s"}`);
|
|
394
418
|
}
|
|
395
419
|
this.#setStatus(
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
`Staged ${parts.join(" + ")} (${outcome.matchedFiles}/${outcome.totalFiles} files matched)`,
|
|
399
|
-
),
|
|
420
|
+
"success",
|
|
421
|
+
`Staged ${parts.join(" + ")} (${outcome.matchedFiles}/${outcome.totalFiles} files matched)`,
|
|
400
422
|
);
|
|
401
423
|
}
|
|
402
424
|
} finally {
|
|
@@ -408,27 +430,27 @@ class GitTuiComponent implements Component {
|
|
|
408
430
|
const abort = new AbortController();
|
|
409
431
|
this.#generationAbort = abort;
|
|
410
432
|
this.#sidebar.setGenerating(true);
|
|
411
|
-
this.#setStatus(
|
|
433
|
+
this.#setStatus("accent", "Generating commit message…");
|
|
412
434
|
try {
|
|
413
435
|
const generated = await this.#host.generateCommitMessage({
|
|
414
436
|
cwd: this.#model.cwd,
|
|
415
437
|
stageIfEmpty: true,
|
|
416
438
|
signal: abort.signal,
|
|
417
439
|
onProgress: message => {
|
|
418
|
-
if (!this.#disposed) this.#setStatus(
|
|
440
|
+
if (!this.#disposed) this.#setStatus("dim", message);
|
|
419
441
|
},
|
|
420
442
|
});
|
|
421
443
|
this.#sidebar.setGeneratedCommit(generated.commit);
|
|
422
|
-
|
|
423
|
-
generated.validationError
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
444
|
+
if (generated.validationError) {
|
|
445
|
+
this.#setStatus("warning", `Generated message needs review: ${generated.validationError}`);
|
|
446
|
+
} else {
|
|
447
|
+
this.#setStatus(
|
|
448
|
+
"success",
|
|
449
|
+
generated.stagedAll
|
|
450
|
+
? "Staged all changes and generated commit message"
|
|
451
|
+
: "Generated commit message",
|
|
452
|
+
);
|
|
453
|
+
}
|
|
432
454
|
} finally {
|
|
433
455
|
if (this.#generationAbort === abort) this.#generationAbort = null;
|
|
434
456
|
this.#sidebar.setGenerating(false);
|
|
@@ -439,7 +461,7 @@ class GitTuiComponent implements Component {
|
|
|
439
461
|
if (action.stageAll) await this.#model.stage();
|
|
440
462
|
await this.#model.commit(action.message, { amend: action.amend });
|
|
441
463
|
this.#sidebar.clearForm();
|
|
442
|
-
this.#setStatus(
|
|
464
|
+
this.#setStatus("success", action.amend ? "Amended commit" : "Created commit");
|
|
443
465
|
break;
|
|
444
466
|
}
|
|
445
467
|
}
|
|
@@ -455,7 +477,7 @@ class GitTuiComponent implements Component {
|
|
|
455
477
|
if (!hunk.patch) return;
|
|
456
478
|
if (action === "discard" && this.#pendingDiscard !== hunk.patch) {
|
|
457
479
|
this.#pendingDiscard = hunk.patch;
|
|
458
|
-
this.#setStatus(
|
|
480
|
+
this.#setStatus("warning", `Discard hunk? Press ${formatKeyHint("x")} (or click) again to confirm`);
|
|
459
481
|
return;
|
|
460
482
|
}
|
|
461
483
|
this.#pendingDiscard = null;
|
|
@@ -466,10 +488,8 @@ class GitTuiComponent implements Component {
|
|
|
466
488
|
else if (action === "unstage") await this.#model.applyPatch(hunk.patch, { cached: true, reverse: true });
|
|
467
489
|
else await this.#model.applyPatch(hunk.patch, { reverse: true });
|
|
468
490
|
this.#setStatus(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
action === "stage" ? "Staged hunk" : action === "unstage" ? "Unstaged hunk" : "Discarded hunk",
|
|
472
|
-
),
|
|
491
|
+
"success",
|
|
492
|
+
action === "stage" ? "Staged hunk" : action === "unstage" ? "Unstaged hunk" : "Discarded hunk",
|
|
473
493
|
);
|
|
474
494
|
await this.#refresh(true);
|
|
475
495
|
} catch (error) {
|
|
@@ -486,12 +506,12 @@ class GitTuiComponent implements Component {
|
|
|
486
506
|
const intent = action === "stage" ? "apply" : "revert";
|
|
487
507
|
const patch = buildLineSelectionPatch(doc, span.from, span.to, intent);
|
|
488
508
|
if (!patch) {
|
|
489
|
-
this.#setStatus(
|
|
509
|
+
this.#setStatus("warning", "Selection contains no changes");
|
|
490
510
|
return;
|
|
491
511
|
}
|
|
492
512
|
if (action === "discard" && this.#pendingDiscard !== patch) {
|
|
493
513
|
this.#pendingDiscard = patch;
|
|
494
|
-
this.#setStatus(
|
|
514
|
+
this.#setStatus("warning", `Discard selected lines? Press ${formatKeyHint("x")} again to confirm`);
|
|
495
515
|
return;
|
|
496
516
|
}
|
|
497
517
|
this.#pendingDiscard = null;
|
|
@@ -503,14 +523,12 @@ class GitTuiComponent implements Component {
|
|
|
503
523
|
await this.#model.applyPatch(patch, { cached: action !== "discard" });
|
|
504
524
|
this.#pane.clearSelection();
|
|
505
525
|
this.#setStatus(
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
: "Discarded selection",
|
|
513
|
-
),
|
|
526
|
+
"success",
|
|
527
|
+
action === "stage"
|
|
528
|
+
? "Staged selection"
|
|
529
|
+
: action === "unstage"
|
|
530
|
+
? "Unstaged selection"
|
|
531
|
+
: "Discarded selection",
|
|
514
532
|
);
|
|
515
533
|
await this.#refresh(true);
|
|
516
534
|
} catch (error) {
|
|
@@ -520,8 +538,9 @@ class GitTuiComponent implements Component {
|
|
|
520
538
|
}
|
|
521
539
|
}
|
|
522
540
|
|
|
523
|
-
#setStatus(text: string): void {
|
|
541
|
+
#setStatus(tone: StatusTone, text: string): void {
|
|
524
542
|
this.#status = text;
|
|
543
|
+
this.#statusTone = tone;
|
|
525
544
|
this.#statusAt = Date.now();
|
|
526
545
|
this.#statusSticky = false;
|
|
527
546
|
this.#ui.requestRender();
|
|
@@ -529,7 +548,7 @@ class GitTuiComponent implements Component {
|
|
|
529
548
|
/** Persistent single-line error status; provider/git messages may span lines. */
|
|
530
549
|
#setError(error: unknown): void {
|
|
531
550
|
const message = error instanceof Error ? error.message : String(error);
|
|
532
|
-
this.#setStatus(
|
|
551
|
+
this.#setStatus("error", message.replace(/\s+/g, " ").trim());
|
|
533
552
|
this.#statusSticky = true;
|
|
534
553
|
}
|
|
535
554
|
|
|
@@ -567,14 +586,12 @@ class GitTuiComponent implements Component {
|
|
|
567
586
|
this.#whitespace =
|
|
568
587
|
this.#whitespace === "off" ? "whitespace" : this.#whitespace === "whitespace" ? "formatting" : "off";
|
|
569
588
|
this.#setStatus(
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
: "Ignoring formatting and import-only changes",
|
|
577
|
-
),
|
|
589
|
+
"dim",
|
|
590
|
+
this.#whitespace === "off"
|
|
591
|
+
? "Showing all changes"
|
|
592
|
+
: this.#whitespace === "whitespace"
|
|
593
|
+
? "Ignoring whitespace-only line changes"
|
|
594
|
+
: "Ignoring formatting and import-only changes",
|
|
578
595
|
);
|
|
579
596
|
this.#rebuildDocument();
|
|
580
597
|
}
|
|
@@ -640,6 +657,7 @@ class GitTuiComponent implements Component {
|
|
|
640
657
|
}
|
|
641
658
|
if (data === "b") return this.#cycleWhitespace();
|
|
642
659
|
if (data === "r") return void this.#refresh(true);
|
|
660
|
+
if (data === "?") return this.#toggleHelp();
|
|
643
661
|
if (data === "c") {
|
|
644
662
|
if (this.#sidebar.focusCommitForm()) this.#setFocus("sidebar");
|
|
645
663
|
return;
|
|
@@ -766,14 +784,14 @@ class GitTuiComponent implements Component {
|
|
|
766
784
|
right.add(" ").button(softPill(` ${glyphs.close} `), () => this.#done.resolve());
|
|
767
785
|
|
|
768
786
|
// The empty middle carries the key hints (or a fresh status message).
|
|
769
|
-
const status = this.#
|
|
787
|
+
const status = this.#visibleStatus() ? theme.fg(this.#statusTone, this.#status) : "";
|
|
770
788
|
const middle =
|
|
771
789
|
status ||
|
|
772
790
|
theme.fg(
|
|
773
791
|
"dim",
|
|
774
792
|
this.#focus === "diff"
|
|
775
|
-
? `${formatKeyHints(["alt+down", "alt+up"])} hunk · ${formatKeyHints(["]", "["])} file · ${formatKeyHints(["shift+up", "shift+down"])} select · ${formatKeyHints(["s", "u"])} stage · ${formatKeyHints(["x", "delete"])} discard · ${formatKeyHint("v")} view · ${formatKeyHint("c")} commit · ${formatKeyHint("q")} quit`
|
|
776
|
-
: `${formatKeyHints(["up", "down"])} move · ${formatKeyHints(["left", "right"])} fold · ${formatKeyHint("space")} stage · ${formatKeyHint("delete")} discard · ${formatKeyHint("enter")} open · ${formatKeyHints(["alt+down", "alt+up"])} hunk · ${formatKeyHint("c")} commit · ${formatKeyHint("t")} tree · ${formatKeyHint("q")} quit`,
|
|
793
|
+
? `${formatKeyHints(["alt+down", "alt+up"])} hunk · ${formatKeyHints(["]", "["])} file · ${formatKeyHints(["shift+up", "shift+down"])} select · ${formatKeyHints(["s", "u"])} stage · ${formatKeyHints(["x", "delete"])} discard · ${formatKeyHint("v")} view · ${formatKeyHint("c")} commit · ${formatKeyHint("?")} keys · ${formatKeyHint("q")} quit`
|
|
794
|
+
: `${formatKeyHints(["up", "down"])} move · ${formatKeyHints(["left", "right"])} fold · ${formatKeyHint("space")} stage · ${formatKeyHint("delete")} discard · ${formatKeyHint("enter")} open · ${formatKeyHints(["alt+down", "alt+up"])} hunk · ${formatKeyHint("c")} commit · ${formatKeyHint("t")} tree · ${formatKeyHint("?")} keys · ${formatKeyHint("q")} quit`,
|
|
777
795
|
);
|
|
778
796
|
const free = width - row.width - right.width - 1;
|
|
779
797
|
const middleText = free > visibleWidth(middle) + 4 ? middle : truncateToWidth(middle, Math.max(0, free - 4));
|
|
@@ -854,6 +872,335 @@ class GitTuiComponent implements Component {
|
|
|
854
872
|
quit(): void {
|
|
855
873
|
this.#done.resolve();
|
|
856
874
|
}
|
|
875
|
+
|
|
876
|
+
/** A fresh or sticky status message shows; older ones fade out. */
|
|
877
|
+
#visibleStatus(): boolean {
|
|
878
|
+
return this.#status !== "" && (this.#statusSticky || Date.now() - this.#statusAt < STATUS_TTL_MS);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/** `?`: the keyboard shortcuts sheet over the app. */
|
|
882
|
+
#toggleHelp(): void {
|
|
883
|
+
if (this.#help) {
|
|
884
|
+
this.#help.hide();
|
|
885
|
+
this.#help = null;
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
const sheet = new GitHelpSheet(() => this.#toggleHelp());
|
|
889
|
+
this.#help = this.#ui.showOverlay(sheet, { anchor: "center", width: "80%", maxHeight: "90%" });
|
|
890
|
+
this.#ui.setFocus(sheet);
|
|
891
|
+
this.#ui.requestRender();
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// ── native ─────────────────────────────────────────────────────────────
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* The native git app (NATIVE_REDESIGN §10, Kraken's vocabulary): the diff
|
|
898
|
+
* pane under a toolbar (file, `+a −d`, scope, change navigation, the view
|
|
899
|
+
* segmented control, whitespace/wrap toggles, Stage file, close), and the
|
|
900
|
+
* changes sheet on the right. Narrow panes stack the sheet under the diff.
|
|
901
|
+
*/
|
|
902
|
+
describe(cx: DescribeContext): NativeNode {
|
|
903
|
+
const narrow = cx.cols < NARROW_COLS;
|
|
904
|
+
const status = this.#visibleStatus();
|
|
905
|
+
const bar = this.#nativeBar.get(
|
|
906
|
+
[
|
|
907
|
+
this.#currentFile,
|
|
908
|
+
this.#pane.doc,
|
|
909
|
+
this.#pane.mode,
|
|
910
|
+
this.#pane.wrap,
|
|
911
|
+
this.#whitespace,
|
|
912
|
+
this.#contents,
|
|
913
|
+
narrow,
|
|
914
|
+
],
|
|
915
|
+
() => this.#describeBar(narrow),
|
|
916
|
+
);
|
|
917
|
+
const body = this.#nativeBody.get(
|
|
918
|
+
[
|
|
919
|
+
this.#pane.state,
|
|
920
|
+
this.#pane.doc,
|
|
921
|
+
this.#pane.mode,
|
|
922
|
+
this.#contents,
|
|
923
|
+
this.#currentFile,
|
|
924
|
+
this.#pane.emptyMessage,
|
|
925
|
+
],
|
|
926
|
+
() => this.#describeBody(),
|
|
927
|
+
);
|
|
928
|
+
const side = this.#sidebar.describe(cx);
|
|
929
|
+
return this.#nativeRoot.get([bar, body, side, narrow, status, this.#status, this.#statusTone], () => {
|
|
930
|
+
const main = col(
|
|
931
|
+
compact([
|
|
932
|
+
bar,
|
|
933
|
+
status &&
|
|
934
|
+
keyed(
|
|
935
|
+
text([span(this.#status, this.#statusTone === "dim" ? "muted" : this.#statusTone)], {
|
|
936
|
+
truncate: "end",
|
|
937
|
+
role: "omp.app.status",
|
|
938
|
+
}),
|
|
939
|
+
"status",
|
|
940
|
+
),
|
|
941
|
+
body,
|
|
942
|
+
]),
|
|
943
|
+
{ role: "omp.app.git.main" },
|
|
944
|
+
);
|
|
945
|
+
return node(narrow ? "col" : "row", { role: narrow ? "omp.app.git-narrow" : "omp.app.git" }, [
|
|
946
|
+
keyed(main, "main"),
|
|
947
|
+
keyed(side, "side"),
|
|
948
|
+
]);
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/** Pointer actions: the toolbar's buttons and segmented control, else the changes sheet's. */
|
|
953
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
954
|
+
if ((event.type === "select" || event.type === "activate") && event.key.endsWith("views")) {
|
|
955
|
+
const view = VIEW_TABS.find(tab => tab.id === event.item);
|
|
956
|
+
if (view) this.#setMode(view.id);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
if (event.type === "action") {
|
|
960
|
+
switch (event.act) {
|
|
961
|
+
case "prev-hunk":
|
|
962
|
+
return this.#jumpHunkOrFile(-1);
|
|
963
|
+
case "next-hunk":
|
|
964
|
+
return this.#jumpHunkOrFile(1);
|
|
965
|
+
case "whitespace":
|
|
966
|
+
return this.#cycleWhitespace();
|
|
967
|
+
case "wrap":
|
|
968
|
+
this.#pane.toggleWrap();
|
|
969
|
+
this.#ui.requestRender();
|
|
970
|
+
return;
|
|
971
|
+
case "stage-file":
|
|
972
|
+
return this.#stageCurrentFile();
|
|
973
|
+
case "help":
|
|
974
|
+
return this.#toggleHelp();
|
|
975
|
+
case "close":
|
|
976
|
+
this.#done.resolve();
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
if (this.#sidebar.handleNativeEvent(event)) {
|
|
981
|
+
if (this.#focus !== "sidebar") this.#setFocus("sidebar");
|
|
982
|
+
else this.#ui.requestRender();
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
#describeBar(narrow: boolean): NativeNode {
|
|
987
|
+
const file = this.#currentFile;
|
|
988
|
+
const doc = this.#pane.doc;
|
|
989
|
+
const left: NativeNode[] = [];
|
|
990
|
+
if (file) {
|
|
991
|
+
const slash = file.path.lastIndexOf("/");
|
|
992
|
+
left.push(
|
|
993
|
+
text([span(file.path.slice(0, slash + 1), "dim"), span(file.path.slice(slash + 1), "strong")], {
|
|
994
|
+
truncate: "start",
|
|
995
|
+
role: "omp.app.git.path",
|
|
996
|
+
title: file.origPath ? `${file.origPath} → ${file.path}` : file.path,
|
|
997
|
+
}),
|
|
998
|
+
);
|
|
999
|
+
if (doc) {
|
|
1000
|
+
left.push(
|
|
1001
|
+
text([span(`+${doc.additions}`, "ins num"), span(" "), span(`−${doc.deletions}`, "del num")], {
|
|
1002
|
+
role: "omp.app.git.stat",
|
|
1003
|
+
}),
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
const scope =
|
|
1007
|
+
file.area === "staged"
|
|
1008
|
+
? { text: "Staged", tone: "success" as const }
|
|
1009
|
+
: file.area === "unstaged"
|
|
1010
|
+
? { text: file.kind === "untracked" ? "Untracked" : "Unstaged", tone: "warning" as const }
|
|
1011
|
+
: { text: this.#model.headCommit?.shortSha ?? "commit", tone: "accent" as const };
|
|
1012
|
+
left.push(node("badge", { text: scope.text, tone: scope.tone }));
|
|
1013
|
+
} else {
|
|
1014
|
+
left.push(text([span(this.#model.branch ?? "detached", "muted")], { role: "omp.app.git.path" }));
|
|
1015
|
+
}
|
|
1016
|
+
const iconButton = (name: string, act: string, title: string, on?: boolean): NativeNode =>
|
|
1017
|
+
node(
|
|
1018
|
+
"icon",
|
|
1019
|
+
{ name, title, aria: title, role: on ? "omp.app.ibtn.set" : "omp.app.ibtn", actions: { click: act } },
|
|
1020
|
+
undefined,
|
|
1021
|
+
act,
|
|
1022
|
+
);
|
|
1023
|
+
const right: NativeNode[] = [
|
|
1024
|
+
row(
|
|
1025
|
+
[
|
|
1026
|
+
iconButton("chev-up", "prev-hunk", `Previous change (${formatKeyHint("alt+up")})`),
|
|
1027
|
+
iconButton("chev", "next-hunk", `Next change (${formatKeyHint("alt+down")})`),
|
|
1028
|
+
],
|
|
1029
|
+
{ gap: "none", align: "center" },
|
|
1030
|
+
),
|
|
1031
|
+
node(
|
|
1032
|
+
"tabs",
|
|
1033
|
+
{
|
|
1034
|
+
items: VIEW_TABS.map(tab => ({ id: tab.id, label: tab.label })),
|
|
1035
|
+
active: this.#pane.mode,
|
|
1036
|
+
role: "omp.app.seg",
|
|
1037
|
+
},
|
|
1038
|
+
undefined,
|
|
1039
|
+
"views",
|
|
1040
|
+
),
|
|
1041
|
+
];
|
|
1042
|
+
if (!narrow) {
|
|
1043
|
+
right.push(
|
|
1044
|
+
iconButton(
|
|
1045
|
+
"type",
|
|
1046
|
+
"whitespace",
|
|
1047
|
+
this.#whitespace === "off"
|
|
1048
|
+
? `Ignore whitespace (${formatKeyHint("b")})`
|
|
1049
|
+
: this.#whitespace === "whitespace"
|
|
1050
|
+
? `Ignoring whitespace; also ignore formatting (${formatKeyHint("b")})`
|
|
1051
|
+
: `Ignoring formatting and imports; show all (${formatKeyHint("b")})`,
|
|
1052
|
+
this.#whitespace !== "off",
|
|
1053
|
+
),
|
|
1054
|
+
iconButton("corner-down-right", "wrap", `Wrap lines (${formatKeyHint("w")})`, this.#pane.wrap),
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
if (file?.area === "unstaged" || file?.area === "staged") {
|
|
1058
|
+
right.push(
|
|
1059
|
+
actionButton(file.area === "unstaged" ? "Stage file" : "Unstage file", "stage-file", {
|
|
1060
|
+
keys: "s",
|
|
1061
|
+
title: `${file.area === "unstaged" ? "Stage" : "Unstage"} ${file.path}`,
|
|
1062
|
+
}),
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
right.push(
|
|
1066
|
+
iconButton("keyboard", "help", `Keyboard shortcuts (${formatKeyHint("?")})`),
|
|
1067
|
+
iconButton("x", "close", `Close (${formatKeyHint("q")})`),
|
|
1068
|
+
);
|
|
1069
|
+
return keyed(
|
|
1070
|
+
row(
|
|
1071
|
+
[
|
|
1072
|
+
row(left, { gap: "sm", align: "center", role: "omp.app.git.where" }),
|
|
1073
|
+
row(right, { gap: "sm", align: "center", role: "omp.app.git.tools" }),
|
|
1074
|
+
],
|
|
1075
|
+
{ justify: "between", align: "center", role: "omp.app.git.bar" },
|
|
1076
|
+
),
|
|
1077
|
+
"bar",
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/** The diff for the view mode, or the loading, empty and media states. */
|
|
1082
|
+
#describeBody(): NativeNode {
|
|
1083
|
+
const doc = this.#pane.doc;
|
|
1084
|
+
const file = this.#currentFile;
|
|
1085
|
+
if (doc && this.#pane.state === "ready") {
|
|
1086
|
+
return node(
|
|
1087
|
+
"diff",
|
|
1088
|
+
{
|
|
1089
|
+
text: unifiedDiff(doc, this.#pane.mode === "file"),
|
|
1090
|
+
path: doc.filePath,
|
|
1091
|
+
mode: this.#pane.mode === "split" ? "split" : "unified",
|
|
1092
|
+
role: "omp.app.git.diff",
|
|
1093
|
+
},
|
|
1094
|
+
undefined,
|
|
1095
|
+
"diff",
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
const contents = this.#contents;
|
|
1099
|
+
if (this.#pane.state === "asset" && file && contents?.kind === "asset") {
|
|
1100
|
+
return keyed(
|
|
1101
|
+
col(
|
|
1102
|
+
[
|
|
1103
|
+
text([span("Binary or media file", "strong")]),
|
|
1104
|
+
node("kv", {
|
|
1105
|
+
items: [
|
|
1106
|
+
{ k: "before", v: assetText(contents.old) },
|
|
1107
|
+
{ k: "after", v: assetText(contents.new) },
|
|
1108
|
+
],
|
|
1109
|
+
layout: "grid",
|
|
1110
|
+
}),
|
|
1111
|
+
],
|
|
1112
|
+
{ gap: "sm", role: "omp.app.git.state" },
|
|
1113
|
+
),
|
|
1114
|
+
"asset",
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
if (this.#pane.state === "streaming" || this.#pane.state === "loading") {
|
|
1118
|
+
return keyed(
|
|
1119
|
+
row([node("spinner", { style: "dots" }), text([span(`Loading ${file?.path ?? "diff"}…`, "muted")])], {
|
|
1120
|
+
gap: "sm",
|
|
1121
|
+
align: "center",
|
|
1122
|
+
role: "omp.app.git.state",
|
|
1123
|
+
}),
|
|
1124
|
+
"loading",
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1127
|
+
return keyed(
|
|
1128
|
+
col(
|
|
1129
|
+
[
|
|
1130
|
+
text([span(this.#pane.emptyMessage, "strong")]),
|
|
1131
|
+
text([
|
|
1132
|
+
span(
|
|
1133
|
+
this.#model.clean ? "The working tree is clean." : "Pick a file on the right to see its changes.",
|
|
1134
|
+
"muted",
|
|
1135
|
+
),
|
|
1136
|
+
]),
|
|
1137
|
+
],
|
|
1138
|
+
{ gap: "xs", role: "omp.app.git.empty" },
|
|
1139
|
+
),
|
|
1140
|
+
"empty",
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* A unified diff of `doc` for the `diff` kind: the tight hunks (Tern folds
|
|
1147
|
+
* the unchanged lines between them), or with `whole` one hunk spanning the
|
|
1148
|
+
* file. Paired changes go out as their `-` block then their `+` block, so the
|
|
1149
|
+
* terminal pairs them for word emphasis.
|
|
1150
|
+
*/
|
|
1151
|
+
function unifiedDiff(doc: DiffDocument, whole: boolean): string {
|
|
1152
|
+
const out: string[] = [];
|
|
1153
|
+
const emit = (rows: DiffDocument["rows"]): void => {
|
|
1154
|
+
let dels: string[] = [];
|
|
1155
|
+
let adds: string[] = [];
|
|
1156
|
+
const flush = (): void => {
|
|
1157
|
+
out.push(...dels, ...adds);
|
|
1158
|
+
dels = [];
|
|
1159
|
+
adds = [];
|
|
1160
|
+
};
|
|
1161
|
+
for (const diffRow of rows) {
|
|
1162
|
+
if (diffRow.kind === "context") {
|
|
1163
|
+
flush();
|
|
1164
|
+
out.push(` ${diffRow.newText}`);
|
|
1165
|
+
continue;
|
|
1166
|
+
}
|
|
1167
|
+
if (diffRow.oldNum !== undefined) dels.push(`-${diffRow.oldText}`);
|
|
1168
|
+
if (diffRow.newNum !== undefined) adds.push(`+${diffRow.newText}`);
|
|
1169
|
+
}
|
|
1170
|
+
flush();
|
|
1171
|
+
};
|
|
1172
|
+
if (whole) {
|
|
1173
|
+
const oldCount = doc.rows.filter(diffRow => diffRow.oldNum !== undefined).length;
|
|
1174
|
+
const newCount = doc.rows.filter(diffRow => diffRow.newNum !== undefined).length;
|
|
1175
|
+
out.push(`@@ -1,${oldCount} +1,${newCount} @@`);
|
|
1176
|
+
emit(doc.rows);
|
|
1177
|
+
} else {
|
|
1178
|
+
for (const hunk of doc.hunks) {
|
|
1179
|
+
out.push(hunk.header);
|
|
1180
|
+
emit(hunk.rows);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
return out.join("\n");
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/** One side of a media/binary change as a short fact line. */
|
|
1187
|
+
function assetText(asset: AssetFileContents["old"]): TspSpan[] {
|
|
1188
|
+
const size = (bytes: number | undefined): string =>
|
|
1189
|
+
bytes === undefined ? "" : bytes < 1024 ? ` · ${bytes} B` : ` · ${(bytes / 1024).toFixed(1)} KB`;
|
|
1190
|
+
switch (asset.kind) {
|
|
1191
|
+
case "empty":
|
|
1192
|
+
return [span("none", "dim")];
|
|
1193
|
+
case "text":
|
|
1194
|
+
return [span(`text${size(asset.byteLength)}`)];
|
|
1195
|
+
case "image":
|
|
1196
|
+
return [span(`image ${asset.image.widthPx}×${asset.image.heightPx}${size(asset.image.byteLength)}`)];
|
|
1197
|
+
case "binary":
|
|
1198
|
+
return [span(`binary${size(asset.byteLength)}`)];
|
|
1199
|
+
case "tooLarge":
|
|
1200
|
+
return [span(`too large to diff${size(asset.byteLength)}`)];
|
|
1201
|
+
case "lfsMissing":
|
|
1202
|
+
return [span(`LFS object ${asset.oid.slice(0, 12)} not fetched${size(asset.byteLength)}`)];
|
|
1203
|
+
}
|
|
857
1204
|
}
|
|
858
1205
|
|
|
859
1206
|
/**
|