@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
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { CommandContext } from './command-registry.ts';
|
|
2
|
-
import type { Panel } from '../panels/types.ts';
|
|
3
|
-
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
4
|
-
|
|
5
|
-
// (the purge): every instanceof-routed branch this file used to carry
|
|
6
|
-
// (FileExplorerPanel/FilePreviewPanel/SymbolOutlinePanel, DELETE;
|
|
7
|
-
// ApprovalPanel/TasksPanel/OrchestrationPanel/AgentInspectorPanel,
|
|
8
|
-
// RETIRE-INTO-FLEET) targeted a panel class that no longer exists. Panels
|
|
9
|
-
// migrated onto the formal `Panel.handlePanelIntegrationAction` hook (the
|
|
10
|
-
// preferred seam, see the comment below) are unaffected; this function now
|
|
11
|
-
// only provides that passthrough. See
|
|
12
|
-
// .goodvibes/audit/2026-07-04-wave6-briefs.json for the disposition
|
|
13
|
-
// map.
|
|
14
|
-
export function handlePanelIntegrationAction(
|
|
15
|
-
panelManager: PanelManager,
|
|
16
|
-
activePanel: Panel | null,
|
|
17
|
-
key: string,
|
|
18
|
-
commandContext?: CommandContext,
|
|
19
|
-
): boolean {
|
|
20
|
-
if (!activePanel) return false;
|
|
21
|
-
|
|
22
|
-
// Prefer the panel's own integration hook when it provides one. Panels migrated
|
|
23
|
-
// onto the formal hook opt out of the instanceof routing below.
|
|
24
|
-
if (activePanel.handlePanelIntegrationAction) {
|
|
25
|
-
const consumed = activePanel.handlePanelIntegrationAction(key, {
|
|
26
|
-
panelManager,
|
|
27
|
-
executeCommand: commandContext?.executeCommand,
|
|
28
|
-
});
|
|
29
|
-
if (consumed) return true;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// panel-mouse-geometry.ts
|
|
3
|
-
//
|
|
4
|
-
// Pure mouse-geometry helpers for the panel workspace, extracted from
|
|
5
|
-
// handler-feed-routes.ts so that file stays under the 800-line architecture
|
|
6
|
-
// cap once the focus verbs and the paste-flood guard both live in
|
|
7
|
-
// it. These map a terminal (row, col) onto the panel/pane/workspace-tab under
|
|
8
|
-
// the cursor. No dependency on the feed-route state types, so no import cycle.
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
12
|
-
import { renderPanelWorkspaceBar } from '../renderer/panel-workspace-bar.ts';
|
|
13
|
-
import type { TabHitRegion } from '../renderer/tab-strip.ts';
|
|
14
|
-
|
|
15
|
-
/** Screen rectangle the panel workspace occupies, plus its vertical split. */
|
|
16
|
-
export type PanelMouseLayout = {
|
|
17
|
-
x: number;
|
|
18
|
-
y: number;
|
|
19
|
-
width: number;
|
|
20
|
-
height: number;
|
|
21
|
-
hasBottomPane: boolean;
|
|
22
|
-
verticalSplitRatio: number;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function clampRatio(value: number): number {
|
|
26
|
-
return Math.max(0.2, Math.min(0.8, value));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function getActivePanelInPane(panelManager: PanelManager, pane: 'top' | 'bottom') {
|
|
30
|
-
const target = pane === 'top' ? panelManager.getTopPane() : panelManager.getBottomPane();
|
|
31
|
-
return target.panels[target.activeIndex] ?? null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function getPanelUnderMouse(
|
|
35
|
-
panelManager: PanelManager,
|
|
36
|
-
layout: PanelMouseLayout | null,
|
|
37
|
-
row: number,
|
|
38
|
-
col: number,
|
|
39
|
-
) {
|
|
40
|
-
if (
|
|
41
|
-
layout === null
|
|
42
|
-
|| !panelManager.isVisible()
|
|
43
|
-
|| panelManager.getAllOpen().length === 0
|
|
44
|
-
|| col < layout.x
|
|
45
|
-
|| col >= layout.x + layout.width
|
|
46
|
-
|| row < layout.y
|
|
47
|
-
|| row >= layout.y + layout.height
|
|
48
|
-
) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const panelRow = row - layout.y;
|
|
53
|
-
if (!layout.hasBottomPane) {
|
|
54
|
-
return getActivePanelInPane(panelManager, 'top');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Single consolidated workspace bar (row 0) + h-separator; the rest splits
|
|
58
|
-
// between the two panes' content.
|
|
59
|
-
const panelAreaRows = Math.max(0, layout.height - 1);
|
|
60
|
-
const contentRows = Math.max(0, panelAreaRows - 1);
|
|
61
|
-
const topContentRows = contentRows <= 1
|
|
62
|
-
? contentRows
|
|
63
|
-
: Math.max(1, Math.floor(contentRows * clampRatio(layout.verticalSplitRatio)));
|
|
64
|
-
// panelRow 0 = workspace bar; rows 1..topContentRows = top pane; rest = bottom.
|
|
65
|
-
return panelRow <= topContentRows
|
|
66
|
-
? getActivePanelInPane(panelManager, 'top')
|
|
67
|
-
: getActivePanelInPane(panelManager, 'bottom');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* If the mouse is over the consolidated workspace tab bar (the first panel
|
|
72
|
-
* row), return the index of the tab under the cursor, else null. Recomputes the
|
|
73
|
-
* tab hit regions by rendering the bar with a layout callback, cheap and keeps
|
|
74
|
-
* the click geometry in lockstep with what was drawn.
|
|
75
|
-
*/
|
|
76
|
-
export function workspaceTabAtMouse(
|
|
77
|
-
panelManager: PanelManager,
|
|
78
|
-
layout: PanelMouseLayout | null,
|
|
79
|
-
row: number,
|
|
80
|
-
col: number,
|
|
81
|
-
): number | null {
|
|
82
|
-
if (
|
|
83
|
-
layout === null
|
|
84
|
-
|| !panelManager.isVisible()
|
|
85
|
-
|| panelManager.getAllOpen().length === 0
|
|
86
|
-
|| row !== layout.y // workspace bar is the first panel row
|
|
87
|
-
|| col < layout.x
|
|
88
|
-
|| col >= layout.x + layout.width
|
|
89
|
-
) {
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
let regions: readonly TabHitRegion[] = [];
|
|
93
|
-
renderPanelWorkspaceBar(panelManager.getWorkspaceTabs(), layout.width, true, (r) => { regions = r; });
|
|
94
|
-
const relCol = col - layout.x;
|
|
95
|
-
const hit = regions.find((rg) => relCol >= rg.startCol && relCol < rg.endCol);
|
|
96
|
-
return hit ? hit.index : null;
|
|
97
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// panel-paste-flood-guard.ts, item 5.
|
|
3
|
-
//
|
|
4
|
-
// A terminal WITHOUT bracketed paste delivers a pasted block as a burst of
|
|
5
|
-
// discrete 1-char 'text' tokens (isPasteToken stays false for every one of
|
|
6
|
-
// them, since that flag only fires for a single token whose value.length > 1
|
|
7
|
-
//, see handler-feed-routes.ts's own Invariant B doc). Before this guard,
|
|
8
|
-
// each such character became a real panel hotkey on a focused non-capturing
|
|
9
|
-
// panel (K arms kill, etc.) once it reached handlePanelFocusToken's per-char
|
|
10
|
-
// dispatch loop.
|
|
11
|
-
//
|
|
12
|
-
// This is a RATE guard: more than PANEL_PASTE_FLOOD_THRESHOLD qualifying
|
|
13
|
-
// tokens within the trailing PANEL_PASTE_FLOOD_WINDOW_MS, evaluated with a
|
|
14
|
-
// real sliding window (old timestamps age out of `timestamps` every call).
|
|
15
|
-
// It is deliberately NOT the retired per-feed char-SUM burst heuristic this
|
|
16
|
-
// same input layer already tore out once (see panel-focus-burst.test.ts's
|
|
17
|
-
// header doc): that old guard summed one feed()'s character count with no
|
|
18
|
-
// timing signal at all, so two ordinary nav keystrokes landing in a single
|
|
19
|
-
// feed(), a real, common case, not an edge case, were misread as a burst
|
|
20
|
-
// and focus was silently flipped to the composer. This guard:
|
|
21
|
-
// - never touches focus (panelFocused is untouched by trackPanelPasteFloodGuard
|
|
22
|
-
// and by its caller);
|
|
23
|
-
// - is keyed on WALL-CLOCK TIMING, not a per-feed token count, so it
|
|
24
|
-
// doesn't care how many tokens land in one feed() call, only how fast
|
|
25
|
-
// they arrive relative to each other;
|
|
26
|
-
// - is sticky once tripped (only a quiet gap, no qualifying token for a
|
|
27
|
-
// full window, clears it) so it doesn't flap dispatch on/off as the
|
|
28
|
-
// count oscillates near the threshold mid-flood.
|
|
29
|
-
//
|
|
30
|
-
// ~8 keys/120ms is far beyond sustained human typing (a fast typist peaks
|
|
31
|
-
// well under that inter-key rate over any real span) but is exactly the
|
|
32
|
-
// shape an unbracketed paste replay takes. It also keeps the pre-existing
|
|
33
|
-
// Invariant B regression tests (2 keys in one feed(), no timing control at
|
|
34
|
-
// all) far under threshold while catching a real flood within its first ~9
|
|
35
|
-
// characters.
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
|
|
38
|
-
export const PANEL_PASTE_FLOOD_WINDOW_MS = 120;
|
|
39
|
-
export const PANEL_PASTE_FLOOD_THRESHOLD = 8;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Guard state, a single persistent instance lives on the caller's
|
|
43
|
-
* long-lived context (handler-feed.ts's InputFeedContext, mirroring how that
|
|
44
|
-
* object already owns `nextPasteId`/`mouseDownRow`/etc.) and is MUTATED IN
|
|
45
|
-
* PLACE by trackPanelPasteFloodGuard below, never replaced, so callers never
|
|
46
|
-
* need to thread a return value back into their own state (unlike
|
|
47
|
-
* `panelFocused`, which handlePanelFocusToken returns because it is NOT a
|
|
48
|
-
* mutable outparam).
|
|
49
|
-
*/
|
|
50
|
-
export interface PanelBurstGuardState {
|
|
51
|
-
timestamps: readonly number[];
|
|
52
|
-
suspended: boolean;
|
|
53
|
-
hintShown: boolean;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface PanelBurstGuardResult {
|
|
57
|
-
/** False while suspended, the caller must drop this token, not dispatch it. */
|
|
58
|
-
readonly dispatch: boolean;
|
|
59
|
-
/** True exactly once per burst: the call that just tripped suspension. */
|
|
60
|
-
readonly showHintNow: boolean;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Advance `guard` (mutated in place) by one qualifying token at time `now` (ms). */
|
|
64
|
-
export function trackPanelPasteFloodGuard(guard: PanelBurstGuardState, now: number): PanelBurstGuardResult {
|
|
65
|
-
const lastAt = guard.timestamps.length > 0 ? guard.timestamps[guard.timestamps.length - 1]! : -Infinity;
|
|
66
|
-
const isQuietGap = now - lastAt > PANEL_PASTE_FLOOD_WINDOW_MS;
|
|
67
|
-
if (isQuietGap && guard.suspended) {
|
|
68
|
-
// A silence at least as long as the window means whatever burst was
|
|
69
|
-
// happening has ended, un-suspend so a LATER burst gets its own fresh
|
|
70
|
-
// count and its own one-shot hint.
|
|
71
|
-
guard.suspended = false;
|
|
72
|
-
guard.hintShown = false;
|
|
73
|
-
}
|
|
74
|
-
guard.timestamps = isQuietGap
|
|
75
|
-
? [now]
|
|
76
|
-
: [...guard.timestamps.filter((t) => t > now - PANEL_PASTE_FLOOD_WINDOW_MS), now];
|
|
77
|
-
if (guard.timestamps.length > PANEL_PASTE_FLOOD_THRESHOLD) {
|
|
78
|
-
guard.suspended = true;
|
|
79
|
-
}
|
|
80
|
-
let showHintNow = false;
|
|
81
|
-
if (guard.suspended && !guard.hintShown) {
|
|
82
|
-
guard.hintShown = true;
|
|
83
|
-
showHintNow = true;
|
|
84
|
-
}
|
|
85
|
-
return { dispatch: !guard.suspended, showHintNow };
|
|
86
|
-
}
|
package/src/panels/base-panel.ts
DELETED
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
import type { Line } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
-
import type { Panel, PanelCategory } from './types.ts';
|
|
3
|
-
import type { ComponentResourceContract, ComponentHealthState } from '../runtime/perf/panel-contracts.ts';
|
|
4
|
-
import type { ComponentHealthMonitor } from '@pellux/goodvibes-sdk/platform/runtime/observability';
|
|
5
|
-
import { UIFactory } from '../renderer/ui-factory.ts';
|
|
6
|
-
import { SPINNER_FRAMES } from '../renderer/ui-primitives.ts';
|
|
7
|
-
import { fitDisplay } from '../utils/terminal-width.ts';
|
|
8
|
-
|
|
9
|
-
/** Canonical error-surface foreground (bad/red), kept out of the render body. */
|
|
10
|
-
const ERROR_FG = '#ef4444';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Frame requester wired by main.ts to the render scheduler. Without it,
|
|
14
|
-
* markDirty() only sets a flag the compositor reads when a frame is ALREADY
|
|
15
|
-
* being composed for another reason (input, streaming), so a live panel
|
|
16
|
-
* (fleet ticks, registry subscriptions) sat visibly stale while the app was
|
|
17
|
-
* idle until the next keypress (a replay finding). The scheduler
|
|
18
|
-
* coalesces same-tick requests, so this stays cheap.
|
|
19
|
-
*/
|
|
20
|
-
let panelFrameRequester: (() => void) | null = null;
|
|
21
|
-
|
|
22
|
-
export function setPanelFrameRequester(requester: (() => void) | null): void {
|
|
23
|
-
panelFrameRequester = requester;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export abstract class BasePanel implements Panel {
|
|
27
|
-
public needsRender = true;
|
|
28
|
-
public isTransient = false;
|
|
29
|
-
public isPinned = false;
|
|
30
|
-
protected readonly componentHealthMonitor?: ComponentHealthMonitor;
|
|
31
|
-
|
|
32
|
-
// -------------------------------------------------------------------------
|
|
33
|
-
// Timer registry
|
|
34
|
-
// -------------------------------------------------------------------------
|
|
35
|
-
|
|
36
|
-
/** All timers registered via registerTimer(). Cleared automatically on onDestroy(). */
|
|
37
|
-
private readonly _timers: Set<ReturnType<typeof setTimeout> | ReturnType<typeof setInterval>> = new Set();
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Register a timer id (from setInterval or setTimeout) so it is
|
|
41
|
-
* automatically cleared when the panel is destroyed. Returns the id
|
|
42
|
-
* unchanged so the call can be chained inline:
|
|
43
|
-
*
|
|
44
|
-
* ```ts
|
|
45
|
-
* this.registerTimer(setInterval(() => this.refresh(), 5_000));
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
protected registerTimer<T extends ReturnType<typeof setTimeout> | ReturnType<typeof setInterval>>(id: T): T {
|
|
49
|
-
this._timers.add(id);
|
|
50
|
-
return id;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Clear a specific timer and remove it from the registry.
|
|
55
|
-
* Safe to call with an id that was never registered or already cleared.
|
|
56
|
-
*/
|
|
57
|
-
protected clearTimer(id: ReturnType<typeof setTimeout> | ReturnType<typeof setInterval>): void {
|
|
58
|
-
clearInterval(id as ReturnType<typeof setInterval>);
|
|
59
|
-
this._timers.delete(id);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// -------------------------------------------------------------------------
|
|
63
|
-
// I2: Error surface slot
|
|
64
|
-
// -------------------------------------------------------------------------
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Last error message to surface in the panel footer.
|
|
68
|
-
* Auto-cleared on the next keystroke by `ScrollableListPanel.handleInput()` (and any
|
|
69
|
-
* subclass that calls `super.handleInput()` or manually calls `this.clearError()` at
|
|
70
|
-
* the start of its handler). BasePanel itself does NOT auto-clear, only subclasses
|
|
71
|
-
* that opt into the contract do.
|
|
72
|
-
*/
|
|
73
|
-
protected lastError: string | null = null;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Set a transient error message. Triggers a re-render.
|
|
77
|
-
* The error will be auto-cleared on the next keystroke if the panel extends
|
|
78
|
-
* `ScrollableListPanel` (which calls `clearError()` at the top of `handleInput()`).
|
|
79
|
-
*/
|
|
80
|
-
protected setError(msg: string): void {
|
|
81
|
-
this.lastError = msg;
|
|
82
|
-
this.needsRender = true;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** Clear the current error. */
|
|
86
|
-
protected clearError(): void {
|
|
87
|
-
this.lastError = null;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Build a single error Line for display above the hints footer.
|
|
92
|
-
* Returns null when there is no active error.
|
|
93
|
-
*
|
|
94
|
-
* Color: bold red foreground (palette-consistent: #ef4444).
|
|
95
|
-
*/
|
|
96
|
-
protected renderErrorLine(width: number): Line | null {
|
|
97
|
-
if (!this.lastError) return null;
|
|
98
|
-
return UIFactory.stringToLine(
|
|
99
|
-
fitDisplay(` ✕ ${this.lastError}`, width),
|
|
100
|
-
width,
|
|
101
|
-
{ fg: ERROR_FG, bold: true },
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// -------------------------------------------------------------------------
|
|
106
|
-
// I3: Loading spinner slot
|
|
107
|
-
// -------------------------------------------------------------------------
|
|
108
|
-
|
|
109
|
-
/** Tracks the loading label for the spinner (undefined = no spinner active). */
|
|
110
|
-
protected loadingState: 'idle' | 'loading' | 'error' = 'idle';
|
|
111
|
-
private _loadingLabel = '';
|
|
112
|
-
|
|
113
|
-
/** Begin loading. Triggers a re-render. */
|
|
114
|
-
protected startLoading(label = 'Loading...'): void {
|
|
115
|
-
this.loadingState = 'loading';
|
|
116
|
-
this._loadingLabel = label;
|
|
117
|
-
this.needsRender = true;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** End loading (returns to idle). Triggers a re-render. */
|
|
121
|
-
protected stopLoading(): void {
|
|
122
|
-
this.loadingState = 'idle';
|
|
123
|
-
this._loadingLabel = '';
|
|
124
|
-
this.needsRender = true;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Run an async operation with the panel's loading spinner visible.
|
|
129
|
-
* The spinner is always cleared on completion, whether the operation succeeds or throws
|
|
130
|
-
* (uses try/finally). Rethrows any error so callers can handle it or forward to setError.
|
|
131
|
-
*
|
|
132
|
-
* @param label Optional label shown next to the spinner.
|
|
133
|
-
* @param fn The async work to run.
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* ```ts
|
|
137
|
-
* try {
|
|
138
|
-
* await this.withLoading('Loading diff…', () => this.fetchDiff());
|
|
139
|
-
* } catch (err) {
|
|
140
|
-
* this.setError(summarizeError(err));
|
|
141
|
-
* }
|
|
142
|
-
* ```
|
|
143
|
-
*/
|
|
144
|
-
protected async withLoading<T>(label: string | undefined, fn: () => Promise<T>): Promise<T> {
|
|
145
|
-
this.startLoading(label);
|
|
146
|
-
try {
|
|
147
|
-
return await fn();
|
|
148
|
-
} finally {
|
|
149
|
-
this.stopLoading();
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Build a spinner Line for the loading state.
|
|
155
|
-
* Returns null when loadingState is not 'loading'.
|
|
156
|
-
*
|
|
157
|
-
* @param width Panel width in columns.
|
|
158
|
-
* @param frame Current animation frame index (caller increments each render).
|
|
159
|
-
*/
|
|
160
|
-
protected renderLoadingLine(width: number, frame = 0): Line | null {
|
|
161
|
-
if (this.loadingState !== 'loading') return null;
|
|
162
|
-
const idx = (frame || Math.floor(Date.now() / 100)) % SPINNER_FRAMES.length;
|
|
163
|
-
const spinner = SPINNER_FRAMES[idx] ?? SPINNER_FRAMES[0]!;
|
|
164
|
-
const text = ` ${spinner} ${this._loadingLabel}`;
|
|
165
|
-
return UIFactory.stringToLine(fitDisplay(text, width), width, { fg: '135', bold: true });
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Optional resource contract for this panel.
|
|
170
|
-
* Override in subclasses to declare a custom contract; leave undefined
|
|
171
|
-
* to use the category default enforced by ComponentHealthMonitor.
|
|
172
|
-
*/
|
|
173
|
-
public resourceContract: Readonly<ComponentResourceContract> | undefined = undefined;
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Live health state populated by ComponentHealthMonitor.
|
|
177
|
-
* Read-only from outside the monitor.
|
|
178
|
-
*/
|
|
179
|
-
public get healthState(): Readonly<ComponentHealthState> | undefined {
|
|
180
|
-
return this.componentHealthMonitor?.getHealth(this.id);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
constructor(
|
|
184
|
-
public readonly id: string,
|
|
185
|
-
public readonly name: string,
|
|
186
|
-
public readonly icon: string,
|
|
187
|
-
public readonly category: PanelCategory,
|
|
188
|
-
componentHealthMonitor?: ComponentHealthMonitor,
|
|
189
|
-
) {
|
|
190
|
-
this.componentHealthMonitor = componentHealthMonitor;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
onActivate(): void { this.needsRender = true; }
|
|
194
|
-
onDeactivate(): void {}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Called when the panel is permanently removed. Subclasses should call
|
|
198
|
-
* `super.onDestroy()` to ensure all registered timers are cleared.
|
|
199
|
-
*/
|
|
200
|
-
onDestroy(): void {
|
|
201
|
-
for (const id of this._timers) {
|
|
202
|
-
clearInterval(id as ReturnType<typeof setInterval>);
|
|
203
|
-
}
|
|
204
|
-
this._timers.clear();
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
abstract render(width: number, height: number): Line[];
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Default mouse-wheel handling: translate a wheel delta into the panel's
|
|
211
|
-
* existing up/down keyboard navigation, so every panel scrolls with the wheel
|
|
212
|
-
* without bespoke code. Panels with richer scroll state (e.g.
|
|
213
|
-
* `ScrollableListPanel`) override this. No-op for panels that don't implement
|
|
214
|
-
* `handleInput`. Returns true if any step was consumed.
|
|
215
|
-
*/
|
|
216
|
-
public handleScroll(deltaRows: number): boolean {
|
|
217
|
-
const self = this as unknown as { handleInput?: (key: string) => boolean };
|
|
218
|
-
if (typeof self.handleInput !== 'function') return false;
|
|
219
|
-
const rows = Math.trunc(deltaRows);
|
|
220
|
-
if (rows === 0) return false;
|
|
221
|
-
const key = rows > 0 ? 'down' : 'up';
|
|
222
|
-
const steps = Math.min(Math.abs(rows), 10); // clamp runaway wheel deltas
|
|
223
|
-
let consumed = false;
|
|
224
|
-
for (let i = 0; i < steps; i++) {
|
|
225
|
-
if (self.handleInput(key)) consumed = true;
|
|
226
|
-
}
|
|
227
|
-
return consumed;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/** Mark this panel dirty, it will be re-rendered on the next compositor frame. */
|
|
231
|
-
public invalidate(): void { this.needsRender = true; }
|
|
232
|
-
|
|
233
|
-
/** Called by the compositor after a successful render to clear the dirty flag. */
|
|
234
|
-
public markRendered(): void { this.needsRender = false; }
|
|
235
|
-
|
|
236
|
-
protected markDirty(): void {
|
|
237
|
-
// Request only on the false→true transition: a pending frame already
|
|
238
|
-
// covers repeat marks, and a panel that dirties itself mid-render must
|
|
239
|
-
// not schedule frames forever.
|
|
240
|
-
const wasDirty = this.needsRender;
|
|
241
|
-
this.needsRender = true;
|
|
242
|
-
if (!wasDirty) panelFrameRequester?.();
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Check whether the panel is currently permitted to render.
|
|
247
|
-
*
|
|
248
|
-
* Consults the shared ComponentHealthMonitor. Returns true if not registered
|
|
249
|
-
* (unthrottled) or if the monitor permits a render at this moment.
|
|
250
|
-
*
|
|
251
|
-
* Call this inside render() or before invoking render() to skip
|
|
252
|
-
* expensive work when throttled:
|
|
253
|
-
*
|
|
254
|
-
* ```ts
|
|
255
|
-
* render(width, height): Line[] {
|
|
256
|
-
* if (!this.canRenderNow()) return this._lastLines ?? [];
|
|
257
|
-
* // ... expensive render ...
|
|
258
|
-
* }
|
|
259
|
-
* ```
|
|
260
|
-
*/
|
|
261
|
-
protected canRenderNow(now: number = Date.now()): boolean {
|
|
262
|
-
return this.componentHealthMonitor?.canRender(this.id, now) ?? true;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Report the duration of a completed render to the health monitor.
|
|
267
|
-
* Call this at the end of render() after measuring wall-clock cost.
|
|
268
|
-
*/
|
|
269
|
-
protected reportRenderDuration(durationMs: number, now: number = Date.now()): void {
|
|
270
|
-
this.componentHealthMonitor?.recordRender(this.id, durationMs, now);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/** Cache of the most recent lines produced by trackedRender. */
|
|
274
|
-
private _lastTrackedLines: Line[] = [];
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Wrap a render body with canRenderNow throttle check, wall-clock timing,
|
|
278
|
-
* and automatic reportRenderDuration.
|
|
279
|
-
*
|
|
280
|
-
* When throttled, returns the previously cached lines (stale but correctly
|
|
281
|
-
* sized) rather than empty lines, avoiding a flicker on every skipped frame.
|
|
282
|
-
*
|
|
283
|
-
* Usage:
|
|
284
|
-
* ```ts
|
|
285
|
-
* render(width: number, height: number): Line[] {
|
|
286
|
-
* return this.trackedRender(() => {
|
|
287
|
-
* // expensive render logic
|
|
288
|
-
* return lines;
|
|
289
|
-
* });
|
|
290
|
-
* }
|
|
291
|
-
* ```
|
|
292
|
-
*/
|
|
293
|
-
protected trackedRender(fn: () => Line[]): Line[] {
|
|
294
|
-
if (!this.canRenderNow()) return this._lastTrackedLines;
|
|
295
|
-
const start = Date.now();
|
|
296
|
-
const lines = fn();
|
|
297
|
-
this.reportRenderDuration(Date.now() - start);
|
|
298
|
-
this._lastTrackedLines = lines;
|
|
299
|
-
return lines;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { PanelManager } from '../panel-manager.ts';
|
|
2
|
-
import type { ResolvedBuiltinPanelDeps } from './shared.ts';
|
|
3
|
-
|
|
4
|
-
// (the purge): thinking, tools, inspector, and wrfc were registered here
|
|
5
|
-
// before the purge. thinking/tools were DELETE-disposition (no surviving
|
|
6
|
-
// human surface, thinking already renders inline in the transcript, tool
|
|
7
|
-
// results render inline plus per-node in Fleet); inspector/wrfc were
|
|
8
|
-
// RETIRE-INTO-FLEET (their live console is subsumed by the Fleet panel,
|
|
9
|
-
// operations.ts:84). See registerOperationsPanels for the fleet
|
|
10
|
-
// registration and .goodvibes/audit/2026-07-04-wave6-briefs.json for
|
|
11
|
-
// the full disposition map.
|
|
12
|
-
export function registerAgentPanels(manager: PanelManager, deps: ResolvedBuiltinPanelDeps): void {
|
|
13
|
-
// Compat: '/panel open agent-logs' and 'inspector' (and any saved
|
|
14
|
-
// layout/muscle memory) still resolve, redirected straight to fleet.
|
|
15
|
-
// Repointed from agent-logs->inspector now that inspector itself
|
|
16
|
-
// is retired; alias resolution is a single hop (PanelManager._resolveId),
|
|
17
|
-
// so this must point at the real surviving id, not at another alias.
|
|
18
|
-
manager.registerAlias('agent-logs', 'fleet');
|
|
19
|
-
manager.registerAlias('inspector', 'fleet');
|
|
20
|
-
manager.registerAlias('wrfc', 'fleet');
|
|
21
|
-
|
|
22
|
-
// (the purge), group B: 'work-plan' and 'project-planning'
|
|
23
|
-
// migrated to the 'work-plan-modal' / 'planning-modal' config-modal surfaces.
|
|
24
|
-
// Their surfaces AND panel→modal redirects are registered centrally in
|
|
25
|
-
// registerBuiltinModals (builtin-modals.ts). Panel registrations retired here.
|
|
26
|
-
void deps;
|
|
27
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import type { PanelManager } from '../panel-manager.ts';
|
|
2
|
-
import { GitPanel } from '../git-panel.ts';
|
|
3
|
-
import { DiffPanel } from '../diff-panel.ts';
|
|
4
|
-
import { DiffReviewPanel } from '../diff-review-panel.ts';
|
|
5
|
-
import { CostTrackerPanel } from '../cost-tracker-panel.ts';
|
|
6
|
-
import type { ResolvedBuiltinPanelDeps } from './shared.ts';
|
|
7
|
-
import { requireUiServices, withUnconfiguredFallback } from './shared.ts';
|
|
8
|
-
|
|
9
|
-
// (the purge): plan, intelligence, explorer, preview, and symbols were
|
|
10
|
-
// registered here before the purge. plan was RETIRE-INTO-FLEET (its
|
|
11
|
-
// execution-plan view is subsumed by Fleet, operations.ts:84); the other
|
|
12
|
-
// four were DELETE-disposition (no surviving human surface, intelligence's
|
|
13
|
-
// read-model still backs the surviving `/intelligence` CLI subcommands, see
|
|
14
|
-
// intelligence-runtime.ts; explorer/preview/symbols had no dedicated
|
|
15
|
-
// read-model to preserve). See .goodvibes/audit/2026-07-04-wave6-briefs.json
|
|
16
|
-
// for the full disposition map.
|
|
17
|
-
export function registerDevelopmentPanels(manager: PanelManager, deps: ResolvedBuiltinPanelDeps): void {
|
|
18
|
-
manager.registerType({
|
|
19
|
-
id: 'git',
|
|
20
|
-
name: 'Git',
|
|
21
|
-
icon: 'G',
|
|
22
|
-
category: 'development',
|
|
23
|
-
description: 'Git status, staged/unstaged changes, and recent commits',
|
|
24
|
-
// sessionChangeTracker is optional: when a caller wires it into
|
|
25
|
-
// BuiltinPanelDeps, the Git panel highlights files touched this session.
|
|
26
|
-
factory: () => new GitPanel(
|
|
27
|
-
requireUiServices(deps).environment.workingDirectory,
|
|
28
|
-
deps.requestRender,
|
|
29
|
-
deps.sessionChangeTracker ? () => deps.sessionChangeTracker!.getChangedFiles() : undefined,
|
|
30
|
-
),
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Compat: '/panel open plan' (and any saved layout/muscle memory) still
|
|
34
|
-
// resolves, redirected to fleet, which absorbs the execution-plan view.
|
|
35
|
-
manager.registerAlias('plan', 'fleet');
|
|
36
|
-
|
|
37
|
-
manager.registerType({
|
|
38
|
-
id: 'diff',
|
|
39
|
-
name: 'Diff',
|
|
40
|
-
icon: 'D',
|
|
41
|
-
category: 'development',
|
|
42
|
-
description: 'Unified diff view of agent file changes',
|
|
43
|
-
factory: () => new DiffPanel(requireUiServices(deps).environment.workingDirectory, deps.requestRender),
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
manager.registerType({
|
|
47
|
-
id: 'review',
|
|
48
|
-
name: 'Review',
|
|
49
|
-
icon: 'R',
|
|
50
|
-
category: 'development',
|
|
51
|
-
description: 'Comment on session diff hunks and steer the comments to the model',
|
|
52
|
-
factory: () => new DiffReviewPanel(
|
|
53
|
-
requireUiServices(deps).environment.workingDirectory,
|
|
54
|
-
deps.requestRender,
|
|
55
|
-
deps.sessionChangeTracker ? () => deps.sessionChangeTracker!.getChangedFiles() : undefined,
|
|
56
|
-
),
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// 'inspector' registration moved to builtin/agent.ts (category
|
|
60
|
-
// 'agent'), it now absorbs the merged agent-logs capabilities.
|
|
61
|
-
|
|
62
|
-
// always registered (was gated behind `if (deps.getOrchestratorUsage)`,
|
|
63
|
-
// so `/panel open cost` reported "Unknown panel" on builds without usage
|
|
64
|
-
// tracking wired). Falls back to a "dependency not configured" empty state.
|
|
65
|
-
{
|
|
66
|
-
const { getOrchestratorUsage, budgetThreshold } = deps;
|
|
67
|
-
manager.registerType({
|
|
68
|
-
id: 'cost',
|
|
69
|
-
name: 'Cost',
|
|
70
|
-
icon: '$',
|
|
71
|
-
category: 'providers',
|
|
72
|
-
description: 'Estimated costs per session, agent, and plan with budget alerts',
|
|
73
|
-
factory: withUnconfiguredFallback(
|
|
74
|
-
getOrchestratorUsage !== undefined,
|
|
75
|
-
'cost', 'Cost', '$', 'providers',
|
|
76
|
-
' Cost tracking not configured for this session.',
|
|
77
|
-
'This runtime was not wired with orchestrator usage tracking at bootstrap, so no cost data is available.',
|
|
78
|
-
() => {
|
|
79
|
-
const ui = requireUiServices(deps);
|
|
80
|
-
return new CostTrackerPanel(ui.events.turns, ui.events.agents, getOrchestratorUsage!, {
|
|
81
|
-
budgetThreshold,
|
|
82
|
-
getAgentStatus: (id) => ui.agents.agentManager.getStatus(id),
|
|
83
|
-
configAccess: {
|
|
84
|
-
get: (key) => deps.configManager.get(key as Parameters<typeof deps.configManager.get>[0]),
|
|
85
|
-
set: (key, value) => deps.configManager.set(key as Parameters<typeof deps.configManager.set>[0], value as never),
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
},
|
|
89
|
-
),
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { PanelManager } from '../panel-manager.ts';
|
|
2
|
-
import type { ResolvedBuiltinPanelDeps } from './shared.ts';
|
|
3
|
-
|
|
4
|
-
// (the purge), group B: 'knowledge' and 'memory' migrated to the
|
|
5
|
-
// 'knowledge-modal' / 'memory-modal' config-modal surfaces. Both surfaces and
|
|
6
|
-
// their panel→modal redirects are registered centrally in registerBuiltinModals
|
|
7
|
-
// (src/panels/builtin-modals.ts). This registrar is intentionally empty
|
|
8
|
-
// post-migration, kept as a stable call site invoked from registerBuiltinPanels.
|
|
9
|
-
export function registerKnowledgePanels(manager: PanelManager, deps: ResolvedBuiltinPanelDeps): void {
|
|
10
|
-
void manager;
|
|
11
|
-
void deps;
|
|
12
|
-
}
|