@pellux/goodvibes-tui 2.0.21 → 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 +58 -0
- package/README.md +16 -16
- package/docs/README.md +4 -4
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- 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 type { Tool } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
-
import type
|
|
2
|
+
import { askDelegatesToAgent, askForbidsWrites, type ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
3
3
|
|
|
4
4
|
type AgentToolArgs = {
|
|
5
5
|
readonly mode?: unknown;
|
|
@@ -92,6 +92,18 @@ export function normalizeWrfcAgentToolInvocation(args: AgentToolArgs, options: W
|
|
|
92
92
|
const lastUserMessage = cleanText(options.getLastUserMessage?.() ?? null);
|
|
93
93
|
const trace = options.onTrace;
|
|
94
94
|
if (args.mode === 'spawn') {
|
|
95
|
+
// The user's own "do not modify files" outranks every promotion below: a
|
|
96
|
+
// write-review-fix chain's fix phase writes files, so a read-only ask
|
|
97
|
+
// (a review, an audit) runs as a plain agent with the task the model
|
|
98
|
+
// delegated. The SDK applies the same rule (rootSpawnIsReadOnlyAsk).
|
|
99
|
+
if (askForbidsWrites(lastUserMessage || cleanText(args.task))) {
|
|
100
|
+
trace?.({
|
|
101
|
+
kind: 'spawn-suppressed-wrfc',
|
|
102
|
+
reason: 'the request forbids writing files',
|
|
103
|
+
task: cleanText(args.task) || '(no task)',
|
|
104
|
+
});
|
|
105
|
+
return { ...args, reviewMode: 'none', dangerously_disable_wrfc: true };
|
|
106
|
+
}
|
|
95
107
|
if (shouldRouteSpawnToWrfc(args)) {
|
|
96
108
|
const reason = resolveSpawnWrfcReason(args);
|
|
97
109
|
trace?.({
|
|
@@ -264,8 +276,16 @@ function isReadOnlyTask(text: string): boolean {
|
|
|
264
276
|
return /^\s*(?:inspect|research|read|find|list|summarize|analy[sz]e|explain|report|investigate|document|describe|audit|evaluate|assess|check|compare|tell|show)\b/i.test(text);
|
|
265
277
|
}
|
|
266
278
|
|
|
279
|
+
/**
|
|
280
|
+
* The chain's task: the user's own words, unless those words are an
|
|
281
|
+
* instruction to delegate ("Spawn one agent to …"). The agent being spawned
|
|
282
|
+
* IS that delegation, so its task is the work the model extracted; handed the
|
|
283
|
+
* delegation instruction itself, an agent without the agent tool can only fail.
|
|
284
|
+
*/
|
|
267
285
|
function selectAuthoritativeTask(candidate: unknown, lastUserMessage: string): string {
|
|
268
|
-
|
|
286
|
+
const delegated = cleanText(candidate);
|
|
287
|
+
if (lastUserMessage && askDelegatesToAgent(lastUserMessage) && delegated) return delegated;
|
|
288
|
+
return lastUserMessage || delegated;
|
|
269
289
|
}
|
|
270
290
|
|
|
271
291
|
function uniqueStrings(groups: readonly unknown[]): string[] | undefined {
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared ms-duration formatters for the
|
|
2
|
+
* Shared ms-duration formatters for the view layer.
|
|
3
3
|
*
|
|
4
4
|
* Two families are exported, each matching a distinct behavior cluster.
|
|
5
5
|
* DO NOT replace these with formatElapsed from utils/format-elapsed.ts,
|
|
6
6
|
* formatElapsed floors to integer seconds and lacks the null/'?ms' guards
|
|
7
|
-
* that the latency
|
|
7
|
+
* that the latency views require.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* was removed as a genuinely orphaned export, no remaining caller anywhere
|
|
12
|
-
* in src/.
|
|
9
|
+
* formatShortDuration was removed as a genuinely orphaned export, with no
|
|
10
|
+
* remaining caller anywhere in src/.
|
|
13
11
|
*/
|
|
14
12
|
|
|
15
13
|
/**
|
|
16
14
|
* Format a latency value in milliseconds with sub-second precision.
|
|
17
15
|
*
|
|
18
|
-
* Used by: provider-health-panel
|
|
19
|
-
*
|
|
20
16
|
* ms <= 0 → 'n/a'
|
|
21
17
|
* ms >= 10000 → '12.3s' (one decimal)
|
|
22
18
|
* ms >= 1000 → '1.23s' (two decimals)
|
|
@@ -23,8 +23,16 @@ const TAGLINE = '[ good vibes ・ A I ・ いい雰囲気
|
|
|
23
23
|
const versionLine = (version: string) =>
|
|
24
24
|
` ✦ v${version} █ terminal AI assistant █ 自動コード ✦`;
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* The splash wordmark gradient, protected: it is part of the GoodVibes mark,
|
|
28
|
+
* identical under every theme and mode, and must never be routed through the
|
|
29
|
+
* theme tokens. conversation-rendering.ts interpolates start to end across
|
|
30
|
+
* each wordmark row.
|
|
31
|
+
*/
|
|
32
|
+
export const SPLASH_GRADIENT = Object.freeze({ start: '#00ffff', end: '#d000ff' } as const);
|
|
33
|
+
|
|
26
34
|
/** Fixed hint line, the three primary shell entry points. */
|
|
27
|
-
const HINT_LINE = 'Ctrl+P
|
|
35
|
+
const HINT_LINE = 'Ctrl+P commands / ? help / F2 agents';
|
|
28
36
|
|
|
29
37
|
export interface SplashOptions {
|
|
30
38
|
workingDir?: string;
|
|
@@ -93,6 +93,13 @@ export function getDisplayWidth(text: string): number {
|
|
|
93
93
|
// corrupting the following text (the "✕t" glitch on the steer error line).
|
|
94
94
|
code === 0x2715 ||
|
|
95
95
|
code === 0x2716 ||
|
|
96
|
+
// ✦ (0x2726, the splash star and the modal group marker), ⏎ (0x23ce)
|
|
97
|
+
// and ⌫ (0x232b, keycap glyphs) have no emoji presentation, so
|
|
98
|
+
// terminals draw them one cell wide too; the block rules below would
|
|
99
|
+
// otherwise count them as 2 and shift everything after them.
|
|
100
|
+
code === 0x2726 ||
|
|
101
|
+
code === 0x23ce ||
|
|
102
|
+
code === 0x232b ||
|
|
96
103
|
code === 0x2022 ||
|
|
97
104
|
code === 0x258d ||
|
|
98
105
|
(code >= 0x2500 && code <= 0x257f)
|
|
@@ -272,6 +279,55 @@ export function wrapText(text: string, width: number): string[] {
|
|
|
272
279
|
return lines;
|
|
273
280
|
}
|
|
274
281
|
|
|
282
|
+
/** Columns one tab takes in a drawn body; the same two spaces a diff body uses (changes-modal.ts wrapTokens). */
|
|
283
|
+
export const BODY_TAB_WIDTH = 2;
|
|
284
|
+
|
|
285
|
+
/** Replace every tab with BODY_TAB_WIDTH spaces, so width math and drawing agree. */
|
|
286
|
+
export function expandTabs(text: string): string {
|
|
287
|
+
return text.includes('\t') ? text.replace(/\t/g, ' '.repeat(BODY_TAB_WIDTH)) : text;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Wrap one body line (a file line, command output) to `width` cells without
|
|
292
|
+
* losing its layout: tabs expand to spaces, a line that fits is returned
|
|
293
|
+
* exactly as it is (leading indentation and inner runs of spaces kept), and a
|
|
294
|
+
* longer line wraps at spaces with every continuation row indented like the
|
|
295
|
+
* first. A word wider than the room left is cut hard. Every returned row is
|
|
296
|
+
* at most `width` cells.
|
|
297
|
+
*/
|
|
298
|
+
export function wrapPreservingIndent(text: string, width: number): string[] {
|
|
299
|
+
const out: string[] = [];
|
|
300
|
+
for (const raw of expandTabs(text).split('\n')) {
|
|
301
|
+
const line = raw.replace(/\s+$/, '');
|
|
302
|
+
if (getDisplayWidth(line) <= width) { out.push(line); continue; }
|
|
303
|
+
const indentText = /^ */.exec(line)![0];
|
|
304
|
+
// Deep indentation leaves no room: continuation rows start at the left edge.
|
|
305
|
+
const indent = indentText.length <= Math.floor(width / 2) ? indentText : '';
|
|
306
|
+
let rest = Array.from(line.slice(indentText.length));
|
|
307
|
+
let prefix = indentText.length <= width - 1 ? indentText : '';
|
|
308
|
+
while (rest.length > 0) {
|
|
309
|
+
const avail = Math.max(1, width - prefix.length);
|
|
310
|
+
// Longest run of `rest` that fits, preferring to break after a space.
|
|
311
|
+
let cut = 0;
|
|
312
|
+
let used = 0;
|
|
313
|
+
let lastSpace = -1;
|
|
314
|
+
for (let i = 0; i < rest.length; i++) {
|
|
315
|
+
const w = getDisplayWidth(rest[i]!);
|
|
316
|
+
if (used + w > avail) break;
|
|
317
|
+
used += w;
|
|
318
|
+
cut = i + 1;
|
|
319
|
+
if (rest[i] === ' ') lastSpace = i + 1;
|
|
320
|
+
}
|
|
321
|
+
const at = cut === rest.length ? cut : lastSpace > 0 ? lastSpace : Math.max(1, cut);
|
|
322
|
+
out.push((prefix + rest.slice(0, at).join('')).replace(/\s+$/, ''));
|
|
323
|
+
rest = rest.slice(at);
|
|
324
|
+
while (rest[0] === ' ') rest.shift();
|
|
325
|
+
prefix = indent;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return out;
|
|
329
|
+
}
|
|
330
|
+
|
|
275
331
|
export function interpolateColor(startHex: string, endHex: string, factor: number): string {
|
|
276
332
|
const parse = (hex: string) => {
|
|
277
333
|
const r = parseInt(hex.slice(1, 3), 16);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { CONFIG_SCHEMA } from '@pellux/goodvibes-sdk/platform/config';
|
|
4
4
|
import { FEATURE_SETTINGS } from '@pellux/goodvibes-sdk/platform/runtime/state';
|
|
@@ -564,15 +564,17 @@ function listSlashCommands(): string[] {
|
|
|
564
564
|
return registry.getAll().map((command) => command.name);
|
|
565
565
|
}
|
|
566
566
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
567
|
+
/**
|
|
568
|
+
* Built-in modals and views: every config-modal surface builtin-modals.ts
|
|
569
|
+
* registers, plus every kit view modal the shell's view openers construct
|
|
570
|
+
* (Agents, Usage, Changes, Notifications, the masked password prompt).
|
|
571
|
+
*/
|
|
572
|
+
function countBuiltinModals(root: string): number {
|
|
573
|
+
const surfaces = readFileSync(join(root, 'src', 'views', 'builtin-modals.ts'), 'utf8');
|
|
574
|
+
const openers = readFileSync(join(root, 'src', 'shell', 'view-openers.ts'), 'utf8');
|
|
575
|
+
const surfaceCount = [...surfaces.matchAll(/registerModalSurface\(/g)].length;
|
|
576
|
+
const viewModals = new Set([...openers.matchAll(/new ([A-Za-z]+Modal)\(/g)].map((m) => m[1]));
|
|
577
|
+
return surfaceCount + viewModals.size;
|
|
576
578
|
}
|
|
577
579
|
|
|
578
580
|
/**
|
|
@@ -590,7 +592,7 @@ export function buildVerificationLedger(root: string): VerificationLedger {
|
|
|
590
592
|
const slashCommandNames = listSlashCommands();
|
|
591
593
|
const cliCommandNames = listCliCommands();
|
|
592
594
|
const slashCommands = slashCommandNames.length;
|
|
593
|
-
const
|
|
595
|
+
const modals = countBuiltinModals(root);
|
|
594
596
|
const cliCommands = cliCommandNames.length;
|
|
595
597
|
const featureFlags = FEATURE_SETTINGS.length;
|
|
596
598
|
const settings = CONFIG_SCHEMA.length;
|
|
@@ -623,12 +625,12 @@ export function buildVerificationLedger(root: string): VerificationLedger {
|
|
|
623
625
|
notes: 'Every command can be routed and invoked with a fake context; external/provider/device commands need live outcome checks.',
|
|
624
626
|
},
|
|
625
627
|
{
|
|
626
|
-
area: 'Built-in
|
|
627
|
-
total:
|
|
628
|
-
localSignalVerified:
|
|
629
|
-
localBehaviorVerified:
|
|
628
|
+
area: 'Built-in modals and views',
|
|
629
|
+
total: modals,
|
|
630
|
+
localSignalVerified: modals,
|
|
631
|
+
localBehaviorVerified: modals,
|
|
630
632
|
externalOutcomeRequired: 0,
|
|
631
|
-
notes: '
|
|
633
|
+
notes: 'Modals and views can be rendered and input-tested against fake read models and real cached state.',
|
|
632
634
|
},
|
|
633
635
|
{
|
|
634
636
|
area: 'Top-level CLI commands',
|
|
@@ -7,7 +7,7 @@ export type AgentInspectorEntryKind = 'user' | 'assistant' | 'tool_call' | 'tool
|
|
|
7
7
|
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
9
|
// Shared agent status / stall constants
|
|
10
|
-
// Used by the
|
|
10
|
+
// Used by the Agents modal's agent views and read-model consumers (formerly also
|
|
11
11
|
// AgentDetailModal, which was retired in).
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ export const AGENT_STALL_THRESHOLD_MS = 5 * 60 * 1000;
|
|
|
22
22
|
* An agent is stalled when it is non-terminal and has been running for at
|
|
23
23
|
* least AGENT_STALL_THRESHOLD_MS without completing.
|
|
24
24
|
*
|
|
25
|
-
* Extracted as a standalone export so read-models and
|
|
25
|
+
* Extracted as a standalone export so read-models and views can share the
|
|
26
26
|
* canonical stall-count logic (TASK-046).
|
|
27
27
|
*/
|
|
28
28
|
export function countStalledAgents(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { ModalSurfaceRegistry } from './modal-surface-registry.ts';
|
|
2
|
+
import type { ResolvedBuiltinViewDeps } from './view-deps.ts';
|
|
3
3
|
import type { ConfigModalSurface, ConfigModalView } from '../input/config-modal-types.ts';
|
|
4
4
|
import { createProviderRuntimeInspectionQuery } from '@/runtime/index.ts';
|
|
5
5
|
import { createRuntimeProviderApi } from '@/runtime/index.ts';
|
|
@@ -32,20 +32,23 @@ import { createDevicesModalSurface } from './modals/devices-modal.ts';
|
|
|
32
32
|
import { createPlanningModalSurface } from './modals/planning-modal.ts';
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* Register the config-modal surfaces
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* panels used). For each surface migrated from a standalone panel this does two things:
|
|
35
|
+
* Register the config-modal surfaces and the old names that open them. Called
|
|
36
|
+
* once at startup from createShellViews (builtin-views.ts). For each surface
|
|
37
|
+
* this does two things:
|
|
39
38
|
* 1. registerModalSurface, the data + actions the config-modal host renders.
|
|
40
|
-
* 2. registerModalRedirect, so `/panel open <old-id>`,
|
|
41
|
-
* alias still resolve to the modal.
|
|
39
|
+
* 2. registerModalRedirect, so `/panel open <old-id>`, notifications and any
|
|
40
|
+
* alias still resolve to the modal (views.ts consults these).
|
|
42
41
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
42
|
+
* `openMaskedEntry` opens the local-auth password prompt (a kit modal), which
|
|
43
|
+
* is how the Local Auth modal's add-user and rotate-password actions keep the
|
|
44
|
+
* password out of argv, history and the transcript.
|
|
46
45
|
*/
|
|
47
|
-
export function registerBuiltinModals(
|
|
48
|
-
|
|
46
|
+
export function registerBuiltinModals(
|
|
47
|
+
manager: ModalSurfaceRegistry,
|
|
48
|
+
deps: ResolvedBuiltinViewDeps,
|
|
49
|
+
openMaskedEntry: (kind: 'add-user' | 'rotate-password', username?: string) => void,
|
|
50
|
+
): void {
|
|
51
|
+
const ui = deps.uiServices;
|
|
49
52
|
|
|
50
53
|
// ── Providers & Connectivity ─────────────────────────────────────────────────
|
|
51
54
|
manager.registerModalSurface(createServicesModalSurface(deps.serviceRegistry, deps.subscriptionManager));
|
|
@@ -71,10 +74,8 @@ export function registerBuiltinModals(manager: PanelManager, deps: ResolvedBuilt
|
|
|
71
74
|
manager.registerModalSurface(createSettingsSyncModalSurface(deps.configManager));
|
|
72
75
|
manager.registerModalRedirect('settings-sync', 'settings-sync-modal');
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// for the masked password-entry path). See builtin/operations.ts.
|
|
77
|
-
manager.registerModalSurface(createLocalAuthModalSurface(deps.localUserAuthManager));
|
|
77
|
+
manager.registerModalSurface(createLocalAuthModalSurface(deps.localUserAuthManager, openMaskedEntry));
|
|
78
|
+
manager.registerModalRedirect('local-auth', 'local-auth-modal');
|
|
78
79
|
|
|
79
80
|
manager.registerModalSurface(createSandboxModalSurface(deps.configManager, deps.sandboxSessionRegistry, deps.requestRender));
|
|
80
81
|
manager.registerModalRedirect('sandbox', 'sandbox-modal');
|
|
@@ -178,7 +179,7 @@ export function registerBuiltinModals(manager: PanelManager, deps: ResolvedBuilt
|
|
|
178
179
|
}));
|
|
179
180
|
manager.registerModalRedirect('project-planning', 'planning-modal');
|
|
180
181
|
|
|
181
|
-
// The retired 'sessions'
|
|
182
|
+
// The retired 'sessions' view folds into the EXISTING session-picker modal
|
|
182
183
|
// (no new config-modal surface); the redirect is a plain hand-off, moved here
|
|
183
184
|
// from the deleted ecosystem bridge.
|
|
184
185
|
manager.registerModalRedirect('sessions', 'sessionPicker');
|
|
@@ -188,11 +189,11 @@ export function registerBuiltinModals(manager: PanelManager, deps: ResolvedBuilt
|
|
|
188
189
|
* Build the companion-pairing connection info lazily (called from the pairing
|
|
189
190
|
* surface's first render, not at registration time) so a missing daemon home
|
|
190
191
|
* degrades to an honest "unavailable" modal instead of throwing at startup.
|
|
191
|
-
* Mirrors the retired
|
|
192
|
+
* Mirrors the retired Qr view factory's construction.
|
|
192
193
|
*/
|
|
193
|
-
function buildPairingConnectionInfo(deps:
|
|
194
|
+
function buildPairingConnectionInfo(deps: ResolvedBuiltinViewDeps): PairingModalConnectionInfo | null {
|
|
194
195
|
try {
|
|
195
|
-
const ui =
|
|
196
|
+
const ui = deps.uiServices;
|
|
196
197
|
const configManager = deps.configManager;
|
|
197
198
|
// Freeze a stable web origin once (never clobbering a user-set value).
|
|
198
199
|
const webOrigin = ensurePublicBaseUrl(configManager);
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* builtin-views.ts, the always-on pieces behind the built-in modals.
|
|
3
|
+
*
|
|
4
|
+
* Built once at startup (runtime/bootstrap-shell.ts):
|
|
5
|
+
* - the UsageTracker, collecting per-turn history and costs from the first
|
|
6
|
+
* turn whether or not the Usage modal is ever opened;
|
|
7
|
+
* - the fleet's action callbacks, acts (pick / conflict / discard) and the
|
|
8
|
+
* ACP spawn controller the Agents modal drives;
|
|
9
|
+
* - every config-modal surface, registered on the ModalSurfaceRegistry with
|
|
10
|
+
* the old names that open it.
|
|
11
|
+
*
|
|
12
|
+
* Two things only exist once the input handler does (the kit modal host): the
|
|
13
|
+
* Changes preview the fleet acts show candidate diffs in, and the local-auth
|
|
14
|
+
* password prompt. They are late-bound through `bridge`, which the shell fills
|
|
15
|
+
* in (shell/ui-openers.ts) before any of them can be used.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
|
|
19
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
20
|
+
import { GOODVIBES_TUI_SURFACE_ROOT } from '../config/surface.ts';
|
|
21
|
+
import { UsageTracker } from '../runtime/usage-tracker.ts';
|
|
22
|
+
import type { FleetActionCallbacks } from '../input/agents-modal.ts';
|
|
23
|
+
import { ModalSurfaceRegistry } from './modal-surface-registry.ts';
|
|
24
|
+
import { registerBuiltinModals } from './builtin-modals.ts';
|
|
25
|
+
import { resolveBuiltinViewDeps, type BuiltinViewDeps } from './view-deps.ts';
|
|
26
|
+
import type { FleetReadModel } from './fleet-read-model.ts';
|
|
27
|
+
import { FleetActs, type FleetDiffSurface } from './fleet-acts.ts';
|
|
28
|
+
import { createFleetGateway } from './fleet-gateway.ts';
|
|
29
|
+
import { FleetSpawn, createAcpSpawnGateway } from './fleet-spawn.ts';
|
|
30
|
+
|
|
31
|
+
export type MaskedEntryOpener = (kind: 'add-user' | 'rotate-password', username?: string) => void;
|
|
32
|
+
|
|
33
|
+
export interface ShellViewBridge {
|
|
34
|
+
/** Show candidate diffs and ask over them (the Changes preview). */
|
|
35
|
+
diffSurface: FleetDiffSurface | null;
|
|
36
|
+
/** Open the local-auth password prompt. */
|
|
37
|
+
openMaskedEntry: MaskedEntryOpener | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ShellViews {
|
|
41
|
+
readonly modalSurfaces: ModalSurfaceRegistry;
|
|
42
|
+
readonly usage: UsageTracker;
|
|
43
|
+
readonly fleet: {
|
|
44
|
+
readonly readModel: FleetReadModel;
|
|
45
|
+
readonly actions: FleetActionCallbacks;
|
|
46
|
+
readonly acts: FleetActs;
|
|
47
|
+
readonly spawn: FleetSpawn;
|
|
48
|
+
};
|
|
49
|
+
readonly configManager: ConfigManager;
|
|
50
|
+
readonly workingDirectory: string;
|
|
51
|
+
/** Files this session edited. */
|
|
52
|
+
readonly getSessionFiles: () => string[];
|
|
53
|
+
readonly localUserAuthManager: UserAuthManager;
|
|
54
|
+
readonly bridge: ShellViewBridge;
|
|
55
|
+
dispose(): void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function createShellViews(deps: BuiltinViewDeps): ShellViews {
|
|
59
|
+
const resolved = resolveBuiltinViewDeps(deps);
|
|
60
|
+
const ui = deps.uiServices;
|
|
61
|
+
const requestRender = deps.requestRender ?? (() => {});
|
|
62
|
+
const bridge: ShellViewBridge = { diffSurface: null, openMaskedEntry: null };
|
|
63
|
+
const fleetReadModel = ui.runtime.fleetReadModel;
|
|
64
|
+
const notify = deps.fleetActsNotify ?? (() => {});
|
|
65
|
+
|
|
66
|
+
const usage = new UsageTracker({
|
|
67
|
+
turnEvents: ui.events.turns,
|
|
68
|
+
agentEvents: ui.events.agents,
|
|
69
|
+
getUsage: () => (deps.orchestrator?.usage ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }) as { input: number; output: number; cacheRead: number; cacheWrite: number; model?: string },
|
|
70
|
+
getContextTokens: () => deps.orchestrator?.lastInputTokens ?? 0,
|
|
71
|
+
getContextWindow: () => deps.getCtxWindow?.() ?? 0,
|
|
72
|
+
getModelId: () => deps.providerRegistry.getCurrentModel().id,
|
|
73
|
+
getAgentStatus: (id) => ui.agents.agentManager.getStatus(id),
|
|
74
|
+
getFleetCost: () => fleetReadModel.getSnapshot().totalCost,
|
|
75
|
+
configManager: resolved.configManager,
|
|
76
|
+
sessionMemoryStore: resolved.sessionMemoryStore,
|
|
77
|
+
sessionReadModel: ui.readModels.session,
|
|
78
|
+
requestRender,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const diffSurface: FleetDiffSurface = {
|
|
82
|
+
show: (title, diff) => bridge.diffSurface?.show(title, diff),
|
|
83
|
+
armConfirm: (opts) => {
|
|
84
|
+
if (bridge.diffSurface) bridge.diffSurface.armConfirm(opts);
|
|
85
|
+
else opts.onCancel?.();
|
|
86
|
+
},
|
|
87
|
+
close: () => bridge.diffSurface?.close(),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const acts = new FleetActs({
|
|
91
|
+
resolveGateway: () => createFleetGateway({
|
|
92
|
+
configManager: resolved.configManager,
|
|
93
|
+
homeDirectory: ui.environment.shellPaths.homeDirectory,
|
|
94
|
+
armFixSessionAttach: deps.armFixSessionAttach ?? (() => {}),
|
|
95
|
+
}),
|
|
96
|
+
diffSurface,
|
|
97
|
+
notify,
|
|
98
|
+
markDirty: requestRender,
|
|
99
|
+
findNode: (nodeId: string) => fleetReadModel.getSnapshot().rows.find((r) => r.node.id === nodeId)?.node ?? null,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const spawn = new FleetSpawn({
|
|
103
|
+
resolveGateway: () => createAcpSpawnGateway({
|
|
104
|
+
configManager: resolved.configManager,
|
|
105
|
+
homeDirectory: ui.environment.shellPaths.homeDirectory,
|
|
106
|
+
}),
|
|
107
|
+
currentDirectory: () => ui.environment.shellPaths.workingDirectory,
|
|
108
|
+
notify,
|
|
109
|
+
markDirty: requestRender,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const actions: FleetActionCallbacks = {
|
|
113
|
+
interrupt: (id) => fleetReadModel.interrupt(id),
|
|
114
|
+
resume: (id) => fleetReadModel.resume(id),
|
|
115
|
+
kill: (id, opts) => fleetReadModel.kill(id, opts),
|
|
116
|
+
getConversationSnapshot: (agentId) => ui.agents.agentManager.getConversationSnapshot(agentId),
|
|
117
|
+
resolveSessionLogPath: (agentId) => ui.environment.shellPaths.resolveProjectPath(GOODVIBES_TUI_SURFACE_ROOT, 'sessions', `${agentId}.jsonl`),
|
|
118
|
+
steer: (id, text) => fleetReadModel.steer(id, text),
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const modalSurfaces = new ModalSurfaceRegistry();
|
|
122
|
+
registerBuiltinModals(modalSurfaces, resolved, (kind, username) => bridge.openMaskedEntry?.(kind, username));
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
modalSurfaces,
|
|
126
|
+
usage,
|
|
127
|
+
fleet: { readModel: fleetReadModel, actions, acts, spawn },
|
|
128
|
+
configManager: resolved.configManager,
|
|
129
|
+
workingDirectory: ui.environment.workingDirectory,
|
|
130
|
+
getSessionFiles: () => deps.sessionChangeTracker?.getChangedFiles() ?? [],
|
|
131
|
+
localUserAuthManager: resolved.localUserAuthManager,
|
|
132
|
+
bridge,
|
|
133
|
+
dispose: () => usage.dispose(),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// useConfirmState<T>, reusable inline confirm/cancel helper
|
|
3
3
|
//
|
|
4
|
-
// ── Project-standard confirm contract (all
|
|
4
|
+
// ── Project-standard confirm contract (all views must match) ──────────────
|
|
5
5
|
//
|
|
6
6
|
// CONFIRM: Enter, Return, or y
|
|
7
7
|
// CANCEL: Esc or n
|
|
8
8
|
// ABSORBED: any other key while confirm is active (keeps confirm pending)
|
|
9
9
|
//
|
|
10
10
|
// Implementation:
|
|
11
|
-
// - Composable: any
|
|
11
|
+
// - Composable: any view holds a ConfirmState<T> field; no new base class
|
|
12
12
|
// - Call handleConfirmInput(confirm, key) BEFORE normal key dispatch.
|
|
13
13
|
// It handles all four outcomes and returns one of the four result tokens.
|
|
14
14
|
// - Call renderConfirmLines(width, state) to render the two-line overlay
|
|
15
15
|
// that replaces normal content while a confirm is pending.
|
|
16
16
|
//
|
|
17
17
|
// ── This file is the canonical contract for all confirm flows ─────────────
|
|
18
|
-
// Any new
|
|
18
|
+
// Any new view confirm flow must use ConfirmState<T> and handleConfirmInput;
|
|
19
19
|
// do not implement a bespoke two-press or Enter-only variant.
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
|
|
22
22
|
import type { Line } from '@pellux/goodvibes-sdk/platform/types';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
23
|
+
import { buildViewLine } from './polish.ts';
|
|
24
|
+
import { DEFAULT_VIEW_PALETTE } from './polish.ts';
|
|
25
25
|
|
|
26
26
|
export interface ConfirmState<T = string> {
|
|
27
27
|
/** The subject of the confirmation (e.g. item name or id). */
|
|
@@ -37,7 +37,7 @@ export interface ConfirmState<T = string> {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Call this from a
|
|
40
|
+
* Call this from a view's handleInput() BEFORE any other key handling.
|
|
41
41
|
*
|
|
42
42
|
* Project-standard confirm contract:
|
|
43
43
|
* - CONFIRM: Enter, Return, or y
|
|
@@ -66,14 +66,14 @@ export function handleConfirmInput<T = string>(
|
|
|
66
66
|
* Callers embed these lines in a workspace section titled 'Confirmation'.
|
|
67
67
|
*/
|
|
68
68
|
export function renderConfirmLines<T = string>(width: number, state: ConfirmState<T>): Line[] {
|
|
69
|
-
const palette =
|
|
69
|
+
const palette = DEFAULT_VIEW_PALETTE;
|
|
70
70
|
const verb = state.verb ?? 'Delete';
|
|
71
71
|
return [
|
|
72
|
-
|
|
72
|
+
buildViewLine(width, [[
|
|
73
73
|
` ${verb} "${state.label}"?`,
|
|
74
74
|
palette.warn,
|
|
75
75
|
]]),
|
|
76
|
-
|
|
76
|
+
buildViewLine(width, [
|
|
77
77
|
[' Enter / y', palette.info],
|
|
78
78
|
[' confirm', palette.dim],
|
|
79
79
|
[' n / Esc', palette.info],
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// Diff review model, pure parsing + steering-payload helpers for the
|
|
3
|
-
// comment-on-hunk review loop (see diff
|
|
3
|
+
// comment-on-hunk review loop (see the diff review view).
|
|
4
4
|
//
|
|
5
5
|
// The diff this operates on is the git working tree vs a base ref (HEAD),
|
|
6
6
|
// filtered to the files the current session actually edited (the SDK's
|
|
7
7
|
// SessionChangeTracker). That is the honest source: it is CURRENT working-tree
|
|
8
|
-
// content, not a turn-start snapshot, the
|
|
8
|
+
// content, not a turn-start snapshot, the diff review view labels it exactly that way.
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
|
|
11
11
|
/** One hunk of one file's diff, with enough structure to steer a comment at it. */
|
|
@@ -169,13 +169,20 @@ export interface HunkComment {
|
|
|
169
169
|
* patch excerpt so the model knows exactly what the comment targets. The
|
|
170
170
|
* `sourceLabel` states the honest provenance of the diff (working tree vs base).
|
|
171
171
|
*/
|
|
172
|
-
export function buildSteerMessage(
|
|
172
|
+
export function buildSteerMessage(
|
|
173
|
+
items: readonly HunkComment[],
|
|
174
|
+
sourceLabel: string,
|
|
175
|
+
/** One-line semantic summaries (functions, classes, imports changed) by file path, when known. */
|
|
176
|
+
semanticByFile?: ReadonlyMap<string, string>,
|
|
177
|
+
): string {
|
|
173
178
|
const blocks = items.map(({ hunk, comment }) => {
|
|
174
179
|
const range = hunkLineRange(hunk);
|
|
180
|
+
const semantic = semanticByFile?.get(hunk.filePath);
|
|
175
181
|
return [
|
|
176
182
|
`Review comment on ${hunk.filePath} (lines ${range.start}-${range.end}, new file):`,
|
|
177
183
|
comment,
|
|
178
184
|
'',
|
|
185
|
+
...(semantic ? [`Structure of this file's change: ${semantic}`, ''] : []),
|
|
179
186
|
'Referenced change:',
|
|
180
187
|
'```diff',
|
|
181
188
|
hunkExcerpt(hunk),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* EvalRegistry, holds the latest evaluation harness run state.
|
|
3
3
|
*
|
|
4
|
-
* (the purge): extracted out of eval
|
|
4
|
+
* (the purge): extracted out of the eval view. 'eval' was
|
|
5
5
|
* DELETE-disposition (no surviving human surface, the evaluation harness
|
|
6
6
|
* is driven and reviewed via the `/eval` CLI command, input/commands/eval.ts)
|
|
7
7
|
* but this registry is still a live consumer of `/eval run` output, so it
|