@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
|
@@ -4,10 +4,10 @@ import { getDisplayWidth, wrapText } from '../utils/terminal-width.ts';
|
|
|
4
4
|
import { getSurfaceContentRows, getTrackedVisibleWindow, getVisibleWindow, type VisibleWindow } from '../renderer/surface-layout.ts';
|
|
5
5
|
import { GLYPHS } from '../renderer/ui-primitives.ts';
|
|
6
6
|
import { type StatusState, STATE_GLYPHS } from '../renderer/status-glyphs.ts';
|
|
7
|
-
import {
|
|
8
|
-
import type {
|
|
7
|
+
import { buildViewLine, buildStyledViewLine, DEFAULT_VIEW_PALETTE } from './polish-core.ts';
|
|
8
|
+
import type { ViewPalette, StyledViewSegment } from './polish-core.ts';
|
|
9
9
|
|
|
10
|
-
// The
|
|
10
|
+
// The view formatting toolkit is split across three modules to stay under the
|
|
11
11
|
// architecture line-count cap; every symbol remains importable from './polish.ts':
|
|
12
12
|
// - ./polish-core.ts palette + base line primitives (leaf)
|
|
13
13
|
// - ./polish-tables.ts table / tree / badge / aligned-row primitives
|
|
@@ -32,9 +32,9 @@ export function buildGuidanceLine(
|
|
|
32
32
|
width: number,
|
|
33
33
|
command: string,
|
|
34
34
|
summary: string,
|
|
35
|
-
palette:
|
|
35
|
+
palette: ViewPalette,
|
|
36
36
|
): Line {
|
|
37
|
-
return
|
|
37
|
+
return buildViewLine(width, [
|
|
38
38
|
[` ${GLYPHS.status.info} `, palette.info],
|
|
39
39
|
[command, palette.info],
|
|
40
40
|
[' - ', palette.dim],
|
|
@@ -42,13 +42,14 @@ export function buildGuidanceLine(
|
|
|
42
42
|
]);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function
|
|
45
|
+
export function buildViewTitle(
|
|
46
46
|
width: number,
|
|
47
47
|
title: string,
|
|
48
|
-
palette:
|
|
48
|
+
palette: ViewPalette,
|
|
49
49
|
): Line {
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
// Two columns between the fill edge and the title (the Measurements padding rule).
|
|
51
|
+
const titleText = fitDisplayText(` ${title}`, width);
|
|
52
|
+
return buildStyledViewLine(width, [
|
|
52
53
|
{ text: titleText, fg: palette.header ?? palette.accent ?? palette.value, bg: palette.headerBg, bold: true },
|
|
53
54
|
], { fillBg: palette.headerBg });
|
|
54
55
|
}
|
|
@@ -56,21 +57,21 @@ export function buildPanelTitle(
|
|
|
56
57
|
export function buildBodyText(
|
|
57
58
|
width: number,
|
|
58
59
|
text: string,
|
|
59
|
-
palette:
|
|
60
|
+
palette: ViewPalette,
|
|
60
61
|
fg: string = palette.value,
|
|
61
62
|
): Line[] {
|
|
62
63
|
const wrapped = wrapText(text, Math.max(10, width - 2));
|
|
63
|
-
return wrapped.map((line) =>
|
|
64
|
+
return wrapped.map((line) => buildStyledViewLine(width, [{ text: ` ${line}`, fg, bg: palette.surfaceBg }], { fillBg: palette.surfaceBg }));
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
export function buildSectionHeader(
|
|
67
68
|
width: number,
|
|
68
69
|
title: string,
|
|
69
|
-
palette:
|
|
70
|
+
palette: ViewPalette,
|
|
70
71
|
): Line {
|
|
71
72
|
const prefix = `${GLYPHS.status.dualPane} ${title}`;
|
|
72
73
|
const divider = GLYPHS.frame.horizontal.repeat(Math.max(0, width - getDisplayWidth(prefix) - 2));
|
|
73
|
-
return
|
|
74
|
+
return buildStyledViewLine(width, [
|
|
74
75
|
{ text: ' ', fg: palette.label, bg: palette.sectionBg },
|
|
75
76
|
{ text: prefix, fg: palette.label, bg: palette.sectionBg, bold: true },
|
|
76
77
|
{ text: ' ', fg: palette.dim, bg: palette.sectionBg },
|
|
@@ -81,7 +82,7 @@ export function buildSectionHeader(
|
|
|
81
82
|
export function buildKeyValueLine(
|
|
82
83
|
width: number,
|
|
83
84
|
entries: ReadonlyArray<{ label: string; value: string; valueColor?: string }>,
|
|
84
|
-
palette:
|
|
85
|
+
palette: ViewPalette,
|
|
85
86
|
): Line {
|
|
86
87
|
const segments: Array<[string, string, string?]> = [];
|
|
87
88
|
for (const entry of entries) {
|
|
@@ -90,16 +91,16 @@ export function buildKeyValueLine(
|
|
|
90
91
|
segments.push([entry.value, entry.valueColor ?? palette.value]);
|
|
91
92
|
segments.push([' ', palette.dim]);
|
|
92
93
|
}
|
|
93
|
-
return
|
|
94
|
+
return buildStyledViewLine(width, segments.map(([text, fg, bg]) => ({ text, fg, bg: bg ?? palette.summaryBg })), { fillBg: palette.summaryBg });
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
export function buildShortcutLine(
|
|
97
98
|
width: number,
|
|
98
99
|
keys: string,
|
|
99
100
|
summary: string,
|
|
100
|
-
palette:
|
|
101
|
+
palette: ViewPalette,
|
|
101
102
|
): Line {
|
|
102
|
-
return
|
|
103
|
+
return buildViewLine(width, [
|
|
103
104
|
[' ', palette.label],
|
|
104
105
|
[keys, palette.info],
|
|
105
106
|
[' ', palette.dim],
|
|
@@ -107,10 +108,10 @@ export function buildShortcutLine(
|
|
|
107
108
|
]);
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
export function
|
|
111
|
+
export function buildViewListRow(
|
|
111
112
|
width: number,
|
|
112
|
-
segments: ReadonlyArray<
|
|
113
|
-
palette:
|
|
113
|
+
segments: ReadonlyArray<StyledViewSegment>,
|
|
114
|
+
palette: ViewPalette,
|
|
114
115
|
options: {
|
|
115
116
|
readonly selected?: boolean;
|
|
116
117
|
readonly selectedBg?: string;
|
|
@@ -124,7 +125,7 @@ export function buildPanelListRow(
|
|
|
124
125
|
const fillBg = selected ? selectedBg : options.fillBg;
|
|
125
126
|
const marker = selected ? `${options.marker ?? GLYPHS.navigation.selected} ` : ' ';
|
|
126
127
|
const markerFg = selected ? (options.markerColor ?? palette.info) : palette.dim;
|
|
127
|
-
return
|
|
128
|
+
return buildStyledViewLine(width, [
|
|
128
129
|
{ text: marker, fg: markerFg, bg: fillBg, bold: selected },
|
|
129
130
|
...segments.map((segment) => ({
|
|
130
131
|
...segment,
|
|
@@ -137,7 +138,7 @@ export function buildSearchInputLine(
|
|
|
137
138
|
width: number,
|
|
138
139
|
label: string,
|
|
139
140
|
value: string,
|
|
140
|
-
palette:
|
|
141
|
+
palette: ViewPalette,
|
|
141
142
|
options: { active?: boolean; bg?: string; emptyLabel?: string; valueColor?: string } = {},
|
|
142
143
|
): Line {
|
|
143
144
|
const active = options.active ?? false;
|
|
@@ -152,33 +153,38 @@ export function buildSearchInputLine(
|
|
|
152
153
|
: hasValue
|
|
153
154
|
? options.valueColor ?? palette.value
|
|
154
155
|
: palette.dim;
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
// Two columns of padding on both sides of the fill; a long draft keeps its
|
|
157
|
+
// end (where the cursor is) in view.
|
|
158
|
+
const room = Math.max(1, width - 4 - getDisplayWidth(label));
|
|
159
|
+
let shown = content;
|
|
160
|
+
while (shown.length > 0 && getDisplayWidth(shown) > room) shown = shown.slice(1);
|
|
161
|
+
return buildStyledViewLine(width, [
|
|
162
|
+
{ text: ' ', fg: palette.label, bg },
|
|
157
163
|
{ text: `${label}`, fg: palette.label, bg },
|
|
158
|
-
{ text:
|
|
164
|
+
{ text: shown, fg, bg, bold: active },
|
|
159
165
|
], { fillBg: bg });
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
/**
|
|
163
|
-
* Build a status pill segment (glyph + label) for use in
|
|
169
|
+
* Build a status pill segment (glyph + label) for use in buildViewLine.
|
|
164
170
|
*
|
|
165
|
-
* Returns
|
|
171
|
+
* Returns StyledViewSegment[], spread directly into a buildViewLine segments
|
|
166
172
|
* array:
|
|
167
|
-
*
|
|
173
|
+
* buildViewLine(width, [[' count ', C.label], ...buildStatusPill('bad', '3')])
|
|
168
174
|
*
|
|
169
175
|
* Convention: raw hex colors may only live inside a palette constant declared at
|
|
170
|
-
* the top of a
|
|
176
|
+
* the top of a view file; buildStatusPill derives its color from the palette.
|
|
171
177
|
*/
|
|
172
178
|
export function buildStatusPill(
|
|
173
179
|
state: StatusState,
|
|
174
180
|
label: string,
|
|
175
181
|
opts?: { glyph?: string; bg?: string; count?: number },
|
|
176
|
-
):
|
|
182
|
+
): StyledViewSegment[] {
|
|
177
183
|
const glyph = opts?.glyph ?? STATE_GLYPHS[state];
|
|
178
|
-
const color = state === 'good' ?
|
|
179
|
-
: state === 'warn' ?
|
|
180
|
-
: state === 'bad' ?
|
|
181
|
-
:
|
|
184
|
+
const color = state === 'good' ? DEFAULT_VIEW_PALETTE.good
|
|
185
|
+
: state === 'warn' ? DEFAULT_VIEW_PALETTE.warn
|
|
186
|
+
: state === 'bad' ? DEFAULT_VIEW_PALETTE.bad
|
|
187
|
+
: DEFAULT_VIEW_PALETTE.info;
|
|
182
188
|
const bg = opts?.bg;
|
|
183
189
|
const text = opts?.count !== undefined ? `${glyph} ${label} (${opts.count})` : `${glyph} ${label}`;
|
|
184
190
|
return [{ text, fg: color, bg }];
|
|
@@ -213,7 +219,7 @@ export function buildMeterLine(
|
|
|
213
219
|
const normalizedFilledChar = options.filledChar ?? GLYPHS.meter.filled;
|
|
214
220
|
const barWidth = Math.max(1, total);
|
|
215
221
|
const clampedFilled = Math.max(0, Math.min(barWidth, filled));
|
|
216
|
-
const segments:
|
|
222
|
+
const segments: StyledViewSegment[] = [{ text: prefix, fg: colors.label ?? colors.filled }];
|
|
217
223
|
if (clampedFilled > 0) {
|
|
218
224
|
segments.push({ text: normalizedFilledChar.repeat(clampedFilled), fg: colors.filled });
|
|
219
225
|
}
|
|
@@ -221,7 +227,7 @@ export function buildMeterLine(
|
|
|
221
227
|
segments.push({ text: emptyChar.repeat(barWidth - clampedFilled), fg: colors.empty });
|
|
222
228
|
}
|
|
223
229
|
segments.push({ text: suffix, fg: colors.label ?? colors.filled });
|
|
224
|
-
return
|
|
230
|
+
return buildStyledViewLine(width, segments);
|
|
225
231
|
}
|
|
226
232
|
|
|
227
233
|
export function buildEmptyState(
|
|
@@ -229,13 +235,13 @@ export function buildEmptyState(
|
|
|
229
235
|
title: string,
|
|
230
236
|
body: string,
|
|
231
237
|
actions: ReadonlyArray<{ command: string; summary: string }>,
|
|
232
|
-
palette:
|
|
238
|
+
palette: ViewPalette,
|
|
233
239
|
): Line[] {
|
|
234
240
|
const lines: Line[] = [];
|
|
235
|
-
lines.push(
|
|
241
|
+
lines.push(buildViewLine(width, [[` ${title}`, palette.empty]]));
|
|
236
242
|
lines.push(...buildBodyText(width, body, palette, palette.dim));
|
|
237
243
|
if (actions.length > 0) {
|
|
238
|
-
lines.push(
|
|
244
|
+
lines.push(buildViewLine(width, [[' Suggested next steps', palette.label]]));
|
|
239
245
|
for (const action of actions) {
|
|
240
246
|
lines.push(buildGuidanceLine(width, action.command, action.summary, palette));
|
|
241
247
|
}
|
|
@@ -247,10 +253,10 @@ export function buildSummaryBlock(
|
|
|
247
253
|
width: number,
|
|
248
254
|
title: string,
|
|
249
255
|
rows: readonly Line[],
|
|
250
|
-
palette:
|
|
256
|
+
palette: ViewPalette,
|
|
251
257
|
): Line[] {
|
|
252
258
|
const lines: Line[] = [
|
|
253
|
-
|
|
259
|
+
buildStyledViewLine(width, [
|
|
254
260
|
{ text: ` ${GLYPHS.status.active} ${title}`, fg: palette.header ?? palette.value, bg: palette.summaryBg, bold: true },
|
|
255
261
|
], { fillBg: palette.summaryBg }),
|
|
256
262
|
];
|
|
@@ -262,10 +268,10 @@ export function buildDetailBlock(
|
|
|
262
268
|
width: number,
|
|
263
269
|
title: string,
|
|
264
270
|
rows: readonly Line[],
|
|
265
|
-
palette:
|
|
271
|
+
palette: ViewPalette,
|
|
266
272
|
): Line[] {
|
|
267
273
|
return [
|
|
268
|
-
|
|
274
|
+
buildStyledViewLine(width, [
|
|
269
275
|
{ text: ` ${GLYPHS.status.review} ${title}`, fg: palette.header ?? palette.value, bg: palette.sectionBg, bold: true },
|
|
270
276
|
], { fillBg: palette.sectionBg }),
|
|
271
277
|
...rows.map((row) => row.map((cell) => (
|
|
@@ -294,12 +300,12 @@ function fitDisplayText(text: string, width: number): string {
|
|
|
294
300
|
return out;
|
|
295
301
|
}
|
|
296
302
|
|
|
297
|
-
export interface
|
|
303
|
+
export interface ViewWorkspaceSection {
|
|
298
304
|
readonly title?: string;
|
|
299
305
|
readonly lines: readonly Line[];
|
|
300
306
|
}
|
|
301
307
|
|
|
302
|
-
export interface
|
|
308
|
+
export interface PrimaryScrollableViewSectionConfig {
|
|
303
309
|
readonly title?: string;
|
|
304
310
|
readonly fixedLines?: readonly Line[];
|
|
305
311
|
readonly scrollableLines: readonly Line[];
|
|
@@ -313,7 +319,7 @@ export interface PrimaryScrollablePanelSectionConfig {
|
|
|
313
319
|
};
|
|
314
320
|
}
|
|
315
321
|
|
|
316
|
-
export interface
|
|
322
|
+
export interface ScrollableViewSectionConfig {
|
|
317
323
|
readonly title?: string;
|
|
318
324
|
readonly fixedLines?: readonly Line[];
|
|
319
325
|
readonly scrollableLines: readonly Line[];
|
|
@@ -327,33 +333,33 @@ export interface ScrollablePanelSectionConfig {
|
|
|
327
333
|
};
|
|
328
334
|
}
|
|
329
335
|
|
|
330
|
-
export interface
|
|
336
|
+
export interface StackedScrollableViewSectionConfig extends ScrollableViewSectionConfig {
|
|
331
337
|
readonly weight?: number;
|
|
332
338
|
}
|
|
333
339
|
|
|
334
|
-
export interface
|
|
340
|
+
export interface ViewWorkspaceConfig {
|
|
335
341
|
readonly title: string;
|
|
336
342
|
readonly intro?: string;
|
|
337
|
-
readonly sections: readonly
|
|
343
|
+
readonly sections: readonly ViewWorkspaceSection[];
|
|
338
344
|
readonly footerLines?: readonly Line[];
|
|
339
|
-
readonly palette:
|
|
345
|
+
readonly palette: ViewPalette;
|
|
340
346
|
}
|
|
341
347
|
|
|
342
|
-
function
|
|
348
|
+
function getViewWorkspaceIntroRows(
|
|
343
349
|
width: number,
|
|
344
350
|
intro: string | undefined,
|
|
345
|
-
palette:
|
|
351
|
+
palette: ViewPalette,
|
|
346
352
|
): number {
|
|
347
353
|
return intro ? buildBodyText(width, intro, palette, palette.dim).length : 0;
|
|
348
354
|
}
|
|
349
355
|
|
|
350
|
-
export function
|
|
356
|
+
export function getViewWorkspaceContentBudget(
|
|
351
357
|
width: number,
|
|
352
358
|
height: number,
|
|
353
|
-
config: Pick<
|
|
359
|
+
config: Pick<ViewWorkspaceConfig, 'intro' | 'footerLines' | 'palette'>,
|
|
354
360
|
): number {
|
|
355
361
|
const footerLines = [...(config.footerLines ?? [])];
|
|
356
|
-
const chromeRows = 1 +
|
|
362
|
+
const chromeRows = 1 + getViewWorkspaceIntroRows(width, config.intro, config.palette) + footerLines.length;
|
|
357
363
|
return Math.max(
|
|
358
364
|
1,
|
|
359
365
|
getSurfaceContentRows({
|
|
@@ -368,27 +374,27 @@ export function getPanelWorkspaceContentBudget(
|
|
|
368
374
|
);
|
|
369
375
|
}
|
|
370
376
|
|
|
371
|
-
export function
|
|
377
|
+
export function getViewWorkspaceSectionRows(section: ViewWorkspaceSection): number {
|
|
372
378
|
return (section.title ? 1 : 0) + section.lines.length;
|
|
373
379
|
}
|
|
374
380
|
|
|
375
|
-
export function
|
|
381
|
+
export function getViewScrollableSectionBudget(
|
|
376
382
|
width: number,
|
|
377
383
|
height: number,
|
|
378
384
|
options: {
|
|
379
385
|
readonly intro?: string;
|
|
380
386
|
readonly footerLines?: readonly Line[];
|
|
381
|
-
readonly palette:
|
|
382
|
-
readonly beforeSections?: readonly
|
|
387
|
+
readonly palette: ViewPalette;
|
|
388
|
+
readonly beforeSections?: readonly ViewWorkspaceSection[];
|
|
383
389
|
readonly currentSectionTitle?: string;
|
|
384
390
|
readonly currentSectionFixedRows?: number;
|
|
385
|
-
readonly afterSections?: readonly
|
|
391
|
+
readonly afterSections?: readonly ViewWorkspaceSection[];
|
|
386
392
|
readonly minRows?: number;
|
|
387
393
|
},
|
|
388
394
|
): number {
|
|
389
|
-
const contentBudget =
|
|
390
|
-
const beforeRows = (options.beforeSections ?? []).reduce((sum, section) => sum +
|
|
391
|
-
const afterRows = (options.afterSections ?? []).reduce((sum, section) => sum +
|
|
395
|
+
const contentBudget = getViewWorkspaceContentBudget(width, height, options);
|
|
396
|
+
const beforeRows = (options.beforeSections ?? []).reduce((sum, section) => sum + getViewWorkspaceSectionRows(section), 0);
|
|
397
|
+
const afterRows = (options.afterSections ?? []).reduce((sum, section) => sum + getViewWorkspaceSectionRows(section), 0);
|
|
392
398
|
const currentHeaderRows = options.currentSectionTitle ? 1 : 0;
|
|
393
399
|
const currentFixedRows = Math.max(0, options.currentSectionFixedRows ?? 0);
|
|
394
400
|
return Math.max(options.minRows ?? 1, contentBudget - beforeRows - currentHeaderRows - currentFixedRows - afterRows);
|
|
@@ -400,17 +406,17 @@ export function resolvePrimaryScrollableSection(
|
|
|
400
406
|
options: {
|
|
401
407
|
readonly intro?: string;
|
|
402
408
|
readonly footerLines?: readonly Line[];
|
|
403
|
-
readonly palette:
|
|
404
|
-
readonly beforeSections?: readonly
|
|
405
|
-
readonly section:
|
|
406
|
-
readonly afterSections?: readonly
|
|
409
|
+
readonly palette: ViewPalette;
|
|
410
|
+
readonly beforeSections?: readonly ViewWorkspaceSection[];
|
|
411
|
+
readonly section: PrimaryScrollableViewSectionConfig;
|
|
412
|
+
readonly afterSections?: readonly ViewWorkspaceSection[];
|
|
407
413
|
},
|
|
408
414
|
): {
|
|
409
|
-
readonly section:
|
|
415
|
+
readonly section: ViewWorkspaceSection;
|
|
410
416
|
readonly scrollOffset: number;
|
|
411
417
|
readonly window: VisibleWindow;
|
|
412
418
|
} {
|
|
413
|
-
return
|
|
419
|
+
return resolveScrollableViewSection(width, height, {
|
|
414
420
|
intro: options.intro,
|
|
415
421
|
footerLines: options.footerLines,
|
|
416
422
|
palette: options.palette,
|
|
@@ -420,24 +426,24 @@ export function resolvePrimaryScrollableSection(
|
|
|
420
426
|
});
|
|
421
427
|
}
|
|
422
428
|
|
|
423
|
-
export function
|
|
429
|
+
export function resolveScrollableViewSection(
|
|
424
430
|
width: number,
|
|
425
431
|
height: number,
|
|
426
432
|
options: {
|
|
427
433
|
readonly intro?: string;
|
|
428
434
|
readonly footerLines?: readonly Line[];
|
|
429
|
-
readonly palette:
|
|
430
|
-
readonly beforeSections?: readonly
|
|
431
|
-
readonly section:
|
|
432
|
-
readonly afterSections?: readonly
|
|
435
|
+
readonly palette: ViewPalette;
|
|
436
|
+
readonly beforeSections?: readonly ViewWorkspaceSection[];
|
|
437
|
+
readonly section: ScrollableViewSectionConfig;
|
|
438
|
+
readonly afterSections?: readonly ViewWorkspaceSection[];
|
|
433
439
|
},
|
|
434
440
|
): {
|
|
435
|
-
readonly section:
|
|
441
|
+
readonly section: ViewWorkspaceSection;
|
|
436
442
|
readonly scrollOffset: number;
|
|
437
443
|
readonly window: VisibleWindow;
|
|
438
444
|
} {
|
|
439
445
|
const fixedLines = [...(options.section.fixedLines ?? [])];
|
|
440
|
-
const budget =
|
|
446
|
+
const budget = getViewScrollableSectionBudget(width, height, {
|
|
441
447
|
intro: options.intro,
|
|
442
448
|
footerLines: options.footerLines,
|
|
443
449
|
palette: options.palette,
|
|
@@ -450,7 +456,7 @@ export function resolveScrollablePanelSection(
|
|
|
450
456
|
// When a window-summary row will render (list longer than the budget can
|
|
451
457
|
// show), it occupies one of the section's rows. Reserve that row up front so
|
|
452
458
|
// the summary is accounted INSIDE the budget; otherwise the appended summary
|
|
453
|
-
// pushes total output one line past the
|
|
459
|
+
// pushes total output one line past the view's exact-height contract and the
|
|
454
460
|
// tail line (typically the footer's keyboard-hints row) is silently dropped.
|
|
455
461
|
const summaryReserved = options.section.appendWindowSummary
|
|
456
462
|
&& options.section.scrollableLines.length > budget
|
|
@@ -477,7 +483,7 @@ export function resolveScrollablePanelSection(
|
|
|
477
483
|
if (options.section.appendWindowSummary && options.section.scrollableLines.length > window.count) {
|
|
478
484
|
const summary = options.section.appendWindowSummary.formatter
|
|
479
485
|
? options.section.appendWindowSummary.formatter(window)
|
|
480
|
-
:
|
|
486
|
+
: buildViewLine(width, [[` showing ${window.start + 1}-${window.end} of ${window.total}`, options.section.appendWindowSummary.dimColor ?? options.palette.dim]]);
|
|
481
487
|
lines.push(summary);
|
|
482
488
|
}
|
|
483
489
|
return {
|
|
@@ -496,20 +502,20 @@ export function resolveStackedScrollableSections(
|
|
|
496
502
|
options: {
|
|
497
503
|
readonly intro?: string;
|
|
498
504
|
readonly footerLines?: readonly Line[];
|
|
499
|
-
readonly palette:
|
|
500
|
-
readonly beforeSections?: readonly
|
|
501
|
-
readonly sections: readonly
|
|
502
|
-
readonly afterSections?: readonly
|
|
505
|
+
readonly palette: ViewPalette;
|
|
506
|
+
readonly beforeSections?: readonly ViewWorkspaceSection[];
|
|
507
|
+
readonly sections: readonly StackedScrollableViewSectionConfig[];
|
|
508
|
+
readonly afterSections?: readonly ViewWorkspaceSection[];
|
|
503
509
|
},
|
|
504
510
|
): ReadonlyArray<{
|
|
505
|
-
readonly section:
|
|
511
|
+
readonly section: ViewWorkspaceSection;
|
|
506
512
|
readonly scrollOffset: number;
|
|
507
513
|
readonly window: VisibleWindow;
|
|
508
514
|
}> {
|
|
509
515
|
if (options.sections.length === 0) return [];
|
|
510
|
-
const contentBudget =
|
|
511
|
-
const beforeRows = (options.beforeSections ?? []).reduce((sum, section) => sum +
|
|
512
|
-
const afterRows = (options.afterSections ?? []).reduce((sum, section) => sum +
|
|
516
|
+
const contentBudget = getViewWorkspaceContentBudget(width, height, options);
|
|
517
|
+
const beforeRows = (options.beforeSections ?? []).reduce((sum, section) => sum + getViewWorkspaceSectionRows(section), 0);
|
|
518
|
+
const afterRows = (options.afterSections ?? []).reduce((sum, section) => sum + getViewWorkspaceSectionRows(section), 0);
|
|
513
519
|
const fixedChrome = options.sections.reduce((sum, section) => (
|
|
514
520
|
sum
|
|
515
521
|
+ (section.title ? 1 : 0)
|
|
@@ -539,7 +545,7 @@ export function resolveStackedScrollableSections(
|
|
|
539
545
|
|
|
540
546
|
return options.sections.map((section, index) => {
|
|
541
547
|
const fixedLines = [...(section.fixedLines ?? [])];
|
|
542
|
-
// Same reservation as
|
|
548
|
+
// Same reservation as resolveScrollableViewSection: a window-summary row
|
|
543
549
|
// occupies one of this section's allocated rows, so shrink the visible
|
|
544
550
|
// window rather than overflowing the stack's exact-height budget.
|
|
545
551
|
const budget = budgets[index]!;
|
|
@@ -564,7 +570,7 @@ export function resolveStackedScrollableSections(
|
|
|
564
570
|
if (section.appendWindowSummary && section.scrollableLines.length > window.count) {
|
|
565
571
|
const summary = section.appendWindowSummary.formatter
|
|
566
572
|
? section.appendWindowSummary.formatter(window)
|
|
567
|
-
:
|
|
573
|
+
: buildViewLine(width, [[` showing ${window.start + 1}-${window.end} of ${window.total}`, section.appendWindowSummary.dimColor ?? options.palette.dim]]);
|
|
568
574
|
lines.push(summary);
|
|
569
575
|
}
|
|
570
576
|
return {
|
|
@@ -579,13 +585,13 @@ export function resolveStackedScrollableSections(
|
|
|
579
585
|
}
|
|
580
586
|
|
|
581
587
|
/**
|
|
582
|
-
* Standardized footer keyboard-hint row so every
|
|
588
|
+
* Standardized footer keyboard-hint row so every view's hints look identical.
|
|
583
589
|
* Each hint renders as `keys` (info color) + `label` (dim).
|
|
584
590
|
*/
|
|
585
591
|
export function buildKeyboardHints(
|
|
586
592
|
width: number,
|
|
587
593
|
hints: ReadonlyArray<{ keys: string; label: string }>,
|
|
588
|
-
palette:
|
|
594
|
+
palette: ViewPalette,
|
|
589
595
|
): Line {
|
|
590
596
|
const segments: Array<[string, string, string?]> = [];
|
|
591
597
|
hints.forEach((hint, i) => {
|
|
@@ -595,21 +601,21 @@ export function buildKeyboardHints(
|
|
|
595
601
|
segments.push([' ', palette.dim]);
|
|
596
602
|
segments.push([hint.label, palette.dim]);
|
|
597
603
|
});
|
|
598
|
-
return
|
|
604
|
+
return buildViewLine(width, segments);
|
|
599
605
|
}
|
|
600
606
|
|
|
601
|
-
export function
|
|
607
|
+
export function buildViewWorkspace(
|
|
602
608
|
width: number,
|
|
603
609
|
height: number,
|
|
604
|
-
config:
|
|
610
|
+
config: ViewWorkspaceConfig,
|
|
605
611
|
): Line[] {
|
|
606
612
|
const lines: Line[] = [];
|
|
607
|
-
lines.push(
|
|
613
|
+
lines.push(buildViewTitle(width, config.title, config.palette));
|
|
608
614
|
if (config.intro) {
|
|
609
615
|
lines.push(...buildBodyText(width, config.intro, config.palette, config.palette.dim));
|
|
610
616
|
}
|
|
611
617
|
const footerLines = [...(config.footerLines ?? [])];
|
|
612
|
-
const contentBudget =
|
|
618
|
+
const contentBudget = getViewWorkspaceContentBudget(width, height, config);
|
|
613
619
|
|
|
614
620
|
let consumed = 0;
|
|
615
621
|
for (let sectionIndex = 0; sectionIndex < config.sections.length; sectionIndex++) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ProjectPlanningQuestion } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
2
2
|
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
|
-
// Answer-action helpers for the Project Planning
|
|
4
|
+
// Answer-action helpers for the Project Planning view.
|
|
5
5
|
//
|
|
6
|
-
// Extracted from project
|
|
6
|
+
// Extracted from the project planning view to keep that module under the
|
|
7
7
|
// architecture line-count cap. Leaf module (only the SDK question type);
|
|
8
|
-
// the
|
|
8
|
+
// the project planning view is their public import site.
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
|
|
11
11
|
export interface PlanningAnswerAction {
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
// provider-health-routes.ts
|
|
3
3
|
//
|
|
4
4
|
// Single-source auth-route posture for the provider console (merge of
|
|
5
|
-
// the retired accounts
|
|
5
|
+
// the retired accounts view into provider-health). All route data flows from
|
|
6
6
|
// ProviderRuntimeInspectionQuery.inspectAll() snapshots; this module only
|
|
7
7
|
// normalizes descriptors (synthesizing them for providers that do not declare
|
|
8
8
|
// routes) and derives the active/preferred route, freshness, issues, and
|
|
9
|
-
// repair hints. It intentionally keeps the full descriptor list so the
|
|
10
|
-
// can render per-route detail (absorbed from the accounts
|
|
9
|
+
// repair hints. It intentionally keeps the full descriptor list so the provider-health modal
|
|
10
|
+
// can render per-route detail (absorbed from the accounts view) instead of a
|
|
11
11
|
// lossy summary record.
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
|
|
14
14
|
import type { ProviderAuthRouteDescriptor } from '@pellux/goodvibes-sdk/platform/providers';
|
|
15
15
|
|
|
16
|
-
export type
|
|
17
|
-
export type
|
|
16
|
+
export type ProviderHealthAuthRoute = ProviderAuthRouteDescriptor['route'] | 'unconfigured';
|
|
17
|
+
export type ProviderHealthAuthFreshness = NonNullable<ProviderAuthRouteDescriptor['freshness']> | 'unconfigured';
|
|
18
18
|
|
|
19
19
|
/** Auth metadata shape carried by ProviderRuntimeInspectionQuery snapshots. */
|
|
20
20
|
export interface ProviderRuntimeAuthMetadata {
|
|
@@ -42,10 +42,10 @@ export interface ProviderAccountPosture {
|
|
|
42
42
|
readonly modelCount: number;
|
|
43
43
|
/** Normalized route descriptors (declared or synthesized). */
|
|
44
44
|
readonly routes: readonly ProviderAuthRouteDescriptor[];
|
|
45
|
-
readonly activeRoute:
|
|
46
|
-
readonly preferredRoute:
|
|
45
|
+
readonly activeRoute: ProviderHealthAuthRoute;
|
|
46
|
+
readonly preferredRoute: ProviderHealthAuthRoute;
|
|
47
47
|
readonly activeRouteReason: string;
|
|
48
|
-
readonly authFreshness:
|
|
48
|
+
readonly authFreshness: ProviderHealthAuthFreshness;
|
|
49
49
|
/** True when any route is expiring (or already expired/pending). */
|
|
50
50
|
readonly expiringSoon: boolean;
|
|
51
51
|
readonly issues: readonly string[];
|
|
@@ -53,7 +53,7 @@ export interface ProviderAccountPosture {
|
|
|
53
53
|
readonly repairHints: readonly string[];
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
const AUTH_ROUTE_PRIORITY: readonly
|
|
56
|
+
const AUTH_ROUTE_PRIORITY: readonly ProviderHealthAuthRoute[] = [
|
|
57
57
|
'subscription-oauth',
|
|
58
58
|
'service-oauth',
|
|
59
59
|
'secret-ref',
|
|
@@ -63,7 +63,7 @@ const AUTH_ROUTE_PRIORITY: readonly ProviderPanelAuthRoute[] = [
|
|
|
63
63
|
'unconfigured',
|
|
64
64
|
] as const;
|
|
65
65
|
|
|
66
|
-
export function routePriority(route:
|
|
66
|
+
export function routePriority(route: ProviderHealthAuthRoute): number {
|
|
67
67
|
const priority = AUTH_ROUTE_PRIORITY.indexOf(route);
|
|
68
68
|
return priority >= 0 ? priority : AUTH_ROUTE_PRIORITY.length;
|
|
69
69
|
}
|
|
@@ -137,7 +137,7 @@ function pickRoute(
|
|
|
137
137
|
/**
|
|
138
138
|
* Derive the console's account/auth posture for one inspectAll() snapshot.
|
|
139
139
|
* This is the only route-posture derivation in the TUI (the retired accounts
|
|
140
|
-
*
|
|
140
|
+
* view's parallel snapshot model was deleted with).
|
|
141
141
|
*/
|
|
142
142
|
export function buildAccountPosture(snapshot: ProviderRuntimeSnapshotLike): ProviderAccountPosture {
|
|
143
143
|
const auth = snapshot.runtime.auth;
|
|
@@ -146,9 +146,9 @@ export function buildAccountPosture(snapshot: ProviderRuntimeSnapshotLike): Prov
|
|
|
146
146
|
const usableRoutes = routes.filter(isRouteUsable);
|
|
147
147
|
const preferredRoute = pickRoute(configuredRoutes.length > 0 ? configuredRoutes : routes);
|
|
148
148
|
const activeRoute = pickRoute(usableRoutes.length > 0 ? usableRoutes : (preferredRoute ? [preferredRoute] : []));
|
|
149
|
-
const activeRouteId:
|
|
150
|
-
const preferredRouteId:
|
|
151
|
-
const authFreshness:
|
|
149
|
+
const activeRouteId: ProviderHealthAuthRoute = activeRoute?.route ?? 'unconfigured';
|
|
150
|
+
const preferredRouteId: ProviderHealthAuthRoute = preferredRoute?.route ?? activeRouteId;
|
|
151
|
+
const authFreshness: ProviderHealthAuthFreshness =
|
|
152
152
|
activeRoute?.freshness ?? (activeRouteId === 'none' ? 'healthy' : 'unconfigured');
|
|
153
153
|
|
|
154
154
|
const issueSet = new Set<string>();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isTextBackspace } from '../input/delete-key-policy.ts';
|
|
2
2
|
|
|
3
|
-
export type
|
|
3
|
+
export type ViewSearchFocusTransition = 'focus-search' | 'focus-list' | null;
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function getViewSearchFocusTransition(
|
|
6
6
|
key: string,
|
|
7
7
|
options: { selectedIndex: number; itemCount: number; focusKeys?: ReadonlyArray<string> },
|
|
8
|
-
):
|
|
8
|
+
): ViewSearchFocusTransition {
|
|
9
9
|
const focusKeys = options.focusKeys ?? ['/'];
|
|
10
10
|
if (focusKeys.includes(key)) return 'focus-search';
|
|
11
11
|
if (key === 'up' && options.selectedIndex <= 0) {
|
|
@@ -17,22 +17,22 @@ export function getPanelSearchFocusTransition(
|
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
//
|
|
20
|
+
// View search filters are end-anchored (no moveable cursor).
|
|
21
21
|
// Per the delete-key policy (src/input/delete-key-policy.ts):
|
|
22
22
|
// 'backspace' removes the last character.
|
|
23
23
|
// 'delete' is a no-op, there is no cursor, so forward-delete is meaningless.
|
|
24
|
-
export function
|
|
24
|
+
export function isViewSearchBackspace(key: string): boolean {
|
|
25
25
|
return isTextBackspace(key);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function
|
|
28
|
+
export function isViewSearchCancel(key: string): boolean {
|
|
29
29
|
return key === 'escape';
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function
|
|
32
|
+
export function isViewSearchCommit(key: string): boolean {
|
|
33
33
|
return key === 'return' || key === 'enter';
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export function
|
|
36
|
+
export function isViewSearchPrintable(key: string): boolean {
|
|
37
37
|
return key.length === 1 && key >= ' ';
|
|
38
38
|
}
|