@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
|
@@ -29,8 +29,8 @@ export interface SelectionResult {
|
|
|
29
29
|
export class SelectionModal {
|
|
30
30
|
public active = false;
|
|
31
31
|
public title = '';
|
|
32
|
-
|
|
33
|
-
public
|
|
32
|
+
/** The always-live search row's query (fuzzy). Typing edits it directly; there is no search mode. */
|
|
33
|
+
public query = '';
|
|
34
34
|
public items: SelectionItem[] = [];
|
|
35
35
|
public filteredItems: SelectionItem[] = [];
|
|
36
36
|
public selectedIndex = 0;
|
|
@@ -44,6 +44,9 @@ export class SelectionModal {
|
|
|
44
44
|
* the generic "Select".
|
|
45
45
|
*/
|
|
46
46
|
public primaryVerbLabel: string | undefined = undefined;
|
|
47
|
+
/** Live-preview hook: called when the highlighted row changes (see open()). */
|
|
48
|
+
private onHighlight: ((item: SelectionItem | null) => void) | undefined = undefined;
|
|
49
|
+
private lastHighlightedId: string | null | undefined = undefined;
|
|
47
50
|
|
|
48
51
|
/** Open the modal with items and title */
|
|
49
52
|
open(
|
|
@@ -54,13 +57,17 @@ export class SelectionModal {
|
|
|
54
57
|
allowSearch?: boolean;
|
|
55
58
|
customActions?: Map<string, SelectionAction>;
|
|
56
59
|
primaryVerbLabel?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Called with the highlighted row right after open and whenever the
|
|
62
|
+
* cursor lands on a different row (move, search). Used for live preview.
|
|
63
|
+
*/
|
|
64
|
+
onHighlight?: (item: SelectionItem | null) => void;
|
|
57
65
|
}
|
|
58
66
|
): void {
|
|
59
67
|
this.title = title;
|
|
60
68
|
this.items = items;
|
|
61
69
|
this.query = '';
|
|
62
70
|
this.allowSearch = opts?.allowSearch ?? true;
|
|
63
|
-
this.searchFocused = false;
|
|
64
71
|
this.customActions = opts?.customActions ?? new Map();
|
|
65
72
|
this.primaryVerbLabel = opts?.primaryVerbLabel;
|
|
66
73
|
this.active = true;
|
|
@@ -73,13 +80,17 @@ export class SelectionModal {
|
|
|
73
80
|
} else {
|
|
74
81
|
this.selectedIndex = 0;
|
|
75
82
|
}
|
|
83
|
+
this.onHighlight = opts?.onHighlight;
|
|
84
|
+
this.lastHighlightedId = undefined;
|
|
85
|
+
this.emitHighlight();
|
|
76
86
|
}
|
|
77
87
|
|
|
78
88
|
close(): void {
|
|
89
|
+
this.onHighlight = undefined;
|
|
90
|
+
this.lastHighlightedId = undefined;
|
|
79
91
|
this.active = false;
|
|
80
92
|
this.title = '';
|
|
81
93
|
this.query = '';
|
|
82
|
-
this.searchFocused = false;
|
|
83
94
|
this.items = [];
|
|
84
95
|
this.filteredItems = [];
|
|
85
96
|
this.selectedIndex = 0;
|
|
@@ -93,6 +104,7 @@ export class SelectionModal {
|
|
|
93
104
|
this.selectedIndex = this.selectedIndex > 0
|
|
94
105
|
? this.selectedIndex - 1
|
|
95
106
|
: this.filteredItems.length - 1;
|
|
107
|
+
this.emitHighlight();
|
|
96
108
|
}
|
|
97
109
|
|
|
98
110
|
moveDown(): void {
|
|
@@ -100,6 +112,7 @@ export class SelectionModal {
|
|
|
100
112
|
this.selectedIndex = this.selectedIndex < this.filteredItems.length - 1
|
|
101
113
|
? this.selectedIndex + 1
|
|
102
114
|
: 0;
|
|
115
|
+
this.emitHighlight();
|
|
103
116
|
}
|
|
104
117
|
|
|
105
118
|
/** Update fuzzy search filter */
|
|
@@ -107,18 +120,7 @@ export class SelectionModal {
|
|
|
107
120
|
this.query = query;
|
|
108
121
|
this.selectedIndex = 0;
|
|
109
122
|
this.filterItems();
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
canFocusSearch(): boolean {
|
|
113
|
-
return this.allowSearch;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
focusSearch(): void {
|
|
117
|
-
if (this.allowSearch) this.searchFocused = true;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
blurSearch(): void {
|
|
121
|
-
this.searchFocused = false;
|
|
123
|
+
this.emitHighlight();
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
/** Get currently highlighted item */
|
|
@@ -127,6 +129,16 @@ export class SelectionModal {
|
|
|
127
129
|
return this.filteredItems[this.selectedIndex] ?? null;
|
|
128
130
|
}
|
|
129
131
|
|
|
132
|
+
/** Notify onHighlight when the highlighted row differs from the last one reported. */
|
|
133
|
+
private emitHighlight(): void {
|
|
134
|
+
if (!this.onHighlight) return;
|
|
135
|
+
const item = this.getSelected();
|
|
136
|
+
const id = item?.id ?? null;
|
|
137
|
+
if (id === this.lastHighlightedId) return;
|
|
138
|
+
this.lastHighlightedId = id;
|
|
139
|
+
this.onHighlight(item);
|
|
140
|
+
}
|
|
141
|
+
|
|
130
142
|
/** Fuzzy match items against query, resets filteredItems */
|
|
131
143
|
private filterItems(): void {
|
|
132
144
|
if (this.query.length === 0) {
|
|
@@ -82,6 +82,12 @@ export class SessionPickerModal {
|
|
|
82
82
|
/** Last status message to show in the modal (e.g. error or success). */
|
|
83
83
|
public statusMessage = '';
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* The always-live search query. Filters the local sessions by name and
|
|
87
|
+
* title; selectedIndex and scrollOffset index the filtered list.
|
|
88
|
+
*/
|
|
89
|
+
public query = '';
|
|
90
|
+
|
|
85
91
|
public constructor(
|
|
86
92
|
private readonly sessionManager: SessionManager,
|
|
87
93
|
private readonly sessionBroker?: SessionReadFacade,
|
|
@@ -122,9 +128,25 @@ export class SessionPickerModal {
|
|
|
122
128
|
this.scrollOffset = 0;
|
|
123
129
|
this.statusMessage = '';
|
|
124
130
|
this.deleteConfirmationTarget = null;
|
|
131
|
+
this.query = '';
|
|
125
132
|
this.active = true;
|
|
126
133
|
}
|
|
127
134
|
|
|
135
|
+
/** The local sessions matching the query (all of them when it is empty). */
|
|
136
|
+
visibleSessions(): SessionInfo[] {
|
|
137
|
+
const q = this.query.trim().toLowerCase();
|
|
138
|
+
if (q.length === 0) return this.sessions;
|
|
139
|
+
return this.sessions.filter((s) => s.name.toLowerCase().includes(q) || (s.title ?? '').toLowerCase().includes(q));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Replace the query; the selection returns to the first match. */
|
|
143
|
+
setQuery(query: string): void {
|
|
144
|
+
this.query = query;
|
|
145
|
+
this.selectedIndex = 0;
|
|
146
|
+
this.scrollOffset = 0;
|
|
147
|
+
this.deleteConfirmationTarget = null;
|
|
148
|
+
}
|
|
149
|
+
|
|
128
150
|
close(): void {
|
|
129
151
|
this.active = false;
|
|
130
152
|
this.statusMessage = '';
|
|
@@ -132,15 +154,17 @@ export class SessionPickerModal {
|
|
|
132
154
|
}
|
|
133
155
|
|
|
134
156
|
moveUp(): void {
|
|
135
|
-
|
|
136
|
-
|
|
157
|
+
const count = this.visibleSessions().length;
|
|
158
|
+
if (count === 0) return;
|
|
159
|
+
this.selectedIndex = (this.selectedIndex - 1 + count) % count;
|
|
137
160
|
this._clampScroll();
|
|
138
161
|
this.deleteConfirmationTarget = null;
|
|
139
162
|
}
|
|
140
163
|
|
|
141
164
|
moveDown(): void {
|
|
142
|
-
|
|
143
|
-
|
|
165
|
+
const count = this.visibleSessions().length;
|
|
166
|
+
if (count === 0) return;
|
|
167
|
+
this.selectedIndex = (this.selectedIndex + 1) % count;
|
|
144
168
|
this._clampScroll();
|
|
145
169
|
this.deleteConfirmationTarget = null;
|
|
146
170
|
}
|
|
@@ -151,7 +175,7 @@ export class SessionPickerModal {
|
|
|
151
175
|
}
|
|
152
176
|
|
|
153
177
|
getSelected(): SessionInfo | null {
|
|
154
|
-
return this.
|
|
178
|
+
return this.visibleSessions()[this.selectedIndex] ?? null;
|
|
155
179
|
}
|
|
156
180
|
|
|
157
181
|
/**
|
|
@@ -195,8 +219,9 @@ export class SessionPickerModal {
|
|
|
195
219
|
// Reload list from the global session manager (removes the deleted entry)
|
|
196
220
|
this.sessions = this.sessionManager.list();
|
|
197
221
|
// Adjust selection
|
|
198
|
-
|
|
199
|
-
|
|
222
|
+
const remaining = this.visibleSessions().length;
|
|
223
|
+
if (this.selectedIndex >= remaining) {
|
|
224
|
+
this.selectedIndex = Math.max(0, remaining - 1);
|
|
200
225
|
}
|
|
201
226
|
this._clampScroll();
|
|
202
227
|
this.deleteConfirmationTarget = null;
|
|
@@ -216,7 +241,7 @@ export class SessionPickerModal {
|
|
|
216
241
|
} else if (this.selectedIndex >= this.scrollOffset + visRows) {
|
|
217
242
|
this.scrollOffset = this.selectedIndex - visRows + 1;
|
|
218
243
|
}
|
|
219
|
-
const maxOffset = Math.max(0, this.
|
|
244
|
+
const maxOffset = Math.max(0, this.visibleSessions().length - visRows);
|
|
220
245
|
this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, maxOffset));
|
|
221
246
|
}
|
|
222
247
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* settings-modal-reset.ts and settings-modal-mutations.ts.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { handleConfirmInput } from '../
|
|
13
|
+
import { handleConfirmInput } from '../views/confirm-state.ts';
|
|
14
14
|
import type { FlagEntry, McpEntry, SettingEntry, SubscriptionEntry } from './settings-modal-types.ts';
|
|
15
15
|
import { buildMcpEntries, buildSubscriptionEntries } from './settings-modal-data.ts';
|
|
16
16
|
import { modelPickerLaunchForKey } from './settings-modal-behavior.ts';
|
|
@@ -34,7 +34,7 @@ export interface ActivateSelectedContext {
|
|
|
34
34
|
setEditBuffer(value: string): void;
|
|
35
35
|
setMcpAllowAllConfirmationTarget(value: string | null): void;
|
|
36
36
|
setSubscriptionLogoutConfirmationTarget(value: string | null): void;
|
|
37
|
-
setPendingSettingsPickerAction(value: 'tts-provider' | 'tts-voice' | null): void;
|
|
37
|
+
setPendingSettingsPickerAction(value: 'tts-provider' | 'tts-voice' | 'theme' | null): void;
|
|
38
38
|
setPendingModelPickerTarget(value: ModelPickerTarget | null): void;
|
|
39
39
|
setPendingProviderModelPickerTarget(value: ModelPickerTarget | null): void;
|
|
40
40
|
}
|
|
@@ -74,6 +74,11 @@ export function activateSelected(ctx: ActivateSelectedContext): void {
|
|
|
74
74
|
ctx.setPendingSettingsPickerAction('tts-voice');
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
+
// The theme row opens a picker with live preview instead of cycling values.
|
|
78
|
+
if (setting.key === 'display.theme') {
|
|
79
|
+
ctx.setPendingSettingsPickerAction('theme');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
77
82
|
|
|
78
83
|
const pickerLaunch = modelPickerLaunchForKey(setting.key);
|
|
79
84
|
if (pickerLaunch !== null) {
|
|
@@ -14,7 +14,7 @@ import type { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
|
14
14
|
import { buildSubscriptionEntries } from './settings-modal-subscriptions.ts';
|
|
15
15
|
import type { SubscriptionManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
16
16
|
import type { ServiceInspectionQuery } from '@/runtime/index.ts';
|
|
17
|
-
import { CODE_INDEX_ENABLED_CONFIG_KEY } from '@pellux/goodvibes-sdk/platform/runtime/operations';
|
|
17
|
+
import { CODE_INDEX_ENABLED_CONFIG_KEY, NOTIFICATIONS_METADATA_ONLY_KEY } from '@pellux/goodvibes-sdk/platform/runtime/operations';
|
|
18
18
|
import {
|
|
19
19
|
WORKTREE_SETUP_CARRY_OVER_GLOBS_CONFIG_KEY,
|
|
20
20
|
WORKTREE_SETUP_COMMANDS_CONFIG_KEY,
|
|
@@ -167,7 +167,7 @@ export function buildSettingGroups(
|
|
|
167
167
|
|
|
168
168
|
// Synthetic behavior.budgetAlertUsd (TUI-local): no schema surface previously,
|
|
169
169
|
// never in /config; /settings-sync show rejects any key not
|
|
170
|
-
// in CONFIG_KEYS. The
|
|
170
|
+
// in CONFIG_KEYS. The Usage modal's 'b' key and /cost budget <usd> remain
|
|
171
171
|
// the primary way to change it; this entry makes the current effective
|
|
172
172
|
// value (and whether it's still the "no budget configured" default)
|
|
173
173
|
// visible from /config behavior too, same rationale as notifyAfterSeconds.
|
|
@@ -190,6 +190,11 @@ export function buildSettingGroups(
|
|
|
190
190
|
behaviorEntries.push(entry);
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
|
+
// behavior.notificationsMetadataOnly is a real SDK schema key (the loop
|
|
194
|
+
// above already added it); it governs the text of every notification row
|
|
195
|
+
// above (desktop, in-terminal, webhook), so it is listed right after them.
|
|
196
|
+
const privacyIndex = behaviorEntries.findIndex((e) => e.setting.key === (NOTIFICATIONS_METADATA_ONLY_KEY as ConfigKey));
|
|
197
|
+
if (privacyIndex >= 0) behaviorEntries.push(...behaviorEntries.splice(privacyIndex, 1));
|
|
193
198
|
}
|
|
194
199
|
|
|
195
200
|
// Inject the storage.codeIndexEnabled toggle into the
|
|
@@ -331,20 +336,20 @@ export function buildNotifyAfterSecondsSyntheticEntry(configManager: Pick<Config
|
|
|
331
336
|
*
|
|
332
337
|
* 0 = no budget configured (disabled). Any positive number = the USD
|
|
333
338
|
* threshold. Default matches BUDGET_ALERT_USD_DEFAULT in cost-utils.ts, the
|
|
334
|
-
* single source of truth
|
|
339
|
+
* single source of truth the Usage modal and budget-breach-notifier.ts share.
|
|
335
340
|
*/
|
|
336
341
|
export const BUDGET_ALERT_USD_SYNTHETIC_SETTING: ConfigSetting = {
|
|
337
342
|
key: BUDGET_ALERT_USD_CONFIG_KEY as ConfigKey,
|
|
338
343
|
type: 'number',
|
|
339
344
|
default: BUDGET_ALERT_USD_DEFAULT,
|
|
340
|
-
description: 'Session cost-budget alert threshold in USD (0 = no budget configured). Set via the
|
|
345
|
+
description: 'Session cost-budget alert threshold in USD (0 = no budget configured). Set via the Usage modal\'s "b" key or /cost budget <usd>; this entry only displays the current effective value.',
|
|
341
346
|
};
|
|
342
347
|
|
|
343
348
|
/**
|
|
344
349
|
* Build the synthetic SettingEntry for behavior.budgetAlertUsd.
|
|
345
350
|
*
|
|
346
351
|
* Delegates parsing/fallback to readBudgetAlertUsd (cost-utils.ts) so this
|
|
347
|
-
* display entry can never disagree with what
|
|
352
|
+
* display entry can never disagree with what the Usage modal and the
|
|
348
353
|
* background budget-breach notifier actually read.
|
|
349
354
|
*/
|
|
350
355
|
export function buildBudgetAlertUsdSyntheticEntry(configManager: Pick<ConfigManager, 'get'>): SettingEntry {
|
|
@@ -370,7 +375,7 @@ export function buildBudgetAlertUsdSyntheticEntry(configManager: Pick<ConfigMana
|
|
|
370
375
|
const NOTIFY_ALERT_SYNTHETIC_SETTINGS: ReadonlyArray<{ readonly key: string; readonly description: string }> = [
|
|
371
376
|
{
|
|
372
377
|
key: 'behavior.notifyOnBudgetBreach',
|
|
373
|
-
description: 'Alert when session cost crosses the configured budget (set via the
|
|
378
|
+
description: 'Alert when session cost crosses the configured budget (set via the Usage modal\'s "b" key).',
|
|
374
379
|
},
|
|
375
380
|
{
|
|
376
381
|
key: 'behavior.notifyOnAgentFailure',
|
|
@@ -93,7 +93,7 @@ export type SettingsCategory =
|
|
|
93
93
|
| 'google'
|
|
94
94
|
| 'danger';
|
|
95
95
|
|
|
96
|
-
export type
|
|
96
|
+
export type SettingsFocusRegion = 'categories' | 'settings';
|
|
97
97
|
|
|
98
98
|
export const SETTINGS_CATEGORY_GROUPS: ReadonlyArray<{
|
|
99
99
|
readonly label: string;
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
type McpEntry,
|
|
38
38
|
type SettingEntry,
|
|
39
39
|
type SettingsCategory,
|
|
40
|
-
type
|
|
40
|
+
type SettingsFocusRegion,
|
|
41
41
|
type SubscriptionEntry,
|
|
42
42
|
} from './settings-modal-types.ts';
|
|
43
43
|
import {
|
|
@@ -113,7 +113,7 @@ export {
|
|
|
113
113
|
type McpEntry,
|
|
114
114
|
type SettingEntry,
|
|
115
115
|
type SettingsCategory,
|
|
116
|
-
type
|
|
116
|
+
type SettingsFocusRegion,
|
|
117
117
|
type SubscriptionEntry,
|
|
118
118
|
} from './settings-modal-types.ts';
|
|
119
119
|
|
|
@@ -130,8 +130,8 @@ export class SettingsModal {
|
|
|
130
130
|
/** Selected setting index within the current category. */
|
|
131
131
|
public selectedIndex = 0;
|
|
132
132
|
|
|
133
|
-
/** Which
|
|
134
|
-
public
|
|
133
|
+
/** Which region (settings list or documentation) receives up/down navigation and Enter/Space actions. */
|
|
134
|
+
public focusRegion: SettingsFocusRegion = 'settings';
|
|
135
135
|
|
|
136
136
|
/** Whether we're in inline edit mode for the selected string/number setting. */
|
|
137
137
|
public editingMode = false;
|
|
@@ -139,8 +139,8 @@ export class SettingsModal {
|
|
|
139
139
|
/** Current value of the inline edit buffer. */
|
|
140
140
|
public editBuffer = '';
|
|
141
141
|
/**
|
|
142
|
-
* Scroll offset (in wrapped lines) of the documentation
|
|
143
|
-
* selected row. The renderer clamps it to the
|
|
142
|
+
* Scroll offset (in wrapped lines) of the documentation region for the
|
|
143
|
+
* selected row. The renderer clamps it to the region's real content height
|
|
144
144
|
* and shows honest more-above/below markers, long feature documentation
|
|
145
145
|
* scrolls, it never clips. Reset whenever the selection changes.
|
|
146
146
|
*/
|
|
@@ -156,7 +156,7 @@ export class SettingsModal {
|
|
|
156
156
|
/** Set when the highlighted setting should open provider selection before model selection. */
|
|
157
157
|
public pendingProviderModelPickerTarget: ModelPickerTarget | null = null;
|
|
158
158
|
/** Set when a highlighted setting needs an external picker owned by the shell route. */
|
|
159
|
-
public pendingSettingsPickerAction: 'tts-provider' | 'tts-voice' | null = null;
|
|
159
|
+
public pendingSettingsPickerAction: 'tts-provider' | 'tts-voice' | 'theme' | null = null;
|
|
160
160
|
/** Provider awaiting explicit logout confirmation, if any. */
|
|
161
161
|
public subscriptionLogoutConfirmationTarget: string | null = null;
|
|
162
162
|
|
|
@@ -251,7 +251,7 @@ export class SettingsModal {
|
|
|
251
251
|
this.connectionEntries = initialConnectionEntries();
|
|
252
252
|
this.categoryIndex = 0;
|
|
253
253
|
this.selectedIndex = 0;
|
|
254
|
-
this.
|
|
254
|
+
this.focusRegion = 'categories';
|
|
255
255
|
this.editingMode = false;
|
|
256
256
|
this.editBuffer = '';
|
|
257
257
|
this.pendingModelPickerTarget = null;
|
|
@@ -268,7 +268,7 @@ export class SettingsModal {
|
|
|
268
268
|
this.active = true;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
/** Scroll the documentation
|
|
271
|
+
/** Scroll the documentation region by `delta` wrapped lines (renderer clamps the top end). */
|
|
272
272
|
scrollContext(delta: number): void {
|
|
273
273
|
this.contextScroll = Math.max(0, this.contextScroll + delta);
|
|
274
274
|
}
|
|
@@ -296,7 +296,7 @@ export class SettingsModal {
|
|
|
296
296
|
this.serviceRegistry = null;
|
|
297
297
|
this.secretsManager = null;
|
|
298
298
|
this.onSettingApplied = null;
|
|
299
|
-
this.
|
|
299
|
+
this.focusRegion = 'settings';
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
/** Enter search mode (focus the search input bar). */
|
|
@@ -355,26 +355,26 @@ export class SettingsModal {
|
|
|
355
355
|
|
|
356
356
|
focusCategories(): void {
|
|
357
357
|
if (this.editingMode) return;
|
|
358
|
-
this.
|
|
358
|
+
this.focusRegion = 'categories';
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
focusSettings(): void {
|
|
362
362
|
if (this.editingMode) return;
|
|
363
|
-
this.
|
|
363
|
+
this.focusRegion = 'settings';
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
-
|
|
366
|
+
toggleFocusRegion(): void {
|
|
367
367
|
if (this.editingMode) return;
|
|
368
|
-
this.
|
|
368
|
+
this.focusRegion = this.focusRegion === 'settings' ? 'categories' : 'settings';
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
moveFocusedUp(): void {
|
|
372
|
-
if (this.
|
|
372
|
+
if (this.focusRegion === 'categories') this.prevCategory();
|
|
373
373
|
else this.moveUp();
|
|
374
374
|
}
|
|
375
375
|
|
|
376
376
|
moveFocusedDown(): void {
|
|
377
|
-
if (this.
|
|
377
|
+
if (this.focusRegion === 'categories') this.nextCategory();
|
|
378
378
|
else this.moveDown();
|
|
379
379
|
}
|
|
380
380
|
|
|
@@ -476,7 +476,7 @@ export class SettingsModal {
|
|
|
476
476
|
if (categoryIndex >= 0) {
|
|
477
477
|
this.categoryIndex = categoryIndex;
|
|
478
478
|
this.selectedIndex = 0;
|
|
479
|
-
this.
|
|
479
|
+
this.focusRegion = 'settings';
|
|
480
480
|
return;
|
|
481
481
|
}
|
|
482
482
|
|
|
@@ -487,7 +487,7 @@ export class SettingsModal {
|
|
|
487
487
|
if (entryIndex >= 0) {
|
|
488
488
|
this.categoryIndex = index;
|
|
489
489
|
this.selectedIndex = entryIndex;
|
|
490
|
-
this.
|
|
490
|
+
this.focusRegion = 'settings';
|
|
491
491
|
return;
|
|
492
492
|
}
|
|
493
493
|
}
|
|
@@ -709,7 +709,7 @@ export class SettingsModal {
|
|
|
709
709
|
// has already applied the change to the gate manager (live flip for
|
|
710
710
|
// runtime-toggleable features, pending-restart marker for startup-gated
|
|
711
711
|
// ones). Re-read the manager for every header bound to this key so the
|
|
712
|
-
// rows and the context
|
|
712
|
+
// rows and the context region show the honest state at the point of change.
|
|
713
713
|
this._syncFeatureHeadersForKey(key);
|
|
714
714
|
|
|
715
715
|
if (result.restartDomain !== null) {
|
|
@@ -721,7 +721,7 @@ export class SettingsModal {
|
|
|
721
721
|
// No-op (result.changed === false, effectMessage === null): leave lastSettingEffectMessage untouched.
|
|
722
722
|
|
|
723
723
|
// Selecting 'prompt' for payments.cvvHandling states the tradeoff at the
|
|
724
|
-
// moment of selection, not just in the documentation
|
|
724
|
+
// moment of selection, not just in the documentation region, see the
|
|
725
725
|
// SDK's own CVV_PROMPT_TRADEOFF_WARNING (platform/payments).
|
|
726
726
|
if (key === PAYMENTS_CVV_HANDLING_CONFIG_KEY && value === 'prompt') {
|
|
727
727
|
this.lastSettingEffectMessage = CVV_PROMPT_TRADEOFF_WARNING;
|
|
@@ -3,7 +3,6 @@ import type { SubmissionIntent } from './submission-intent.ts';
|
|
|
3
3
|
export interface SubmissionRouterInput {
|
|
4
4
|
readonly text: string;
|
|
5
5
|
readonly commandMode?: boolean;
|
|
6
|
-
readonly panelFocused?: boolean;
|
|
7
6
|
readonly hasAttachments?: boolean;
|
|
8
7
|
}
|
|
9
8
|
|
|
@@ -12,7 +11,7 @@ export interface SubmissionRouterInput {
|
|
|
12
11
|
// 'plan' composer intent/label. The /plan mode-toggle is a plain slash command.
|
|
13
12
|
const PLAN_COMMANDS = new Set(['project-plan', 'planning']);
|
|
14
13
|
const REVIEW_COMMANDS = new Set(['review']);
|
|
15
|
-
const
|
|
14
|
+
const LEGACY_PANEL_COMMANDS = new Set(['panel']);
|
|
16
15
|
const ORCHESTRATION_COMMANDS = new Set([
|
|
17
16
|
'wrfc',
|
|
18
17
|
'orchestration',
|
|
@@ -30,11 +29,7 @@ export function routeSubmissionIntent(input: SubmissionRouterInput): SubmissionI
|
|
|
30
29
|
const hasAttachments = input.hasAttachments ?? false;
|
|
31
30
|
|
|
32
31
|
if (!trimmed) {
|
|
33
|
-
return {
|
|
34
|
-
kind: input.panelFocused ? 'panel-action' : 'empty',
|
|
35
|
-
label: input.panelFocused ? 'panel action' : 'prompt',
|
|
36
|
-
hasAttachments,
|
|
37
|
-
};
|
|
32
|
+
return { kind: 'empty', label: 'prompt', hasAttachments };
|
|
38
33
|
}
|
|
39
34
|
|
|
40
35
|
if (trimmed.startsWith('!#')) {
|
|
@@ -53,8 +48,8 @@ export function routeSubmissionIntent(input: SubmissionRouterInput): SubmissionI
|
|
|
53
48
|
if (REVIEW_COMMANDS.has(commandName)) {
|
|
54
49
|
return { kind: 'review', label: 'review', commandName, hasAttachments };
|
|
55
50
|
}
|
|
56
|
-
if (
|
|
57
|
-
return { kind: '
|
|
51
|
+
if (LEGACY_PANEL_COMMANDS.has(commandName)) {
|
|
52
|
+
return { kind: 'view-action', label: 'open view', commandName, hasAttachments };
|
|
58
53
|
}
|
|
59
54
|
if (ORCHESTRATION_COMMANDS.has(commandName)) {
|
|
60
55
|
return { kind: 'orchestration', label: 'orchestration', commandName, hasAttachments };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* surface-modal-host.ts, a stack of self-contained kit modals.
|
|
3
|
+
*
|
|
4
|
+
* A SurfaceModal owns its keys, its own sub-levels and its rendering (drawn
|
|
5
|
+
* with the surface kit). The host keeps them in a stack on the InputHandler:
|
|
6
|
+
*
|
|
7
|
+
* - Keys go to the top modal only (focus always belongs to the top modal).
|
|
8
|
+
* - Esc pops exactly one level: the top modal's own sub-level first
|
|
9
|
+
* (escape() returns true), otherwise the top modal closes. The next Esc
|
|
10
|
+
* reaches the modal underneath, then the rest of the Esc chain
|
|
11
|
+
* (handler-modal-stack.ts: close modal, clear composer, cancel turn).
|
|
12
|
+
* - Every modal in the stack renders, bottom to top; each one dims what is
|
|
13
|
+
* underneath it.
|
|
14
|
+
*
|
|
15
|
+
* The command palette and the confirm dialog are SurfaceModals; any new modal
|
|
16
|
+
* can be one without touching the handler plumbing again.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { InputToken } from '@pellux/goodvibes-sdk/platform/core';
|
|
20
|
+
import type { SurfaceLayer } from '../renderer/surface-kit.ts';
|
|
21
|
+
|
|
22
|
+
export type SurfaceModalCloseReason = 'escape' | 'done' | 'cleared';
|
|
23
|
+
|
|
24
|
+
export interface SurfaceModal {
|
|
25
|
+
/** A short identifier (tests, diagnostics). */
|
|
26
|
+
readonly name: string;
|
|
27
|
+
/** Handle a key or text token while this modal is on top. */
|
|
28
|
+
handleToken(token: InputToken, host: SurfaceModalHost): void;
|
|
29
|
+
/** Esc: pop one of this modal's own sub-levels and return true, or return false to close the modal. */
|
|
30
|
+
escape?(): boolean;
|
|
31
|
+
/** Draw the modal for a screen of the given size. */
|
|
32
|
+
render(screenWidth: number, screenHeight: number): SurfaceLayer;
|
|
33
|
+
/** Called once when the modal leaves the stack. */
|
|
34
|
+
onClose?(reason: SurfaceModalCloseReason): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class SurfaceModalHost {
|
|
38
|
+
private readonly stack: SurfaceModal[] = [];
|
|
39
|
+
|
|
40
|
+
/** Called after the stack changes (wired to the render request). */
|
|
41
|
+
onChange: (() => void) | null = null;
|
|
42
|
+
|
|
43
|
+
get active(): boolean {
|
|
44
|
+
return this.stack.length > 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get depth(): number {
|
|
48
|
+
return this.stack.length;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
top(): SurfaceModal | undefined {
|
|
52
|
+
return this.stack[this.stack.length - 1];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The open modals, bottom first. */
|
|
56
|
+
modals(): readonly SurfaceModal[] {
|
|
57
|
+
return this.stack;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Open a modal on top of whatever is open. Opening one already in the stack moves it to the top. */
|
|
61
|
+
push(modal: SurfaceModal): void {
|
|
62
|
+
const existing = this.stack.indexOf(modal);
|
|
63
|
+
if (existing >= 0) this.stack.splice(existing, 1);
|
|
64
|
+
this.stack.push(modal);
|
|
65
|
+
this.onChange?.();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Remove a modal (usually the top one closing itself after acting). */
|
|
69
|
+
close(modal: SurfaceModal, reason: SurfaceModalCloseReason = 'done'): void {
|
|
70
|
+
const index = this.stack.indexOf(modal);
|
|
71
|
+
if (index < 0) return;
|
|
72
|
+
this.stack.splice(index, 1);
|
|
73
|
+
modal.onClose?.(reason);
|
|
74
|
+
this.onChange?.();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Esc: one level. Returns false when nothing was open. */
|
|
78
|
+
escape(): boolean {
|
|
79
|
+
const top = this.top();
|
|
80
|
+
if (!top) return false;
|
|
81
|
+
if (top.escape?.() === true) {
|
|
82
|
+
this.onChange?.();
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
this.close(top, 'escape');
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Route a token to the top modal. Returns false when nothing was open. */
|
|
90
|
+
handleToken(token: InputToken): boolean {
|
|
91
|
+
const top = this.top();
|
|
92
|
+
if (!top) return false;
|
|
93
|
+
top.handleToken(token, this);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Close everything (e.g. when the whole modal stack is cleared). */
|
|
98
|
+
clear(): void {
|
|
99
|
+
while (this.stack.length > 0) {
|
|
100
|
+
const modal = this.stack.pop()!;
|
|
101
|
+
modal.onClose?.('cleared');
|
|
102
|
+
}
|
|
103
|
+
this.onChange?.();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Layers for the compositor, bottom first. */
|
|
107
|
+
render(screenWidth: number, screenHeight: number): SurfaceLayer[] {
|
|
108
|
+
return this.stack.map((modal) => modal.render(screenWidth, screenHeight));
|
|
109
|
+
}
|
|
110
|
+
}
|