@oh-my-pi/pi-tui 18.4.3 → 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 +36 -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/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 +37 -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/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 +7 -0
- 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 +7 -0
- package/dist/types/setup/scenes/splash.d.ts +8 -0
- package/dist/types/setup/scenes/types.d.ts +6 -1
- 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/terminal-capabilities.d.ts +1 -1
- package/dist/types/terminal.d.ts +27 -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.d.ts +8 -0
- 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 +346 -11
- 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/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 +37 -0
- 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 +216 -27
- 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 +21 -0
- 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/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 +175 -1
- 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 +583 -23
- 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 +122 -13
- package/src/setup/scenes/splash.ts +28 -1
- package/src/setup/scenes/theme.ts +88 -3
- package/src/setup/scenes/types.ts +7 -1
- package/src/setup/startup-splash.ts +46 -9
- package/src/setup/wizard-overlay.ts +140 -23
- package/src/status-line/component.ts +398 -16
- 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/terminal-capabilities.ts +7 -0
- package/src/terminal.ts +130 -2
- 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/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/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 +180 -49
- 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 +247 -2
- 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/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.ts +113 -1
- package/src/tools/write.ts +144 -5
- package/src/tools/xdev.ts +64 -1
- package/src/tui.ts +294 -3
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard shortcuts sheet of the git TUI (`?`).
|
|
3
|
+
*
|
|
4
|
+
* The keys are the git TUI's own (see `git-tui.ts` and `sidebar.ts`); this
|
|
5
|
+
* sheet only lists them. ANSI draws grouped `key description` rows; the
|
|
6
|
+
* native render is the hotkeys sheet (NATIVE_REDESIGN §9.7): a glass sheet
|
|
7
|
+
* titled "Keyboard shortcuts" with one section per group and a two-column
|
|
8
|
+
* table whose key cells carry the `key` span token, so Tern draws keycaps.
|
|
9
|
+
*/
|
|
10
|
+
import { formatKeyHint } from "../../app-keybindings";
|
|
11
|
+
import type { KeyName } from "../../key-hint-format";
|
|
12
|
+
import { matchesKey } from "../../keys";
|
|
13
|
+
import { col, node, span } from "../../native/describe";
|
|
14
|
+
import type { NativeNode } from "../../native/node";
|
|
15
|
+
import { theme } from "../../theme/theme";
|
|
16
|
+
import type { Component } from "../../tui";
|
|
17
|
+
import { truncateToWidth, visibleWidth } from "../../utils";
|
|
18
|
+
|
|
19
|
+
interface Shortcut {
|
|
20
|
+
readonly keys: readonly KeyName[];
|
|
21
|
+
readonly label: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const GROUPS: readonly { readonly title: string; readonly rows: readonly Shortcut[] }[] = [
|
|
25
|
+
{
|
|
26
|
+
title: "Move",
|
|
27
|
+
rows: [
|
|
28
|
+
{ keys: ["up", "down"], label: "Move the selection" },
|
|
29
|
+
{ keys: ["left", "right"], label: "Fold or unfold a folder or section" },
|
|
30
|
+
{ keys: ["enter"], label: "Open the file in the diff" },
|
|
31
|
+
{ keys: ["tab"], label: "Switch between the diff and the changes" },
|
|
32
|
+
{ keys: ["]", "["], label: "Next or previous file" },
|
|
33
|
+
{ keys: ["alt+down", "alt+up"], label: "Next or previous change" },
|
|
34
|
+
{ keys: ["g", "shift+g"], label: "First or last row" },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
title: "Stage",
|
|
39
|
+
rows: [
|
|
40
|
+
{ keys: ["space"], label: "Stage or unstage the row" },
|
|
41
|
+
{ keys: ["s", "u"], label: "Stage or unstage (the hunk or selected lines in the diff)" },
|
|
42
|
+
{ keys: ["shift+up", "shift+down"], label: "Select lines in the diff" },
|
|
43
|
+
{ keys: ["x"], label: "Discard the hunk or selected lines (press twice)" },
|
|
44
|
+
{ keys: ["delete"], label: "Discard the file or folder (press twice)" },
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
title: "View",
|
|
49
|
+
rows: [
|
|
50
|
+
{ keys: ["v"], label: "Cycle the diff view" },
|
|
51
|
+
{ keys: ["1", "2", "3", "4"], label: "File, split, inline or hunk view" },
|
|
52
|
+
{ keys: ["w"], label: "Wrap long lines" },
|
|
53
|
+
{ keys: ["b"], label: "Ignore whitespace, then formatting" },
|
|
54
|
+
{ keys: ["t"], label: "Paths or folder tree" },
|
|
55
|
+
{ keys: ["r"], label: "Refresh" },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: "Commit",
|
|
60
|
+
rows: [
|
|
61
|
+
{ keys: ["c"], label: "Write the commit message (empty: generate one)" },
|
|
62
|
+
{ keys: ["escape"], label: "Leave the field" },
|
|
63
|
+
{ keys: ["q"], label: "Quit" },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
/** The shortcuts overlay; any of `?`, escape or `q` closes it. */
|
|
69
|
+
export class GitHelpSheet implements Component {
|
|
70
|
+
readonly nativeOverlay = { role: "omp.overlay.hotkeys", head: "Keyboard shortcuts", size: "lg" } as const;
|
|
71
|
+
readonly #close: () => void;
|
|
72
|
+
#native: NativeNode | undefined;
|
|
73
|
+
|
|
74
|
+
constructor(close: () => void) {
|
|
75
|
+
this.#close = close;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
handleInput(data: string): void {
|
|
79
|
+
if (data === "?" || data === "q" || matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) this.#close();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
describe(): NativeNode {
|
|
83
|
+
this.#native ??= col(
|
|
84
|
+
GROUPS.map(group =>
|
|
85
|
+
node(
|
|
86
|
+
"section",
|
|
87
|
+
{ head: group.title, role: "omp.hotkeys.group" },
|
|
88
|
+
[
|
|
89
|
+
node("table", {
|
|
90
|
+
role: "omp.hotkeys.table",
|
|
91
|
+
cols: [
|
|
92
|
+
{ id: "keys", head: "Keys" },
|
|
93
|
+
{ id: "does", head: "Action", grow: 1 },
|
|
94
|
+
],
|
|
95
|
+
rows: group.rows.map((row, index) => ({
|
|
96
|
+
id: String(index),
|
|
97
|
+
cells: { keys: row.keys.map(key => span(formatKeyHint(key), "key")), does: row.label },
|
|
98
|
+
})),
|
|
99
|
+
}),
|
|
100
|
+
],
|
|
101
|
+
group.title,
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
{ gap: "lg", role: "omp.app.git.help" },
|
|
105
|
+
);
|
|
106
|
+
return this.#native;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
render(width: number): readonly string[] {
|
|
110
|
+
const keyWidth = Math.max(
|
|
111
|
+
...GROUPS.flatMap(group => group.rows.map(row => visibleWidth(row.keys.map(formatKeyHint).join(" ")))),
|
|
112
|
+
);
|
|
113
|
+
const lines = [truncateToWidth(` ${theme.bold("Keyboard shortcuts")}`, width), ""];
|
|
114
|
+
for (const group of GROUPS) {
|
|
115
|
+
lines.push(truncateToWidth(` ${theme.fg("muted", group.title)}`, width));
|
|
116
|
+
for (const row of group.rows) {
|
|
117
|
+
const keys = row.keys.map(formatKeyHint).join(" ");
|
|
118
|
+
const pad = " ".repeat(Math.max(1, keyWidth - visibleWidth(keys) + 2));
|
|
119
|
+
lines.push(truncateToWidth(` ${theme.fg("accent", keys)}${pad}${row.label}`, width));
|
|
120
|
+
}
|
|
121
|
+
lines.push("");
|
|
122
|
+
}
|
|
123
|
+
lines.push(truncateToWidth(` ${theme.fg("dim", `${formatKeyHint("escape")} close`)}`, width));
|
|
124
|
+
return lines;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
invalidate(): void {
|
|
128
|
+
this.#native = undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
package/src/apps/git/sidebar.ts
CHANGED
|
@@ -17,6 +17,10 @@ import { MenuSelection } from "../../components/menu-selection";
|
|
|
17
17
|
import { ScrollView } from "../../components/scroll-view";
|
|
18
18
|
import { TreeView } from "../../components/tree-view";
|
|
19
19
|
import { matchesKey } from "../../keys";
|
|
20
|
+
import { col, compact, item, keyed, list, node, row, span, stableKey, text } from "../../native/describe";
|
|
21
|
+
import { Memo } from "../../native/memo";
|
|
22
|
+
import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../../native/node";
|
|
23
|
+
import type { TspProps, TspSpan } from "@oh-my-pi/pi-wire";
|
|
20
24
|
import { TERMINAL } from "../../terminal-capabilities";
|
|
21
25
|
import { truncateToWidth, visibleWidth } from "../../utils";
|
|
22
26
|
import { getEditorTheme, theme } from "../../theme/theme";
|
|
@@ -79,6 +83,7 @@ const KIND_LETTER: Record<ChangedFile["kind"], string> = {
|
|
|
79
83
|
conflicted: "U",
|
|
80
84
|
};
|
|
81
85
|
|
|
86
|
+
/** Status tones of the native change pills (the ANSI letter colours). */
|
|
82
87
|
const KIND_COLOR: Record<ChangedFile["kind"], "warning" | "success" | "error" | "accent" | "muted"> = {
|
|
83
88
|
modified: "warning",
|
|
84
89
|
added: "success",
|
|
@@ -231,6 +236,43 @@ class GitFileTree {
|
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
238
|
|
|
239
|
+
/** A quiet text button (`Stage all`): a clickable row the role sheet draws as `.btn.quiet`. */
|
|
240
|
+
function quietButton(label: string, act: string, title: string): NativeNode {
|
|
241
|
+
return node("row", { role: "omp.app.qbtn", actions: { click: act }, title }, [text(label)], act);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** A text field at rest: its value (or placeholder) as text; a click starts editing it. */
|
|
245
|
+
function fieldText(
|
|
246
|
+
value: string,
|
|
247
|
+
placeholder: string,
|
|
248
|
+
act: string,
|
|
249
|
+
selected: boolean,
|
|
250
|
+
role = "omp.app.git.field",
|
|
251
|
+
): NativeNode {
|
|
252
|
+
return text(value ? value : [span(placeholder, "dim")], {
|
|
253
|
+
truncate: "end",
|
|
254
|
+
role: selected ? `${role}.on` : role,
|
|
255
|
+
actions: { click: act },
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Props of an `input` node described by a text field, minus identity. */
|
|
260
|
+
function inputProps(described: NativeNode): TspProps<"input"> {
|
|
261
|
+
return described.k === "input" ? { ...described.p } : {};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** The `editor` node inside an {@link Editor}'s description (the editor itself, or the column holding it). */
|
|
265
|
+
function editorNode(described: NativeNode): NativeNode | undefined {
|
|
266
|
+
if (described.k === "editor") return described;
|
|
267
|
+
for (const child of described.c ?? []) if ("k" in child && child.k === "editor") return child;
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Props of a described `editor` node. */
|
|
272
|
+
function editorProps(described: NativeNode): TspProps<"editor"> {
|
|
273
|
+
return described.k === "editor" ? { ...described.p } : {};
|
|
274
|
+
}
|
|
275
|
+
|
|
234
276
|
/** File row: status letter, dimmed directory, bright basename, +/− counts. */
|
|
235
277
|
function fileRowText(file: ChangedFile, width: number, selected: boolean, focused: boolean, depth?: number): string {
|
|
236
278
|
const prefix = `${theme.fg(KIND_COLOR[file.kind], KIND_LETTER[file.kind])} `;
|
|
@@ -355,6 +397,9 @@ export class Sidebar {
|
|
|
355
397
|
| undefined;
|
|
356
398
|
/** Tree depth per target key (file/dir rows only); parent-jump for `←`. */
|
|
357
399
|
readonly #entryDepth = new Map<string, number>();
|
|
400
|
+
/** Native item key → the target it selects, refreshed by every {@link describe}. */
|
|
401
|
+
readonly #nativeTargets = new Map<string, Target>();
|
|
402
|
+
readonly #nativeMemo = new Memo();
|
|
358
403
|
readonly #scrollView = new ScrollView([], { height: 1, totalRows: 0, scrollbar: "never" });
|
|
359
404
|
/** One-shot: the next render scrolls the selected row into view. Set on
|
|
360
405
|
* explicit selection changes so wheel scrolling can roam freely. */
|
|
@@ -892,6 +937,452 @@ export class Sidebar {
|
|
|
892
937
|
}
|
|
893
938
|
}
|
|
894
939
|
|
|
940
|
+
// ── native ─────────────────────────────────────────────────────────────
|
|
941
|
+
|
|
942
|
+
/**
|
|
943
|
+
* The changes sheet (NATIVE_REDESIGN §10): a head with the change count,
|
|
944
|
+
* the branch and a Path/Tree segmented control; one list per section under
|
|
945
|
+
* a quiet head whose `Stage all`/`Unstage all` show on hover; the commit
|
|
946
|
+
* composer docked below. A clean tree shows the HEAD commit instead. Text
|
|
947
|
+
* fields are live `input`/`editor` nodes only while they own the keys, so
|
|
948
|
+
* the terminal's caret follows the keyboard.
|
|
949
|
+
*/
|
|
950
|
+
describe(cx: DescribeContext): NativeNode {
|
|
951
|
+
this.#rebuildTargets();
|
|
952
|
+
const selected = this.selected;
|
|
953
|
+
const selectedKey = selected ? targetKey(selected) : undefined;
|
|
954
|
+
const editing = this.editing ? selected?.kind : undefined;
|
|
955
|
+
const summaryInput = editing === "summary" ? this.summary.input.describe(cx) : undefined;
|
|
956
|
+
const aiInput = editing === "stage-ai-input" ? this.aiInput.input.describe(cx) : undefined;
|
|
957
|
+
const descriptionEditor = editing === "description" ? editorNode(this.description.describe(cx)) : undefined;
|
|
958
|
+
return this.#nativeMemo.get(
|
|
959
|
+
[
|
|
960
|
+
this.#model.clean,
|
|
961
|
+
this.#model.unstaged,
|
|
962
|
+
this.#model.staged,
|
|
963
|
+
this.#model.headCommit,
|
|
964
|
+
this.#model.branch,
|
|
965
|
+
selectedKey,
|
|
966
|
+
this.focused,
|
|
967
|
+
this.viewStyle,
|
|
968
|
+
this.#treeVersion,
|
|
969
|
+
this.amend,
|
|
970
|
+
this.generating,
|
|
971
|
+
this.#aiPromptOpen,
|
|
972
|
+
this.summary.getValue(),
|
|
973
|
+
this.description.getText(),
|
|
974
|
+
summaryInput,
|
|
975
|
+
aiInput,
|
|
976
|
+
descriptionEditor,
|
|
977
|
+
],
|
|
978
|
+
() => {
|
|
979
|
+
this.#nativeTargets.clear();
|
|
980
|
+
const on = (target: Target): boolean => this.focused && selectedKey === targetKey(target);
|
|
981
|
+
const children = this.#model.clean
|
|
982
|
+
? this.#describeHead(selectedKey)
|
|
983
|
+
: [
|
|
984
|
+
this.#describeChangesHead(),
|
|
985
|
+
keyed(
|
|
986
|
+
col(
|
|
987
|
+
[
|
|
988
|
+
...this.#describeSection("unstaged", selectedKey, on, aiInput),
|
|
989
|
+
...this.#describeSection("staged", selectedKey, on, undefined),
|
|
990
|
+
],
|
|
991
|
+
{ role: "omp.app.git.changes", gap: "sm" },
|
|
992
|
+
),
|
|
993
|
+
"changes",
|
|
994
|
+
),
|
|
995
|
+
this.#describeCommit(on, summaryInput, descriptionEditor),
|
|
996
|
+
];
|
|
997
|
+
return col(children, { role: "omp.app.git.side" });
|
|
998
|
+
},
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* Pointer actions on the changes sheet: list clicks select (a folder also
|
|
1004
|
+
* folds, a second click on the selected file stages it, as the ANSI click
|
|
1005
|
+
* does), double clicks activate, the segmented control switches Path/Tree,
|
|
1006
|
+
* and the quiet buttons run their row's action. False when not the
|
|
1007
|
+
* sidebar's event.
|
|
1008
|
+
*/
|
|
1009
|
+
handleNativeEvent(event: NativeUiEvent): boolean {
|
|
1010
|
+
if (event.type === "select" || event.type === "activate") {
|
|
1011
|
+
if (event.item === "path" || event.item === "tree") {
|
|
1012
|
+
this.viewStyle = event.item;
|
|
1013
|
+
this.#treeVersion++;
|
|
1014
|
+
this.#requestRender();
|
|
1015
|
+
return true;
|
|
1016
|
+
}
|
|
1017
|
+
const target = this.#nativeTargets.get(event.item);
|
|
1018
|
+
if (!target) return false;
|
|
1019
|
+
const wasSelected = this.selected !== undefined && targetKey(this.selected) === targetKey(target);
|
|
1020
|
+
this.#select(target);
|
|
1021
|
+
if (event.type === "activate" || target.kind === "dir" || (target.kind === "file" && wasSelected)) {
|
|
1022
|
+
this.#activate(target);
|
|
1023
|
+
}
|
|
1024
|
+
return true;
|
|
1025
|
+
}
|
|
1026
|
+
if (event.type !== "action") return false;
|
|
1027
|
+
switch (event.act) {
|
|
1028
|
+
case "fold-unstaged":
|
|
1029
|
+
case "fold-staged":
|
|
1030
|
+
this.#toggleSection(event.act === "fold-unstaged" ? "unstaged" : "staged");
|
|
1031
|
+
return true;
|
|
1032
|
+
case "stage-all":
|
|
1033
|
+
case "unstage-all":
|
|
1034
|
+
case "stage-ai":
|
|
1035
|
+
this.#activate({ kind: event.act });
|
|
1036
|
+
return true;
|
|
1037
|
+
case "amend":
|
|
1038
|
+
this.#select({ kind: "amend" });
|
|
1039
|
+
this.#toggleAmend();
|
|
1040
|
+
return true;
|
|
1041
|
+
case "commit":
|
|
1042
|
+
this.#select({ kind: "commit-button" });
|
|
1043
|
+
this.#submitCommit();
|
|
1044
|
+
return true;
|
|
1045
|
+
case "edit-summary":
|
|
1046
|
+
this.#select({ kind: "summary" });
|
|
1047
|
+
return true;
|
|
1048
|
+
case "edit-description":
|
|
1049
|
+
this.#select({ kind: "description" });
|
|
1050
|
+
return true;
|
|
1051
|
+
case "edit-ai":
|
|
1052
|
+
this.#select({ kind: "stage-ai-input" });
|
|
1053
|
+
return true;
|
|
1054
|
+
default:
|
|
1055
|
+
return false;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/** Item key of `target` in the native lists, registered for event lookup. */
|
|
1060
|
+
#nativeKey(target: Target): string {
|
|
1061
|
+
const key = stableKey(targetKey(target));
|
|
1062
|
+
this.#nativeTargets.set(key, target);
|
|
1063
|
+
return key;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
/** `3 changes on main` and the Path/Tree segmented control. */
|
|
1067
|
+
#describeChangesHead(): NativeNode {
|
|
1068
|
+
const total = this.#model.unstaged.length + this.#model.staged.length;
|
|
1069
|
+
const head = row(
|
|
1070
|
+
[
|
|
1071
|
+
row(
|
|
1072
|
+
compact([
|
|
1073
|
+
text([span(`${total} change${total === 1 ? "" : "s"}`, "strong")]),
|
|
1074
|
+
this.#model.branch !== null && text([span("on", "muted")]),
|
|
1075
|
+
this.#model.branch !== null &&
|
|
1076
|
+
text([span(this.#model.branch, "mono")], { role: "omp.app.git.branch", truncate: "middle" }),
|
|
1077
|
+
]),
|
|
1078
|
+
{ gap: "xs", align: "center", role: "omp.app.git.title" },
|
|
1079
|
+
),
|
|
1080
|
+
this.#describeStyleToggle(),
|
|
1081
|
+
],
|
|
1082
|
+
{ justify: "between", align: "center", role: "omp.app.git.head" },
|
|
1083
|
+
);
|
|
1084
|
+
return keyed(head, "head");
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
#describeStyleToggle(): NativeNode {
|
|
1088
|
+
return node(
|
|
1089
|
+
"tabs",
|
|
1090
|
+
{
|
|
1091
|
+
items: [
|
|
1092
|
+
{ id: "path", label: "Path" },
|
|
1093
|
+
{ id: "tree", label: "Tree" },
|
|
1094
|
+
],
|
|
1095
|
+
active: this.viewStyle,
|
|
1096
|
+
role: "omp.app.seg",
|
|
1097
|
+
},
|
|
1098
|
+
undefined,
|
|
1099
|
+
"style",
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/** One section: a quiet head (fold chevron, name, count, hover actions) over its file list. */
|
|
1104
|
+
#describeSection(
|
|
1105
|
+
area: SectionTarget["area"],
|
|
1106
|
+
selectedKey: string | undefined,
|
|
1107
|
+
on: (target: Target) => boolean,
|
|
1108
|
+
aiInput: NativeNode | undefined,
|
|
1109
|
+
): NativeChild[] {
|
|
1110
|
+
const files = area === "unstaged" ? this.#model.unstaged : this.#model.staged;
|
|
1111
|
+
const folded = this.#collapsedSections.has(area);
|
|
1112
|
+
const section: SectionTarget = { kind: "section", area };
|
|
1113
|
+
const actions: NativeNode[] =
|
|
1114
|
+
area === "unstaged"
|
|
1115
|
+
? [
|
|
1116
|
+
quietButton("Stage all", "stage-all", "Stage every change (space on the head)"),
|
|
1117
|
+
node(
|
|
1118
|
+
"icon",
|
|
1119
|
+
{
|
|
1120
|
+
name: "wand",
|
|
1121
|
+
role: "omp.app.ibtn",
|
|
1122
|
+
title: "Stage by description…",
|
|
1123
|
+
aria: "Stage by description",
|
|
1124
|
+
actions: { click: "stage-ai" },
|
|
1125
|
+
},
|
|
1126
|
+
undefined,
|
|
1127
|
+
"ai",
|
|
1128
|
+
),
|
|
1129
|
+
]
|
|
1130
|
+
: [quietButton("Unstage all", "unstage-all", "Unstage every change (space on the head)")];
|
|
1131
|
+
const head = row(
|
|
1132
|
+
[
|
|
1133
|
+
row(
|
|
1134
|
+
[
|
|
1135
|
+
node("icon", { name: folded ? "chev-r" : "chev" }),
|
|
1136
|
+
text(area === "unstaged" ? "Unstaged" : "Staged"),
|
|
1137
|
+
text([span(String(files.length), "num")], { role: "omp.app.git.count" }),
|
|
1138
|
+
],
|
|
1139
|
+
{ gap: "xs", align: "center", actions: { click: `fold-${area}` }, title: folded ? "Show" : "Hide" },
|
|
1140
|
+
),
|
|
1141
|
+
row(files.length > 0 ? actions : [], { gap: "xs", align: "center", role: "omp.app.git.acts" }),
|
|
1142
|
+
],
|
|
1143
|
+
{
|
|
1144
|
+
justify: "between",
|
|
1145
|
+
align: "center",
|
|
1146
|
+
role: on(section) ? "omp.app.git.sechead.on" : "omp.app.git.sechead",
|
|
1147
|
+
},
|
|
1148
|
+
);
|
|
1149
|
+
const out: NativeChild[] = [keyed(head, `${area}-head`)];
|
|
1150
|
+
if (area === "unstaged" && this.#aiPromptOpen) {
|
|
1151
|
+
const target: Target = { kind: "stage-ai-input" };
|
|
1152
|
+
out.push(
|
|
1153
|
+
keyed(
|
|
1154
|
+
aiInput
|
|
1155
|
+
? node("input", {
|
|
1156
|
+
...inputProps(aiInput),
|
|
1157
|
+
placeholder: "What should we stage?",
|
|
1158
|
+
role: "omp.app.git.field.on",
|
|
1159
|
+
})
|
|
1160
|
+
: fieldText(this.aiInput.getValue(), "What should we stage?", "edit-ai", on(target)),
|
|
1161
|
+
"ai",
|
|
1162
|
+
),
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
if (!folded) {
|
|
1166
|
+
const entries = this.#fileEntries(files, area);
|
|
1167
|
+
const selected = entries.find(entry => targetKey(entry.target) === selectedKey);
|
|
1168
|
+
out.push(
|
|
1169
|
+
list(
|
|
1170
|
+
entries.map(entry => this.#describeEntry(entry)),
|
|
1171
|
+
{
|
|
1172
|
+
selected: selected ? this.#nativeKey(selected.target) : null,
|
|
1173
|
+
empty: area === "unstaged" ? "Nothing to stage" : "Nothing staged yet",
|
|
1174
|
+
role: "omp.app.git.files",
|
|
1175
|
+
actions: { click: "select", dblclick: "activate" },
|
|
1176
|
+
},
|
|
1177
|
+
area,
|
|
1178
|
+
),
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
return out;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
/** A file row (status pill, name, `+a −d`) or a folder row of the tree view. */
|
|
1185
|
+
#describeEntry(entry: SidebarFileEntry): NativeNode {
|
|
1186
|
+
const depth = Math.min(entry.depth ?? 0, 8);
|
|
1187
|
+
const key = this.#nativeKey(entry.target);
|
|
1188
|
+
const file = entry.file;
|
|
1189
|
+
if (!file) {
|
|
1190
|
+
return item(key, {
|
|
1191
|
+
label: [span(entry.dirName ?? "")],
|
|
1192
|
+
icon: "folder",
|
|
1193
|
+
role: `omp.app.git.dir-d${depth}`,
|
|
1194
|
+
tone: entry.collapsed ? "muted" : undefined,
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
const slash = file.path.lastIndexOf("/");
|
|
1198
|
+
const label =
|
|
1199
|
+
this.viewStyle === "tree" || slash < 0
|
|
1200
|
+
? [span(file.path.slice(slash + 1))]
|
|
1201
|
+
: [span(file.path.slice(0, slash + 1), "dim"), span(file.path.slice(slash + 1))];
|
|
1202
|
+
const stats: TspSpan[] = [];
|
|
1203
|
+
if (file.additions) stats.push(span(`+${file.additions}`, "ins num"));
|
|
1204
|
+
if (file.deletions) stats.push(span(`${stats.length > 0 ? " " : ""}−${file.deletions}`, "del num"));
|
|
1205
|
+
return item(key, {
|
|
1206
|
+
label,
|
|
1207
|
+
detail: file.origPath ? [span(`from ${file.origPath}`, "dim")] : undefined,
|
|
1208
|
+
value: stats.length > 0 ? stats : undefined,
|
|
1209
|
+
hint: [KIND_LETTER[file.kind]],
|
|
1210
|
+
tone: KIND_COLOR[file.kind],
|
|
1211
|
+
role: `omp.app.git.file-d${this.viewStyle === "tree" ? depth : 0}`,
|
|
1212
|
+
title: `${file.kind}: ${file.path}`,
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* The commit composer (skill §5 "Forms docked in a sheet"): a borderless
|
|
1218
|
+
* summary with a counter only while typing, the body below, a quiet
|
|
1219
|
+
* `Amend` toggle and the neutral commit button.
|
|
1220
|
+
*/
|
|
1221
|
+
#describeCommit(
|
|
1222
|
+
on: (target: Target) => boolean,
|
|
1223
|
+
summaryInput: NativeNode | undefined,
|
|
1224
|
+
descriptionEditor: NativeNode | undefined,
|
|
1225
|
+
): NativeNode {
|
|
1226
|
+
const summary = this.summary.getValue();
|
|
1227
|
+
const description = this.description.getText();
|
|
1228
|
+
const left = SUMMARY_LIMIT - summary.length;
|
|
1229
|
+
const summaryField = summaryInput
|
|
1230
|
+
? row(
|
|
1231
|
+
[
|
|
1232
|
+
node("input", { ...inputProps(summaryInput), placeholder: "Summary", grow: 1 }),
|
|
1233
|
+
text([span(String(left), left < 0 ? "warning num" : "num")], { role: "omp.app.git.count" }),
|
|
1234
|
+
],
|
|
1235
|
+
{ gap: "sm", align: "center", role: "omp.app.git.summary.on" },
|
|
1236
|
+
)
|
|
1237
|
+
: fieldText(summary, "Summary", "edit-summary", on({ kind: "summary" }), "omp.app.git.summary");
|
|
1238
|
+
const bodyField = descriptionEditor
|
|
1239
|
+
? node("editor", {
|
|
1240
|
+
...editorProps(descriptionEditor),
|
|
1241
|
+
placeholder: "Description",
|
|
1242
|
+
maxLines: 5,
|
|
1243
|
+
role: "omp.app.git.body.on",
|
|
1244
|
+
})
|
|
1245
|
+
: fieldText(
|
|
1246
|
+
description.split("\n", 1)[0] + (description.includes("\n") ? " …" : ""),
|
|
1247
|
+
"Description",
|
|
1248
|
+
"edit-description",
|
|
1249
|
+
on({ kind: "description" }),
|
|
1250
|
+
"omp.app.git.body",
|
|
1251
|
+
);
|
|
1252
|
+
const hasChanges = this.#model.staged.length > 0 || this.#model.unstaged.length > 0 || this.amend;
|
|
1253
|
+
const canCommit =
|
|
1254
|
+
hasChanges && !this.generating && (summary.trim().length > 0 || description.trim().length === 0);
|
|
1255
|
+
const label = this.generating
|
|
1256
|
+
? "Generating message…"
|
|
1257
|
+
: summary.trim().length === 0 && description.trim().length === 0
|
|
1258
|
+
? "Generate message"
|
|
1259
|
+
: this.#model.staged.length > 0
|
|
1260
|
+
? "Commit"
|
|
1261
|
+
: "Stage all & commit";
|
|
1262
|
+
// The panels' button (omp-panels.css `omp.btn`): accent while the keyboard is on it, muted when it can't run.
|
|
1263
|
+
const commitTone = !canCommit ? "muted" : on({ kind: "commit-button" }) ? "accent" : undefined;
|
|
1264
|
+
return col(
|
|
1265
|
+
[
|
|
1266
|
+
keyed(summaryField, "summary"),
|
|
1267
|
+
keyed(bodyField, "body"),
|
|
1268
|
+
keyed(
|
|
1269
|
+
row(
|
|
1270
|
+
[
|
|
1271
|
+
row([node("icon", { name: this.amend ? "check" : "commit" }), text("Amend")], {
|
|
1272
|
+
gap: "xs",
|
|
1273
|
+
align: "center",
|
|
1274
|
+
role: `omp.app.git.toggle${this.amend ? ".set" : ""}${on({ kind: "amend" }) ? ".on" : ""}`,
|
|
1275
|
+
actions: { click: "amend" },
|
|
1276
|
+
title: "Amend the previous commit",
|
|
1277
|
+
}),
|
|
1278
|
+
row(compact([this.generating && node("spinner", { style: "dots" }), text(label)]), {
|
|
1279
|
+
gap: "xs",
|
|
1280
|
+
align: "center",
|
|
1281
|
+
role: "omp.btn",
|
|
1282
|
+
tone: commitTone,
|
|
1283
|
+
actions: canCommit ? { click: "commit" } : undefined,
|
|
1284
|
+
title:
|
|
1285
|
+
this.#model.staged.length > 0
|
|
1286
|
+
? "Commit the staged changes"
|
|
1287
|
+
: "Stage everything, then commit",
|
|
1288
|
+
}),
|
|
1289
|
+
],
|
|
1290
|
+
{ justify: "between", align: "center", role: "omp.app.git.foot" },
|
|
1291
|
+
),
|
|
1292
|
+
"foot",
|
|
1293
|
+
),
|
|
1294
|
+
],
|
|
1295
|
+
{ gap: "sm", role: "omp.app.git.commit" },
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/** Clean tree: the HEAD commit (subject, body, author, parents) over its file list. */
|
|
1300
|
+
#describeHead(selectedKey: string | undefined): NativeChild[] {
|
|
1301
|
+
const head = this.#model.headCommit;
|
|
1302
|
+
if (!head) {
|
|
1303
|
+
return [keyed(text([span("No commits yet", "muted")], { role: "omp.app.git.empty" }), "empty")];
|
|
1304
|
+
}
|
|
1305
|
+
const when = head.authorDate ? new Date(head.authorDate) : null;
|
|
1306
|
+
const initials = head.authorName
|
|
1307
|
+
.split(/\s+/)
|
|
1308
|
+
.filter(Boolean)
|
|
1309
|
+
.slice(0, 2)
|
|
1310
|
+
.map(word => word[0]!.toUpperCase())
|
|
1311
|
+
.join("");
|
|
1312
|
+
const commit = col(
|
|
1313
|
+
compact([
|
|
1314
|
+
text([span(head.subject, "strong")], { wrap: "word", role: "omp.app.git.subject" }),
|
|
1315
|
+
head.body.trim() !== "" && text(head.body.trim(), { wrap: "word", lines: 8, role: "omp.app.git.message" }),
|
|
1316
|
+
row(
|
|
1317
|
+
[
|
|
1318
|
+
text(initials || "?", { role: "omp.app.git.avatar", title: head.authorEmail }),
|
|
1319
|
+
col(
|
|
1320
|
+
compact([
|
|
1321
|
+
text([span(head.authorName, "strong")], { truncate: "end" }),
|
|
1322
|
+
text([span(head.authorEmail, "dim")], { truncate: "end" }),
|
|
1323
|
+
]),
|
|
1324
|
+
{ gap: "none" },
|
|
1325
|
+
),
|
|
1326
|
+
],
|
|
1327
|
+
{ gap: "sm", align: "center", role: "omp.app.git.author" },
|
|
1328
|
+
),
|
|
1329
|
+
node("kv", {
|
|
1330
|
+
items: compact([
|
|
1331
|
+
when && !Number.isNaN(when.getTime()) ? { k: "authored", v: when.toLocaleString() } : undefined,
|
|
1332
|
+
head.parents.length > 0
|
|
1333
|
+
? {
|
|
1334
|
+
k: head.parents.length === 1 ? "parent" : "parents",
|
|
1335
|
+
v: [span(head.parents.map(sha => sha.slice(0, 8)).join(" "), "mono accent")],
|
|
1336
|
+
}
|
|
1337
|
+
: undefined,
|
|
1338
|
+
]),
|
|
1339
|
+
layout: "grid",
|
|
1340
|
+
}),
|
|
1341
|
+
]),
|
|
1342
|
+
{ gap: "sm", role: "omp.app.git.commit-info" },
|
|
1343
|
+
);
|
|
1344
|
+
const out: NativeChild[] = [keyed(commit, "head")];
|
|
1345
|
+
if (!head.filesLoaded) {
|
|
1346
|
+
out.push(keyed(text([span("Loading changed files…", "muted")]), "loading"));
|
|
1347
|
+
return out;
|
|
1348
|
+
}
|
|
1349
|
+
const additions = head.files.reduce((sum, file) => sum + (file.additions ?? 0), 0);
|
|
1350
|
+
const deletions = head.files.reduce((sum, file) => sum + (file.deletions ?? 0), 0);
|
|
1351
|
+
out.push(
|
|
1352
|
+
keyed(
|
|
1353
|
+
row(
|
|
1354
|
+
[
|
|
1355
|
+
text([
|
|
1356
|
+
span(`${head.files.length} file${head.files.length === 1 ? "" : "s"}`, "strong"),
|
|
1357
|
+
span(" "),
|
|
1358
|
+
span(`+${additions}`, "ins num"),
|
|
1359
|
+
span(" "),
|
|
1360
|
+
span(`−${deletions}`, "del num"),
|
|
1361
|
+
span(` ${head.shortSha}`, "dim mono"),
|
|
1362
|
+
]),
|
|
1363
|
+
this.#describeStyleToggle(),
|
|
1364
|
+
],
|
|
1365
|
+
{ justify: "between", align: "center", role: "omp.app.git.head" },
|
|
1366
|
+
),
|
|
1367
|
+
"files-head",
|
|
1368
|
+
),
|
|
1369
|
+
);
|
|
1370
|
+
const entries = this.#fileEntries(head.files, "commit");
|
|
1371
|
+
const selected = entries.find(entry => targetKey(entry.target) === selectedKey);
|
|
1372
|
+
out.push(
|
|
1373
|
+
list(
|
|
1374
|
+
entries.map(entry => this.#describeEntry(entry)),
|
|
1375
|
+
{
|
|
1376
|
+
selected: selected ? this.#nativeKey(selected.target) : null,
|
|
1377
|
+
role: "omp.app.git.files",
|
|
1378
|
+
actions: { click: "select", dblclick: "activate" },
|
|
1379
|
+
},
|
|
1380
|
+
"commit-files",
|
|
1381
|
+
),
|
|
1382
|
+
);
|
|
1383
|
+
return out;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
895
1386
|
/** Wheel scroll over the sidebar. */
|
|
896
1387
|
handleWheel(delta: number): void {
|
|
897
1388
|
this.#scrollView.scroll(delta * 3);
|