@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
package/src/panels/types.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import type { Line } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
-
import type { StatusState } from '../renderer/status-glyphs.ts';
|
|
3
|
-
import type { ComponentResourceContract, ComponentHealthState } from '../runtime/perf/panel-contracts.ts';
|
|
4
|
-
// Routed through the `@/` alias (not `./panel-manager.ts`) so this foundational
|
|
5
|
-
// types module stays a leaf in the relative-import graph the architecture
|
|
6
|
-
// cycle-checker walks. Type-only, erased at runtime, no real dependency edge.
|
|
7
|
-
import type { PanelManager } from '@/panels/panel-manager.ts';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Context passed to a panel's `handlePanelIntegrationAction` hook so it can
|
|
11
|
-
* drive cross-panel behavior (e.g. file-explorer opening the preview panel)
|
|
12
|
-
* without the input layer needing `instanceof` knowledge of each panel type.
|
|
13
|
-
*/
|
|
14
|
-
export interface PanelIntegrationContext {
|
|
15
|
-
readonly panelManager: PanelManager;
|
|
16
|
-
readonly executeCommand?: (name: string, args: string[]) => Promise<unknown>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* A cross-panel deep-link target (item 4): a specific node a panel
|
|
21
|
-
* should select + reveal when opened via `PanelManager.open(id, pane, target)`,
|
|
22
|
-
* e.g. a Fleet tree node keyed by its process id and (optionally) its
|
|
23
|
-
* ProcessKind for disambiguation. Panel-agnostic on purpose, only panels that
|
|
24
|
-
* have a "node" concept implement `Panel.receiveDeepLink`.
|
|
25
|
-
*/
|
|
26
|
-
export interface PanelDeepLinkTarget {
|
|
27
|
-
readonly id: string;
|
|
28
|
-
readonly kind?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Named logical key identifiers emitted by the input tokenizer.
|
|
33
|
-
* These are the ONLY key names that will appear in `handleInput` calls;
|
|
34
|
-
* the tokenizer never emits DOM/browser-style names like 'ArrowUp' or 'Enter'.
|
|
35
|
-
*
|
|
36
|
-
* Printable single-character input is passed through as-is; the `string & {}`
|
|
37
|
-
* fallback preserves that handling while making named-key completions discoverable
|
|
38
|
-
* in editors and keeping non-null single-character values compatible.
|
|
39
|
-
*/
|
|
40
|
-
export type NamedKey =
|
|
41
|
-
| 'up' | 'down' | 'left' | 'right'
|
|
42
|
-
| 'home' | 'end' | 'pageup' | 'pagedown'
|
|
43
|
-
| 'insert' | 'delete' | 'backspace'
|
|
44
|
-
| 'enter' | 'return' | 'escape' | 'space' | 'tab'
|
|
45
|
-
| 'f1' | 'f2' | 'f3' | 'f4' | 'f5' | 'f6'
|
|
46
|
-
| 'f7' | 'f8' | 'f9' | 'f10' | 'f11' | 'f12';
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* The full key type accepted by `Panel.handleInput`.
|
|
50
|
-
*
|
|
51
|
-
* Named keys (arrow keys, modifiers, function keys) are represented by
|
|
52
|
-
* lowercase `NamedKey` members. Single printable characters are passed
|
|
53
|
-
* verbatim via the `string & {}` escape hatch so panels can handle 'j', 'k',
|
|
54
|
-
* 'r', etc. without losing type safety on the named members.
|
|
55
|
-
*/
|
|
56
|
-
export type KeyName = NamedKey | (string & {});
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* the former single 'monitoring' bucket held 33 panels pre-merge,
|
|
60
|
-
* too coarse for the picker to be useful and too large for any one operator
|
|
61
|
-
* mental model. Split into named operator domains so each category holds a
|
|
62
|
-
* bounded, coherent set (no category may exceed 10 registrations):
|
|
63
|
-
* - providers: provider/model connectivity, cost, and token usage
|
|
64
|
-
* - security-policy: auth, policy governance, and isolation posture
|
|
65
|
-
* - automation-control: hooks, plugins, marketplace, automation jobs, worktrees
|
|
66
|
-
* - incidents-diagnostics: failure review, eval gates, API call debugging
|
|
67
|
-
* - runtime-ops: live operator consoles (cockpit, tasks, orchestration, comms)
|
|
68
|
-
*/
|
|
69
|
-
export type PanelCategory =
|
|
70
|
-
| 'development'
|
|
71
|
-
| 'agent'
|
|
72
|
-
| 'session'
|
|
73
|
-
| 'ai'
|
|
74
|
-
| 'providers'
|
|
75
|
-
| 'security-policy'
|
|
76
|
-
| 'automation-control'
|
|
77
|
-
| 'incidents-diagnostics'
|
|
78
|
-
| 'runtime-ops';
|
|
79
|
-
|
|
80
|
-
export interface Panel {
|
|
81
|
-
id: string;
|
|
82
|
-
name: string;
|
|
83
|
-
icon: string; // single char for tab bar
|
|
84
|
-
category: PanelCategory;
|
|
85
|
-
|
|
86
|
-
// Lifecycle
|
|
87
|
-
onActivate(): void;
|
|
88
|
-
onDeactivate(): void;
|
|
89
|
-
onDestroy(): void;
|
|
90
|
-
|
|
91
|
-
// Rendering
|
|
92
|
-
render(width: number, height: number): Line[];
|
|
93
|
-
|
|
94
|
-
// State
|
|
95
|
-
isTransient: boolean;
|
|
96
|
-
isPinned: boolean;
|
|
97
|
-
needsRender: boolean;
|
|
98
|
-
|
|
99
|
-
// Dirty-flag contract (activated panel render skipping)
|
|
100
|
-
/** Mark this panel as needing a re-render on the next frame. */
|
|
101
|
-
invalidate(): void;
|
|
102
|
-
/** Called by the compositor after a successful render to clear the dirty flag. */
|
|
103
|
-
markRendered(): void;
|
|
104
|
-
|
|
105
|
-
// Resource contract (optional, panels may declare resource requirements)
|
|
106
|
-
resourceContract?: Readonly<ComponentResourceContract>;
|
|
107
|
-
|
|
108
|
-
// Health state (optional, set by ComponentHealthMonitor when panel is registered)
|
|
109
|
-
healthState?: Readonly<ComponentHealthState>;
|
|
110
|
-
|
|
111
|
-
// Input (optional)
|
|
112
|
-
handleInput?(key: KeyName): boolean;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Optional: report `true` while this panel has an active inline text
|
|
116
|
-
* capture (e.g. a `/`-to-filter or search buffer) that deliberately wants
|
|
117
|
-
* every character of a burst, paste, or several keystrokes typed fast
|
|
118
|
-
* enough to land in one `input.feed()` call, delivered to `handleInput`
|
|
119
|
-
* one at a time, same as it always has. When this returns `false` or is
|
|
120
|
-
* not implemented, the input router treats a printable burst as never a
|
|
121
|
-
* deliberate single-key panel hotkey and routes it to the composer
|
|
122
|
-
* instead of exploding it into per-char `handleInput` calls (see
|
|
123
|
-
* `handlePanelFocusToken` in `src/input/handler-feed-routes.ts`).
|
|
124
|
-
*/
|
|
125
|
-
isCapturingTextBurst?(): boolean;
|
|
126
|
-
|
|
127
|
-
// Scroll input (optional)
|
|
128
|
-
// Positive delta scrolls down; negative delta scrolls up.
|
|
129
|
-
handleScroll?(deltaRows: number): boolean;
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Cross-panel integration hook (optional). Called before the panel's own
|
|
133
|
-
* `handleInput` when a navigation/confirm key is pressed, so a panel can
|
|
134
|
-
* drive another panel (e.g. open a file in the preview panel). Return `true`
|
|
135
|
-
* to consume the key. The legacy `handlePanelIntegrationAction` router in
|
|
136
|
-
* `src/input/panel-integration-actions.ts` consults this first, then falls
|
|
137
|
-
* back to its built-in `instanceof` routing.
|
|
138
|
-
*/
|
|
139
|
-
handlePanelIntegrationAction?(key: string, ctx: PanelIntegrationContext): boolean;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Optional: called by the global Ctrl+X (`panel-close`) shortcut BEFORE it
|
|
143
|
-
* closes this panel (handler-shortcuts.ts). Return `true` to consume
|
|
144
|
-
* Ctrl+X for an in-panel action instead, e.g. FleetPanel (session
|
|
145
|
-
* tabs) detaches its active tab and leaves the panel open. Return `false`
|
|
146
|
-
* (or omit this hook) to fall through to the ordinary close behavior.
|
|
147
|
-
* Ctrl+X never reaches a panel's own `handleInput` (ctrl/meta combos are
|
|
148
|
-
* intercepted earlier, see handlePanelFocusToken in
|
|
149
|
-
* src/input/handler-feed-routes.ts), so this is the one seam a panel has
|
|
150
|
-
* to intervene before the global shortcut acts.
|
|
151
|
-
*/
|
|
152
|
-
interceptPanelClose?(): boolean;
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Optional: consume a deep-link target handed in by `PanelManager.open(id,
|
|
156
|
-
* pane, target)` (item 4), select + reveal the matching node on the
|
|
157
|
-
* panel's next snapshot. A panel without a "node" concept simply doesn't
|
|
158
|
-
* implement this (the call is a no-op via optional chaining in
|
|
159
|
-
* PanelManager). A panel that DOES implement it owns its own honest
|
|
160
|
-
* "not found" surface (e.g. FleetPanel.setError) when the target no longer
|
|
161
|
-
* resolves, PanelManager has no transcript/print seam to report on its
|
|
162
|
-
* behalf.
|
|
163
|
-
*/
|
|
164
|
-
receiveDeepLink?(target: PanelDeepLinkTarget): void;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export interface PanelRegistration extends Pick<Panel, 'id' | 'name' | 'icon' | 'category'> {
|
|
168
|
-
factory: () => Panel;
|
|
169
|
-
description: string;
|
|
170
|
-
/**
|
|
171
|
-
* lifecycle flags. `preload` and `retainOnClose` are independent,
|
|
172
|
-
* a panel can eagerly instantiate without being kept alive on close, or be
|
|
173
|
-
* kept alive on close without eager bootstrap instantiation. They happened
|
|
174
|
-
* to be identical for all builtin panels before this split (both driven by
|
|
175
|
-
* a single `preload: true`); that existing 10-panel retained set is
|
|
176
|
-
* preserved unchanged by giving each of those 10 registrations both flags.
|
|
177
|
-
*
|
|
178
|
-
* - `preload`, instantiate this panel during `PanelManager.prewarmRegistered()`
|
|
179
|
-
* (called once at bootstrap) so its factory runs and it starts
|
|
180
|
-
* accumulating background data (subscriptions, timers) before the user
|
|
181
|
-
* ever opens the workspace. Panels without `preload` are instantiated
|
|
182
|
-
* lazily on first `open()`.
|
|
183
|
-
* - `retainOnClose`, when this panel is closed, keep the live instance in
|
|
184
|
-
* `PanelManager`'s retained-panel map (background subscriptions/timers
|
|
185
|
-
* keep running) instead of calling `onDestroy()`. Reopening returns the
|
|
186
|
-
* same instance with its accumulated state intact. Panels without
|
|
187
|
-
* `retainOnClose` are destroyed on close and rebuilt fresh next open.
|
|
188
|
-
*/
|
|
189
|
-
preload?: boolean;
|
|
190
|
-
retainOnClose?: boolean;
|
|
191
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
2
|
-
import type { WrfcState, Constraint, ConstraintFinding } from '@pellux/goodvibes-sdk/platform/agents';
|
|
3
|
-
import { DEFAULT_PANEL_PALETTE, extendPalette } from './polish.ts';
|
|
4
|
-
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
// Colour palette + formatting helpers for the WRFC panel.
|
|
7
|
-
//
|
|
8
|
-
// Extracted from wrfc-panel.ts to keep that module under the architecture
|
|
9
|
-
// line-count cap. Leaf module (only polish + terminal-width + sdk types); the
|
|
10
|
-
// panel re-exports the public helpers so ./wrfc-panel.ts stays their import site.
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
export const C = extendPalette(DEFAULT_PANEL_PALETTE, {
|
|
13
|
-
// WRFC state-machine colours (domain status -- no shared equivalent)
|
|
14
|
-
passed: '#22c55e', // green
|
|
15
|
-
failed: '#ef4444', // red
|
|
16
|
-
reviewing: '#eab308', // yellow
|
|
17
|
-
engineering:'#22d3ee', // cyan
|
|
18
|
-
fixing: '#f97316', // orange
|
|
19
|
-
pending: '#6b7280', // grey
|
|
20
|
-
gating: '#a78bfa', // violet
|
|
21
|
-
committing: '#38bdf8', // sky
|
|
22
|
-
integrating:'#818cf8', // indigo
|
|
23
|
-
|
|
24
|
-
// Issue-severity ramp (domain -- no shared equivalent)
|
|
25
|
-
issueCrit: '#ef4444',
|
|
26
|
-
issueMaj: '#f97316',
|
|
27
|
-
issueMin: '#eab308',
|
|
28
|
-
issueSug: '#6b7280',
|
|
29
|
-
|
|
30
|
-
// Selection + divider chrome with no shared equivalent
|
|
31
|
-
selected: '#1e40af', // selection bg
|
|
32
|
-
selectedFg: '#f8fafc',
|
|
33
|
-
border: '#334155',
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
// Helpers
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
const SPARKLINE_CHARS = '._-:=+*#';
|
|
40
|
-
|
|
41
|
-
export function sparkline(scores: number[], maxScore = 10): string {
|
|
42
|
-
if (scores.length === 0) return '';
|
|
43
|
-
return scores
|
|
44
|
-
.map(s => {
|
|
45
|
-
const ratio = Math.max(0, Math.min(1, s / maxScore));
|
|
46
|
-
const idx = Math.round(ratio * (SPARKLINE_CHARS.length - 1));
|
|
47
|
-
return SPARKLINE_CHARS[idx];
|
|
48
|
-
})
|
|
49
|
-
.join('');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function stateColor(state: WrfcState): string {
|
|
53
|
-
switch (state) {
|
|
54
|
-
case 'passed': return C.passed;
|
|
55
|
-
case 'failed': return C.failed;
|
|
56
|
-
case 'reviewing': return C.reviewing;
|
|
57
|
-
case 'engineering': return C.engineering;
|
|
58
|
-
case 'fixing': return C.fixing;
|
|
59
|
-
case 'gating':
|
|
60
|
-
case 'awaiting_gates': return C.gating;
|
|
61
|
-
case 'committing': return C.committing;
|
|
62
|
-
case 'integrating': return C.integrating;
|
|
63
|
-
default: return C.pending;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function stateLabel(state: WrfcState): string {
|
|
68
|
-
switch (state) {
|
|
69
|
-
case 'engineering': return 'ENG';
|
|
70
|
-
case 'reviewing': return 'REV';
|
|
71
|
-
case 'fixing': return 'FIX';
|
|
72
|
-
case 'gating': return 'GATE';
|
|
73
|
-
case 'awaiting_gates': return 'WAIT';
|
|
74
|
-
case 'committing': return 'COMMIT';
|
|
75
|
-
case 'integrating': return 'INTG';
|
|
76
|
-
case 'passed': return 'PASS';
|
|
77
|
-
case 'failed': return 'FAIL';
|
|
78
|
-
default: return 'PEND';
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function issueColor(severity: string): string {
|
|
83
|
-
switch (severity) {
|
|
84
|
-
case 'critical': return C.issueCrit;
|
|
85
|
-
case 'major': return C.issueMaj;
|
|
86
|
-
case 'minor': return C.issueMin;
|
|
87
|
-
default: return C.issueSug;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function issuePrefix(severity: string): string {
|
|
92
|
-
switch (severity) {
|
|
93
|
-
case 'critical': return '[CRIT] ';
|
|
94
|
-
case 'major': return '[MAJR] ';
|
|
95
|
-
case 'minor': return '[MINR] ';
|
|
96
|
-
default: return '[SUGG] ';
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function truncate(s: string, max: number): string {
|
|
101
|
-
return truncateDisplay(s, max);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// ---------------------------------------------------------------------------
|
|
105
|
-
// Constraint helpers
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Returns display tag, foreground colour, and dim flag for a single constraint
|
|
110
|
-
* based on whether a reviewer finding exists for it.
|
|
111
|
-
*/
|
|
112
|
-
export function constraintStatusMarker(
|
|
113
|
-
constraint: Constraint,
|
|
114
|
-
findings: ConstraintFinding[] | undefined,
|
|
115
|
-
): { tag: string; fg: string; dim: boolean } {
|
|
116
|
-
const finding = findings?.find(f => f.constraintId === constraint.id);
|
|
117
|
-
if (!finding) {
|
|
118
|
-
return { tag: '[UNV]', fg: C.dim, dim: true };
|
|
119
|
-
}
|
|
120
|
-
if (finding.satisfied) {
|
|
121
|
-
return { tag: '[SAT]', fg: C.good, dim: false };
|
|
122
|
-
}
|
|
123
|
-
// Unsatisfied, use severity to pick colour and tag text
|
|
124
|
-
const sev = finding.severity ?? 'major';
|
|
125
|
-
let sevTag: string;
|
|
126
|
-
let fg: string;
|
|
127
|
-
switch (sev) {
|
|
128
|
-
case 'critical': sevTag = '[UNS CRIT]'; fg = C.issueCrit; break;
|
|
129
|
-
case 'minor': sevTag = '[UNS MINOR]'; fg = C.issueMin; break;
|
|
130
|
-
default: sevTag = '[UNS MAJOR]'; fg = C.issueMaj; break;
|
|
131
|
-
}
|
|
132
|
-
return { tag: sevTag, fg, dim: false };
|
|
133
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { type Line, type Cell, createStyledCell } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
-
import { UIFactory } from './ui-factory.ts';
|
|
3
|
-
import { getDisplayWidth, padDisplayEnd } from '../utils/terminal-width.ts';
|
|
4
|
-
import { DIFF_TONES } from './ui-primitives.ts';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* renderDiffView - Render a unified diff string as styled Line[].
|
|
8
|
-
* '+' lines in green, '-' lines in red, '@@' hunks in blue (DIFF_TONES.hunk,
|
|
9
|
-
* shared with diff-panel.ts and git-panel.ts's inline diff).
|
|
10
|
-
*/
|
|
11
|
-
export function renderDiffView(diffText: string, width: number, filename?: string): Line[] {
|
|
12
|
-
const lines: Line[] = [];
|
|
13
|
-
const BG = '#0a0a0a';
|
|
14
|
-
|
|
15
|
-
// Filename header
|
|
16
|
-
if (filename) {
|
|
17
|
-
const header = ` ≡ ${filename} `;
|
|
18
|
-
lines.push(UIFactory.stringToLine(padDisplayEnd(header, width), width, { fg: '#1a1a1a', bg: '#569cd6', bold: true }));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const diffLines = diffText.split('\n');
|
|
22
|
-
let oldLineNo = 0;
|
|
23
|
-
let newLineNo = 0;
|
|
24
|
-
|
|
25
|
-
for (const raw of diffLines) {
|
|
26
|
-
if (raw === '') {
|
|
27
|
-
const emptyLine = makeFilledLine(width, BG);
|
|
28
|
-
lines.push(emptyLine);
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Hunk header: @@ -old,count +new,count @@
|
|
33
|
-
if (raw.startsWith('@@')) {
|
|
34
|
-
const hunkMatch = raw.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
35
|
-
if (hunkMatch) {
|
|
36
|
-
oldLineNo = parseInt(hunkMatch[1], 10) - 1;
|
|
37
|
-
newLineNo = parseInt(hunkMatch[2], 10) - 1;
|
|
38
|
-
}
|
|
39
|
-
lines.push(makeStyledLine(raw, width, DIFF_TONES.hunk, '#0f1f1f', false));
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// File headers: --- and +++
|
|
44
|
-
if (raw.startsWith('--- ') || raw.startsWith('+++ ')) {
|
|
45
|
-
lines.push(makeStyledLine(raw, width, '244', BG, false));
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Added line
|
|
50
|
-
if (raw.startsWith('+')) {
|
|
51
|
-
newLineNo++;
|
|
52
|
-
const lineLabel = `${String(newLineNo).padStart(4)} `;
|
|
53
|
-
const content = raw.slice(1);
|
|
54
|
-
lines.push(makeGutterLine('+', lineLabel, content, width, DIFF_TONES.add, '#0a1a0a'));
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Removed line
|
|
59
|
-
if (raw.startsWith('-')) {
|
|
60
|
-
oldLineNo++;
|
|
61
|
-
const lineLabel = `${String(oldLineNo).padStart(4)} `;
|
|
62
|
-
const content = raw.slice(1);
|
|
63
|
-
lines.push(makeGutterLine('-', lineLabel, content, width, DIFF_TONES.del, '#1a0a0a'));
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Context line
|
|
68
|
-
if (raw.startsWith(' ') || (!raw.startsWith('\\') && raw.length > 0)) {
|
|
69
|
-
oldLineNo++;
|
|
70
|
-
newLineNo++;
|
|
71
|
-
const lineLabel = `${String(oldLineNo).padStart(4)} `;
|
|
72
|
-
const content = raw.startsWith(' ') ? raw.slice(1) : raw;
|
|
73
|
-
lines.push(makeGutterLine(' ', lineLabel, content, width, '244', BG));
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return lines;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** Build a line with gutter indicator, line number, and content. */
|
|
81
|
-
function makeGutterLine(
|
|
82
|
-
gutter: string,
|
|
83
|
-
lineLabel: string,
|
|
84
|
-
content: string,
|
|
85
|
-
width: number,
|
|
86
|
-
fg: string,
|
|
87
|
-
bg: string
|
|
88
|
-
): Line {
|
|
89
|
-
const line = makeFilledLine(width, bg);
|
|
90
|
-
let cx = 0;
|
|
91
|
-
|
|
92
|
-
// Gutter char
|
|
93
|
-
line[cx++] = createStyledCell(gutter, { fg, bg, bold: gutter !== ' ' });
|
|
94
|
-
|
|
95
|
-
// Line number
|
|
96
|
-
for (const ch of lineLabel) {
|
|
97
|
-
if (cx >= width) break;
|
|
98
|
-
line[cx++] = createStyledCell(ch, { fg: '238', bg, dim: true });
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Content
|
|
102
|
-
for (const ch of content) {
|
|
103
|
-
if (cx >= width) break;
|
|
104
|
-
const cw = getDisplayWidth(ch);
|
|
105
|
-
const code = ch.charCodeAt(0);
|
|
106
|
-
if (code < 32) { cx++; continue; }
|
|
107
|
-
line[cx] = createStyledCell(ch, { fg, bg });
|
|
108
|
-
if (cw === 2 && cx + 1 < width) line[cx + 1] = { ...line[cx], char: '' };
|
|
109
|
-
cx += cw;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return line;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Build a simple styled line from text. */
|
|
116
|
-
function makeStyledLine(text: string, width: number, fg: string, bg: string, bold: boolean): Line {
|
|
117
|
-
const line = makeFilledLine(width, bg);
|
|
118
|
-
let cx = 0;
|
|
119
|
-
for (const ch of text) {
|
|
120
|
-
if (cx >= width) break;
|
|
121
|
-
const cw = getDisplayWidth(ch);
|
|
122
|
-
const code = ch.charCodeAt(0);
|
|
123
|
-
if (code < 32) { cx++; continue; }
|
|
124
|
-
line[cx] = createStyledCell(ch, { fg, bg, bold });
|
|
125
|
-
if (cw === 2 && cx + 1 < width) line[cx + 1] = { ...line[cx], char: '' };
|
|
126
|
-
cx += cw;
|
|
127
|
-
}
|
|
128
|
-
return line;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** Create a line filled with bg color. */
|
|
132
|
-
function makeFilledLine(width: number, bg: string): Cell[] {
|
|
133
|
-
return Array.from({ length: width }, () => createStyledCell(' ', { bg }));
|
|
134
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// fleet-tab-strip.ts
|
|
3
|
-
//
|
|
4
|
-
// Renders FleetPanel's session-tab strip by reusing
|
|
5
|
-
// renderTabStrip exactly as panel-workspace-bar.ts does for the workspace
|
|
6
|
-
// tab bar. Deliberately a SEPARATE, visually distinct strip from the
|
|
7
|
-
// workspace bar: workspace tabs switch PANELS, fleet session tabs switch
|
|
8
|
-
// ATTACHED PROCESSES within one panel, conflating their styling would blur
|
|
9
|
-
// that distinction for the operator.
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
import type { Line } from '@pellux/goodvibes-sdk/platform/types';
|
|
13
|
-
import type { FleetTabsState } from '../panels/fleet-tabs.ts';
|
|
14
|
-
import { renderTabStrip, type TabHitRegion } from './tab-strip.ts';
|
|
15
|
-
import { UI_TONES } from './ui-primitives.ts';
|
|
16
|
-
|
|
17
|
-
const ACTIVE_FG = UI_TONES.fg.primary;
|
|
18
|
-
const ACTIVE_BG = UI_TONES.bg.selected;
|
|
19
|
-
const INACTIVE_FG = UI_TONES.fg.muted;
|
|
20
|
-
const SEPARATOR_FG = UI_TONES.fg.dim;
|
|
21
|
-
const LABEL_FG = UI_TONES.fg.secondary;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Render the fleet session-tab strip, or `null` when there are no attached
|
|
25
|
-
* tabs, the panel omits the strip entirely in that case (root-tab-only),
|
|
26
|
-
* which is what keeps the pre-session-tab fleet-panel goldens byte-identical.
|
|
27
|
-
*/
|
|
28
|
-
export function renderFleetTabStrip(
|
|
29
|
-
state: FleetTabsState,
|
|
30
|
-
width: number,
|
|
31
|
-
onLayout?: (regions: readonly TabHitRegion[]) => void,
|
|
32
|
-
): Line | null {
|
|
33
|
-
if (state.tabs.length === 0) return null;
|
|
34
|
-
return renderTabStrip({
|
|
35
|
-
width,
|
|
36
|
-
onLayout,
|
|
37
|
-
tabs: [
|
|
38
|
-
{ label: 'Tree', active: state.activeTabIndex === 0 },
|
|
39
|
-
...state.tabs.map((tab, index) => ({
|
|
40
|
-
label: tab.label,
|
|
41
|
-
active: state.activeTabIndex === index + 1,
|
|
42
|
-
})),
|
|
43
|
-
],
|
|
44
|
-
prefixLabel: ' SESSIONS ',
|
|
45
|
-
style: {
|
|
46
|
-
activeFg: ACTIVE_FG,
|
|
47
|
-
activeBg: ACTIVE_BG,
|
|
48
|
-
activeBold: true,
|
|
49
|
-
inactiveFg: INACTIVE_FG,
|
|
50
|
-
separatorFg: SEPARATOR_FG,
|
|
51
|
-
labelFg: LABEL_FG,
|
|
52
|
-
overflowFg: SEPARATOR_FG,
|
|
53
|
-
trailingFg: INACTIVE_FG,
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* footer-tips.ts, the persistent discoverability hint shown in the shell
|
|
3
|
-
* footer's tip slot.
|
|
4
|
-
*
|
|
5
|
-
* instead of a single frozen "/help for commands" line, the footer
|
|
6
|
-
* surfaces a rotating set of the highest-value affordances (panels, process
|
|
7
|
-
* monitor, help, quit). Rotation is *contextual, not timed*: when an agent turn
|
|
8
|
-
* is actively running, the process-monitor tip is promoted to the front so the
|
|
9
|
-
* operator can jump to F2 while work is in flight. Selection is a pure function
|
|
10
|
-
* of context so the footer renders deterministically (golden frames stay
|
|
11
|
-
* stable), no wall-clock input.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export interface FooterTipContext {
|
|
15
|
-
/** True while an agent turn is actively running (streaming / tools / hooks). */
|
|
16
|
-
readonly agentActive: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Composer status labels that mean an agent turn is actively in flight. */
|
|
20
|
-
const ACTIVE_TURN_STATUSES = new Set(['preflight', 'streaming', 'tools', 'post-hooks']);
|
|
21
|
-
|
|
22
|
-
/** Derive agent-active state from the composer status label passed to the footer. */
|
|
23
|
-
export function isAgentActive(composerStatus: string | undefined): boolean {
|
|
24
|
-
return composerStatus !== undefined && ACTIVE_TURN_STATUSES.has(composerStatus);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Ctrl+P is a TOGGLE (open+focus when nothing is open or unfocused,
|
|
28
|
-
// hide when the workspace already has focus, see openPanelPicker in
|
|
29
|
-
// shell/ui-openers.ts). The bare noun 'panels' undersold that; naming the verb
|
|
30
|
-
// keeps the tip honest about what the chord actually does.
|
|
31
|
-
const TIP_PANELS = 'Ctrl+P toggle panels';
|
|
32
|
-
// F2 now opens the Fleet panel (the process modal was retired), so the
|
|
33
|
-
// tip names 'fleet', not 'processes'.
|
|
34
|
-
const TIP_PROCESSES = 'F2 fleet';
|
|
35
|
-
const TIP_HELP = '? help';
|
|
36
|
-
// f: an empty-composer Ctrl+C does NOT quit on the first press, it arms a
|
|
37
|
-
// ~1s "press again to exit" confirm, and only a SECOND Ctrl+C within that window
|
|
38
|
-
// exits (an intentional accidental-exit guard). The old 'Ctrl+C quit' tip
|
|
39
|
-
// implied a single press quits, so two presses seconds apart appeared to do
|
|
40
|
-
// nothing. 'Ctrl+C x2 quit' matches the real double-press contract (and the
|
|
41
|
-
// help overlay's "Ctrl+C x2 Exit" row).
|
|
42
|
-
const TIP_QUIT = 'Ctrl+C x2 quit';
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Build the footer discoverability tip. Segments join with the shared middle
|
|
46
|
-
* dot. Agent-active state promotes the process-monitor tip to the front.
|
|
47
|
-
*/
|
|
48
|
-
export function buildFooterTip(ctx: FooterTipContext): string {
|
|
49
|
-
const lead = ctx.agentActive
|
|
50
|
-
? [TIP_PROCESSES, TIP_PANELS, TIP_HELP]
|
|
51
|
-
: [TIP_PANELS, TIP_PROCESSES, TIP_HELP];
|
|
52
|
-
return [...lead, TIP_QUIT].join(' · ');
|
|
53
|
-
}
|