@pellux/goodvibes-tui 2.0.21 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -1
- package/README.md +30 -29
- package/docs/README.md +8 -5
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- package/package.json +28 -19
- package/src/cli/management.ts +5 -2
- package/src/cli/tui-startup.ts +34 -39
- package/src/core/agent-view-render.ts +157 -0
- package/src/core/approval-alert.ts +49 -11
- package/src/core/bookmark-navigation.ts +7 -1
- package/src/core/budget-breach-notifier.ts +27 -8
- package/src/core/compaction-receipt.ts +1 -1
- package/src/core/context-usage.ts +1 -1
- package/src/core/conversation-compaction-render.ts +3 -3
- package/src/core/conversation-display-only.ts +86 -0
- package/src/core/conversation-event-navigation.ts +27 -0
- package/src/core/conversation-line-cache.ts +216 -447
- package/src/core/conversation-render-context.ts +20 -27
- package/src/core/conversation-rendering.ts +157 -575
- package/src/core/conversation-splash-state.ts +6 -1
- package/src/core/conversation-types.ts +35 -0
- package/src/core/conversation-usage.ts +12 -0
- package/src/core/conversation.ts +130 -131
- package/src/core/long-task-notifier.ts +100 -31
- package/src/core/notices.ts +75 -0
- package/src/core/pairing-tailscale-gateway.ts +1 -1
- package/src/core/process-output-log.ts +143 -0
- package/src/core/rewind-receipt.ts +1 -1
- package/src/core/session-focus.ts +190 -0
- package/src/core/session-resume-core.ts +23 -81
- package/src/core/stream-event-wiring.ts +31 -5
- package/src/core/system-message-noise.ts +2 -2
- package/src/core/system-message-router.ts +16 -18
- package/src/core/turn-event-wiring.ts +272 -33
- package/src/core/work-tree-focus.ts +290 -0
- package/src/core/work-tree-fold-store.ts +143 -0
- package/src/core/work-tree-model.ts +799 -0
- package/src/core/work-tree-render.ts +384 -0
- package/src/core/work-tree-sources.ts +184 -0
- package/src/core/work-tree-wiring.ts +176 -0
- package/src/core/workstream-notification.ts +36 -6
- package/src/core/wrfc-notice-titles.ts +37 -0
- package/src/input/agents-modal-text.ts +119 -0
- package/src/input/agents-modal.ts +699 -0
- package/src/input/bookmark-modal.ts +33 -9
- package/src/input/changes-git.ts +251 -0
- package/src/input/changes-modal.ts +629 -0
- package/src/input/changes-model.ts +125 -0
- package/src/input/command-palette-types.ts +41 -0
- package/src/input/command-palette.ts +272 -0
- package/src/input/command-reference.ts +2 -2
- package/src/input/command-registry.ts +77 -35
- package/src/input/commands/acp-runtime.ts +19 -9
- package/src/input/commands/channel-runtime.ts +2 -2
- package/src/input/commands/ci-runtime.ts +1 -1
- package/src/input/commands/codebase-runtime.ts +1 -1
- package/src/input/commands/config.ts +7 -1
- package/src/input/commands/context-window.ts +25 -19
- package/src/input/commands/control-room-runtime.ts +18 -18
- package/src/input/commands/conversation-runtime.ts +0 -1
- package/src/input/commands/cost-runtime.ts +29 -20
- package/src/input/commands/diff-runtime.ts +35 -181
- package/src/input/commands/eval.ts +1 -1
- package/src/input/commands/experience-runtime.ts +3 -7
- package/src/input/commands/fresh-conversation.ts +86 -0
- package/src/input/commands/git-runtime.ts +5 -22
- package/src/input/commands/graph-runtime.ts +1 -1
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/health-runtime.ts +8 -9
- package/src/input/commands/hooks-runtime.ts +2 -2
- package/src/input/commands/hosted-runtime.ts +3 -3
- package/src/input/commands/incident-runtime.ts +3 -3
- package/src/input/commands/intelligence-runtime.ts +6 -9
- package/src/input/commands/knowledge.ts +2 -2
- package/src/input/commands/legacy-panel-command.ts +57 -0
- package/src/input/commands/local-auth-runtime.ts +8 -9
- package/src/input/commands/local-provider-runtime.ts +7 -4
- package/src/input/commands/local-runtime.ts +12 -15
- package/src/input/commands/local-setup-review.ts +1 -1
- package/src/input/commands/local-setup.ts +13 -19
- package/src/input/commands/memory.ts +1 -1
- package/src/input/commands/notify-runtime.ts +9 -0
- package/src/input/commands/operator-runtime.ts +10 -12
- package/src/input/commands/permissions-provenance.ts +3 -3
- package/src/input/commands/planning-runtime.ts +7 -7
- package/src/input/commands/platform-sandbox-runtime.ts +2 -2
- package/src/input/commands/platform-services-runtime.ts +1 -1
- package/src/input/commands/policy-dispatch.ts +2 -2
- package/src/input/commands/policy.ts +3 -3
- package/src/input/commands/provider.ts +1 -1
- package/src/input/commands/remote-runtime.ts +1 -1
- package/src/input/commands/review-runtime.ts +39 -94
- package/src/input/commands/rewind-runtime.ts +81 -108
- package/src/input/commands/runtime-services.ts +15 -17
- package/src/input/commands/services-runtime.ts +2 -2
- package/src/input/commands/session-content.ts +21 -5
- package/src/input/commands/session-workflow.ts +13 -38
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/shell-core.ts +19 -4
- package/src/input/commands/skills-runtime.ts +2 -2
- package/src/input/commands/status-runtime.ts +13 -0
- package/src/input/commands/subscription-runtime.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +2 -8
- package/src/input/commands/work-plan-runtime.ts +4 -4
- package/src/input/commands/workstream-attempts.ts +24 -47
- package/src/input/commands/workstream-runtime.ts +2 -2
- package/src/input/commands/worktree-runtime.ts +3 -3
- package/src/input/commands.ts +3 -1
- package/src/input/composer-editor.ts +44 -0
- package/src/input/concealed-input.ts +1 -1
- package/src/input/config-modal-types.ts +20 -8
- package/src/input/config-modal.ts +106 -105
- package/src/input/confirm-dialog-types.ts +28 -0
- package/src/input/confirm-dialog.ts +70 -0
- package/src/input/delete-key-policy.ts +3 -3
- package/src/input/feed-context-factory.ts +15 -16
- package/src/input/handler-command-route.ts +7 -42
- package/src/input/handler-content-actions.ts +16 -15
- package/src/input/handler-feed-routes.ts +26 -211
- package/src/input/handler-feed.ts +68 -95
- package/src/input/handler-interactions.ts +5 -3
- package/src/input/handler-modal-routes.ts +215 -216
- package/src/input/handler-modal-stack.ts +81 -11
- package/src/input/handler-modal-token-routes.ts +4 -0
- package/src/input/handler-onboarding.ts +0 -1
- package/src/input/handler-picker-routes.ts +65 -107
- package/src/input/handler-session-view-route.ts +149 -0
- package/src/input/handler-shortcuts.ts +16 -154
- package/src/input/handler-types.ts +4 -2
- package/src/input/handler-ui-state.ts +45 -15
- package/src/input/handler-work-tree-route.ts +123 -0
- package/src/input/handler.ts +25 -70
- package/src/input/keybindings.ts +16 -71
- package/src/input/masked-entry-modal.ts +117 -0
- package/src/input/mcp-workspace.ts +48 -17
- package/src/input/model-picker-filter.ts +8 -0
- package/src/input/model-picker-open.ts +99 -0
- package/src/input/model-picker-types.ts +1 -1
- package/src/input/model-picker.ts +92 -9
- package/src/input/notifications-modal.ts +123 -0
- package/src/input/overlay-filter.ts +26 -0
- package/src/input/profile-picker-modal.ts +37 -8
- package/src/input/search.ts +3 -3
- package/src/input/selection-modal-queue.ts +2 -0
- package/src/input/selection-modal.ts +28 -16
- package/src/input/session-picker-modal.ts +33 -8
- package/src/input/settings-modal-activation.ts +7 -2
- package/src/input/settings-modal-data.ts +11 -6
- package/src/input/settings-modal-types.ts +1 -1
- package/src/input/settings-modal.ts +20 -20
- package/src/input/submission-intent.ts +1 -1
- package/src/input/submission-router.ts +4 -9
- package/src/input/surface-modal-host.ts +110 -0
- package/src/input/theme-settings-actions.ts +82 -0
- package/src/input/usage-modal.ts +183 -0
- package/src/input/views.ts +97 -0
- package/src/main.ts +175 -165
- package/src/permissions/hunk-selection.ts +1 -1
- package/src/permissions/prompt-card.ts +511 -0
- package/src/permissions/prompt.ts +59 -622
- package/src/renderer/agents-modal.ts +310 -0
- package/src/renderer/autocomplete-overlay.ts +42 -220
- package/src/renderer/back-to-bottom.ts +80 -0
- package/src/renderer/block-actions-overlay.ts +30 -48
- package/src/renderer/bookmark-modal.ts +48 -79
- package/src/renderer/changes-modal.ts +325 -0
- package/src/renderer/code-block.ts +184 -106
- package/src/renderer/command-palette.ts +93 -0
- package/src/renderer/composer-fragments.ts +4 -4
- package/src/renderer/composer.ts +146 -0
- package/src/renderer/compositor.ts +26 -160
- package/src/renderer/config-modal.ts +185 -81
- package/src/renderer/confirm-dialog.ts +50 -0
- package/src/renderer/context-inspector.ts +116 -154
- package/src/renderer/context-status-hint.ts +4 -4
- package/src/renderer/conversation-layout.ts +20 -0
- package/src/renderer/conversation-overlays.ts +94 -84
- package/src/renderer/conversation-surface.ts +19 -38
- package/src/renderer/diff-tint.ts +98 -0
- package/src/renderer/file-picker-overlay.ts +63 -90
- package/src/renderer/footer-targets.ts +38 -0
- package/src/renderer/git-status.ts +3 -4
- package/src/renderer/header-line.ts +140 -117
- package/src/renderer/help-overlay.ts +133 -219
- package/src/renderer/history-search-overlay.ts +15 -12
- package/src/renderer/lane-graph/bead.ts +800 -0
- package/src/renderer/lane-graph/glyphs.ts +134 -0
- package/src/renderer/lane-graph/layout.ts +248 -0
- package/src/renderer/lane-graph/paint.ts +537 -0
- package/src/renderer/lane-graph/semantic-memo.ts +77 -0
- package/src/renderer/layout-engine.ts +2 -57
- package/src/renderer/layout.ts +7 -13
- package/src/renderer/markdown-inline.ts +2 -1
- package/src/renderer/markdown-table.ts +17 -12
- package/src/renderer/markdown.ts +92 -34
- package/src/renderer/masked-entry-modal.ts +78 -0
- package/src/renderer/mcp-workspace.ts +166 -203
- package/src/renderer/model-workspace.ts +381 -436
- package/src/renderer/notifications-modal.ts +116 -0
- package/src/renderer/onboarding/onboarding-wizard.ts +178 -588
- package/src/renderer/process-view.ts +192 -0
- package/src/renderer/profile-picker-modal.ts +58 -110
- package/src/renderer/search-overlay.ts +6 -3
- package/src/renderer/selection-modal-overlay.ts +87 -327
- package/src/renderer/semantic-diff.ts +2 -2
- package/src/renderer/session-chips.ts +102 -0
- package/src/renderer/session-picker-modal.ts +177 -297
- package/src/renderer/settings-modal-connections.ts +14 -23
- package/src/renderer/settings-modal-context.ts +367 -0
- package/src/renderer/settings-modal-helpers.ts +6 -11
- package/src/renderer/settings-modal.ts +322 -726
- package/src/renderer/shell-surface.ts +277 -175
- package/src/renderer/shortcuts-overlay.ts +217 -0
- package/src/renderer/status-line.ts +475 -0
- package/src/renderer/surface-compose.ts +174 -0
- package/src/renderer/surface-kit-extra.ts +303 -0
- package/src/renderer/surface-kit-list.ts +366 -0
- package/src/renderer/surface-kit-parts.ts +360 -0
- package/src/renderer/surface-kit.ts +568 -0
- package/src/renderer/syntax-highlighter.ts +280 -197
- package/src/renderer/syntax-theme.ts +51 -0
- package/src/renderer/system-message.ts +0 -1
- package/src/renderer/term-caps.ts +42 -1
- package/src/renderer/terminal-bg-probe.ts +116 -19
- package/src/renderer/terminal-palette-probe.ts +322 -0
- package/src/renderer/terminal-palette-reader.ts +183 -0
- package/src/renderer/terminal-palette.ts +58 -0
- package/src/renderer/theme-mode-config.ts +16 -1
- package/src/renderer/theme.ts +234 -207
- package/src/renderer/thinking.ts +0 -1
- package/src/renderer/throbber.ts +188 -0
- package/src/renderer/toast-center.ts +119 -0
- package/src/renderer/ui-factory.ts +39 -602
- package/src/renderer/ui-primitives.ts +8 -25
- package/src/renderer/usage-modal.ts +353 -0
- package/src/renderer/user-message.ts +58 -0
- package/src/renderer/voice-capture-chip.ts +53 -0
- package/src/runtime/bootstrap-command-context.ts +0 -5
- package/src/runtime/bootstrap-command-parts.ts +38 -89
- package/src/runtime/bootstrap-core.ts +13 -15
- package/src/runtime/bootstrap-hook-bridge.ts +12 -21
- package/src/runtime/bootstrap-notifier-sync.ts +17 -1
- package/src/runtime/bootstrap-shell.ts +16 -50
- package/src/runtime/bootstrap.ts +14 -14
- package/src/runtime/client/fleet-union.ts +5 -5
- package/src/runtime/client/hosted-exit.ts +2 -2
- package/src/runtime/client/hosted-sessions.ts +1 -1
- package/src/runtime/client/spine-adoption.ts +1 -1
- package/src/runtime/context-accounting-source.ts +5 -4
- package/src/runtime/index.ts +1 -0
- package/src/runtime/notification-dispatch.ts +102 -29
- package/src/runtime/recovery-offer-wiring.ts +4 -1
- package/src/runtime/recovery-prompt.ts +31 -15
- package/src/runtime/runtime-services-types.ts +10 -6
- package/src/runtime/services.ts +17 -12
- package/src/runtime/session-continuity-hints.ts +2 -5
- package/src/runtime/session-inbound-inputs.ts +1 -1
- package/src/runtime/session-resume-liveness-confirm.ts +14 -2
- package/src/runtime/startup-typeahead-gate.ts +103 -0
- package/src/runtime/store/domains/domain-read-matrix.ts +0 -1
- package/src/runtime/store/domains/index.ts +0 -8
- package/src/runtime/store/selectors/index.ts +0 -28
- package/src/runtime/store/state.ts +0 -8
- package/src/runtime/ui-services.ts +4 -6
- package/src/runtime/usage-tracker.ts +348 -0
- package/src/runtime/wrfc-persistence.ts +4 -4
- package/src/shell/blocking-input.ts +92 -2
- package/src/shell/recovery-input-helpers.ts +1 -1
- package/src/shell/session-views.ts +539 -0
- package/src/shell/status-report.ts +86 -0
- package/src/shell/transcript-scroll.ts +68 -0
- package/src/shell/ui-openers.ts +84 -172
- package/src/shell/view-openers.ts +205 -0
- package/src/tools/wrfc-agent-guard.ts +22 -2
- package/src/utils/format-duration.ts +4 -8
- package/src/utils/splash-lines.ts +9 -1
- package/src/utils/terminal-width.ts +56 -0
- package/src/verification/live-verifier.ts +0 -10
- package/src/version.ts +1 -1
- package/src/{panels → views}/agent-inspector-shared.ts +2 -2
- package/src/{panels → views}/builtin-modals.ts +22 -21
- package/src/views/builtin-views.ts +135 -0
- package/src/{panels → views}/confirm-state.ts +9 -9
- package/src/{panels → views}/diff-review-model.ts +10 -3
- package/src/{panels → views}/eval-registry.ts +1 -1
- package/src/{panels → views}/fleet-acts.ts +49 -85
- package/src/{panels/fleet-panel-format.ts → views/fleet-format.ts} +40 -40
- package/src/{panels → views}/fleet-gateway.ts +5 -5
- package/src/{panels → views}/fleet-observed-render.ts +16 -16
- package/src/{panels → views}/fleet-read-model.ts +9 -9
- package/src/{panels/fleet-tabs.ts → views/fleet-session-tabs.ts} +13 -13
- package/src/{panels → views}/fleet-spawn.ts +33 -49
- package/src/{panels → views}/fleet-steer.ts +12 -12
- package/src/{panels → views}/fleet-stop.ts +4 -4
- package/src/{panels → views}/fleet-transcript.ts +26 -27
- package/src/{panels/fleet-panel-worktree-detail.ts → views/fleet-worktree-detail.ts} +7 -7
- package/src/{panels → views}/hosted-session-feed.ts +6 -6
- package/src/views/modal-surface-registry.ts +41 -0
- package/src/{panels → views}/modals/devices-modal.ts +2 -2
- package/src/{panels → views}/modals/hooks-modal.ts +13 -13
- package/src/{panels → views}/modals/keybindings-modal.ts +19 -27
- package/src/{panels → views}/modals/knowledge-modal.ts +6 -5
- package/src/{panels → views}/modals/local-auth-modal.ts +22 -21
- package/src/{panels → views}/modals/marketplace-modal.ts +11 -11
- package/src/{panels → views}/modals/memory-modal.ts +8 -8
- package/src/{panels → views}/modals/modal-surface-helpers.ts +15 -5
- package/src/{panels → views}/modals/pairing-modal.ts +9 -9
- package/src/{panels → views}/modals/planning-modal.ts +15 -20
- package/src/{panels → views}/modals/plugins-modal.ts +6 -6
- package/src/{panels → views}/modals/policy-modal.ts +13 -5
- package/src/{panels → views}/modals/provider-health-modal.ts +4 -4
- package/src/{panels → views}/modals/remote-modal.ts +3 -3
- package/src/{panels → views}/modals/sandbox-modal.ts +4 -4
- package/src/{panels → views}/modals/security-modal.ts +22 -16
- package/src/{panels → views}/modals/services-modal.ts +3 -3
- package/src/{panels → views}/modals/settings-sync-modal.ts +4 -4
- package/src/{panels → views}/modals/skills-modal.ts +9 -9
- package/src/{panels → views}/modals/subscription-modal.ts +3 -3
- package/src/{panels → views}/modals/work-plan-modal.ts +10 -13
- package/src/views/notifications-feed.ts +314 -0
- package/src/{panels → views}/polish-core.ts +38 -36
- package/src/{panels → views}/polish-tables.ts +35 -26
- package/src/{panels → views}/polish.ts +101 -95
- package/src/{panels → views}/project-planning-answer-actions.ts +3 -3
- package/src/{panels → views}/provider-health-routes.ts +14 -14
- package/src/{panels → views}/search-focus.ts +8 -8
- package/src/{panels → views}/session-maintenance.ts +11 -11
- package/src/views/skills-discovery.ts +159 -0
- package/src/views/view-deps.ts +80 -0
- package/src/views/view-panel-adapter.ts +53 -0
- package/src/{panels → views}/workstream-graph-render.ts +1 -1
- package/src/core/conversation-fold.ts +0 -101
- package/src/core/conversation-turn-structure.ts +0 -464
- package/src/core/conversation-user-receipts.ts +0 -42
- package/src/input/commands/operator-panel-runtime.ts +0 -186
- package/src/input/panel-integration-actions.ts +0 -33
- package/src/input/panel-mouse-geometry.ts +0 -97
- package/src/input/panel-paste-flood-guard.ts +0 -86
- package/src/panels/base-panel.ts +0 -301
- package/src/panels/builtin/agent.ts +0 -27
- package/src/panels/builtin/development.ts +0 -92
- package/src/panels/builtin/knowledge.ts +0 -12
- package/src/panels/builtin/operations.ts +0 -177
- package/src/panels/builtin/session.ts +0 -81
- package/src/panels/builtin/shared.ts +0 -357
- package/src/panels/builtin-panels.ts +0 -28
- package/src/panels/cost-tracker-panel.ts +0 -746
- package/src/panels/diff-panel.ts +0 -797
- package/src/panels/diff-review-panel.ts +0 -395
- package/src/panels/expandable-list-panel.ts +0 -189
- package/src/panels/fleet-deep-link.ts +0 -31
- package/src/panels/fleet-panel.ts +0 -799
- package/src/panels/git-panel.ts +0 -800
- package/src/panels/hosted-session-panel.ts +0 -221
- package/src/panels/index.ts +0 -21
- package/src/panels/local-auth-panel.ts +0 -478
- package/src/panels/notifications-feed.ts +0 -127
- package/src/panels/notifications-panel.ts +0 -160
- package/src/panels/panel-confirm-overlay.ts +0 -72
- package/src/panels/panel-manager.ts +0 -791
- package/src/panels/plugins-panel.ts +0 -371
- package/src/panels/scrollable-list-panel.ts +0 -498
- package/src/panels/skills-panel.ts +0 -454
- package/src/panels/token-budget-panel.ts +0 -688
- package/src/panels/types.ts +0 -191
- package/src/panels/wrfc-panel-format.ts +0 -133
- package/src/renderer/diff-view.ts +0 -134
- package/src/renderer/fleet-tab-strip.ts +0 -56
- package/src/renderer/footer-tips.ts +0 -53
- package/src/renderer/fullscreen-primitives.ts +0 -146
- package/src/renderer/fullscreen-workspace.ts +0 -194
- package/src/renderer/hint-grammar.ts +0 -52
- package/src/renderer/modal-factory.ts +0 -480
- package/src/renderer/overlay-box.ts +0 -154
- package/src/renderer/overlay-viewport.ts +0 -104
- package/src/renderer/panel-composite.ts +0 -145
- package/src/renderer/panel-workspace-bar.ts +0 -54
- package/src/renderer/process-indicator.ts +0 -163
- package/src/renderer/tab-strip.ts +0 -222
- package/src/renderer/text-layout.ts +0 -31
- package/src/renderer/tool-call.ts +0 -276
- package/src/renderer/tool-result-expanded-lines.ts +0 -48
- package/src/renderer/tool-result-summary.ts +0 -219
- package/src/runtime/diagnostics/panels/index.ts +0 -21
- package/src/runtime/diagnostics/panels/ops.ts +0 -156
- package/src/runtime/perf/panel-contracts.ts +0 -32
- package/src/runtime/store/domains/panels.ts +0 -117
- package/src/verification/verification-ledger.ts +0 -707
- /package/src/{panels → views}/memory-consolidation-gateway.ts +0 -0
- /package/src/{panels → views}/modals/modal-theme.ts +0 -0
- /package/src/{panels → views}/provider-health-domains.ts +0 -0
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { join } from 'node:path';
|
|
13
13
|
import { Orchestrator, type OrchestratorUserInputOptions } from '@pellux/goodvibes-sdk/platform/core';
|
|
14
14
|
import { AcpManager } from '@pellux/goodvibes-sdk/platform/acp';
|
|
15
|
-
import {
|
|
15
|
+
import { getTierForContextWindow, getTierPromptSupplement } from '@pellux/goodvibes-sdk/platform/providers';
|
|
16
16
|
import { logger, summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
17
17
|
import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
18
18
|
import type { WorkspaceTrustLevel } from '@pellux/goodvibes-sdk/platform/runtime/operations';
|
|
@@ -39,6 +39,7 @@ import type { UiRuntimeServices } from './ui-services.ts';
|
|
|
39
39
|
import { initializeBootstrapCore } from './bootstrap-core.ts';
|
|
40
40
|
import { ensureBootModelResolvable } from './provider-fallback.ts';
|
|
41
41
|
import { createBootstrapShell } from './bootstrap-shell.ts';
|
|
42
|
+
import type { ShellViews } from '../views/builtin-views.ts';
|
|
42
43
|
import { announceResumeState } from './resume-notice.ts';
|
|
43
44
|
import { announceInstallHealth } from './install-self-check-startup.ts';
|
|
44
45
|
import { buildSharedOrchestratorCoreServices, refreshMemoryRecallSnapshot } from './orchestrator-core-services.ts';
|
|
@@ -86,6 +87,8 @@ export type BootstrapContext = RuntimeContext & {
|
|
|
86
87
|
commandContext: CommandContext;
|
|
87
88
|
/** Shell-facing read models, events, and narrow runtime services. */
|
|
88
89
|
uiServices: UiRuntimeServices;
|
|
90
|
+
/** The always-on read models and config-modal surfaces behind the built-in modals. */
|
|
91
|
+
views: ShellViews;
|
|
89
92
|
/** Persists and navigates input history across sessions. */
|
|
90
93
|
inputHistory: InputHistory;
|
|
91
94
|
/** Provides git branch/dirty state for the header. */
|
|
@@ -120,7 +123,7 @@ export type BootstrapContext = RuntimeContext & {
|
|
|
120
123
|
* @remarks
|
|
121
124
|
* Route operational messages through this rather than calling
|
|
122
125
|
* conversation.addSystemMessage() directly so routing-target config
|
|
123
|
-
* (panel/conversation/both) and the forced-inline critical prefixes stay
|
|
126
|
+
* (target 'panel' / 'conversation' / 'both') and the forced-inline critical prefixes stay
|
|
124
127
|
* centralized in one place.
|
|
125
128
|
*/
|
|
126
129
|
systemMessageRouter: SystemMessageRouter;
|
|
@@ -143,7 +146,7 @@ export type BootstrapContext = RuntimeContext & {
|
|
|
143
146
|
* 4. Runtime bus subscriptions (WRFC, subagent, hook bridge)
|
|
144
147
|
* 5. Providers, webhooks, PermissionManager, HookDispatcher
|
|
145
148
|
* 6. Orchestrator + AcpManager
|
|
146
|
-
* 7. MCP auto-connect + workspace/
|
|
149
|
+
* 7. MCP auto-connect + workspace/view manager
|
|
147
150
|
* 8. Command registry + plugin init + CommandContext
|
|
148
151
|
* 9. Input handler wiring
|
|
149
152
|
* 10. Input history, splash options
|
|
@@ -195,7 +198,6 @@ export async function bootstrapRuntime(
|
|
|
195
198
|
const {
|
|
196
199
|
automationManager,
|
|
197
200
|
hookDispatcher,
|
|
198
|
-
panelManager,
|
|
199
201
|
pluginManager,
|
|
200
202
|
} = services;
|
|
201
203
|
// A saved custom-provider model must never crash boot, see provider-fallback.ts.
|
|
@@ -219,9 +221,10 @@ export async function bootstrapRuntime(
|
|
|
219
221
|
permissionManager,
|
|
220
222
|
getSystemPrompt: () => {
|
|
221
223
|
const currentModel = providerRegistry.getCurrentModel();
|
|
222
|
-
|
|
223
|
-
const tier = getTierForContextWindow(
|
|
224
|
-
|
|
224
|
+
// An unknown window (null) picks the standard tier, never the small-model one.
|
|
225
|
+
const tier = getTierForContextWindow(providerRegistry.getKnownContextWindowForModel(currentModel));
|
|
226
|
+
// The main session is a conversation: never the agent-run completion-report demand.
|
|
227
|
+
const supplement = getTierPromptSupplement(tier, { audience: 'conversation' });
|
|
225
228
|
return joinPromptParts(runtime.systemPrompt, TUI_ORCHESTRATION_GUARDRAILS, supplement);
|
|
226
229
|
},
|
|
227
230
|
hookDispatcher,
|
|
@@ -543,7 +546,7 @@ export async function bootstrapRuntime(
|
|
|
543
546
|
label: 'external-services',
|
|
544
547
|
run: async () => {
|
|
545
548
|
// Register the persistent companion-pairing token as the daemon's shared
|
|
546
|
-
// bearer, so tokens scanned from the /qrcode
|
|
549
|
+
// bearer, so tokens scanned from the /qrcode modal's QR actually
|
|
547
550
|
// authenticate against the daemon this surface adopts.
|
|
548
551
|
const daemonHomeDir = join(services.homeDirectory, '.goodvibes', 'daemon');
|
|
549
552
|
const companionTokenRecord = resolveDaemonCompanionToken(daemonHomeDir, GOODVIBES_TUI_SURFACE_ROOT);
|
|
@@ -689,6 +692,7 @@ export async function bootstrapRuntime(
|
|
|
689
692
|
selection,
|
|
690
693
|
commandContext,
|
|
691
694
|
uiServices,
|
|
695
|
+
views: shell.views,
|
|
692
696
|
inputHistory,
|
|
693
697
|
gitStatusProvider,
|
|
694
698
|
lastGitInfoRef,
|
|
@@ -753,12 +757,8 @@ export async function bootstrapRuntime(
|
|
|
753
757
|
// task manager exist unconditionally so pre-gate tasks stay visible. ───────
|
|
754
758
|
ctx.commandContext.ops.acpManager = acpManager;
|
|
755
759
|
if (opsControlPlane) {
|
|
756
|
-
ctx.commandContext.
|
|
757
|
-
|
|
758
|
-
else {
|
|
759
|
-
panelManager.open('ops-control');
|
|
760
|
-
requestRender();
|
|
761
|
-
}
|
|
760
|
+
ctx.commandContext.openOpsView = () => {
|
|
761
|
+
ctx.commandContext.openView?.('ops-control');
|
|
762
762
|
};
|
|
763
763
|
}
|
|
764
764
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* fleet-union.ts, the
|
|
2
|
+
* fleet-union.ts, the Agents modal shows everything running, not just what this
|
|
3
3
|
* terminal started.
|
|
4
4
|
*
|
|
5
5
|
* ── What moved to the SDK, and what stays here ────────────────────────────
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
* reason string a steer/archive against a daemon-only row gets, rather than a
|
|
12
12
|
* bare false). This module is now a thin wrapper over that policy.
|
|
13
13
|
*
|
|
14
|
-
* What stays here is the
|
|
14
|
+
* What stays here is the modal binding: the TUI's own `FleetReadModel`
|
|
15
15
|
* interface (interrupt/resume/kill/steer/archive, subscribe, snapshots) and
|
|
16
16
|
* `buildFleetSnapshot`, the tree-builder + honest cost/token aggregator this
|
|
17
|
-
* repo's
|
|
17
|
+
* repo's Agents modal renders from. Rebuilding through the SAME builder the
|
|
18
18
|
* local view uses, rather than summing two halves, is what keeps the
|
|
19
19
|
* rollups, the cost/token totals and the blocked-on-user ordering computed
|
|
20
20
|
* once, over the whole fleet.
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* `interrupt`/`resume`/`kill`/`steer` reach this process's own children. A
|
|
34
34
|
* daemon row has no child here to signal, so those refuse, and `steer`,
|
|
35
35
|
* which has a reason channel, says why rather than returning a bare false
|
|
36
|
-
* that reads as "the agent ignored you". The
|
|
36
|
+
* that reads as "the agent ignored you". The modal's own act surface
|
|
37
37
|
* (fleet-gateway.ts) already drives the daemon's verbs for the acts the
|
|
38
38
|
* daemon serves.
|
|
39
39
|
*/
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
type DaemonVerbCaller,
|
|
50
50
|
} from '@pellux/goodvibes-sdk/platform/runtime/client';
|
|
51
51
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
52
|
-
import { buildFleetSnapshot, type FleetReadModel, type FleetSnapshot } from '../../
|
|
52
|
+
import { buildFleetSnapshot, type FleetReadModel, type FleetSnapshot } from '../../views/fleet-read-model.ts';
|
|
53
53
|
|
|
54
54
|
/** Re-exported so an importer that only needs the SDK's policy has one import site. */
|
|
55
55
|
export { DEFAULT_FLEET_REFRESH_MS, daemonOnlyFleetActRefusal, mergeFleetNodes, readDaemonFleetRows };
|
|
@@ -26,7 +26,7 @@ import { logger, summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
|
26
26
|
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
27
27
|
import { createDaemonVerbCaller } from './operator-endpoint.ts';
|
|
28
28
|
import { createHostedSessionsClient } from './hosted-sessions.ts';
|
|
29
|
-
import { getSharedHostedSessionFeed, type HostedSessionFeed } from '../../
|
|
29
|
+
import { getSharedHostedSessionFeed, type HostedSessionFeed } from '../../views/hosted-session-feed.ts';
|
|
30
30
|
|
|
31
31
|
/** How long the exit will wait for the detach before giving up on it. */
|
|
32
32
|
export const HOSTED_DETACH_ON_EXIT_TIMEOUT_MS = 1_500;
|
|
@@ -34,7 +34,7 @@ export const HOSTED_DETACH_ON_EXIT_TIMEOUT_MS = 1_500;
|
|
|
34
34
|
export interface LeaveHostedSessionOnExitOptions {
|
|
35
35
|
readonly configManager: ConfigManager;
|
|
36
36
|
readonly homeDirectory: string | (() => string);
|
|
37
|
-
/** Defaults to the shared feed the `/hosted` command and the
|
|
37
|
+
/** Defaults to the shared feed the `/hosted` command and the hosted-sessions modal use. */
|
|
38
38
|
readonly feed?: HostedSessionFeed | undefined;
|
|
39
39
|
readonly timeoutMs?: number | undefined;
|
|
40
40
|
}
|
|
@@ -68,7 +68,7 @@ export function terminalHostedClientId(): string {
|
|
|
68
68
|
return cachedClientId;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
/** The narrow client the command layer and the
|
|
71
|
+
/** The narrow client the command layer and the hosted-sessions modal share. */
|
|
72
72
|
export interface HostedSessionsClient {
|
|
73
73
|
/** This terminal's attach identity, the same string the records carry. */
|
|
74
74
|
readonly clientId: string;
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* - `sessions.inputs.list` / `sessions.inputs.deliver`, the inbound steer
|
|
30
30
|
* path, so a message another surface queued for THIS session lands in the
|
|
31
31
|
* turn machinery here and is acknowledged on the wire.
|
|
32
|
-
* - `sessions.list`, the cross-surface union the
|
|
32
|
+
* - `sessions.list`, the cross-surface union the modals read, interval-
|
|
33
33
|
* refreshed and served synchronously.
|
|
34
34
|
* - the memory spine's wire transport, folded into the same handler by the
|
|
35
35
|
* SDK, this module's own `syncMemorySpineToHostStatus` call is retired;
|
|
@@ -24,7 +24,7 @@ export interface CompactionActivityBus {
|
|
|
24
24
|
* - getTurnInjections() → Orchestrator.getTurnInjections() (the same bounded
|
|
25
25
|
* ring `/recall injections` renders from).
|
|
26
26
|
* - getTokenState() → Orchestrator.usage / lastInputTokens (the same
|
|
27
|
-
* counters the footer's context bar and
|
|
27
|
+
* counters the footer's context bar and the usage modal read), plus the
|
|
28
28
|
* current model's context window from the provider registry.
|
|
29
29
|
* - getCompactionState() → compactionCount from SessionLineageTracker (the
|
|
30
30
|
* same counter session-maintenance and /compact read); isCompacting is
|
|
@@ -35,7 +35,7 @@ export interface CompactionActivityBus {
|
|
|
35
35
|
*/
|
|
36
36
|
export interface ContextAccountingSourceDeps {
|
|
37
37
|
readonly orchestrator: Pick<Orchestrator, 'getTurnInjections' | 'usage' | 'lastInputTokens'>;
|
|
38
|
-
readonly providerRegistry: Pick<ProviderRegistry, 'getCurrentModel' | '
|
|
38
|
+
readonly providerRegistry: Pick<ProviderRegistry, 'getCurrentModel' | 'getKnownContextWindowForModel'>;
|
|
39
39
|
readonly sessionLineageTracker: Pick<SessionLineageTracker, 'getCompactionCount'>;
|
|
40
40
|
readonly runtimeBus?: CompactionActivityBus | null | undefined;
|
|
41
41
|
readonly sessionId: string;
|
|
@@ -83,11 +83,12 @@ export function createContextAccountingSource(deps: ContextAccountingSourceDeps)
|
|
|
83
83
|
getTurnInjections: () => deps.orchestrator.getTurnInjections(),
|
|
84
84
|
getTokenState: () => {
|
|
85
85
|
const currentModel = deps.providerRegistry.getCurrentModel();
|
|
86
|
-
|
|
86
|
+
// null when nothing states the window (a guess, or disproven by a larger accepted request).
|
|
87
|
+
const contextWindow = deps.providerRegistry.getKnownContextWindowForModel(currentModel);
|
|
87
88
|
return {
|
|
88
89
|
measured: { ...deps.orchestrator.usage },
|
|
89
90
|
lastInputTokens: deps.orchestrator.lastInputTokens,
|
|
90
|
-
contextWindow: contextWindow > 0 ? contextWindow : null,
|
|
91
|
+
contextWindow: contextWindow !== null && contextWindow > 0 ? contextWindow : null,
|
|
91
92
|
};
|
|
92
93
|
},
|
|
93
94
|
getCompactionState: () => ({
|
package/src/runtime/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* The SDK's NotificationRouter decides where each domain notification goes
|
|
6
6
|
* (conversation / status_bar / panel_only) and collapses bursts and batches.
|
|
7
7
|
* Nothing in the running app routed real notifications before this: the
|
|
8
|
-
* panel_only feed (
|
|
8
|
+
* panel_only feed (views/notifications-feed.ts) and the notifications modal existed with no
|
|
9
9
|
* upstream. This module builds the router, records every panel_only decision
|
|
10
10
|
* (including burst-collapsed ones) into the shared feed, and bridges the
|
|
11
11
|
* runtime event bus so real domain events become notifications.
|
|
@@ -14,12 +14,19 @@
|
|
|
14
14
|
import { createNotificationRouter, type NotificationRouter } from '@pellux/goodvibes-sdk/platform/runtime/ui';
|
|
15
15
|
import type { Notification, RoutingDecision, RuntimeEventBus, RuntimeEventDomain } from '@/runtime/index.ts';
|
|
16
16
|
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
17
|
-
import { getSharedNotificationFeed, type
|
|
17
|
+
import { getSharedNotificationFeed, type NotificationFeed } from '../views/notifications-feed.ts';
|
|
18
|
+
import { publishNotice, type NoticeSink } from '../core/notices.ts';
|
|
18
19
|
import { memoryPressureLine, memoryPressureLevel, type MemoryPressurePayload } from '@pellux/goodvibes-sdk/platform/runtime/memory';
|
|
20
|
+
import { runtimeEventKey } from '@pellux/goodvibes-sdk/platform/runtime/bootstrap';
|
|
19
21
|
|
|
20
22
|
export interface NotificationDispatcher {
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Route a notification; a panel_only (or burst-collapsed) decision lands in
|
|
25
|
+
* the feed. `eventKey` names the runtime event it came from (the SDK's
|
|
26
|
+
* runtimeEventKey), so the feed keeps one entry when the same event also
|
|
27
|
+
* arrives as a conversation notice. Returns the decision.
|
|
28
|
+
*/
|
|
29
|
+
dispatch(notification: Notification, eventKey?: string): RoutingDecision;
|
|
23
30
|
/** Surface batch-held notifications (call on a timer / when quiet-typing ends). */
|
|
24
31
|
flush(): void;
|
|
25
32
|
readonly router: NotificationRouter;
|
|
@@ -28,7 +35,7 @@ export interface NotificationDispatcher {
|
|
|
28
35
|
/**
|
|
29
36
|
* The runtime event domains whose events surface as operational notifications.
|
|
30
37
|
* Deliberately a curated set of user-relevant, completion/attention-shaped
|
|
31
|
-
* domains, not every domain, so the
|
|
38
|
+
* domains, not every domain, so the notifications modal reflects meaningful operational
|
|
32
39
|
* activity rather than raw event churn. The router's per-domain verbosity and
|
|
33
40
|
* burst/batch policies still collapse floods within these.
|
|
34
41
|
*/
|
|
@@ -41,46 +48,102 @@ export const NOTIFICATION_BRIDGE_DOMAINS: readonly RuntimeEventDomain[] = [
|
|
|
41
48
|
'security',
|
|
42
49
|
];
|
|
43
50
|
|
|
44
|
-
/**
|
|
45
|
-
export
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return words.map((word, index) => (index === 0 ? word[0]!.toUpperCase() + word.slice(1) : word)).join(' ');
|
|
51
|
+
/** A runtime event a person reads in the notification history: its plain title and severity. */
|
|
52
|
+
export interface PersonFacingEvent {
|
|
53
|
+
readonly title: string;
|
|
54
|
+
readonly level: Notification['level'];
|
|
49
55
|
}
|
|
50
56
|
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
/**
|
|
58
|
+
* The runtime events that become notification-history entries, by event type,
|
|
59
|
+
* with the plain title each one shows. Everything else on the bridged domains
|
|
60
|
+
* (stream deltas, progress ticks, gate results, state changes, queue and start
|
|
61
|
+
* events) is internal traffic and never enters the history: this table is an
|
|
62
|
+
* allowlist, so a new SDK event type stays out until someone names it here.
|
|
63
|
+
*/
|
|
64
|
+
export const PERSON_FACING_EVENTS: Readonly<Record<string, PersonFacingEvent>> = {
|
|
65
|
+
// agents
|
|
66
|
+
AGENT_COMPLETED: { title: 'Agent finished', level: 'info' },
|
|
67
|
+
AGENT_FAILED: { title: 'Agent failed', level: 'warning' },
|
|
68
|
+
AGENT_CANCELLED: { title: 'Agent cancelled', level: 'info' },
|
|
69
|
+
AGENT_AWAITING_MESSAGE: { title: 'Agent is waiting for a reply', level: 'info' },
|
|
70
|
+
// tasks
|
|
71
|
+
TASK_COMPLETED: { title: 'Task finished', level: 'info' },
|
|
72
|
+
TASK_FAILED: { title: 'Task failed', level: 'warning' },
|
|
73
|
+
TASK_BLOCKED: { title: 'Task blocked', level: 'warning' },
|
|
74
|
+
TASK_CANCELLED: { title: 'Task cancelled', level: 'info' },
|
|
75
|
+
// workflows (review chains)
|
|
76
|
+
WORKFLOW_CHAIN_PASSED: { title: 'Review chain passed', level: 'info' },
|
|
77
|
+
WORKFLOW_CHAIN_FAILED: { title: 'Review chain failed', level: 'warning' },
|
|
78
|
+
WORKFLOW_CASCADE_ABORTED: { title: 'Review chain stopped', level: 'warning' },
|
|
79
|
+
WORKFLOW_AUTO_COMMITTED: { title: 'Reviewed changes committed', level: 'info' },
|
|
80
|
+
WORKFLOW_SCORE_REGRESSION: { title: 'Review score dropped', level: 'warning' },
|
|
81
|
+
// automation (scheduled jobs)
|
|
82
|
+
AUTOMATION_RUN_COMPLETED: { title: 'Scheduled job finished', level: 'info' },
|
|
83
|
+
AUTOMATION_RUN_FAILED: { title: 'Scheduled job failed', level: 'warning' },
|
|
84
|
+
AUTOMATION_JOB_AUTO_DISABLED: { title: 'Scheduled job turned off after repeated failures', level: 'warning' },
|
|
85
|
+
AUTOMATION_SCHEDULE_ERROR: { title: 'Schedule could not be read', level: 'warning' },
|
|
86
|
+
// deliveries (outgoing channel messages)
|
|
87
|
+
DELIVERY_FAILED: { title: 'Message delivery failed', level: 'warning' },
|
|
88
|
+
DELIVERY_DEAD_LETTERED: { title: 'Message could not be delivered', level: 'warning' },
|
|
89
|
+
// security
|
|
90
|
+
AUTH_FAILED: { title: 'Sign-in failed', level: 'warning' },
|
|
91
|
+
COMPANION_PAIR_REQUESTED: { title: 'Device pairing requested', level: 'info' },
|
|
92
|
+
COMPANION_PAIR_VERIFIED: { title: 'Device paired', level: 'info' },
|
|
93
|
+
COMPANION_TOKEN_REVOKED: { title: 'Device access revoked', level: 'info' },
|
|
94
|
+
TOKEN_ROTATION_WARNING: { title: 'Access token expires soon', level: 'warning' },
|
|
95
|
+
TOKEN_ROTATION_EXPIRED: { title: 'Access token expired', level: 'warning' },
|
|
96
|
+
TOKEN_BLOCKED: { title: 'Access token blocked', level: 'warning' },
|
|
97
|
+
TOKEN_SCOPE_VIOLATION: { title: 'Request refused: outside the token\'s permissions', level: 'warning' },
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/** The history entry an event type makes, or undefined for internal traffic that is not recorded. */
|
|
101
|
+
export function personFacingEvent(type: string): PersonFacingEvent | undefined {
|
|
102
|
+
return Object.prototype.hasOwnProperty.call(PERSON_FACING_EVENTS, type) ? PERSON_FACING_EVENTS[type] : undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The detail line an event payload carries (an error or cancel reason, a chain's landing outcome, or the commit it made), if any. */
|
|
106
|
+
export function eventDetail(payload: unknown): string | undefined {
|
|
107
|
+
if (!payload || typeof payload !== 'object') return undefined;
|
|
108
|
+
const record = payload as Record<string, unknown>;
|
|
109
|
+
// `note`: a passed review chain's landing outcome (committed, or why not, e.g. a refusing commit hook).
|
|
110
|
+
for (const field of ['error', 'reason', 'note']) {
|
|
111
|
+
const value = record[field];
|
|
112
|
+
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
113
|
+
}
|
|
114
|
+
const commit = record['commitHash'];
|
|
115
|
+
if (typeof commit === 'string' && commit.trim()) return `commit ${commit.trim().slice(0, 7)}`;
|
|
116
|
+
return undefined;
|
|
57
117
|
}
|
|
58
118
|
|
|
59
119
|
export function createNotificationDispatcher(
|
|
60
120
|
configManager: Pick<ConfigManager, 'get'>,
|
|
61
|
-
feed:
|
|
121
|
+
feed: NotificationFeed = getSharedNotificationFeed(),
|
|
62
122
|
): NotificationDispatcher {
|
|
63
123
|
const router = createNotificationRouter(undefined, undefined, configManager);
|
|
64
|
-
|
|
124
|
+
/** Event keys of notifications the router is holding in a batch, for when the batch is flushed. */
|
|
125
|
+
const heldEventKeys = new WeakMap<Notification, string>();
|
|
126
|
+
const recordIfFeedTarget = (notification: Notification, decision: RoutingDecision, eventKey: string | undefined): void => {
|
|
65
127
|
if (decision.suppressed) return;
|
|
66
|
-
if (decision.target === 'panel_only') feed.record(notification, decision);
|
|
128
|
+
if (decision.target === 'panel_only') feed.record(notification, decision, eventKey);
|
|
67
129
|
};
|
|
68
130
|
return {
|
|
69
131
|
router,
|
|
70
|
-
dispatch(notification) {
|
|
132
|
+
dispatch(notification, eventKey) {
|
|
71
133
|
const decision = router.route(notification);
|
|
72
|
-
|
|
134
|
+
if (eventKey) heldEventKeys.set(notification, eventKey);
|
|
135
|
+
recordIfFeedTarget(notification, decision, eventKey);
|
|
73
136
|
return decision;
|
|
74
137
|
},
|
|
75
138
|
flush() {
|
|
76
139
|
for (const { notification } of router.flush()) {
|
|
77
|
-
// A flushed batch head surfaces as a batch-collapsed
|
|
140
|
+
// A flushed batch head surfaces as a batch-collapsed feed entry; the
|
|
78
141
|
// feed folds all sharing this batch key into one running-count row.
|
|
79
142
|
feed.record(notification, {
|
|
80
143
|
target: 'panel_only',
|
|
81
144
|
reasonCode: 'batch_window_collapsed',
|
|
82
145
|
batchKey: `${notification.domain}:${notification.level}`,
|
|
83
|
-
});
|
|
146
|
+
}, heldEventKeys.get(notification));
|
|
84
147
|
}
|
|
85
148
|
},
|
|
86
149
|
};
|
|
@@ -114,9 +177,10 @@ export function wireMemoryPressureNotice(
|
|
|
114
177
|
}
|
|
115
178
|
|
|
116
179
|
/**
|
|
117
|
-
* Bridge the runtime event bus to the dispatcher: each event
|
|
118
|
-
*
|
|
119
|
-
*
|
|
180
|
+
* Bridge the runtime event bus to the dispatcher: each person-facing event
|
|
181
|
+
* (PERSON_FACING_EVENTS) in a curated domain becomes a notification with its
|
|
182
|
+
* plain title and is routed. Internal events are not recorded at all. Returns
|
|
183
|
+
* an unsubscribe function that detaches every domain listener.
|
|
120
184
|
*/
|
|
121
185
|
export function wireRuntimeNotificationBridge(
|
|
122
186
|
runtimeBus: RuntimeEventBus,
|
|
@@ -125,14 +189,23 @@ export function wireRuntimeNotificationBridge(
|
|
|
125
189
|
): () => void {
|
|
126
190
|
const unsubscribes = domains.map((domain) =>
|
|
127
191
|
runtimeBus.onDomain(domain, (envelope) => {
|
|
192
|
+
const event = personFacingEvent(envelope.type);
|
|
193
|
+
if (!event) return;
|
|
194
|
+
const body = eventDetail(envelope.payload);
|
|
128
195
|
dispatcher.dispatch({
|
|
129
196
|
id: envelope.traceId ?? `${domain}-${envelope.type}-${envelope.ts}`,
|
|
130
197
|
domain,
|
|
131
|
-
level:
|
|
132
|
-
title:
|
|
198
|
+
level: event.level,
|
|
199
|
+
title: event.title,
|
|
200
|
+
...(body ? { body } : {}),
|
|
133
201
|
timestamp: envelope.ts,
|
|
134
|
-
});
|
|
202
|
+
}, runtimeEventKey(envelope.type, envelope.payload));
|
|
135
203
|
}),
|
|
136
204
|
);
|
|
137
205
|
return () => { for (const unsubscribe of unsubscribes) unsubscribe(); };
|
|
138
206
|
}
|
|
207
|
+
|
|
208
|
+
/** The shell's conversation notice sink: every system notice is a toast and a history entry (core/notices.ts). */
|
|
209
|
+
export function createShellNoticeSink(feed: NotificationFeed = getSharedNotificationFeed()): NoticeSink {
|
|
210
|
+
return (content, { restored }) => publishNotice(feed, content, { restored });
|
|
211
|
+
}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* numbers on screen describe the conversation actually in memory.
|
|
28
28
|
*/
|
|
29
29
|
import { applyRecoverySnapshot, confirmRecoveryRestore } from '@pellux/goodvibes-sdk/platform/runtime/operations';
|
|
30
|
-
import type { RecoveryPromptDeps } from './recovery-prompt.ts';
|
|
30
|
+
import type { RecoveryPromptDeps, RecoveryTypeaheadHooks } from './recovery-prompt.ts';
|
|
31
31
|
import type { ConversationManager, ConversationMessageSnapshot } from '../core/conversation.ts';
|
|
32
32
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
33
33
|
import type { SessionSurface } from '@/runtime/index.ts';
|
|
@@ -44,6 +44,8 @@ export interface RecoveryOfferWiringInput {
|
|
|
44
44
|
readonly writeLastSessionPointer: (sessionId: string) => void;
|
|
45
45
|
readonly receipt: (line: string) => void;
|
|
46
46
|
readonly render: () => void;
|
|
47
|
+
/** Holds typeahead out of the offer modal (see RecoveryPromptDeps.typeahead). */
|
|
48
|
+
readonly typeahead?: RecoveryTypeaheadHooks;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export function buildRecoveryOfferWiring(input: RecoveryOfferWiringInput): RecoveryPromptDeps {
|
|
@@ -54,6 +56,7 @@ export function buildRecoveryOfferWiring(input: RecoveryOfferWiringInput): Recov
|
|
|
54
56
|
get openSelection() { return input.commandContext.openSelection; },
|
|
55
57
|
receipt: input.receipt,
|
|
56
58
|
render: input.render,
|
|
59
|
+
...(input.typeahead ? { typeahead: input.typeahead } : {}),
|
|
57
60
|
applySnapshot: ({ sessionId }) => {
|
|
58
61
|
const persist = (messages: ConversationMessageSnapshot[]): void => {
|
|
59
62
|
input.sessionManager.save(sessionId, messages as never[], {
|
|
@@ -111,6 +111,19 @@ export interface RecoveryPromptDeps {
|
|
|
111
111
|
* session has the newest snapshot".
|
|
112
112
|
*/
|
|
113
113
|
readonly targetSessionId?: string;
|
|
114
|
+
/**
|
|
115
|
+
* Keys typed before the offer appeared must not answer it. Called right
|
|
116
|
+
* before the first modal opens (arm) and once the whole flow is over
|
|
117
|
+
* (settled), so the shell can hold typeahead out of the modal and replay it
|
|
118
|
+
* into the composer afterwards (runtime/startup-typeahead-gate.ts).
|
|
119
|
+
*/
|
|
120
|
+
readonly typeahead?: RecoveryTypeaheadHooks;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** See RecoveryPromptDeps.typeahead. */
|
|
124
|
+
export interface RecoveryTypeaheadHooks {
|
|
125
|
+
readonly onModalShown: () => void;
|
|
126
|
+
readonly onFlowSettled: () => void;
|
|
114
127
|
}
|
|
115
128
|
|
|
116
129
|
// ─── Honest fact formatting ─────────────────────────────────────────────────
|
|
@@ -284,6 +297,7 @@ function findOfferableSnapshot(deps: RecoveryPromptDeps): RecoveryFileInfo | nul
|
|
|
284
297
|
* a failure anywhere in here must not take a boot down.
|
|
285
298
|
*/
|
|
286
299
|
export async function offerRecoverySnapshot(deps: RecoveryPromptDeps): Promise<RecoveryPromptOutcome> {
|
|
300
|
+
let shown = false;
|
|
287
301
|
try {
|
|
288
302
|
// Housekeeping first: recovery time is when the removal ledger gets its
|
|
289
303
|
// bounds actually applied to disk and says what it discarded. Without this
|
|
@@ -308,6 +322,8 @@ export async function offerRecoverySnapshot(deps: RecoveryPromptDeps): Promise<R
|
|
|
308
322
|
const bytes = deps.snapshotBytes ? deps.snapshotBytes(info.sessionId) : defaultSnapshotBytes(deps.surface, info.sessionId);
|
|
309
323
|
const facts = describeRecoverySnapshot(info, { nowMs, bytes });
|
|
310
324
|
|
|
325
|
+
deps.typeahead?.onModalShown();
|
|
326
|
+
shown = true;
|
|
311
327
|
const answer = await ask(open, RECOVERY_OFFER_TITLE, buildRecoveryOfferItems(facts));
|
|
312
328
|
|
|
313
329
|
if (answer === 'resume') {
|
|
@@ -359,28 +375,28 @@ export async function offerRecoverySnapshot(deps: RecoveryPromptDeps): Promise<R
|
|
|
359
375
|
// Best-effort by construction: a recovery offer that fails must leave the
|
|
360
376
|
// snapshot untouched and the boot unharmed.
|
|
361
377
|
return 'none';
|
|
378
|
+
} finally {
|
|
379
|
+
if (shown) deps.typeahead?.onFlowSettled();
|
|
362
380
|
}
|
|
363
381
|
}
|
|
364
382
|
|
|
365
383
|
// ─── Startup wiring ─────────────────────────────────────────────────────────
|
|
366
384
|
|
|
367
385
|
/**
|
|
368
|
-
* Raise the recovery offer
|
|
386
|
+
* Raise the recovery offer at startup, BEFORE the shell's first frame.
|
|
369
387
|
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
* the
|
|
388
|
+
* The modal is opened synchronously (offerRecoverySnapshot runs synchronously
|
|
389
|
+
* up to the modal), so the first frame the user ever sees already has the
|
|
390
|
+
* question on it: the composer is never live underneath a question that is
|
|
391
|
+
* about to appear. It used to be raised on a macrotask after the first frame,
|
|
392
|
+
* which on a busy boot came seconds after the composer was drawn and took the
|
|
393
|
+
* keys typed into it (the search row got the text, Enter resumed). Keys typed
|
|
394
|
+
* before the frame was painted are the typeahead gate's job
|
|
395
|
+
* (deps.typeahead, startup-typeahead-gate.ts).
|
|
375
396
|
*
|
|
376
|
-
*
|
|
377
|
-
* swallows its own errors
|
|
378
|
-
* boundary.
|
|
397
|
+
* Fire-and-forget: nothing awaits the answer, and every failure mode ends with
|
|
398
|
+
* the snapshot untouched (offerRecoverySnapshot swallows its own errors).
|
|
379
399
|
*/
|
|
380
|
-
export function
|
|
381
|
-
|
|
382
|
-
void offerRecoverySnapshot(deps).catch(() => {
|
|
383
|
-
// Best-effort: a failed offer must never take the shell down.
|
|
384
|
-
});
|
|
385
|
-
}, 0).unref?.();
|
|
400
|
+
export function startRecoveryOffer(deps: RecoveryPromptDeps): Promise<RecoveryPromptOutcome> {
|
|
401
|
+
return offerRecoverySnapshot(deps);
|
|
386
402
|
}
|
|
@@ -54,7 +54,7 @@ import type { RuntimeEventBus, DistributedRuntimeManager, RemoteRunnerRegistry,
|
|
|
54
54
|
import type { VoiceProviderRegistry, VoiceService } from '@pellux/goodvibes-sdk/platform/voice';
|
|
55
55
|
import type { CacheRegistry, PauseController, MemoryGovernor } from '@pellux/goodvibes-sdk/platform/runtime/memory';
|
|
56
56
|
import type { WebSearchProviderRegistry, WebSearchService } from '@pellux/goodvibes-sdk/platform/web-search';
|
|
57
|
-
import type {
|
|
57
|
+
import type { ViewPanelAdapter } from '../views/view-panel-adapter.ts';
|
|
58
58
|
import type { HookActivityTracker } from '@pellux/goodvibes-sdk/platform/hooks';
|
|
59
59
|
import type { HookDispatcher, HookWorkbench } from '@pellux/goodvibes-sdk/platform/hooks';
|
|
60
60
|
import type { PluginManager } from '@pellux/goodvibes-sdk/platform/plugins';
|
|
@@ -118,7 +118,11 @@ export interface RuntimeServices {
|
|
|
118
118
|
readonly runtimeBus: RuntimeEventBus;
|
|
119
119
|
readonly runtimeStore: RuntimeStore;
|
|
120
120
|
readonly runtimeDispatch: DomainDispatch;
|
|
121
|
-
|
|
121
|
+
/**
|
|
122
|
+
* The SDK's panel-manager contract (the operator API's panels.list /
|
|
123
|
+
* panels.open), answered by the modal views.
|
|
124
|
+
*/
|
|
125
|
+
readonly panelManager: ViewPanelAdapter;
|
|
122
126
|
readonly keybindingsManager: KeybindingsManager;
|
|
123
127
|
readonly routeBindings: RouteBindingManager;
|
|
124
128
|
readonly surfaceRegistry: SurfaceRegistry;
|
|
@@ -128,7 +132,7 @@ export interface RuntimeServices {
|
|
|
128
132
|
readonly watcherRegistry: WatcherRegistry;
|
|
129
133
|
/**
|
|
130
134
|
* This surface's own record of the asks IT raised, what the approval card
|
|
131
|
-
* and the
|
|
135
|
+
* and the modal renders. Not authoritative: `requestApproval` below raises the
|
|
132
136
|
* same ask on the daemon, whose record every other surface reads.
|
|
133
137
|
*/
|
|
134
138
|
readonly approvalBroker: ApprovalBroker;
|
|
@@ -168,7 +172,7 @@ export interface RuntimeServices {
|
|
|
168
172
|
readonly localhostFetchApproval: ReturnType<typeof buildLocalhostFetchApproval>;
|
|
169
173
|
/** Terminal prompt-answer handler that rides the approval broker; shared by the tool registry and orchestrator so an interactive command's prompt gets an ask/card on every surface. */
|
|
170
174
|
readonly execPromptAnswerHandler: ReturnType<typeof buildExecPromptAnswerHandler>;
|
|
171
|
-
/** Routes curated runtime-domain events into the panel_only notification feed (the
|
|
175
|
+
/** Routes curated runtime-domain events into the panel_only notification feed (the notifications modal's live producer). */
|
|
172
176
|
readonly notificationDispatcher: NotificationDispatcher;
|
|
173
177
|
/** Durable user-origin permission rules (remembered approvals); permissions.rules.* surface. Mirrors the SDK composition. */
|
|
174
178
|
readonly userPermissionRuleStore: UserPermissionRuleStore;
|
|
@@ -280,10 +284,10 @@ export interface RuntimeServices {
|
|
|
280
284
|
/** Controller the governor uses to pause/resume the deferrable background jobs under pressure. */
|
|
281
285
|
readonly pauseController: PauseController;
|
|
282
286
|
readonly sessionLiveTurnControls: SessionLiveTurnControlsHolder;
|
|
283
|
-
/** Unified live process registry (agents, WRFC chains, workflows, watchers, background processes) backing the
|
|
287
|
+
/** Unified live process registry (agents, WRFC chains, workflows, watchers, background processes) backing the Agents modal; archive-aware, finished subtrees can be moved to the session archive view. */
|
|
284
288
|
readonly processRegistry: ArchivableProcessRegistry;
|
|
285
289
|
/**
|
|
286
|
-
* What the
|
|
290
|
+
* What the Agents modal reads: this surface's own registry rows UNION the
|
|
287
291
|
* adopted daemon's, deduped by node id with the local (live, actionable) copy
|
|
288
292
|
* winning. Interval-refreshed on the daemon half, see client/fleet-union.ts.
|
|
289
293
|
*/
|