@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,371 +0,0 @@
|
|
|
1
|
-
import type { Line } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
-
import { createEmptyLine } from '@pellux/goodvibes-sdk/platform/types';
|
|
3
|
-
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
4
|
-
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
5
|
-
import type { PanelIntegrationContext } from './types.ts';
|
|
6
|
-
import type { PluginManager, PluginManagerObserver, PluginStatus } from '@pellux/goodvibes-sdk/platform/plugins';
|
|
7
|
-
import {
|
|
8
|
-
type ConfirmState,
|
|
9
|
-
handleConfirmInput,
|
|
10
|
-
renderConfirmLines,
|
|
11
|
-
} from './confirm-state.ts';
|
|
12
|
-
import {
|
|
13
|
-
buildDetailBlock,
|
|
14
|
-
buildEmptyState,
|
|
15
|
-
buildKeyValueLine,
|
|
16
|
-
buildKeyboardHints,
|
|
17
|
-
buildPanelLine,
|
|
18
|
-
buildPanelWorkspace,
|
|
19
|
-
DEFAULT_PANEL_PALETTE,
|
|
20
|
-
type PanelPalette,
|
|
21
|
-
} from './polish.ts';
|
|
22
|
-
|
|
23
|
-
// Base chrome only, title band, state colors, and text tokens all come
|
|
24
|
-
// straight from DEFAULT_PANEL_PALETTE.
|
|
25
|
-
const C = DEFAULT_PANEL_PALETTE;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* PluginsPanel drives real plugin-manager mutations (enable/disable/
|
|
29
|
-
* verify/lift-quarantine) from the keyboard, not just read-only inspection.
|
|
30
|
-
* `PluginManagerObserver` alone (the read-only surface most panels need) has
|
|
31
|
-
* no mutation methods, so the constructor param is widened to also require
|
|
32
|
-
* the handful of `PluginManager` methods this panel actually calls. The real
|
|
33
|
-
* runtime object passed at bootstrap (`services.pluginManager`, a full
|
|
34
|
-
* `PluginManager` instance, see src/runtime/services.ts) already satisfies
|
|
35
|
-
* this widened shape.
|
|
36
|
-
*/
|
|
37
|
-
export type PluginManagerControls = PluginManagerObserver
|
|
38
|
-
& Pick<PluginManager, 'enable' | 'disable' | 'verify' | 'liftQuarantine'>;
|
|
39
|
-
|
|
40
|
-
type PluginConfirmSubject = { readonly kind: 'disable' | 'lift-quarantine'; readonly name: string };
|
|
41
|
-
|
|
42
|
-
function trustColor(tier: PluginStatus['trustTier']): string {
|
|
43
|
-
switch (tier) {
|
|
44
|
-
case 'trusted':
|
|
45
|
-
return C.good;
|
|
46
|
-
case 'limited':
|
|
47
|
-
return C.warn;
|
|
48
|
-
case 'untrusted':
|
|
49
|
-
return C.bad;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function statusColor(status: PluginStatus): string {
|
|
54
|
-
if (status.quarantined) return C.bad;
|
|
55
|
-
if (status.active) return C.good;
|
|
56
|
-
if (status.enabled) return C.warn;
|
|
57
|
-
return C.dim;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function statusLabel(status: PluginStatus): string {
|
|
61
|
-
if (status.quarantined) return 'QUARANTINED';
|
|
62
|
-
if (status.active) return 'ACTIVE';
|
|
63
|
-
if (status.enabled) return 'ENABLED';
|
|
64
|
-
return 'DISABLED';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export class PluginsPanel extends ScrollableListPanel<PluginStatus> {
|
|
68
|
-
private readonly manager: PluginManagerControls;
|
|
69
|
-
private readonly unsub: (() => void) | null;
|
|
70
|
-
/** Pending destructive/state-changing confirm for 'd' disable and 'q' lift-quarantine. */
|
|
71
|
-
private confirmAction: ConfirmState<PluginConfirmSubject> | null = null;
|
|
72
|
-
/** Result of the last 'v' verify press, rendered in the detail block until the selection or a new verify changes it. */
|
|
73
|
-
private _verifyResult: { name: string; valid: boolean; fingerprint?: string | undefined; reason?: string | undefined } | null = null;
|
|
74
|
-
|
|
75
|
-
public constructor(manager: PluginManagerControls) {
|
|
76
|
-
super('plugins', 'Plugins', '◐', 'automation-control');
|
|
77
|
-
this.showSelectionGutter = true; // I5: non-color selection affordance
|
|
78
|
-
this.filterEnabled = true;
|
|
79
|
-
this.filterLabel = 'Filter plugins';
|
|
80
|
-
this.manager = manager;
|
|
81
|
-
this.unsub = manager.subscribe(() => this.markDirty());
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
protected override filterMatches(plugin: PluginStatus, q: string): boolean {
|
|
85
|
-
return plugin.name.toLowerCase().includes(q)
|
|
86
|
-
|| plugin.trustTier.toLowerCase().includes(q)
|
|
87
|
-
|| plugin.version.toLowerCase().includes(q);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// selection is preserved across onActivate, BasePanel's default
|
|
91
|
-
// (mark dirty, no index reset) is exactly what we want, so no override.
|
|
92
|
-
|
|
93
|
-
public override onDestroy(): void {
|
|
94
|
-
this.unsub?.();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// -------------------------------------------------------------------------
|
|
98
|
-
// Input, e=enable, d=disable (confirm), v=verify, q=lift quarantine (confirm)
|
|
99
|
-
// -------------------------------------------------------------------------
|
|
100
|
-
|
|
101
|
-
public handleInput(key: string): boolean {
|
|
102
|
-
if (this.lastError !== null) this.clearError();
|
|
103
|
-
|
|
104
|
-
if (this.confirmAction) {
|
|
105
|
-
const result = handleConfirmInput(this.confirmAction, key);
|
|
106
|
-
if (result === 'confirmed') {
|
|
107
|
-
this._executeConfirmed(this.confirmAction.subject);
|
|
108
|
-
this.confirmAction = null;
|
|
109
|
-
this.markDirty();
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
if (result === 'cancelled') {
|
|
113
|
-
this.confirmAction = null;
|
|
114
|
-
this.markDirty();
|
|
115
|
-
}
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (!this.filterActive) {
|
|
120
|
-
switch (key) {
|
|
121
|
-
case 'e':
|
|
122
|
-
this._enableSelected();
|
|
123
|
-
return true;
|
|
124
|
-
case 'd':
|
|
125
|
-
this._requestDisable();
|
|
126
|
-
return true;
|
|
127
|
-
case 'v':
|
|
128
|
-
this._verifySelected();
|
|
129
|
-
return true;
|
|
130
|
-
case 'q': {
|
|
131
|
-
const plugin = this.getSelectedItem();
|
|
132
|
-
if (!plugin?.quarantined) return false;
|
|
133
|
-
this._requestLiftQuarantine();
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
case 'm': {
|
|
137
|
-
// Consumed here only when there is a quarantined plugin selected;
|
|
138
|
-
// the actual /recall dispatch happens in handlePanelIntegrationAction
|
|
139
|
-
// below, which needs the executeCommand bridge from the router.
|
|
140
|
-
const plugin = this.getSelectedItem();
|
|
141
|
-
return Boolean(plugin?.quarantined);
|
|
142
|
-
}
|
|
143
|
-
default:
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return super.handleInput(key);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* optional one-key capture-to-memory for a quarantined plugin, 'm'
|
|
153
|
-
* dispatches `/recall capture plugin <name>` (recall-capture.ts:146 pattern)
|
|
154
|
-
* instead of requiring the operator to type the command by hand.
|
|
155
|
-
*/
|
|
156
|
-
public handlePanelIntegrationAction(key: string, ctx: PanelIntegrationContext): boolean {
|
|
157
|
-
if (key !== 'm' || !ctx.executeCommand) return false;
|
|
158
|
-
const plugin = this.getSelectedItem();
|
|
159
|
-
if (!plugin?.quarantined) return false;
|
|
160
|
-
void ctx.executeCommand('recall', ['capture', 'plugin', plugin.name]).catch(() => {});
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
private _enableSelected(): void {
|
|
165
|
-
const plugin = this.getSelectedItem();
|
|
166
|
-
if (!plugin) return;
|
|
167
|
-
void this.manager.enable(plugin.name).then((result) => {
|
|
168
|
-
if (!result.ok) this.setError(`Enable failed: ${result.error ?? 'unknown error'}`);
|
|
169
|
-
this.markDirty();
|
|
170
|
-
}).catch((err) => {
|
|
171
|
-
this.setError(`Enable failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
172
|
-
this.markDirty();
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
private _requestDisable(): void {
|
|
177
|
-
const plugin = this.getSelectedItem();
|
|
178
|
-
if (!plugin) return;
|
|
179
|
-
this.confirmAction = { subject: { kind: 'disable', name: plugin.name }, label: plugin.name, verb: 'Disable' };
|
|
180
|
-
this.markDirty();
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
private _requestLiftQuarantine(): void {
|
|
184
|
-
const plugin = this.getSelectedItem();
|
|
185
|
-
if (!plugin?.quarantined) return;
|
|
186
|
-
this.confirmAction = { subject: { kind: 'lift-quarantine', name: plugin.name }, label: plugin.name, verb: 'Lift quarantine on' };
|
|
187
|
-
this.markDirty();
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
private _verifySelected(): void {
|
|
191
|
-
const plugin = this.getSelectedItem();
|
|
192
|
-
if (!plugin) return;
|
|
193
|
-
const result = this.manager.verify(plugin.name);
|
|
194
|
-
if (!result.ok && result.reason?.toLowerCase().includes('not found')) {
|
|
195
|
-
this._verifyResult = null;
|
|
196
|
-
this.setError(`Verify failed: ${result.reason}`);
|
|
197
|
-
this.markDirty();
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
this._verifyResult = { name: plugin.name, valid: result.valid, fingerprint: result.fingerprint, reason: result.reason };
|
|
201
|
-
this.markDirty();
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
private _executeConfirmed(subject: PluginConfirmSubject): void {
|
|
205
|
-
if (subject.kind === 'disable') {
|
|
206
|
-
void this.manager.disable(subject.name).then((result) => {
|
|
207
|
-
if (!result.ok) this.setError(`Disable failed: ${result.error ?? 'unknown error'}`);
|
|
208
|
-
this.markDirty();
|
|
209
|
-
}).catch((err) => {
|
|
210
|
-
this.setError(`Disable failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
211
|
-
this.markDirty();
|
|
212
|
-
});
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
const result = this.manager.liftQuarantine(subject.name);
|
|
216
|
-
if (!result.ok) this.setError(`Lift quarantine failed: ${result.error ?? 'unknown error'}`);
|
|
217
|
-
this.markDirty();
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
protected override getPalette(): PanelPalette {
|
|
221
|
-
return C;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
protected getItems(): readonly PluginStatus[] {
|
|
225
|
-
return this.manager.list();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
protected renderItem(plugin: PluginStatus, _index: number, selected: boolean, width: number): Line {
|
|
229
|
-
const bg = selected ? C.selectBg : undefined;
|
|
230
|
-
return buildPanelLine(width, [
|
|
231
|
-
[' ', C.label, bg],
|
|
232
|
-
[plugin.name.padEnd(22), C.value, bg],
|
|
233
|
-
[` ${statusLabel(plugin).padEnd(11)}`, statusColor(plugin), bg],
|
|
234
|
-
[` ${plugin.trustTier.toUpperCase().padEnd(10)}`, trustColor(plugin.trustTier), bg],
|
|
235
|
-
[` ${plugin.version}`, C.dim, bg],
|
|
236
|
-
]);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
protected override getEmptyStateMessage(): string {
|
|
240
|
-
return ' No plugins discovered.';
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
protected override getEmptyStateActions(): Array<{ command: string; summary: string }> {
|
|
244
|
-
return [
|
|
245
|
-
{ command: '/plugin list', summary: 'inspect plugin discovery paths and current registry state' },
|
|
246
|
-
{ command: '/marketplace', summary: 'review curated ecosystem entries and provenance posture' },
|
|
247
|
-
];
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
public render(width: number, height: number): Line[] {
|
|
251
|
-
const intro = 'Plugin trust, capabilities, signatures, and quarantine posture for the active ecosystem surface.';
|
|
252
|
-
const plugins = this.getItems();
|
|
253
|
-
|
|
254
|
-
if (plugins.length === 0) {
|
|
255
|
-
const workspace = buildPanelWorkspace(width, height, {
|
|
256
|
-
title: 'Plugin Control Room',
|
|
257
|
-
intro,
|
|
258
|
-
sections: [{
|
|
259
|
-
lines: buildEmptyState(
|
|
260
|
-
width,
|
|
261
|
-
' No plugins discovered.',
|
|
262
|
-
'Use /plugin list for search paths, install hints, and trust review before activating plugin-backed flows.',
|
|
263
|
-
[
|
|
264
|
-
{ command: '/plugin list', summary: 'inspect plugin discovery paths and current registry state' },
|
|
265
|
-
{ command: '/marketplace', summary: 'review curated ecosystem entries and provenance posture' },
|
|
266
|
-
],
|
|
267
|
-
C,
|
|
268
|
-
),
|
|
269
|
-
}],
|
|
270
|
-
palette: C,
|
|
271
|
-
});
|
|
272
|
-
while (workspace.length < height) workspace.push(createEmptyLine(width));
|
|
273
|
-
return workspace;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Provenance/error posture header, surface trust + quarantine pressure first.
|
|
277
|
-
const quarantined = plugins.filter((p) => p.quarantined).length;
|
|
278
|
-
const untrusted = plugins.filter((p) => p.trustTier === 'untrusted').length;
|
|
279
|
-
const active = plugins.filter((p) => p.active).length;
|
|
280
|
-
const headerLines: Line[] = [
|
|
281
|
-
buildKeyValueLine(width, [
|
|
282
|
-
{ label: 'plugins', value: String(plugins.length), valueColor: C.info },
|
|
283
|
-
{ label: 'active', value: String(active), valueColor: active > 0 ? C.good : C.dim },
|
|
284
|
-
{ label: 'untrusted', value: String(untrusted), valueColor: untrusted > 0 ? C.warn : C.dim },
|
|
285
|
-
{ label: 'quarantined', value: String(quarantined), valueColor: quarantined > 0 ? C.bad : C.dim },
|
|
286
|
-
], C),
|
|
287
|
-
];
|
|
288
|
-
|
|
289
|
-
this.clampSelection();
|
|
290
|
-
const selected = this.getSelectedItem()!;
|
|
291
|
-
const selectedCaps = this.manager.capabilities(selected.name);
|
|
292
|
-
const trustRecord = this.manager.getTrustRecord(selected.name);
|
|
293
|
-
const quarantineRecord = this.manager.getQuarantineRecord(selected.name);
|
|
294
|
-
const detailRows: Line[] = [
|
|
295
|
-
buildPanelLine(width, [
|
|
296
|
-
[' Plugin: ', C.label],
|
|
297
|
-
[selected.name, C.value],
|
|
298
|
-
[' v', C.label],
|
|
299
|
-
[selected.version, C.dim],
|
|
300
|
-
[' State: ', C.label],
|
|
301
|
-
[statusLabel(selected), statusColor(selected)],
|
|
302
|
-
[' Trust: ', C.label],
|
|
303
|
-
[selected.trustTier, trustColor(selected.trustTier)],
|
|
304
|
-
]),
|
|
305
|
-
buildPanelLine(width, [
|
|
306
|
-
[' Description: ', C.label],
|
|
307
|
-
[truncateDisplay(selected.description, Math.max(0, width - 15)), C.dim],
|
|
308
|
-
]),
|
|
309
|
-
];
|
|
310
|
-
|
|
311
|
-
if (selectedCaps) {
|
|
312
|
-
detailRows.push(buildPanelLine(width, [
|
|
313
|
-
[' Capabilities: ', C.label],
|
|
314
|
-
[String(selectedCaps.requested.length), C.value],
|
|
315
|
-
[' High-risk: ', C.label],
|
|
316
|
-
[String(selectedCaps.highRisk.length), selectedCaps.highRisk.length > 0 ? C.warn : C.good],
|
|
317
|
-
[' Blocked: ', C.label],
|
|
318
|
-
[String(selectedCaps.blocked.length), selectedCaps.blocked.length > 0 ? C.bad : C.good],
|
|
319
|
-
]));
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (trustRecord?.signatureFingerprint) {
|
|
323
|
-
detailRows.push(buildPanelLine(width, [
|
|
324
|
-
[' Signature: ', C.label],
|
|
325
|
-
[truncateDisplay(trustRecord.signatureFingerprint, Math.max(0, width - 14)), C.info],
|
|
326
|
-
]));
|
|
327
|
-
} else {
|
|
328
|
-
detailRows.push(buildPanelLine(width, [[' Signature: unsigned (no provenance fingerprint on record)', C.warn]]));
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (quarantineRecord) {
|
|
332
|
-
detailRows.push(buildPanelLine(width, [
|
|
333
|
-
[' Quarantine: ', C.label],
|
|
334
|
-
[truncateDisplay(quarantineRecord.reason, Math.max(0, width - 14)), C.bad],
|
|
335
|
-
]));
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (this._verifyResult && this._verifyResult.name === selected.name) {
|
|
339
|
-
const vr = this._verifyResult;
|
|
340
|
-
const verifySegments: Array<[string, string, string?]> = [
|
|
341
|
-
[' Verify: ', C.label],
|
|
342
|
-
[vr.valid ? 'VALID' : 'INVALID', vr.valid ? C.good : C.bad],
|
|
343
|
-
];
|
|
344
|
-
if (vr.fingerprint) verifySegments.push([` fp=${truncateDisplay(vr.fingerprint, 20)}`, C.info]);
|
|
345
|
-
if (!vr.valid && vr.reason) verifySegments.push([` ${truncateDisplay(vr.reason, Math.max(0, width - 40))}`, C.warn]);
|
|
346
|
-
detailRows.push(buildPanelLine(width, verifySegments));
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (this.confirmAction) detailRows.push(...renderConfirmLines(width, this.confirmAction));
|
|
350
|
-
|
|
351
|
-
const hints = this.filterActive
|
|
352
|
-
? [{ keys: 'type', label: 'filter' }, { keys: 'Enter', label: 'apply' }, { keys: 'Esc', label: 'clear' }]
|
|
353
|
-
: [
|
|
354
|
-
{ keys: 'Up/Down', label: 'move' },
|
|
355
|
-
{ keys: 'e', label: 'enable' },
|
|
356
|
-
{ keys: 'd', label: 'disable' },
|
|
357
|
-
{ keys: 'v', label: 'verify' },
|
|
358
|
-
...(selected.quarantined ? [{ keys: 'q', label: 'lift quarantine' }, { keys: 'm', label: 'capture to memory' }] : []),
|
|
359
|
-
{ keys: '/', label: 'filter' },
|
|
360
|
-
];
|
|
361
|
-
|
|
362
|
-
return this.renderList(width, height, {
|
|
363
|
-
title: 'Plugin Control Room',
|
|
364
|
-
header: headerLines,
|
|
365
|
-
footer: [
|
|
366
|
-
...buildDetailBlock(width, `Plugin · ${selected.name}`, detailRows, C),
|
|
367
|
-
buildKeyboardHints(width, hints, C),
|
|
368
|
-
],
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
}
|