@pellux/goodvibes-tui 2.0.21 → 2.1.1
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 +65 -1
- package/README.md +30 -29
- package/docs/README.md +8 -5
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- package/package.json +28 -19
- package/src/cli/management.ts +5 -2
- package/src/cli/tui-startup.ts +34 -39
- package/src/core/agent-view-render.ts +157 -0
- package/src/core/approval-alert.ts +49 -11
- package/src/core/bookmark-navigation.ts +7 -1
- package/src/core/budget-breach-notifier.ts +27 -8
- package/src/core/compaction-receipt.ts +1 -1
- package/src/core/context-usage.ts +1 -1
- package/src/core/conversation-compaction-render.ts +3 -3
- package/src/core/conversation-display-only.ts +86 -0
- package/src/core/conversation-event-navigation.ts +27 -0
- package/src/core/conversation-line-cache.ts +216 -447
- package/src/core/conversation-render-context.ts +20 -27
- package/src/core/conversation-rendering.ts +157 -575
- package/src/core/conversation-splash-state.ts +6 -1
- package/src/core/conversation-types.ts +35 -0
- package/src/core/conversation-usage.ts +12 -0
- package/src/core/conversation.ts +130 -131
- package/src/core/long-task-notifier.ts +100 -31
- package/src/core/notices.ts +75 -0
- package/src/core/pairing-tailscale-gateway.ts +1 -1
- package/src/core/process-output-log.ts +143 -0
- package/src/core/rewind-receipt.ts +1 -1
- package/src/core/session-focus.ts +190 -0
- package/src/core/session-resume-core.ts +23 -81
- package/src/core/stream-event-wiring.ts +31 -5
- package/src/core/system-message-noise.ts +2 -2
- package/src/core/system-message-router.ts +16 -18
- package/src/core/turn-event-wiring.ts +272 -33
- package/src/core/work-tree-focus.ts +290 -0
- package/src/core/work-tree-fold-store.ts +143 -0
- package/src/core/work-tree-model.ts +799 -0
- package/src/core/work-tree-render.ts +384 -0
- package/src/core/work-tree-sources.ts +184 -0
- package/src/core/work-tree-wiring.ts +176 -0
- package/src/core/workstream-notification.ts +36 -6
- package/src/core/wrfc-notice-titles.ts +37 -0
- package/src/input/agents-modal-text.ts +119 -0
- package/src/input/agents-modal.ts +699 -0
- package/src/input/bookmark-modal.ts +33 -9
- package/src/input/changes-git.ts +251 -0
- package/src/input/changes-modal.ts +629 -0
- package/src/input/changes-model.ts +125 -0
- package/src/input/command-palette-types.ts +41 -0
- package/src/input/command-palette.ts +272 -0
- package/src/input/command-reference.ts +2 -2
- package/src/input/command-registry.ts +77 -35
- package/src/input/commands/acp-runtime.ts +19 -9
- package/src/input/commands/channel-runtime.ts +2 -2
- package/src/input/commands/ci-runtime.ts +1 -1
- package/src/input/commands/codebase-runtime.ts +1 -1
- package/src/input/commands/config.ts +7 -1
- package/src/input/commands/context-window.ts +25 -19
- package/src/input/commands/control-room-runtime.ts +18 -18
- package/src/input/commands/conversation-runtime.ts +0 -1
- package/src/input/commands/cost-runtime.ts +29 -20
- package/src/input/commands/diff-runtime.ts +35 -181
- package/src/input/commands/eval.ts +1 -1
- package/src/input/commands/experience-runtime.ts +3 -7
- package/src/input/commands/fresh-conversation.ts +86 -0
- package/src/input/commands/git-runtime.ts +5 -22
- package/src/input/commands/graph-runtime.ts +1 -1
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/health-runtime.ts +8 -9
- package/src/input/commands/hooks-runtime.ts +2 -2
- package/src/input/commands/hosted-runtime.ts +3 -3
- package/src/input/commands/incident-runtime.ts +3 -3
- package/src/input/commands/intelligence-runtime.ts +6 -9
- package/src/input/commands/knowledge.ts +2 -2
- package/src/input/commands/legacy-panel-command.ts +57 -0
- package/src/input/commands/local-auth-runtime.ts +8 -9
- package/src/input/commands/local-provider-runtime.ts +7 -4
- package/src/input/commands/local-runtime.ts +12 -15
- package/src/input/commands/local-setup-review.ts +1 -1
- package/src/input/commands/local-setup.ts +13 -19
- package/src/input/commands/memory.ts +1 -1
- package/src/input/commands/notify-runtime.ts +9 -0
- package/src/input/commands/operator-runtime.ts +10 -12
- package/src/input/commands/permissions-provenance.ts +3 -3
- package/src/input/commands/planning-runtime.ts +7 -7
- package/src/input/commands/platform-sandbox-runtime.ts +2 -2
- package/src/input/commands/platform-services-runtime.ts +1 -1
- package/src/input/commands/policy-dispatch.ts +2 -2
- package/src/input/commands/policy.ts +3 -3
- package/src/input/commands/provider.ts +1 -1
- package/src/input/commands/remote-runtime.ts +1 -1
- package/src/input/commands/review-runtime.ts +39 -94
- package/src/input/commands/rewind-runtime.ts +81 -108
- package/src/input/commands/runtime-services.ts +15 -17
- package/src/input/commands/services-runtime.ts +2 -2
- package/src/input/commands/session-content.ts +21 -5
- package/src/input/commands/session-workflow.ts +13 -38
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/shell-core.ts +19 -4
- package/src/input/commands/skills-runtime.ts +2 -2
- package/src/input/commands/status-runtime.ts +13 -0
- package/src/input/commands/subscription-runtime.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +2 -8
- package/src/input/commands/work-plan-runtime.ts +4 -4
- package/src/input/commands/workstream-attempts.ts +24 -47
- package/src/input/commands/workstream-runtime.ts +2 -2
- package/src/input/commands/worktree-runtime.ts +3 -3
- package/src/input/commands.ts +3 -1
- package/src/input/composer-editor.ts +44 -0
- package/src/input/concealed-input.ts +1 -1
- package/src/input/config-modal-types.ts +20 -8
- package/src/input/config-modal.ts +106 -105
- package/src/input/confirm-dialog-types.ts +28 -0
- package/src/input/confirm-dialog.ts +70 -0
- package/src/input/delete-key-policy.ts +3 -3
- package/src/input/feed-context-factory.ts +15 -16
- package/src/input/handler-command-route.ts +7 -42
- package/src/input/handler-content-actions.ts +16 -15
- package/src/input/handler-feed-routes.ts +26 -211
- package/src/input/handler-feed.ts +68 -95
- package/src/input/handler-interactions.ts +5 -3
- package/src/input/handler-modal-routes.ts +215 -216
- package/src/input/handler-modal-stack.ts +81 -11
- package/src/input/handler-modal-token-routes.ts +4 -0
- package/src/input/handler-onboarding.ts +0 -1
- package/src/input/handler-picker-routes.ts +65 -107
- package/src/input/handler-session-view-route.ts +149 -0
- package/src/input/handler-shortcuts.ts +16 -154
- package/src/input/handler-types.ts +4 -2
- package/src/input/handler-ui-state.ts +45 -15
- package/src/input/handler-work-tree-route.ts +123 -0
- package/src/input/handler.ts +25 -70
- package/src/input/keybindings.ts +16 -71
- package/src/input/masked-entry-modal.ts +117 -0
- package/src/input/mcp-workspace.ts +48 -17
- package/src/input/model-picker-filter.ts +8 -0
- package/src/input/model-picker-open.ts +99 -0
- package/src/input/model-picker-types.ts +1 -1
- package/src/input/model-picker.ts +92 -9
- package/src/input/notifications-modal.ts +123 -0
- package/src/input/overlay-filter.ts +26 -0
- package/src/input/profile-picker-modal.ts +37 -8
- package/src/input/search.ts +3 -3
- package/src/input/selection-modal-queue.ts +2 -0
- package/src/input/selection-modal.ts +28 -16
- package/src/input/session-picker-modal.ts +33 -8
- package/src/input/settings-modal-activation.ts +7 -2
- package/src/input/settings-modal-data.ts +11 -6
- package/src/input/settings-modal-types.ts +1 -1
- package/src/input/settings-modal.ts +20 -20
- package/src/input/submission-intent.ts +1 -1
- package/src/input/submission-router.ts +4 -9
- package/src/input/surface-modal-host.ts +110 -0
- package/src/input/theme-settings-actions.ts +82 -0
- package/src/input/usage-modal.ts +183 -0
- package/src/input/views.ts +97 -0
- package/src/main.ts +175 -165
- package/src/permissions/hunk-selection.ts +1 -1
- package/src/permissions/prompt-card.ts +511 -0
- package/src/permissions/prompt.ts +59 -622
- package/src/renderer/agents-modal.ts +310 -0
- package/src/renderer/autocomplete-overlay.ts +42 -220
- package/src/renderer/back-to-bottom.ts +80 -0
- package/src/renderer/block-actions-overlay.ts +30 -48
- package/src/renderer/bookmark-modal.ts +48 -79
- package/src/renderer/changes-modal.ts +325 -0
- package/src/renderer/code-block.ts +184 -106
- package/src/renderer/command-palette.ts +93 -0
- package/src/renderer/composer-fragments.ts +4 -4
- package/src/renderer/composer.ts +146 -0
- package/src/renderer/compositor.ts +26 -160
- package/src/renderer/config-modal.ts +185 -81
- package/src/renderer/confirm-dialog.ts +50 -0
- package/src/renderer/context-inspector.ts +116 -154
- package/src/renderer/context-status-hint.ts +4 -4
- package/src/renderer/conversation-layout.ts +20 -0
- package/src/renderer/conversation-overlays.ts +94 -84
- package/src/renderer/conversation-surface.ts +19 -38
- package/src/renderer/diff-tint.ts +98 -0
- package/src/renderer/file-picker-overlay.ts +63 -90
- package/src/renderer/footer-targets.ts +38 -0
- package/src/renderer/git-status.ts +3 -4
- package/src/renderer/header-line.ts +140 -117
- package/src/renderer/help-overlay.ts +133 -219
- package/src/renderer/history-search-overlay.ts +15 -12
- package/src/renderer/lane-graph/bead.ts +800 -0
- package/src/renderer/lane-graph/glyphs.ts +134 -0
- package/src/renderer/lane-graph/layout.ts +248 -0
- package/src/renderer/lane-graph/paint.ts +537 -0
- package/src/renderer/lane-graph/semantic-memo.ts +77 -0
- package/src/renderer/layout-engine.ts +2 -57
- package/src/renderer/layout.ts +7 -13
- package/src/renderer/markdown-inline.ts +2 -1
- package/src/renderer/markdown-table.ts +17 -12
- package/src/renderer/markdown.ts +92 -34
- package/src/renderer/masked-entry-modal.ts +78 -0
- package/src/renderer/mcp-workspace.ts +166 -203
- package/src/renderer/model-workspace.ts +381 -436
- package/src/renderer/notifications-modal.ts +116 -0
- package/src/renderer/onboarding/onboarding-wizard.ts +178 -588
- package/src/renderer/process-view.ts +192 -0
- package/src/renderer/profile-picker-modal.ts +58 -110
- package/src/renderer/search-overlay.ts +6 -3
- package/src/renderer/selection-modal-overlay.ts +87 -327
- package/src/renderer/semantic-diff.ts +2 -2
- package/src/renderer/session-chips.ts +102 -0
- package/src/renderer/session-picker-modal.ts +177 -297
- package/src/renderer/settings-modal-connections.ts +14 -23
- package/src/renderer/settings-modal-context.ts +367 -0
- package/src/renderer/settings-modal-helpers.ts +6 -11
- package/src/renderer/settings-modal.ts +322 -726
- package/src/renderer/shell-surface.ts +277 -175
- package/src/renderer/shortcuts-overlay.ts +217 -0
- package/src/renderer/status-line.ts +475 -0
- package/src/renderer/surface-compose.ts +174 -0
- package/src/renderer/surface-kit-extra.ts +303 -0
- package/src/renderer/surface-kit-list.ts +366 -0
- package/src/renderer/surface-kit-parts.ts +360 -0
- package/src/renderer/surface-kit.ts +568 -0
- package/src/renderer/syntax-highlighter.ts +280 -197
- package/src/renderer/syntax-theme.ts +51 -0
- package/src/renderer/system-message.ts +0 -1
- package/src/renderer/term-caps.ts +42 -1
- package/src/renderer/terminal-bg-probe.ts +116 -19
- package/src/renderer/terminal-palette-probe.ts +322 -0
- package/src/renderer/terminal-palette-reader.ts +183 -0
- package/src/renderer/terminal-palette.ts +58 -0
- package/src/renderer/theme-mode-config.ts +16 -1
- package/src/renderer/theme.ts +234 -207
- package/src/renderer/thinking.ts +0 -1
- package/src/renderer/throbber.ts +188 -0
- package/src/renderer/toast-center.ts +119 -0
- package/src/renderer/ui-factory.ts +39 -602
- package/src/renderer/ui-primitives.ts +8 -25
- package/src/renderer/usage-modal.ts +353 -0
- package/src/renderer/user-message.ts +58 -0
- package/src/renderer/voice-capture-chip.ts +53 -0
- package/src/runtime/bootstrap-command-context.ts +0 -5
- package/src/runtime/bootstrap-command-parts.ts +38 -89
- package/src/runtime/bootstrap-core.ts +13 -15
- package/src/runtime/bootstrap-hook-bridge.ts +12 -21
- package/src/runtime/bootstrap-notifier-sync.ts +17 -1
- package/src/runtime/bootstrap-shell.ts +16 -50
- package/src/runtime/bootstrap.ts +14 -14
- package/src/runtime/client/fleet-union.ts +5 -5
- package/src/runtime/client/hosted-exit.ts +2 -2
- package/src/runtime/client/hosted-sessions.ts +1 -1
- package/src/runtime/client/spine-adoption.ts +1 -1
- package/src/runtime/context-accounting-source.ts +5 -4
- package/src/runtime/index.ts +1 -0
- package/src/runtime/notification-dispatch.ts +102 -29
- package/src/runtime/recovery-offer-wiring.ts +4 -1
- package/src/runtime/recovery-prompt.ts +31 -15
- package/src/runtime/runtime-services-types.ts +10 -6
- package/src/runtime/services.ts +17 -12
- package/src/runtime/session-continuity-hints.ts +2 -5
- package/src/runtime/session-inbound-inputs.ts +1 -1
- package/src/runtime/session-resume-liveness-confirm.ts +14 -2
- package/src/runtime/startup-typeahead-gate.ts +103 -0
- package/src/runtime/store/domains/domain-read-matrix.ts +0 -1
- package/src/runtime/store/domains/index.ts +0 -8
- package/src/runtime/store/selectors/index.ts +0 -28
- package/src/runtime/store/state.ts +0 -8
- package/src/runtime/ui-services.ts +4 -6
- package/src/runtime/usage-tracker.ts +348 -0
- package/src/runtime/wrfc-persistence.ts +4 -4
- package/src/shell/blocking-input.ts +92 -2
- package/src/shell/recovery-input-helpers.ts +1 -1
- package/src/shell/session-views.ts +539 -0
- package/src/shell/status-report.ts +86 -0
- package/src/shell/transcript-scroll.ts +68 -0
- package/src/shell/ui-openers.ts +84 -172
- package/src/shell/view-openers.ts +205 -0
- package/src/tools/wrfc-agent-guard.ts +22 -2
- package/src/utils/format-duration.ts +4 -8
- package/src/utils/splash-lines.ts +9 -1
- package/src/utils/terminal-width.ts +56 -0
- package/src/verification/live-verifier.ts +0 -10
- package/src/version.ts +1 -1
- package/src/{panels → views}/agent-inspector-shared.ts +2 -2
- package/src/{panels → views}/builtin-modals.ts +22 -21
- package/src/views/builtin-views.ts +135 -0
- package/src/{panels → views}/confirm-state.ts +9 -9
- package/src/{panels → views}/diff-review-model.ts +10 -3
- package/src/{panels → views}/eval-registry.ts +1 -1
- package/src/{panels → views}/fleet-acts.ts +49 -85
- package/src/{panels/fleet-panel-format.ts → views/fleet-format.ts} +40 -40
- package/src/{panels → views}/fleet-gateway.ts +5 -5
- package/src/{panels → views}/fleet-observed-render.ts +16 -16
- package/src/{panels → views}/fleet-read-model.ts +9 -9
- package/src/{panels/fleet-tabs.ts → views/fleet-session-tabs.ts} +13 -13
- package/src/{panels → views}/fleet-spawn.ts +33 -49
- package/src/{panels → views}/fleet-steer.ts +12 -12
- package/src/{panels → views}/fleet-stop.ts +4 -4
- package/src/{panels → views}/fleet-transcript.ts +26 -27
- package/src/{panels/fleet-panel-worktree-detail.ts → views/fleet-worktree-detail.ts} +7 -7
- package/src/{panels → views}/hosted-session-feed.ts +6 -6
- package/src/views/modal-surface-registry.ts +41 -0
- package/src/{panels → views}/modals/devices-modal.ts +2 -2
- package/src/{panels → views}/modals/hooks-modal.ts +13 -13
- package/src/{panels → views}/modals/keybindings-modal.ts +19 -27
- package/src/{panels → views}/modals/knowledge-modal.ts +6 -5
- package/src/{panels → views}/modals/local-auth-modal.ts +22 -21
- package/src/{panels → views}/modals/marketplace-modal.ts +11 -11
- package/src/{panels → views}/modals/memory-modal.ts +8 -8
- package/src/{panels → views}/modals/modal-surface-helpers.ts +15 -5
- package/src/{panels → views}/modals/pairing-modal.ts +9 -9
- package/src/{panels → views}/modals/planning-modal.ts +15 -20
- package/src/{panels → views}/modals/plugins-modal.ts +6 -6
- package/src/{panels → views}/modals/policy-modal.ts +13 -5
- package/src/{panels → views}/modals/provider-health-modal.ts +4 -4
- package/src/{panels → views}/modals/remote-modal.ts +3 -3
- package/src/{panels → views}/modals/sandbox-modal.ts +4 -4
- package/src/{panels → views}/modals/security-modal.ts +22 -16
- package/src/{panels → views}/modals/services-modal.ts +3 -3
- package/src/{panels → views}/modals/settings-sync-modal.ts +4 -4
- package/src/{panels → views}/modals/skills-modal.ts +9 -9
- package/src/{panels → views}/modals/subscription-modal.ts +3 -3
- package/src/{panels → views}/modals/work-plan-modal.ts +10 -13
- package/src/views/notifications-feed.ts +314 -0
- package/src/{panels → views}/polish-core.ts +38 -36
- package/src/{panels → views}/polish-tables.ts +35 -26
- package/src/{panels → views}/polish.ts +101 -95
- package/src/{panels → views}/project-planning-answer-actions.ts +3 -3
- package/src/{panels → views}/provider-health-routes.ts +14 -14
- package/src/{panels → views}/search-focus.ts +8 -8
- package/src/{panels → views}/session-maintenance.ts +11 -11
- package/src/views/skills-discovery.ts +159 -0
- package/src/views/view-deps.ts +80 -0
- package/src/views/view-panel-adapter.ts +53 -0
- package/src/{panels → views}/workstream-graph-render.ts +1 -1
- package/src/core/conversation-fold.ts +0 -101
- package/src/core/conversation-turn-structure.ts +0 -464
- package/src/core/conversation-user-receipts.ts +0 -42
- package/src/input/commands/operator-panel-runtime.ts +0 -186
- package/src/input/panel-integration-actions.ts +0 -33
- package/src/input/panel-mouse-geometry.ts +0 -97
- package/src/input/panel-paste-flood-guard.ts +0 -86
- package/src/panels/base-panel.ts +0 -301
- package/src/panels/builtin/agent.ts +0 -27
- package/src/panels/builtin/development.ts +0 -92
- package/src/panels/builtin/knowledge.ts +0 -12
- package/src/panels/builtin/operations.ts +0 -177
- package/src/panels/builtin/session.ts +0 -81
- package/src/panels/builtin/shared.ts +0 -357
- package/src/panels/builtin-panels.ts +0 -28
- package/src/panels/cost-tracker-panel.ts +0 -746
- package/src/panels/diff-panel.ts +0 -797
- package/src/panels/diff-review-panel.ts +0 -395
- package/src/panels/expandable-list-panel.ts +0 -189
- package/src/panels/fleet-deep-link.ts +0 -31
- package/src/panels/fleet-panel.ts +0 -799
- package/src/panels/git-panel.ts +0 -800
- package/src/panels/hosted-session-panel.ts +0 -221
- package/src/panels/index.ts +0 -21
- package/src/panels/local-auth-panel.ts +0 -478
- package/src/panels/notifications-feed.ts +0 -127
- package/src/panels/notifications-panel.ts +0 -160
- package/src/panels/panel-confirm-overlay.ts +0 -72
- package/src/panels/panel-manager.ts +0 -791
- package/src/panels/plugins-panel.ts +0 -371
- package/src/panels/scrollable-list-panel.ts +0 -498
- package/src/panels/skills-panel.ts +0 -454
- package/src/panels/token-budget-panel.ts +0 -688
- package/src/panels/types.ts +0 -191
- package/src/panels/wrfc-panel-format.ts +0 -133
- package/src/renderer/diff-view.ts +0 -134
- package/src/renderer/fleet-tab-strip.ts +0 -56
- package/src/renderer/footer-tips.ts +0 -53
- package/src/renderer/fullscreen-primitives.ts +0 -146
- package/src/renderer/fullscreen-workspace.ts +0 -194
- package/src/renderer/hint-grammar.ts +0 -52
- package/src/renderer/modal-factory.ts +0 -480
- package/src/renderer/overlay-box.ts +0 -154
- package/src/renderer/overlay-viewport.ts +0 -104
- package/src/renderer/panel-composite.ts +0 -145
- package/src/renderer/panel-workspace-bar.ts +0 -54
- package/src/renderer/process-indicator.ts +0 -163
- package/src/renderer/tab-strip.ts +0 -222
- package/src/renderer/text-layout.ts +0 -31
- package/src/renderer/tool-call.ts +0 -276
- package/src/renderer/tool-result-expanded-lines.ts +0 -48
- package/src/renderer/tool-result-summary.ts +0 -219
- package/src/runtime/diagnostics/panels/index.ts +0 -21
- package/src/runtime/diagnostics/panels/ops.ts +0 -156
- package/src/runtime/perf/panel-contracts.ts +0 -32
- package/src/runtime/store/domains/panels.ts +0 -117
- package/src/verification/verification-ledger.ts +0 -707
- /package/src/{panels → views}/memory-consolidation-gateway.ts +0 -0
- /package/src/{panels → views}/modals/modal-theme.ts +0 -0
- /package/src/{panels → views}/provider-health-domains.ts +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* footer-targets.ts, which footer rows open a view when clicked.
|
|
3
|
+
*
|
|
4
|
+
* The status line (the row carrying the context bar and cost) opens the
|
|
5
|
+
* Usage modal on a click. The footer builder tags those Line arrays with a symbol-keyed
|
|
6
|
+
* property (invisible to rendering, iteration and golden frames); the shell
|
|
7
|
+
* turns the tags into screen rows each frame and the mouse route reads them.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Line } from '@pellux/goodvibes-sdk/platform/types';
|
|
11
|
+
|
|
12
|
+
/** What a clickable footer row opens. */
|
|
13
|
+
export type FooterTarget = 'usage';
|
|
14
|
+
|
|
15
|
+
const FOOTER_TARGET = Symbol('footer-target');
|
|
16
|
+
|
|
17
|
+
type TaggedLine = Line & { [FOOTER_TARGET]?: FooterTarget };
|
|
18
|
+
|
|
19
|
+
/** Mark a footer row as opening `target` when clicked; returns the same line. */
|
|
20
|
+
export function tagFooterLine(line: Line, target: FooterTarget): Line {
|
|
21
|
+
(line as TaggedLine)[FOOTER_TARGET] = target;
|
|
22
|
+
return line;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The target a footer row opens, or undefined. */
|
|
26
|
+
function footerTargetOf(line: Line): FooterTarget | undefined {
|
|
27
|
+
return (line as TaggedLine)[FOOTER_TARGET];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Screen row → target for a footer drawn with its first row at `startRow`. */
|
|
31
|
+
export function footerTargetRows(footer: readonly Line[], startRow: number): ReadonlyMap<number, FooterTarget> {
|
|
32
|
+
const rows = new Map<number, FooterTarget>();
|
|
33
|
+
footer.forEach((line, index) => {
|
|
34
|
+
const target = footerTargetOf(line);
|
|
35
|
+
if (target) rows.set(startRow + index, target);
|
|
36
|
+
});
|
|
37
|
+
return rows;
|
|
38
|
+
}
|
|
@@ -55,10 +55,9 @@ export class GitStatusProvider {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* Start a lightweight live-repo-state poll.
|
|
59
|
-
* never trusting a cached "is this a repo" flag (
|
|
60
|
-
*
|
|
61
|
-
* GitService.isGitRepo() check) but amortizes the cost for the header: the
|
|
58
|
+
* Start a lightweight live-repo-state poll. Follows the Changes modal's principle of
|
|
59
|
+
* never trusting a cached "is this a repo" flag (its git diff actions are
|
|
60
|
+
* all gated on a fresh GitService.isGitRepo() check) but amortizes the cost for the header: the
|
|
62
61
|
* cheap synchronous isGitRepo() spawn runs every tick; the heavier async
|
|
63
62
|
* status()+branch() fetch (this.refresh()) only runs when that boolean
|
|
64
63
|
* actually flips, e.g. an external `git init`, or `.git` removed.
|
|
@@ -1,146 +1,169 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* header-line.ts, the
|
|
3
|
-
* conversation title, optional git segment, and the right-hand model/provider
|
|
4
|
-
* pair.
|
|
2
|
+
* header-line.ts, the one-row header.
|
|
5
3
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* col 1 GoodVibes, bold, in the theme's brand -> brandEnd gradient
|
|
5
|
+
* (the theme's gradient, never the protected splash constant)
|
|
6
|
+
* then the version (faint) and the session title (muted)
|
|
7
|
+
* right the branch with a warning-colored dirty dot (ahead/behind counts
|
|
8
|
+
* muted), 3 columns, then the serving model ending at width-2,
|
|
9
|
+
* followed by the failover marker in the warning color while the
|
|
10
|
+
* serving backend is not the configured one
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* the
|
|
14
|
-
*
|
|
12
|
+
* No rule row under it; on the main screen one empty row (withHeaderGap)
|
|
13
|
+
* keeps the output off it. The header is the one place for session identity:
|
|
14
|
+
* title, branch, model. Inside an agent or process view the title gives way
|
|
15
|
+
* to the breadcrumb (main › engineer, the last name in its own color) and the
|
|
16
|
+
* right side names that session: the agent's model, or the process's pid,
|
|
17
|
+
* uptime and port. On a narrow row the marker falls back to its short
|
|
18
|
+
* form, then is dropped whole (a half-cut marker reads worse than none); the
|
|
19
|
+
* branch goes before the marker does, the title before either.
|
|
15
20
|
*/
|
|
16
21
|
|
|
17
22
|
import { type Line, createEmptyLine } from '@pellux/goodvibes-sdk/platform/types';
|
|
18
23
|
import { VERSION } from '../version.ts';
|
|
19
|
-
import { getDisplayWidth } from '../utils/terminal-width.ts';
|
|
24
|
+
import { getDisplayWidth, interpolateColor, truncateDisplay } from '../utils/terminal-width.ts';
|
|
20
25
|
import type { GitHeaderInfo } from './git-status.ts';
|
|
21
|
-
import {
|
|
26
|
+
import { activeTokens } from './theme.ts';
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
const BRAND = 'GoodVibes';
|
|
29
|
+
const BRAND_X = 1;
|
|
30
|
+
const GAP = 3;
|
|
31
|
+
|
|
32
|
+
interface Seg { readonly text: string; readonly fg: string; readonly bold?: boolean }
|
|
33
|
+
|
|
34
|
+
/** An agent or process view: the breadcrumb in place of the title, the session's own right side. */
|
|
35
|
+
export interface HeaderView {
|
|
36
|
+
/** main, then each level down to the one shown; the last is drawn bold in its color. */
|
|
37
|
+
readonly crumbs: ReadonlyArray<{ readonly text: string; readonly fg: string; readonly bold?: boolean }>;
|
|
38
|
+
/** Replaces the branch and model on the right (the agent's model; pid · uptime · port). */
|
|
39
|
+
readonly right: string;
|
|
40
|
+
readonly rightFg?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function put(line: Line, x: number, endX: number, seg: Seg): number {
|
|
44
|
+
let cx = x;
|
|
45
|
+
for (const ch of seg.text) {
|
|
46
|
+
const w = getDisplayWidth(ch);
|
|
47
|
+
if (w <= 0) continue;
|
|
48
|
+
if (cx + w > endX) break;
|
|
49
|
+
line[cx] = { char: ch, fg: seg.fg, bg: '', bold: seg.bold ?? false, dim: false, underline: false, italic: false, strikethrough: false };
|
|
50
|
+
if (w === 2 && cx + 1 < line.length) line[cx + 1] = { ...line[cx]!, char: '' };
|
|
51
|
+
cx += w;
|
|
34
52
|
}
|
|
35
|
-
|
|
36
|
-
return { text, width: getDisplayWidth(text) };
|
|
53
|
+
return cx;
|
|
37
54
|
}
|
|
38
55
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
* dropped entirely. Dropping it is safe, what remains is still the SERVING
|
|
47
|
-
* backend, so the header never claims the configured backend is answering.
|
|
48
|
-
* The footer carries the full marker with far more room (see ui-factory's
|
|
49
|
-
* prioritized context segments).
|
|
50
|
-
*/
|
|
51
|
-
function fitHeaderNote(note: string, usedWidth: number, width: number): string {
|
|
52
|
-
if (!note) return '';
|
|
53
|
-
const full = `· ${note} `;
|
|
54
|
-
if (usedWidth + getDisplayWidth(full) <= width) return full;
|
|
55
|
-
const short = '· divergent ';
|
|
56
|
-
return usedWidth + getDisplayWidth(short) <= width ? short : '';
|
|
56
|
+
function branchSegments(gitInfo: GitHeaderInfo): Seg[] {
|
|
57
|
+
const t = activeTokens();
|
|
58
|
+
const segs: Seg[] = [{ text: gitInfo.branch, fg: t.textMuted }];
|
|
59
|
+
if (gitInfo.ahead > 0) segs.push({ text: ` +${gitInfo.ahead}`, fg: t.textMuted });
|
|
60
|
+
if (gitInfo.behind > 0) segs.push({ text: ` -${gitInfo.behind}`, fg: t.textMuted });
|
|
61
|
+
if (gitInfo.dirty) segs.push({ text: ' ●', fg: t.warning });
|
|
62
|
+
return segs;
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
/**
|
|
60
|
-
* Render the header row
|
|
66
|
+
* Render the header row.
|
|
61
67
|
*
|
|
62
|
-
* @param width
|
|
63
|
-
* @param model
|
|
64
|
-
* @param
|
|
65
|
-
* @param
|
|
66
|
-
* @param
|
|
67
|
-
* @param
|
|
68
|
-
*
|
|
69
|
-
* @param note - Divergence marker naming the configured selection when the
|
|
70
|
-
* serving backend is not the one the user chose; '' otherwise.
|
|
68
|
+
* @param width - Terminal columns.
|
|
69
|
+
* @param model - Serving model id (core/active-model-identity.ts).
|
|
70
|
+
* @param title - Optional session title, truncated to fit.
|
|
71
|
+
* @param gitInfo - Optional branch/dirty/ahead-behind.
|
|
72
|
+
* @param version - Defaults to the live build VERSION; tests pin a fixture.
|
|
73
|
+
* @param modelNote - The failover marker (core/active-model-identity.ts), set
|
|
74
|
+
* only while serving differs from the configured model.
|
|
71
75
|
*/
|
|
72
76
|
export function renderHeaderLine(
|
|
73
77
|
width: number,
|
|
74
78
|
model: string,
|
|
75
|
-
provider: string,
|
|
76
79
|
title?: string,
|
|
77
80
|
gitInfo?: GitHeaderInfo,
|
|
78
81
|
version: string = VERSION,
|
|
79
|
-
|
|
82
|
+
modelNote?: string,
|
|
83
|
+
view?: HeaderView,
|
|
80
84
|
): Line[] {
|
|
81
|
-
const
|
|
82
|
-
// Header/footer/thinking paint on the transparent terminal background, so
|
|
83
|
-
// they read chrome.* (light-terminal-aware), NOT fg.*/state.*, which stay
|
|
84
|
-
// tuned for the opaque dark modal/panel boxes. Read live per render so a
|
|
85
|
-
// mode flip re-resolves without any module reload (see theme.ts).
|
|
86
|
-
const t = activeUiTones();
|
|
87
|
-
const CYAN = t.accent.brand;
|
|
88
|
-
const GREY = t.chrome.faint;
|
|
89
|
-
const TITLE_COLOR = t.chrome.label;
|
|
90
|
-
const brand = ` GoodVibes `;
|
|
91
|
-
const ver = `v${version} `;
|
|
92
|
-
const stats = ` ${model} `;
|
|
93
|
-
const prov = `(${provider}) `;
|
|
94
|
-
const gitWidth = gitInfo ? buildGitSegment(gitInfo).width : 0;
|
|
95
|
-
// Resolve the marker before the title so the title's fit calculation
|
|
96
|
-
// reserves room for it too.
|
|
97
|
-
const noteStr = fitHeaderNote(note, getDisplayWidth(brand + ver + stats + prov) + gitWidth, width);
|
|
85
|
+
const t = activeTokens();
|
|
98
86
|
const line = createEmptyLine(width);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
87
|
+
for (const cell of line) cell.bg = '';
|
|
88
|
+
const end = width - 1; // exclusive: the model ends at width-2
|
|
89
|
+
if (view) return [renderViewHeader(line, width, version, view)];
|
|
90
|
+
|
|
91
|
+
// Right side first, so the title knows how much room it has.
|
|
92
|
+
const leftMin = BRAND_X + BRAND.length + 1 + getDisplayWidth(version);
|
|
93
|
+
const fits = (w: number): boolean => leftMin + GAP + w <= end;
|
|
94
|
+
let note = '';
|
|
95
|
+
if (modelNote) {
|
|
96
|
+
const full = ` · ${modelNote}`;
|
|
97
|
+
const short = ' · divergent';
|
|
98
|
+
const baseW = getDisplayWidth(model);
|
|
99
|
+
if (fits(baseW + getDisplayWidth(full))) note = full;
|
|
100
|
+
else if (fits(baseW + getDisplayWidth(short))) note = short;
|
|
101
|
+
}
|
|
102
|
+
const modelW = getDisplayWidth(model) + getDisplayWidth(note);
|
|
103
|
+
const branch = gitInfo ? branchSegments(gitInfo) : [];
|
|
104
|
+
const branchW = branch.reduce((s, seg) => s + getDisplayWidth(seg.text), 0);
|
|
105
|
+
const showBranch = branchW > 0 && fits(branchW + GAP + modelW);
|
|
106
|
+
const rightW = modelW + (showBranch ? branchW + GAP : 0);
|
|
107
|
+
const rightX = Math.max(leftMin + GAP, end - rightW);
|
|
108
|
+
|
|
109
|
+
// Brand, version, title.
|
|
110
|
+
let x = BRAND_X;
|
|
111
|
+
[...BRAND].forEach((ch, i) => {
|
|
112
|
+
x = put(line, x, end, { text: ch, fg: interpolateColor(t.brand, t.brandEnd, i / (BRAND.length - 1)), bold: true });
|
|
113
|
+
});
|
|
114
|
+
x = put(line, x + 1, end, { text: version, fg: t.textFaint });
|
|
103
115
|
if (title) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const rightReserved = getDisplayWidth(stats + prov + noteStr) + gitWidth;
|
|
107
|
-
const maxTitleW = width - curX - rightReserved - 1;
|
|
108
|
-
let displayTitle: string;
|
|
109
|
-
if (getDisplayWidth(titleStr) <= maxTitleW) {
|
|
110
|
-
displayTitle = titleStr;
|
|
111
|
-
} else {
|
|
112
|
-
let truncated = '';
|
|
113
|
-
let w = 0;
|
|
114
|
-
for (const ch of titleStr) {
|
|
115
|
-
const cw = getDisplayWidth(ch);
|
|
116
|
-
if (w + cw > maxTitleW - 3) { truncated += '...'; break; }
|
|
117
|
-
truncated += ch;
|
|
118
|
-
w += cw;
|
|
119
|
-
}
|
|
120
|
-
displayTitle = truncated;
|
|
121
|
-
}
|
|
122
|
-
for (const char of displayTitle) { if (curX < width) line[curX++] = { char, fg: TITLE_COLOR, bg: '', bold: false, dim: true, underline: false, italic: false, strikethrough: false }; }
|
|
116
|
+
const room = rightX - GAP - (x + 2);
|
|
117
|
+
if (room >= 4) put(line, x + 2, rightX - GAP, { text: truncateDisplay(title, room), fg: t.textMuted });
|
|
123
118
|
}
|
|
124
|
-
|
|
125
|
-
let
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (gitInfo.dirty || gitInfo.ahead > 0 || gitInfo.behind > 0) {
|
|
130
|
-
gitFg = t.chrome.warn; // yellow when dirty or out-of-sync
|
|
131
|
-
}
|
|
119
|
+
|
|
120
|
+
let rx = rightX;
|
|
121
|
+
if (showBranch) {
|
|
122
|
+
for (const seg of branch) rx = put(line, rx, end, seg);
|
|
123
|
+
rx += GAP;
|
|
132
124
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
for (const char of stats) { if (rightX < width) line[rightX++] = { char, fg: CYAN, bg: '', bold: true, dim: false, underline: false, italic: false, strikethrough: false }; }
|
|
137
|
-
for (const char of prov) { if (rightX < width) line[rightX++] = { char, fg: GREY, bg: '', bold: false, dim: true, underline: false, italic: false, strikethrough: false }; }
|
|
138
|
-
// The marker reads as a warning, not as chrome: serving has left the
|
|
139
|
-
// selection the user made and that is worth noticing.
|
|
140
|
-
for (const char of noteStr) { if (rightX >= 0 && rightX < width) line[rightX++] = { char, fg: t.chrome.warn, bg: '', bold: false, dim: false, underline: false, italic: false, strikethrough: false }; }
|
|
141
|
-
lines.push(line);
|
|
142
|
-
const underline = createEmptyLine(width);
|
|
143
|
-
for (let x = 0; x < width; x++) underline[x] = { char: '━', fg: t.chrome.faint, bg: '', bold: false, dim: false, underline: false, italic: false, strikethrough: false };
|
|
144
|
-
lines.push(underline);
|
|
145
|
-
return lines;
|
|
125
|
+
rx = put(line, rx, end, { text: model, fg: t.text });
|
|
126
|
+
if (note) put(line, rx, end, { text: note, fg: t.warning });
|
|
127
|
+
return [line];
|
|
146
128
|
}
|
|
129
|
+
|
|
130
|
+
/** The header inside an agent or process view. */
|
|
131
|
+
function renderViewHeader(line: Line, width: number, version: string, view: HeaderView): Line {
|
|
132
|
+
const t = activeTokens();
|
|
133
|
+
const end = width - 1;
|
|
134
|
+
let x = BRAND_X;
|
|
135
|
+
[...BRAND].forEach((ch, i) => {
|
|
136
|
+
x = put(line, x, end, { text: ch, fg: interpolateColor(t.brand, t.brandEnd, i / (BRAND.length - 1)), bold: true });
|
|
137
|
+
});
|
|
138
|
+
x = put(line, x + 1, end, { text: version, fg: t.textFaint });
|
|
139
|
+
const crumbsW = view.crumbs.reduce((s, c, i) => s + (i > 0 ? 3 : 0) + getDisplayWidth(c.text), 0);
|
|
140
|
+
// The right side yields before the breadcrumb does: where you are matters more than the model name.
|
|
141
|
+
const roomForRight = end - (x + 2 + crumbsW + GAP);
|
|
142
|
+
const right = roomForRight >= 4 ? truncateDisplay(view.right, roomForRight) : '';
|
|
143
|
+
const rightX = end - getDisplayWidth(right);
|
|
144
|
+
const crumbEnd = right ? rightX - GAP : end;
|
|
145
|
+
x += 2;
|
|
146
|
+
view.crumbs.forEach((crumb, i) => {
|
|
147
|
+
if (i > 0) x = put(line, x + 1, crumbEnd, { text: '›', fg: t.textFaint }) + 1;
|
|
148
|
+
const last = i === view.crumbs.length - 1;
|
|
149
|
+
const room = crumbEnd - x;
|
|
150
|
+
x = put(line, x, crumbEnd, { text: last ? truncateDisplay(crumb.text, Math.max(0, room)) : crumb.text, fg: crumb.fg, bold: crumb.bold });
|
|
151
|
+
});
|
|
152
|
+
if (right) put(line, rightX, end, { text: right, fg: view.rightFg ?? t.text });
|
|
153
|
+
return line;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The main screen's header block with its gap: the header row (and the
|
|
158
|
+
* session chips row, when it shows), then one empty row, so output never
|
|
159
|
+
* touches the header. An agent or process view's body starts with its own
|
|
160
|
+
* empty row, so a view does not take this one.
|
|
161
|
+
*/
|
|
162
|
+
export function withHeaderGap(header: readonly Line[], width: number): Line[] {
|
|
163
|
+
const gap = createEmptyLine(width);
|
|
164
|
+
for (const cell of gap) cell.bg = '';
|
|
165
|
+
return [...header, gap];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Rows the gap under the main screen's header adds. */
|
|
169
|
+
export const HEADER_GAP_ROWS = 1;
|