@pellux/goodvibes-tui 2.0.20 → 2.1.0
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 +70 -0
- package/README.md +16 -16
- package/docs/README.md +4 -4
- package/docs/foundation-artifacts/operator-contract.json +59 -4
- package/package.json +16 -6
- 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-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/verification-ledger.ts +18 -16
- 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/{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,5 +1,5 @@
|
|
|
1
1
|
import { MODAL_TONES } from './modal-theme.ts';
|
|
2
|
-
import { infoRow } from './modal-surface-helpers.ts';
|
|
2
|
+
import { infoRow, headerRow } from './modal-surface-helpers.ts';
|
|
3
3
|
import { listHookPointContracts } from '@pellux/goodvibes-sdk/platform/hooks';
|
|
4
4
|
import type {
|
|
5
5
|
HookActivityTracker,
|
|
@@ -18,11 +18,11 @@ import type {
|
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
19
19
|
// Hooks → config-modal surface (group-B port). Two tabs: 'Hooks' (active
|
|
20
20
|
// registrations + contract posture) and 'Activity' (recent runtime activity +
|
|
21
|
-
// managed authoring + last simulation, the
|
|
21
|
+
// managed authoring + last simulation, the earlier view's expand-activity view, now a
|
|
22
22
|
// dedicated tab). All sources are in-memory (dispatcher/workbench/tracker hold
|
|
23
23
|
// live state), so buildView reads live and refresh() is a no-op. Toggle/remove/
|
|
24
24
|
// simulate route to their `/hooks` command path. Selection-blind port: the
|
|
25
|
-
//
|
|
25
|
+
// view's selected-hook contract detail is folded into each hook row label.
|
|
26
26
|
// ---------------------------------------------------------------------------
|
|
27
27
|
|
|
28
28
|
export type HooksModalDispatcher = Pick<HookDispatcher, 'listHooks' | 'getChains'>;
|
|
@@ -68,11 +68,11 @@ class HooksModalSurface implements ConfigModalSurface {
|
|
|
68
68
|
if (hooks.length === 0) {
|
|
69
69
|
const rows: ConfigModalRow[] = [
|
|
70
70
|
infoRow('empty:0', 'No hooks are currently registered.'),
|
|
71
|
-
infoRow('empty:1', `contracts ${contracts.length} chains ${chains.length} managed ${managedHooks.length}`, {
|
|
72
|
-
infoRow('empty:2', `hooks file: ${hooksFilePath}`, {
|
|
73
|
-
|
|
74
|
-
infoRow('empty:hooks', '/hooks — review hook contracts and managed authoring actions', {
|
|
75
|
-
infoRow('empty:settings', '/settings — review hook/runtime behavior in the settings surface', {
|
|
71
|
+
infoRow('empty:1', `contracts ${contracts.length} chains ${chains.length} managed ${managedHooks.length}`, { fg: MODAL_TONES.dim }),
|
|
72
|
+
infoRow('empty:2', `hooks file: ${hooksFilePath}`, { fg: MODAL_TONES.dim }),
|
|
73
|
+
headerRow('empty:title', 'Next steps'),
|
|
74
|
+
infoRow('empty:hooks', '/hooks — review hook contracts and managed authoring actions', { fg: MODAL_TONES.dim }),
|
|
75
|
+
infoRow('empty:settings', '/settings — review hook/runtime behavior in the settings surface', { fg: MODAL_TONES.dim }),
|
|
76
76
|
];
|
|
77
77
|
return { id: 'hooks', label: 'Hooks', rows, emptyText: '' };
|
|
78
78
|
}
|
|
@@ -101,7 +101,7 @@ class HooksModalSurface implements ConfigModalSurface {
|
|
|
101
101
|
const rows: ConfigModalRow[] = [];
|
|
102
102
|
const recentActivity = this.deps.hookActivityTracker.listRecent(20);
|
|
103
103
|
if (recentActivity.length === 0) {
|
|
104
|
-
rows.push(infoRow('act:none', 'No hook activity recorded yet.', {
|
|
104
|
+
rows.push(infoRow('act:none', 'No hook activity recorded yet.', { fg: MODAL_TONES.dim }));
|
|
105
105
|
} else {
|
|
106
106
|
recentActivity.forEach((record, i) => {
|
|
107
107
|
const decisionText = record.ok ? (record.decision ?? 'ok') : 'error';
|
|
@@ -110,18 +110,18 @@ class HooksModalSurface implements ConfigModalSurface {
|
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
rows.push(
|
|
113
|
+
rows.push(headerRow('auth:title', 'Authoring'));
|
|
114
114
|
const recentAuthoring = this.deps.hookWorkbench.listRecentActions(3);
|
|
115
115
|
if (recentAuthoring.length === 0) {
|
|
116
|
-
rows.push(infoRow('auth:none', 'No managed hook authoring actions recorded yet.', {
|
|
116
|
+
rows.push(infoRow('auth:none', 'No managed hook authoring actions recorded yet.', { fg: MODAL_TONES.dim }));
|
|
117
117
|
} else {
|
|
118
|
-
recentAuthoring.forEach((action, i) => rows.push(infoRow(`auth:${i}`, `${action.kind.padEnd(14)} ${action.target}`, {
|
|
118
|
+
recentAuthoring.forEach((action, i) => rows.push(infoRow(`auth:${i}`, `${action.kind.padEnd(14)} ${action.target}`, { fg: MODAL_TONES.dim })));
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
const lastSimulation = this.deps.hookWorkbench.getLastSimulation();
|
|
122
122
|
if (lastSimulation) {
|
|
123
123
|
rows.push(infoRow('sim:path', `last simulation: ${lastSimulation.eventPath}`));
|
|
124
|
-
rows.push(infoRow('sim:matches', `matches: hooks=${lastSimulation.matchedHooks.length} chains=${lastSimulation.matchedChains.length}`, {
|
|
124
|
+
rows.push(infoRow('sim:matches', `matches: hooks=${lastSimulation.matchedHooks.length} chains=${lastSimulation.matchedChains.length}`, { fg: MODAL_TONES.dim }));
|
|
125
125
|
}
|
|
126
126
|
return { id: 'activity', label: 'Activity', rows, emptyText: 'No hook activity recorded yet.' };
|
|
127
127
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MODAL_TONES } from './modal-theme.ts';
|
|
2
|
+
import { infoRow, headerRow } from './modal-surface-helpers.ts';
|
|
2
3
|
import type {
|
|
3
4
|
ConfigModalActionContext,
|
|
4
5
|
ConfigModalRow,
|
|
@@ -10,14 +11,13 @@ import { KeybindingsManager } from '../../input/keybindings.ts';
|
|
|
10
11
|
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
12
13
|
// Docs + Shortcuts → 'keybindings' config-modal surface (group-B port).
|
|
13
|
-
// A MERGE of the retired
|
|
14
|
+
// A MERGE of the retired Docs view (tools/models/shortcuts) and the
|
|
14
15
|
// shortcuts-overlay reference. Three tabs: 'Tools', 'Models', and 'Shortcuts'
|
|
15
16
|
// (the categorized keyboard reference, driven live off keybindingsManager so
|
|
16
17
|
// user overrides show up, followed by an exhaustive 'All Bindings (live)'
|
|
17
|
-
// table). Enter opens
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// detail is folded into each row label. The panel's live '/' filter is dropped
|
|
18
|
+
// table). Enter opens Agents on processes running the selected tool
|
|
19
|
+
// (/agents --target <tool>:tool) or switches the active model (/model). Selection-blind port: the earlier view's selected tool/model
|
|
20
|
+
// detail is folded into each row label. The earlier view's live '/' filter is dropped
|
|
21
21
|
// (the host has no query state).
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
23
23
|
|
|
@@ -58,7 +58,7 @@ class KeybindingsModalSurface implements ConfigModalSurface {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
private toolsTab(): ConfigModalTab {
|
|
61
|
-
if (!this.deps.toolRegistry) return { id: 'tools', label: 'Tools', rows: [infoRow('tools:none', 'Tool registry not wired into this session.', {
|
|
61
|
+
if (!this.deps.toolRegistry) return { id: 'tools', label: 'Tools', rows: [infoRow('tools:none', 'Tool registry not wired into this session.', { fg: MODAL_TONES.dim })], emptyText: 'Tool registry not wired into this session.' };
|
|
62
62
|
const tools = this.deps.toolRegistry.list();
|
|
63
63
|
const rows: ConfigModalRow[] = tools.map((tool) => {
|
|
64
64
|
const d = tool.definition;
|
|
@@ -70,11 +70,11 @@ class KeybindingsModalSurface implements ConfigModalSurface {
|
|
|
70
70
|
const detail = [d.description, meta.join(' | ') || null].filter((s): s is string => Boolean(s)).join(' · ');
|
|
71
71
|
return { id: `tool:${d.name}`, label: detail ? `${d.name.padEnd(22)} ${detail}` : d.name };
|
|
72
72
|
});
|
|
73
|
-
return { id: 'tools', label: 'Tools', rows, emptyText: 'No tools registered.', hints: ['enter open in
|
|
73
|
+
return { id: 'tools', label: 'Tools', rows, emptyText: 'No tools registered.', hints: ['enter open in agents'] };
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
private modelsTab(): ConfigModalTab {
|
|
77
|
-
if (!this.deps.providerRegistry) return { id: 'models', label: 'Models', rows: [infoRow('models:none', 'Provider registry not wired into this session.', {
|
|
77
|
+
if (!this.deps.providerRegistry) return { id: 'models', label: 'Models', rows: [infoRow('models:none', 'Provider registry not wired into this session.', { fg: MODAL_TONES.dim })], emptyText: 'Provider registry not wired into this session.' };
|
|
78
78
|
const activeKey = this.deps.providerRegistry.getCurrentModel?.()?.registryKey;
|
|
79
79
|
const rows: ConfigModalRow[] = this.sortedModels().map((model) => {
|
|
80
80
|
const ctxK = model.contextWindow > 0 ? `${(model.contextWindow / 1000).toFixed(0)}k` : '?';
|
|
@@ -86,19 +86,18 @@ class KeybindingsModalSurface implements ConfigModalSurface {
|
|
|
86
86
|
|
|
87
87
|
private shortcutsTab(): ConfigModalTab {
|
|
88
88
|
const km = this.deps.keybindingsManager;
|
|
89
|
-
if (!km) return { id: 'shortcuts', label: 'Shortcuts', rows: [infoRow('sc:none', 'Keybindings manager not wired into this session.', {
|
|
89
|
+
if (!km) return { id: 'shortcuts', label: 'Shortcuts', rows: [infoRow('sc:none', 'Keybindings manager not wired into this session.', { fg: MODAL_TONES.dim })], emptyText: 'Keybindings manager not wired into this session.' };
|
|
90
90
|
const kb = (action: Parameters<KeybindingsManager['getComboLabel']>[0]) => km.getComboLabel(action);
|
|
91
91
|
const rows: ConfigModalRow[] = [];
|
|
92
92
|
let n = 0;
|
|
93
93
|
const category = (title: string, entries: ReadonlyArray<readonly [string, string]>): void => {
|
|
94
|
-
rows.push(
|
|
94
|
+
rows.push(headerRow(`sc:t:${n++}`, title));
|
|
95
95
|
for (const [key, desc] of entries) rows.push(infoRow(`sc:${n++}`, `${key.padEnd(20)} ${desc}`));
|
|
96
96
|
};
|
|
97
|
-
category('Navigation', [['Up / Down', 'Scroll / history recall'], ['PageUp / PageDn', 'Scroll by full page'], ['Home / End', 'Jump to start / end of line'], [kb('search'), 'Search conversation'], ['n / N (search)', 'Next / previous match'], ['Mouse wheel', 'Scroll conversation
|
|
97
|
+
category('Navigation', [['Up / Down', 'Scroll / history recall'], ['PageUp / PageDn', 'Scroll by full page'], ['Home / End', 'Jump to start / end of line'], [kb('search'), 'Search conversation'], ['n / N (search)', 'Next / previous match'], ['Mouse wheel', 'Scroll the conversation']]);
|
|
98
98
|
category('Editing', [['Enter', 'Submit message'], ['Shift+Enter', 'Insert newline'], ['@', 'Open file picker'], ['/', 'Slash command mode'], [kb('paste'), 'Paste (image priority)'], [`${kb('undo')} / ${kb('redo')}`, 'Undo / redo'], [kb('clear-prompt'), 'Clear prompt'], [kb('delete-word'), 'Delete word backward'], [kb('kill-line'), 'Kill to end of line']]);
|
|
99
|
-
category('Actions', [['Tab', 'Collapse/expand block'], [kb('bookmark'), 'Bookmark block'], [kb('block-copy'), 'Copy block to clipboard'], [kb('block-save'), 'Save block to file'], [kb('copy-selection'), 'Copy selection'], ['F2', '
|
|
100
|
-
category('
|
|
101
|
-
category('In-Panel Controls', [['j / k', 'Move selection down / up'], ['g / G', 'Jump to top / bottom'], ['/', 'Filter the list']]);
|
|
99
|
+
category('Actions', [['Tab', 'Collapse/expand block'], [kb('bookmark'), 'Bookmark block'], [kb('block-copy'), 'Copy block to clipboard'], [kb('block-save'), 'Save block to file'], [kb('copy-selection'), 'Copy selection'], ['F2', 'Agents'], ['?', 'Help overlay'], [`${kb('clear-cancel')} x2`, 'Exit']]);
|
|
100
|
+
category('Views', [[kb('command-palette'), 'Command palette: every command and view'], [`F2 / ${kb('open-agents')}`, 'Agents'], ['/usage', 'Usage: context, tokens and cost'], ['/changes', 'Changes: files, diff, review'], ['/notifications', 'Notification history'], ['Esc', 'Close the top modal (one level)']]);
|
|
102
101
|
const allBindings = km.getAll().map((entry) => [entry.combos.length > 0 ? entry.combos.map((combo) => km.formatCombo(combo)).join(', ') : '(unbound)', entry.description] as const);
|
|
103
102
|
category('All Bindings (live)', allBindings);
|
|
104
103
|
return { id: 'shortcuts', label: 'Shortcuts', rows, emptyText: 'No shortcuts recorded.' };
|
|
@@ -112,19 +111,12 @@ class KeybindingsModalSurface implements ConfigModalSurface {
|
|
|
112
111
|
if (id === 'refresh') { ctx.setStatus('Docs & shortcuts are read live.'); ctx.requestRender(); return; }
|
|
113
112
|
if (id !== 'activate') return;
|
|
114
113
|
if (ctx.tabId === 'tools') {
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
// tool DEFINITION, not a live process, so FleetPanel.receiveDeepLink
|
|
119
|
-
// will not currently find a match and shows its honest "node no longer
|
|
120
|
-
// present" line. The plumbing is still worth wiring now (matches the
|
|
121
|
-
// work-plan agent/wrfc jumps' shape), it starts resolving for free the
|
|
122
|
-
// day fleet grows a per-tool-call node (the retired DocsPanel's own
|
|
123
|
-
// comment already anticipated this: "no filter-by-tool equivalent
|
|
124
|
-
// there yet").
|
|
114
|
+
// The tool name rides as a `<tool>:tool` target: the Agents modal
|
|
115
|
+
// selects the first process whose current step is that tool, or says
|
|
116
|
+
// nothing is running it right now.
|
|
125
117
|
const toolName = ctx.row?.id.startsWith('tool:') ? ctx.row.id.slice('tool:'.length) : null;
|
|
126
|
-
void ctx.executeCommand?.('
|
|
127
|
-
ctx.setStatus(
|
|
118
|
+
void ctx.executeCommand?.('agents', toolName ? ['--target', `${toolName}:tool`] : []);
|
|
119
|
+
ctx.setStatus(toolName ? `Opened Agents on ${toolName}.` : 'Opened Agents.');
|
|
128
120
|
return;
|
|
129
121
|
}
|
|
130
122
|
if (ctx.tabId === 'models') {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MODAL_TONES } from './modal-theme.ts';
|
|
2
|
+
import { infoRow, headerRow } from './modal-surface-helpers.ts';
|
|
2
3
|
import type {
|
|
3
4
|
ConfigModalActionContext,
|
|
4
5
|
ConfigModalRow,
|
|
@@ -11,10 +12,10 @@ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
12
13
|
// Knowledge (graph) → config-modal surface (group-B port). Two tabs:
|
|
13
14
|
// 'Browse' (sources/nodes/issues + schedules) and 'Review' (the open-issue
|
|
14
|
-
// queue), the
|
|
15
|
+
// queue), the earlier view's browse/review toggle, now host tabs. Issue review
|
|
15
16
|
// mutations (accept/reject/resolve/reopen) route to the `/knowledge
|
|
16
17
|
// review-issue` command. 'm' cross-opens the memory surface. Selection-blind
|
|
17
|
-
// port: the
|
|
18
|
+
// port: the earlier view's selected-row id/detail is folded into each row label.
|
|
18
19
|
// refresh() is the only place this module touches the SDK.
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
20
21
|
|
|
@@ -108,8 +109,8 @@ class KnowledgeModalSurface implements ConfigModalSurface {
|
|
|
108
109
|
];
|
|
109
110
|
const rows: ConfigModalRow[] = this.browseRows.map((row) => this.rowFor(row));
|
|
110
111
|
if (this.schedules.length > 0) {
|
|
111
|
-
rows.push(
|
|
112
|
-
this.schedules.slice(0, 4).forEach((s, i) => rows.push(infoRow(`sched:${i}`, `${s.enabled ? 'on ' : 'off'} ${s.label}`, s.enabled ? undefined : {
|
|
112
|
+
rows.push(headerRow('sched:title', 'Schedules'));
|
|
113
|
+
this.schedules.slice(0, 4).forEach((s, i) => rows.push(infoRow(`sched:${i}`, `${s.enabled ? 'on ' : 'off'} ${s.label}`, s.enabled ? undefined : { fg: MODAL_TONES.dim })));
|
|
113
114
|
}
|
|
114
115
|
return { id: 'browse', label: 'Browse', header, rows, emptyText: 'No ingested knowledge yet.', hints: ['m memory'] };
|
|
115
116
|
}
|
|
@@ -5,7 +5,7 @@ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
|
5
5
|
import { postureLine, kv } from './modal-surface-helpers.ts';
|
|
6
6
|
|
|
7
7
|
/** Mutation surface the surface needs to gate p/d/b on, a subset of UserAuthManager,
|
|
8
|
-
* mirroring
|
|
8
|
+
* mirroring the retired local-auth view's own `hasLocalAuthMutations` guard. */
|
|
9
9
|
type LocalAuthMutations = Pick<UserAuthManager, 'addUser' | 'deleteUser' | 'rotatePassword' | 'clearBootstrapCredentialFile'>;
|
|
10
10
|
|
|
11
11
|
function hasLocalAuthMutations(value: LocalAuthInspectionQuery): value is LocalAuthInspectionQuery & LocalAuthMutations {
|
|
@@ -25,14 +25,13 @@ function usernameOf(row: ConfigModalRow | null): string | null {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Local-auth config-modal surface (
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* transcript. This surface never renders, accepts, or holds a password.
|
|
28
|
+
* Local-auth config-modal surface. `inspect()` is synchronous, so buildView
|
|
29
|
+
* reads it live every tick. add-user and rotate-password open the masked
|
|
30
|
+
* password prompt (input/masked-entry-modal.ts) on top of this modal, the one
|
|
31
|
+
* path that keeps a plaintext password out of argv, history and the
|
|
32
|
+
* transcript; delete-user and clear-bootstrap-file dispatch through the
|
|
33
|
+
* `/local-auth` command. This surface never renders, accepts, or holds a
|
|
34
|
+
* password.
|
|
36
35
|
*/
|
|
37
36
|
class LocalAuthModalSurface implements ConfigModalSurface {
|
|
38
37
|
readonly name = 'local-auth-modal';
|
|
@@ -42,7 +41,10 @@ class LocalAuthModalSurface implements ConfigModalSurface {
|
|
|
42
41
|
* consulted; see settings-sync-modal's `hasStaged` for the same idiom). */
|
|
43
42
|
private bootstrapPresent = false;
|
|
44
43
|
|
|
45
|
-
constructor(
|
|
44
|
+
constructor(
|
|
45
|
+
private readonly authManager: LocalAuthInspectionQuery,
|
|
46
|
+
private readonly openMaskedEntry: (kind: 'add-user' | 'rotate-password', username?: string) => void,
|
|
47
|
+
) {}
|
|
46
48
|
|
|
47
49
|
readonly actions: ConfigModalAction[] = [
|
|
48
50
|
{ key: 'a', id: 'add-user', label: 'add user' },
|
|
@@ -93,20 +95,16 @@ class LocalAuthModalSurface implements ConfigModalSurface {
|
|
|
93
95
|
|
|
94
96
|
onAction(id: string, ctx: ConfigModalActionContext): void {
|
|
95
97
|
switch (id) {
|
|
96
|
-
//
|
|
97
|
-
// which renders on the LocalAuthPanel and cannot draw or capture input
|
|
98
|
-
// underneath this fullscreen modal. Point the operator at the command
|
|
99
|
-
// (which opens masked entry) rather than dispatching it into a hidden
|
|
100
|
-
// surface, the secure flow stays a keystroke away, just not from here.
|
|
98
|
+
// The password prompt opens on top of this modal and never echoes.
|
|
101
99
|
case 'add-user':
|
|
102
|
-
ctx.
|
|
103
|
-
|
|
100
|
+
if (!hasLocalAuthMutations(this.authManager)) { ctx.setStatus('Local auth mutations are not available in this session.'); break; }
|
|
101
|
+
this.openMaskedEntry('add-user');
|
|
104
102
|
break;
|
|
105
103
|
case 'rotate-pw': {
|
|
106
104
|
const username = usernameOf(ctx.row);
|
|
107
105
|
if (!username) return;
|
|
108
|
-
ctx.
|
|
109
|
-
|
|
106
|
+
if (!hasLocalAuthMutations(this.authManager)) { ctx.setStatus('Local auth mutations are not available in this session.'); break; }
|
|
107
|
+
this.openMaskedEntry('rotate-password', username);
|
|
110
108
|
break;
|
|
111
109
|
}
|
|
112
110
|
case 'delete': {
|
|
@@ -127,6 +125,9 @@ class LocalAuthModalSurface implements ConfigModalSurface {
|
|
|
127
125
|
}
|
|
128
126
|
}
|
|
129
127
|
|
|
130
|
-
export function createLocalAuthModalSurface(
|
|
131
|
-
|
|
128
|
+
export function createLocalAuthModalSurface(
|
|
129
|
+
authManager: LocalAuthInspectionQuery,
|
|
130
|
+
openMaskedEntry: (kind: 'add-user' | 'rotate-password', username?: string) => void = () => {},
|
|
131
|
+
): ConfigModalSurface {
|
|
132
|
+
return new LocalAuthModalSurface(authManager, openMaskedEntry);
|
|
132
133
|
}
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
ConfigModalView,
|
|
6
6
|
} from '../../input/config-modal-types.ts';
|
|
7
7
|
import { MODAL_TONES } from './modal-theme.ts';
|
|
8
|
-
import { infoRow } from './modal-surface-helpers.ts';
|
|
8
|
+
import { infoRow, headerRow } from './modal-surface-helpers.ts';
|
|
9
9
|
import {
|
|
10
10
|
loadEcosystemCatalog,
|
|
11
11
|
listInstalledEcosystemEntries,
|
|
@@ -20,7 +20,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
|
|
|
20
20
|
import { tmpdir } from 'node:os';
|
|
21
21
|
import { join } from 'node:path';
|
|
22
22
|
|
|
23
|
-
/** Live deps the marketplace modal captures (mirrors the
|
|
23
|
+
/** Live deps the marketplace modal captures (mirrors the earlier view factory). */
|
|
24
24
|
export interface MarketplaceModalDeps {
|
|
25
25
|
readonly readModel?: UiReadModel<UiMarketplaceSnapshot>;
|
|
26
26
|
readonly ecosystemPaths?: EcosystemCatalogPathOptions;
|
|
@@ -41,16 +41,16 @@ const KINDS: readonly EcosystemEntryKind[] = ['plugin', 'skill', 'hook-pack', 'p
|
|
|
41
41
|
* Marketplace → config-modal surface (group-B port). Local-first
|
|
42
42
|
* publish/import catalog (NOT a remote store) with provenance, compatibility,
|
|
43
43
|
* and install posture. Disk catalog loads happen in refresh() (never in
|
|
44
|
-
* buildView), mirroring the
|
|
44
|
+
* buildView), mirroring the earlier view's explicit render()/refresh() split.
|
|
45
45
|
* Install/uninstall route to the `/marketplace` command path (charter: no
|
|
46
46
|
* destructive confirm folded into a modal).
|
|
47
47
|
*
|
|
48
|
-
* Honest empty-state: the
|
|
48
|
+
* Honest empty-state: the earlier view's original "No curated marketplace
|
|
49
49
|
* entries found yet." copy implied a curated remote catalog. It isn't one,
|
|
50
50
|
* loadEcosystemCatalog only ever reads .goodvibes/ecosystem/<kind>s.json under
|
|
51
51
|
* the project/home, populated solely by `/marketplace publish` and
|
|
52
52
|
* `/marketplace bundle import`. The empty-state copy below (locked byte-for-byte
|
|
53
|
-
* in the golden) names that reality. Selection-blind port: the
|
|
53
|
+
* in the golden) names that reality. Selection-blind port: the earlier view's
|
|
54
54
|
* selected-entry compatibility/risk/state detail is folded into each row label.
|
|
55
55
|
*/
|
|
56
56
|
class MarketplaceModalSurface implements ConfigModalSurface {
|
|
@@ -129,10 +129,10 @@ class MarketplaceModalSurface implements ConfigModalSurface {
|
|
|
129
129
|
rows.push(infoRow('empty:0', 'This is your local plugin, skill, hook-pack, and policy-pack catalog; not a remote store.'));
|
|
130
130
|
rows.push(infoRow('empty:1', "It's empty because nothing has been published or imported into this workspace yet. Entries appear here once you publish a local component or import a bundle."));
|
|
131
131
|
}
|
|
132
|
-
rows.push(
|
|
133
|
-
rows.push(infoRow('empty:publish', '/marketplace publish <kind> <path> — publish local plugins/skills into the catalog', {
|
|
134
|
-
rows.push(infoRow('empty:import', '/marketplace bundle import <path> — import a catalog bundle from disk', {
|
|
135
|
-
rows.push(infoRow('empty:review', '/marketplace catalog review — inspect the current local catalog posture', {
|
|
132
|
+
rows.push(headerRow('empty:title', 'Populate it'));
|
|
133
|
+
rows.push(infoRow('empty:publish', '/marketplace publish <kind> <path> — publish local plugins/skills into the catalog', { fg: MODAL_TONES.dim }));
|
|
134
|
+
rows.push(infoRow('empty:import', '/marketplace bundle import <path> — import a catalog bundle from disk', { fg: MODAL_TONES.dim }));
|
|
135
|
+
rows.push(infoRow('empty:review', '/marketplace catalog review — inspect the current local catalog posture', { fg: MODAL_TONES.dim }));
|
|
136
136
|
return {
|
|
137
137
|
title: 'Marketplace',
|
|
138
138
|
tabs: [{ id: 'catalog', label: 'Catalog', rows, emptyText: '' }],
|
|
@@ -165,9 +165,9 @@ class MarketplaceModalSurface implements ConfigModalSurface {
|
|
|
165
165
|
// Recommendations (displayed with their command; digit-jump dropped).
|
|
166
166
|
const recommendations = snapshot?.recommendations ?? [];
|
|
167
167
|
if (recommendations.length > 0) {
|
|
168
|
-
rows.push(
|
|
168
|
+
rows.push(headerRow('rec:title', 'Recommended'));
|
|
169
169
|
for (const [i, rec] of recommendations.slice(0, 3).entries()) {
|
|
170
|
-
rows.push(infoRow(`rec:${i}`, `${rec.title}: ${rec.command}`, {
|
|
170
|
+
rows.push(infoRow(`rec:${i}`, `${rec.title}: ${rec.command}`, { fg: MODAL_TONES.dim }));
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -13,12 +13,12 @@ import { classifyConsolidationFetchError } from '../memory-consolidation-gateway
|
|
|
13
13
|
// ---------------------------------------------------------------------------
|
|
14
14
|
// Memory → config-modal surface (group-B port). Two tabs: 'All Records'
|
|
15
15
|
// (the full record list) and 'Review Queue' (the operator review queue), the
|
|
16
|
-
// same split the
|
|
16
|
+
// same split the earlier view toggled with Tab, now real host tabs. Review-state
|
|
17
17
|
// mutations (reviewed/stale/contradicted/fresh) and record delete route to the
|
|
18
18
|
// existing `/recall review` / `/recall remove` command path (charter: no
|
|
19
19
|
// destructive mutation direct-called from a modal). Selection-blind port: the
|
|
20
|
-
//
|
|
21
|
-
// each row label. `memoryRegistry` absent → the retired
|
|
20
|
+
// view's selected-record scope/class/tags/provenance detail is folded into
|
|
21
|
+
// each row label. `memoryRegistry` absent → the retired Memory view's
|
|
22
22
|
// "not configured" copy renders as an honest degraded state.
|
|
23
23
|
//
|
|
24
24
|
// Read path (memory-spine adoption): reads go through the spine client's
|
|
@@ -68,7 +68,7 @@ export interface MemoryModalDeps {
|
|
|
68
68
|
/**
|
|
69
69
|
* Resolve the memory-consolidation-receipts gateway (memory-consolidation-gateway.ts),
|
|
70
70
|
* lazily, called fresh each time the Proposals tab (re)fetches, exactly like
|
|
71
|
-
* the
|
|
71
|
+
* the Agents modal's `resolveGateway` (fleet-gateway.ts / fleet-acts.ts). Absent
|
|
72
72
|
* in a session with no daemon-backed control plane wired: the Proposals tab
|
|
73
73
|
* then renders its "unavailable" honest state without ever attempting a fetch.
|
|
74
74
|
*/
|
|
@@ -105,8 +105,8 @@ function rankForReview(records: readonly MemoryRecordLike[], limit: number): Mem
|
|
|
105
105
|
.slice(0, limit);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
// Mirrors
|
|
109
|
-
// retired
|
|
108
|
+
// Mirrors the retired knowledge-view registration's withUnconfiguredFallback copy for the
|
|
109
|
+
// retired memory view verbatim.
|
|
110
110
|
const NOT_CONFIGURED_TITLE = 'Memory registry not configured for this session.';
|
|
111
111
|
const NOT_CONFIGURED_BODY = 'This runtime was not wired with a project memory registry at bootstrap, so no memory data is available.';
|
|
112
112
|
|
|
@@ -324,8 +324,8 @@ class MemoryModalSurface implements ConfigModalSurface {
|
|
|
324
324
|
};
|
|
325
325
|
switch (id) {
|
|
326
326
|
case 'markReviewed': review('reviewed', Math.max(record.confidence, 85)); break;
|
|
327
|
-
case 'markStale': review('stale', Math.min(record.confidence, 40), 'marked stale from the memory
|
|
328
|
-
case 'markContradicted': review('contradicted', 0, 'marked contradicted from the memory
|
|
327
|
+
case 'markStale': review('stale', Math.min(record.confidence, 40), 'marked stale from the memory modal'); break;
|
|
328
|
+
case 'markContradicted': review('contradicted', 0, 'marked contradicted from the memory modal'); break;
|
|
329
329
|
case 'markFresh': review('fresh', Math.max(record.confidence, 60)); break;
|
|
330
330
|
case 'remove': void ctx.executeCommand?.('recall', ['remove', record.id]); ctx.setStatus(`Dispatched /recall remove ${record.id}.`); break;
|
|
331
331
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { ModalSectionStyle } from '../../
|
|
1
|
+
import { DEFAULT_VIEW_PALETTE } from '../polish.ts';
|
|
2
|
+
import type { ModalSectionStyle } from '../../input/config-modal-types.ts';
|
|
3
3
|
import type { ConfigModalRow } from '../../input/config-modal-types.ts';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Shared formatting helpers for config-modal surfaces. Row styling reuses
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* DEFAULT_VIEW_PALETTE (theme tokens). The frame, tabs, search row, group
|
|
8
|
+
* headers and keycap hints are drawn by the modal surface kit in
|
|
9
|
+
* renderConfigModal; surfaces only describe rows.
|
|
9
10
|
*/
|
|
10
|
-
export const PALETTE =
|
|
11
|
+
export const PALETTE = DEFAULT_VIEW_PALETTE;
|
|
11
12
|
|
|
12
13
|
export type Tone = 'good' | 'bad' | 'warn' | 'info' | 'dim' | 'value';
|
|
13
14
|
|
|
@@ -52,3 +53,12 @@ export function postureLine(cells: string[]): string {
|
|
|
52
53
|
export function infoRow(id: string, label: string, style?: ModalSectionStyle): ConfigModalRow {
|
|
53
54
|
return { id, label, selectable: false, ...(style ? { style } : {}) };
|
|
54
55
|
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A group header row (a section title such as "Next steps"). The kit draws it
|
|
59
|
+
* as a ✦ lowercase accent header with a blank row above it; it is never
|
|
60
|
+
* selectable and never filtered out by the search row.
|
|
61
|
+
*/
|
|
62
|
+
export function headerRow(id: string, label: string): ConfigModalRow {
|
|
63
|
+
return { id, label, selectable: false, header: true };
|
|
64
|
+
}
|
|
@@ -86,7 +86,7 @@ export interface PairingModalDeps {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// Fixed-width placeholder, deliberately NOT derived from the real secret's
|
|
89
|
-
// length (mirrors
|
|
89
|
+
// length (mirrors the retired pairing view's SECRET_MASK), so masking doesn't leak length.
|
|
90
90
|
const SECRET_MASK = '••••••••••••';
|
|
91
91
|
|
|
92
92
|
class PairingModalSurface implements ConfigModalSurface {
|
|
@@ -149,20 +149,20 @@ class PairingModalSurface implements ConfigModalSurface {
|
|
|
149
149
|
const displayLink = this.revealed ? deepLink : SECRET_MASK;
|
|
150
150
|
|
|
151
151
|
const rows: ConfigModalRow[] = [];
|
|
152
|
-
rows.push(infoRow('intro', 'Scan with the GoodVibes web app to pair this device; it opens already signed in.', {
|
|
152
|
+
rows.push(infoRow('intro', 'Scan with the GoodVibes web app to pair this device; it opens already signed in.', { fg: MODAL_TONES.dim }));
|
|
153
153
|
rows.push(infoRow('url', `Web app ${url}`));
|
|
154
154
|
rows.push(infoRow('name', `Device ${tokenName}`));
|
|
155
155
|
rows.push(infoRow('token', `Token ${displayToken}`, { fg: MODAL_TONES.reasoning }));
|
|
156
|
-
rows.push(infoRow('link', `Link ${displayLink}`, {
|
|
156
|
+
rows.push(infoRow('link', `Link ${displayLink}`, { fg: MODAL_TONES.dim }));
|
|
157
157
|
if (this.deps.controlPlaneReadModel) {
|
|
158
158
|
const connected = this.deps.controlPlaneReadModel.getSnapshot().activeClientIds.length;
|
|
159
|
-
rows.push(infoRow('companions', `Devices connected: ${connected}`, connected > 0 ? { fg: MODAL_TONES.good } : {
|
|
159
|
+
rows.push(infoRow('companions', `Devices connected: ${connected}`, connected > 0 ? { fg: MODAL_TONES.good } : { fg: MODAL_TONES.dim }));
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
// The offer set carried by this pairing, each named with its plain-language
|
|
163
163
|
// consequence, each declinable in the web app.
|
|
164
164
|
if (offers.length > 0) {
|
|
165
|
-
rows.push(infoRow('offers-h', 'Offers (each declinable when you pair):', {
|
|
165
|
+
rows.push(infoRow('offers-h', 'Offers (each declinable when you pair):', { fg: MODAL_TONES.dim }));
|
|
166
166
|
formatPairingOffers(offers).forEach((line, i) => rows.push(infoRow(`offer:${i}`, line)));
|
|
167
167
|
}
|
|
168
168
|
// The labeled browser-capability list, what the paired device actually gets
|
|
@@ -170,7 +170,7 @@ class PairingModalSurface implements ConfigModalSurface {
|
|
|
170
170
|
// never hidden behind a dead button.
|
|
171
171
|
const capabilities = formatPostureCapabilities(posture);
|
|
172
172
|
if (capabilities.length > 0) {
|
|
173
|
-
rows.push(infoRow('caps-h', 'This device will get:', {
|
|
173
|
+
rows.push(infoRow('caps-h', 'This device will get:', { fg: MODAL_TONES.dim }));
|
|
174
174
|
capabilities.forEach((line, i) => rows.push(infoRow(`cap:${i}`, line)));
|
|
175
175
|
}
|
|
176
176
|
// The ONE honest LAN line, the SDK posture's own notice (LAN_PLAIN_HTTP_NOTICE),
|
|
@@ -205,16 +205,16 @@ class PairingModalSurface implements ConfigModalSurface {
|
|
|
205
205
|
if (!ts || !ts.available) return; // absence stays quiet
|
|
206
206
|
const httpsUrl = this.serveReceipt?.url ?? ts.httpsUrl;
|
|
207
207
|
if (httpsUrl) {
|
|
208
|
-
rows.push(infoRow('ts-h', 'Encrypted access (Tailscale):', {
|
|
208
|
+
rows.push(infoRow('ts-h', 'Encrypted access (Tailscale):', { fg: MODAL_TONES.dim }));
|
|
209
209
|
rows.push(infoRow('ts-url', ` ${httpsUrl}`, { fg: MODAL_TONES.good }));
|
|
210
210
|
} else {
|
|
211
211
|
rows.push(infoRow('ts-h', 'Tailscale detected: press t to serve this app over https (MagicDNS).', { fg: MODAL_TONES.reasoning }));
|
|
212
212
|
}
|
|
213
213
|
const receipt = this.serveReceipt ?? ts.lastServe;
|
|
214
214
|
if (receipt) {
|
|
215
|
-
rows.push(infoRow('ts-receipt', ` ${receipt.ok ? '✓' : '✗'} ${receipt.detail}`, receipt.ok ? {
|
|
215
|
+
rows.push(infoRow('ts-receipt', ` ${receipt.ok ? '✓' : '✗'} ${receipt.detail}`, receipt.ok ? { fg: MODAL_TONES.dim } : { fg: MODAL_TONES.warn }));
|
|
216
216
|
} else if (this.serving) {
|
|
217
|
-
rows.push(infoRow('ts-serving', ' Serving over tailscale…', {
|
|
217
|
+
rows.push(infoRow('ts-serving', ' Serving over tailscale…', { fg: MODAL_TONES.dim }));
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
|
|
@@ -53,11 +53,6 @@ interface PlanningModalSnapshot {
|
|
|
53
53
|
|
|
54
54
|
interface TextLine { readonly content: string; readonly fg?: string; }
|
|
55
55
|
|
|
56
|
-
const GOOD = MODAL_TONES.good;
|
|
57
|
-
const WARN = MODAL_TONES.warn;
|
|
58
|
-
const BAD = MODAL_TONES.bad;
|
|
59
|
-
const INFO = MODAL_TONES.info;
|
|
60
|
-
|
|
61
56
|
function getCurrentQuestion(state: ProjectPlanningState, evaluation: ProjectPlanningEvaluation | null): ProjectPlanningQuestion | null {
|
|
62
57
|
const open = state.openQuestions.find((question) => (question.status ?? 'open') === 'open');
|
|
63
58
|
return open ?? evaluation?.nextQuestion ?? null;
|
|
@@ -65,7 +60,7 @@ function getCurrentQuestion(state: ProjectPlanningState, evaluation: ProjectPlan
|
|
|
65
60
|
|
|
66
61
|
function buildStateLines(state: ProjectPlanningState, evaluation: ProjectPlanningEvaluation | null): TextLine[] {
|
|
67
62
|
const readiness = evaluation?.readiness ?? state.readiness;
|
|
68
|
-
const readinessColor = readiness === 'executable' ?
|
|
63
|
+
const readinessColor = readiness === 'executable' ? MODAL_TONES.good : readiness === 'needs-user-input' ? MODAL_TONES.warn : undefined;
|
|
69
64
|
const blockingGaps = (evaluation?.gaps ?? []).filter((gap) => gap.severity === 'blocking').length;
|
|
70
65
|
const lines: TextLine[] = [
|
|
71
66
|
{ content: `readiness ${readiness} approved ${state.executionApproved ? 'yes' : 'no'} questions ${state.openQuestions.length} open / ${state.answeredQuestions.length} answered`, ...(readinessColor ? { fg: readinessColor } : {}) },
|
|
@@ -74,14 +69,14 @@ function buildStateLines(state: ProjectPlanningState, evaluation: ProjectPlannin
|
|
|
74
69
|
];
|
|
75
70
|
if (state.scope) lines.push({ content: `scope: ${state.scope}` });
|
|
76
71
|
if (state.knownContext.length) lines.push({ content: `known context: ${state.knownContext.join(' | ')}` });
|
|
77
|
-
if (evaluation?.nextQuestion) lines.push({ content: `next question: ${evaluation.nextQuestion.prompt}`, fg:
|
|
72
|
+
if (evaluation?.nextQuestion) lines.push({ content: `next question: ${evaluation.nextQuestion.prompt}`, fg: MODAL_TONES.info });
|
|
78
73
|
return lines;
|
|
79
74
|
}
|
|
80
75
|
|
|
81
76
|
function buildGapsLines(evaluation: ProjectPlanningEvaluation | null): TextLine[] {
|
|
82
77
|
const gaps = evaluation?.gaps ?? [];
|
|
83
|
-
if (gaps.length === 0) return [{ content: 'Readiness gaps: none.', fg:
|
|
84
|
-
return [{ content: 'Readiness gaps:' }, ...gaps.slice(0, 12).map((gap) => ({ content: ` ${gap.severity.toUpperCase()} ${gap.kind}: ${gap.message}`, fg: gap.severity === 'blocking' ?
|
|
78
|
+
if (gaps.length === 0) return [{ content: 'Readiness gaps: none.', fg: MODAL_TONES.good }];
|
|
79
|
+
return [{ content: 'Readiness gaps:' }, ...gaps.slice(0, 12).map((gap) => ({ content: ` ${gap.severity.toUpperCase()} ${gap.kind}: ${gap.message}`, fg: gap.severity === 'blocking' ? MODAL_TONES.bad : MODAL_TONES.warn }))];
|
|
85
80
|
}
|
|
86
81
|
|
|
87
82
|
function buildTasksLines(state: ProjectPlanningState): TextLine[] {
|
|
@@ -90,18 +85,18 @@ function buildTasksLines(state: ProjectPlanningState): TextLine[] {
|
|
|
90
85
|
lines.push({ content: ' No decomposed tasks recorded yet.' });
|
|
91
86
|
} else {
|
|
92
87
|
for (const task of state.tasks) {
|
|
93
|
-
lines.push({ content: ` ${task.id}: ${task.title} [${task.status ?? 'pending'}]${task.canRunConcurrently ? ' - concurrent' : ''}`, ...(task.blockedOnUserInput ? { fg:
|
|
88
|
+
lines.push({ content: ` ${task.id}: ${task.title} [${task.status ?? 'pending'}]${task.canRunConcurrently ? ' - concurrent' : ''}`, ...(task.blockedOnUserInput ? { fg: MODAL_TONES.warn } : {}) });
|
|
94
89
|
if (task.dependencies?.length) lines.push({ content: ` dependencies: ${task.dependencies.join(', ')}` });
|
|
95
|
-
if (task.verification?.length) lines.push({ content: ` verification: ${task.verification.join(' | ')}`, fg:
|
|
90
|
+
if (task.verification?.length) lines.push({ content: ` verification: ${task.verification.join(' | ')}`, fg: MODAL_TONES.good });
|
|
96
91
|
}
|
|
97
92
|
}
|
|
98
93
|
if (state.verificationGates.length) {
|
|
99
94
|
lines.push({ content: 'Verification gates:' });
|
|
100
|
-
for (const gate of state.verificationGates) lines.push({ content: ` ${gate.id}: ${gate.description} [${gate.status ?? 'pending'}]`, fg: gate.required === false ? undefined :
|
|
95
|
+
for (const gate of state.verificationGates) lines.push({ content: ` ${gate.id}: ${gate.description} [${gate.status ?? 'pending'}]`, fg: gate.required === false ? undefined : MODAL_TONES.good });
|
|
101
96
|
}
|
|
102
97
|
if (state.agentAssignments.length) {
|
|
103
98
|
lines.push({ content: 'Agent handoff candidates:' });
|
|
104
|
-
for (const assignment of state.agentAssignments) lines.push({ content: ` ${assignment.taskId}: ${assignment.agentType ?? 'none'}${assignment.canRunConcurrently ? ' - can run concurrently' : ''}`, fg:
|
|
99
|
+
for (const assignment of state.agentAssignments) lines.push({ content: ` ${assignment.taskId}: ${assignment.agentType ?? 'none'}${assignment.canRunConcurrently ? ' - can run concurrently' : ''}`, fg: MODAL_TONES.info });
|
|
105
100
|
}
|
|
106
101
|
return lines;
|
|
107
102
|
}
|
|
@@ -111,7 +106,7 @@ function buildDecisionsLines(state: ProjectPlanningState, storedDecisions: reado
|
|
|
111
106
|
for (const decision of [...storedDecisions, ...state.decisions]) byId.set(decision.id, decision);
|
|
112
107
|
const decisions = [...byId.values()];
|
|
113
108
|
if (decisions.length === 0) return [{ content: 'Decisions: none recorded yet.' }];
|
|
114
|
-
return [{ content: 'Decisions:' }, ...decisions.slice(0, 12).map((decision) => ({ content: ` ${decision.title}: ${decision.decision} [${decision.status ?? 'accepted'}]`, fg: decision.status === 'rejected' ?
|
|
109
|
+
return [{ content: 'Decisions:' }, ...decisions.slice(0, 12).map((decision) => ({ content: ` ${decision.title}: ${decision.decision} [${decision.status ?? 'accepted'}]`, fg: decision.status === 'rejected' ? MODAL_TONES.bad : undefined }))];
|
|
115
110
|
}
|
|
116
111
|
|
|
117
112
|
function buildLanguageLines(language: ProjectPlanningLanguageArtifact | null): TextLine[] {
|
|
@@ -119,9 +114,9 @@ function buildLanguageLines(language: ProjectPlanningLanguageArtifact | null): T
|
|
|
119
114
|
const lines: TextLine[] = [{ content: 'Project language:' }];
|
|
120
115
|
for (const term of language.terms.slice(0, 8)) {
|
|
121
116
|
lines.push({ content: ` ${term.term}: ${term.definition}` });
|
|
122
|
-
if (term.avoid?.length) lines.push({ content: ` avoid: ${term.avoid.join(', ')}`, fg:
|
|
117
|
+
if (term.avoid?.length) lines.push({ content: ` avoid: ${term.avoid.join(', ')}`, fg: MODAL_TONES.bad });
|
|
123
118
|
}
|
|
124
|
-
for (const ambiguity of language.ambiguities.slice(0, 8)) lines.push({ content: ` resolved ambiguity - ${ambiguity.phrase}: ${ambiguity.resolution}`, fg:
|
|
119
|
+
for (const ambiguity of language.ambiguities.slice(0, 8)) lines.push({ content: ` resolved ambiguity - ${ambiguity.phrase}: ${ambiguity.resolution}`, fg: MODAL_TONES.info });
|
|
125
120
|
return lines;
|
|
126
121
|
}
|
|
127
122
|
|
|
@@ -177,7 +172,7 @@ class PlanningModalSurface implements ConfigModalSurface {
|
|
|
177
172
|
|
|
178
173
|
buildView(): ConfigModalView {
|
|
179
174
|
if (!this.snapshot) {
|
|
180
|
-
return { title: 'Planning', tabs: [{ id: 'planning', label: 'Planning', rows: [infoRow('load', this.loading ? 'Loading project planning state...' : 'Project planning state unavailable.', {
|
|
175
|
+
return { title: 'Planning', tabs: [{ id: 'planning', label: 'Planning', rows: [infoRow('load', this.loading ? 'Loading project planning state...' : 'Project planning state unavailable.', { fg: MODAL_TONES.dim })] }], hints: ['r refresh'] };
|
|
181
176
|
}
|
|
182
177
|
|
|
183
178
|
const { status, state, evaluation, decisions, language } = this.snapshot;
|
|
@@ -197,9 +192,9 @@ class PlanningModalSurface implements ConfigModalSurface {
|
|
|
197
192
|
const { question, actions } = this.currentAnswerActions();
|
|
198
193
|
if (question) {
|
|
199
194
|
line({ content: 'Answer Current Question' });
|
|
200
|
-
line({ content: question.prompt, fg:
|
|
195
|
+
line({ content: question.prompt, fg: MODAL_TONES.info });
|
|
201
196
|
if (question.whyItMatters) line({ content: `Why this matters: ${question.whyItMatters}` });
|
|
202
|
-
if (question.recommendedAnswer && !isGenericRecommendation(question.recommendedAnswer)) line({ content: `Recommendation: ${question.recommendedAnswer}`, fg:
|
|
197
|
+
if (question.recommendedAnswer && !isGenericRecommendation(question.recommendedAnswer)) line({ content: `Recommendation: ${question.recommendedAnswer}`, fg: MODAL_TONES.good });
|
|
203
198
|
for (const action of actions) {
|
|
204
199
|
rows.push({ id: action.id, label: `${action.label} - ${action.detail}`, ...(action.disabled ? { selectable: false } : {}) });
|
|
205
200
|
}
|
|
@@ -270,7 +265,7 @@ function buildGoldenService(): PlanningModalService {
|
|
|
270
265
|
openQuestions: [{ id: 'golden-question-1', prompt: 'What is in scope for this golden fixture?', whyItMatters: 'Keeps the render deterministic.', recommendedAnswer: 'Use a focused first-pass scope for this goal.', status: 'open' }],
|
|
271
266
|
answeredQuestions: [{ id: 'golden-question-0', prompt: 'Is this a golden fixture?', status: 'answered', answer: 'Yes.', answeredAt: 0 }],
|
|
272
267
|
decisions: [], assumptions: [], constraints: [], risks: [],
|
|
273
|
-
tasks: [{ id: 'golden-task-1', title: 'Implement the golden fixture', status: 'pending', dependencies: [], verification: ['bun test src/test/
|
|
268
|
+
tasks: [{ id: 'golden-task-1', title: 'Implement the golden fixture', status: 'pending', dependencies: [], verification: ['bun test src/test/views/modals/planning-modal.test.ts'] }],
|
|
274
269
|
dependencies: [], verificationGates: [{ id: 'golden-gate-1', description: 'Golden render is byte-stable.', status: 'pending', required: true }],
|
|
275
270
|
agentAssignments: [{ taskId: 'golden-task-1', agentType: 'worker', canRunConcurrently: false }],
|
|
276
271
|
readiness: 'needs-user-input', executionApproved: false, createdAt: 0, updatedAt: 0,
|