@pellux/goodvibes-tui 1.16.1 → 1.18.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 +138 -9
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +5490 -1806
- package/package.json +7 -7
- package/src/cli/completions/generate.ts +5 -4
- package/src/cli/config-overrides.ts +51 -11
- package/src/cli/doctor.ts +4 -5
- package/src/cli/entrypoint.ts +13 -8
- package/src/cli/help.ts +7 -6
- package/src/cli/launch-auto-update.ts +214 -0
- package/src/cli/management-commands.ts +82 -15
- package/src/cli/management.ts +0 -2
- package/src/cli/parser.ts +5 -0
- package/src/cli/status.ts +13 -0
- package/src/cli/surface-command.ts +5 -5
- package/src/cli/tui-startup.ts +60 -97
- package/src/cli/types.ts +2 -0
- package/src/config/index.ts +1 -1
- package/src/config/tui-extension-settings.ts +33 -0
- package/src/core/composer-state.ts +1 -1
- package/src/core/consolidation-receipt.ts +41 -0
- package/src/core/conversation-line-cache.ts +3 -3
- package/src/core/conversation-rendering.ts +18 -9
- package/src/core/conversation.ts +2 -2
- package/src/core/long-task-notifier.ts +7 -7
- package/src/core/memory-provenance.ts +67 -0
- package/src/core/pairing-devices.ts +49 -0
- package/src/core/pairing-handoff.ts +101 -0
- package/src/core/pairing-offers.ts +83 -0
- package/src/core/pairing-origin.ts +78 -0
- package/src/core/pairing-tailscale-gateway.ts +56 -0
- package/src/core/power-chip-source.ts +91 -0
- package/src/core/power-status.ts +95 -0
- package/src/core/stable-host.ts +171 -0
- package/src/core/stream-event-wiring.ts +29 -6
- package/src/core/system-message-noise.ts +1 -1
- package/src/core/system-message-router.ts +6 -6
- package/src/core/turn-budget-outcome.ts +60 -0
- package/src/core/turn-cancellation.ts +40 -1
- package/src/core/turn-event-wiring.ts +14 -8
- package/src/daemon/cli.ts +64 -58
- package/src/daemon/lifecycle.ts +41 -0
- package/src/daemon/service-commands.ts +5 -5
- package/src/export/cost-utils.ts +128 -6
- package/src/input/autocomplete.ts +2 -2
- package/src/input/command-registry.ts +55 -9
- package/src/input/commands/acp-runtime.ts +72 -0
- package/src/input/commands/ci-runtime.ts +5 -1
- package/src/input/commands/codebase-runtime.ts +6 -6
- package/src/input/commands/cost-runtime.ts +1 -1
- package/src/input/commands/devices-runtime.ts +109 -0
- package/src/input/commands/git-runtime.ts +28 -4
- package/src/input/commands/graph-runtime.ts +45 -0
- package/src/input/commands/health-runtime.ts +2 -2
- package/src/input/commands/intelligence-runtime.ts +1 -1
- package/src/input/commands/local-auth-runtime.ts +1 -1
- package/src/input/commands/local-provider-runtime.ts +49 -10
- package/src/input/commands/local-runtime.ts +53 -5
- package/src/input/commands/memory.ts +2 -2
- package/src/input/commands/operator-panel-runtime.ts +5 -5
- package/src/input/commands/operator-rpc.ts +32 -11
- package/src/input/commands/permissions-provenance.ts +1 -1
- package/src/input/commands/permissions-runtime.ts +99 -8
- package/src/input/commands/planning-runtime.ts +3 -3
- package/src/input/commands/platform-sandbox-runtime.ts +1 -1
- package/src/input/commands/power-runtime.ts +56 -0
- package/src/input/commands/provider-accounts-runtime.ts +71 -6
- package/src/input/commands/provider.ts +7 -5
- package/src/input/commands/qrcode-runtime.ts +14 -19
- package/src/input/commands/queue-runtime.ts +70 -0
- package/src/input/commands/recall-files-git.ts +13 -51
- package/src/input/commands/recall-files.ts +8 -11
- package/src/input/commands/recall-review.ts +2 -2
- package/src/input/commands/relay-runtime.ts +1 -1
- package/src/input/commands/remote-runtime.ts +1 -1
- package/src/input/commands/runtime-services.ts +4 -4
- package/src/input/commands/schedule-runtime.ts +14 -7
- package/src/input/commands/services-runtime.ts +1 -1
- package/src/input/commands/session-workflow.ts +2 -2
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/share-runtime.ts +1 -1
- package/src/input/commands/shell-core.ts +46 -68
- package/src/input/commands/subscription-runtime.ts +1 -1
- package/src/input/commands/update-runtime.ts +153 -96
- package/src/input/commands/work-plan-runtime.ts +1 -1
- package/src/input/commands/workstream-attempts.ts +6 -1
- package/src/input/commands/workstream-runtime.ts +46 -27
- package/src/input/commands/worktree-runtime.ts +35 -8
- package/src/input/commands.ts +10 -2
- package/src/input/config-modal-types.ts +14 -3
- package/src/input/config-modal.ts +75 -13
- package/src/input/feature-unit-layout.ts +93 -82
- package/src/input/feed-context-factory.ts +2 -2
- package/src/input/handler-command-route.ts +2 -2
- package/src/input/handler-content-actions.ts +1 -1
- package/src/input/handler-feed-routes.ts +7 -7
- package/src/input/handler-feed.ts +4 -4
- package/src/input/handler-interactions.ts +3 -2
- package/src/input/handler-modal-routes.ts +12 -4
- package/src/input/handler-modal-token-routes.ts +1 -1
- package/src/input/handler-onboarding-daemon-adopt.ts +2 -2
- package/src/input/handler-onboarding.ts +3 -2
- package/src/input/handler-picker-routes.ts +26 -13
- package/src/input/handler-shortcuts.ts +29 -6
- package/src/input/handler.ts +2 -2
- package/src/input/keybindings.ts +21 -3
- package/src/input/onboarding/onboarding-feature-units.ts +34 -27
- package/src/input/onboarding/onboarding-provider-key-fields.ts +112 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +22 -21
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +17 -0
- package/src/input/onboarding/onboarding-wizard-network-adopt.ts +2 -2
- package/src/input/onboarding/onboarding-wizard-steps.ts +30 -42
- package/src/input/panel-integration-actions.ts +2 -2
- package/src/input/panel-mouse-geometry.ts +1 -1
- package/src/input/panel-paste-flood-guard.ts +1 -1
- package/src/input/provider-key-intake.ts +167 -0
- package/src/input/sandbox-exec-config.ts +2 -2
- package/src/input/selection-modal.ts +1 -1
- package/src/input/settings-modal-activation.ts +5 -0
- package/src/input/settings-modal-adjustment.ts +4 -31
- package/src/input/settings-modal-data.ts +52 -57
- package/src/input/settings-modal-mutations.ts +12 -68
- package/src/input/settings-modal-types.ts +27 -17
- package/src/input/settings-modal.ts +74 -55
- package/src/main.ts +90 -90
- package/src/panels/agent-inspector-shared.ts +4 -4
- package/src/panels/base-panel.ts +2 -2
- package/src/panels/builtin/agent.ts +4 -4
- package/src/panels/builtin/development.ts +4 -4
- package/src/panels/builtin/knowledge.ts +1 -1
- package/src/panels/builtin/operations.ts +83 -11
- package/src/panels/builtin/session.ts +5 -5
- package/src/panels/builtin/shared.ts +16 -4
- package/src/panels/builtin-modals.ts +59 -42
- package/src/panels/builtin-panels.ts +1 -1
- package/src/panels/cost-tracker-panel.ts +124 -7
- package/src/panels/diff-panel.ts +39 -6
- package/src/panels/eval-registry.ts +2 -2
- package/src/panels/fleet-acts.ts +446 -0
- package/src/panels/fleet-deep-link.ts +1 -1
- package/src/panels/fleet-gateway.ts +117 -0
- package/src/panels/fleet-observed-render.ts +128 -0
- package/src/panels/fleet-panel-format.ts +163 -11
- package/src/panels/fleet-panel-worktree-detail.ts +14 -0
- package/src/panels/fleet-panel.ts +73 -57
- package/src/panels/fleet-read-model.ts +84 -14
- package/src/panels/fleet-spawn.ts +266 -0
- package/src/panels/fleet-steer.ts +2 -2
- package/src/panels/fleet-stop.ts +41 -5
- package/src/panels/fleet-tabs.ts +15 -16
- package/src/panels/fleet-transcript.ts +5 -5
- package/src/panels/git-panel.ts +2 -2
- package/src/panels/index.ts +4 -1
- package/src/panels/local-auth-panel.ts +1 -1
- package/src/panels/memory-consolidation-gateway.ts +94 -0
- package/src/panels/modals/devices-modal.ts +161 -0
- package/src/panels/modals/hooks-modal.ts +1 -1
- package/src/panels/modals/keybindings-modal.ts +2 -2
- package/src/panels/modals/knowledge-modal.ts +1 -1
- package/src/panels/modals/marketplace-modal.ts +4 -4
- package/src/panels/modals/memory-modal.ts +153 -9
- package/src/panels/modals/modal-surface-helpers.ts +1 -1
- package/src/panels/modals/modal-theme.ts +1 -1
- package/src/panels/modals/pairing-modal.ts +198 -68
- package/src/panels/modals/planning-modal.ts +2 -2
- package/src/panels/modals/plugins-modal.ts +1 -1
- package/src/panels/modals/policy-modal.ts +1 -1
- package/src/panels/modals/security-modal.ts +7 -1
- package/src/panels/modals/skills-modal.ts +1 -1
- package/src/panels/modals/work-plan-modal.ts +3 -3
- package/src/panels/notifications-feed.ts +127 -0
- package/src/panels/notifications-panel.ts +160 -0
- package/src/panels/panel-manager.ts +9 -9
- package/src/panels/plugins-panel.ts +4 -4
- package/src/panels/project-planning-answer-actions.ts +1 -1
- package/src/panels/provider-health-routes.ts +2 -2
- package/src/panels/skills-panel.ts +4 -5
- package/src/panels/token-budget-panel.ts +11 -3
- package/src/panels/types.ts +5 -5
- package/src/panels/workstream-graph-render.ts +123 -0
- package/src/permissions/broker-approval-card.ts +201 -0
- package/src/permissions/hunk-selection.ts +28 -4
- package/src/permissions/prompt.ts +244 -29
- package/src/renderer/autocomplete-overlay.ts +107 -54
- package/src/renderer/code-block.ts +2 -2
- package/src/renderer/compaction-history-modal.ts +1 -1
- package/src/renderer/compaction-preview.ts +1 -1
- package/src/renderer/compaction-quality.ts +1 -1
- package/src/renderer/composer-fragments.ts +69 -0
- package/src/renderer/compositor.ts +2 -2
- package/src/renderer/config-modal.ts +1 -1
- package/src/renderer/conversation-overlays.ts +1 -1
- package/src/renderer/footer-tips.ts +3 -3
- package/src/renderer/hint-grammar.ts +1 -1
- package/src/renderer/modal-factory.ts +1 -1
- package/src/renderer/model-picker-overlay.ts +1 -1
- package/src/renderer/model-workspace.ts +7 -2
- package/src/renderer/panel-composite.ts +2 -2
- package/src/renderer/panel-workspace-bar.ts +1 -1
- package/src/renderer/process-indicator.ts +1 -1
- package/src/renderer/selection-modal-overlay.ts +1 -1
- package/src/renderer/session-picker-modal.ts +2 -2
- package/src/renderer/settings-modal-helpers.ts +23 -5
- package/src/renderer/settings-modal.ts +129 -39
- package/src/renderer/shell-surface.ts +6 -0
- package/src/renderer/terminal-bg-probe.ts +1 -1
- package/src/renderer/theme.ts +3 -3
- package/src/renderer/tool-call.ts +13 -7
- package/src/renderer/tool-result-summary.ts +1 -1
- package/src/renderer/turn-injection.ts +7 -6
- package/src/renderer/ui-factory.ts +38 -1
- package/src/runtime/bootstrap-command-context.ts +7 -2
- package/src/runtime/bootstrap-command-parts.ts +9 -5
- package/src/runtime/bootstrap-core.ts +41 -41
- package/src/runtime/bootstrap-hook-bridge.ts +1 -1
- package/src/runtime/bootstrap-shell.ts +13 -5
- package/src/runtime/bootstrap.ts +34 -32
- package/src/runtime/channel-composition.ts +46 -0
- package/src/runtime/code-index-services.ts +3 -4
- package/src/runtime/daemon-attach-notices.ts +120 -0
- package/src/runtime/durability-services.ts +90 -0
- package/src/runtime/embedded-service-factories.ts +40 -0
- package/src/runtime/feature-settings.ts +147 -0
- package/src/runtime/fleet-services.ts +41 -0
- package/src/runtime/idle-power-services.ts +85 -0
- package/src/runtime/index.ts +6 -21
- package/src/runtime/interaction-seams.ts +109 -0
- package/src/runtime/legacy-daemon-migration.ts +29 -19
- package/src/runtime/memory-fold.ts +1 -1
- package/src/runtime/notification-dispatch.ts +110 -0
- package/src/runtime/onboarding/apply.ts +3 -29
- package/src/runtime/onboarding/fast-path.ts +39 -6
- package/src/runtime/onboarding/provider-key-capture.ts +126 -0
- package/src/runtime/onboarding/snapshot.ts +0 -1
- package/src/runtime/onboarding/types.ts +9 -3
- package/src/runtime/power-keepawake-remote.ts +75 -0
- package/src/runtime/process-lifecycle.ts +3 -1
- package/src/runtime/provider-fallback.ts +55 -0
- package/src/runtime/provider-optimizer-wiring.ts +55 -0
- package/src/runtime/release-artifacts.ts +19 -103
- package/src/runtime/resume-notice.ts +1 -1
- package/src/runtime/services.ts +113 -113
- package/src/runtime/session-continuity-hints.ts +38 -0
- package/src/runtime/surface-feature-flags.ts +40 -9
- package/src/runtime/terminal-output-guard.ts +2 -2
- package/src/runtime/trust/workspace-registration.ts +10 -2
- package/src/runtime/trust/workspace-trust.ts +58 -31
- package/src/runtime/ui-services.ts +6 -1
- package/src/runtime/update-check.ts +15 -69
- package/src/runtime/workstream-services.ts +2 -2
- package/src/shell/blocking-input.ts +108 -132
- package/src/shell/recovery-input-helpers.ts +53 -166
- package/src/shell/ui-openers.ts +38 -6
- package/src/utils/format-duration.ts +1 -1
- package/src/verification/verification-ledger.ts +21 -4
- package/src/version.ts +1 -1
- package/src/input/commands/flags-runtime.ts +0 -328
|
@@ -74,6 +74,7 @@ export interface BootstrapCommandActionOptions {
|
|
|
74
74
|
|
|
75
75
|
export interface BootstrapCommandSectionOptions {
|
|
76
76
|
readonly configManager: ConfigManager;
|
|
77
|
+
readonly pairingTokens?: import('@pellux/goodvibes-sdk/platform/pairing').PairingTokenManager;
|
|
77
78
|
readonly featureFlagManager?: FeatureFlagManager;
|
|
78
79
|
readonly providerRegistry: ProviderRegistry;
|
|
79
80
|
readonly conversation: ConversationManager;
|
|
@@ -86,7 +87,7 @@ export interface BootstrapCommandSectionOptions {
|
|
|
86
87
|
readonly mcpRegistry: McpRegistry;
|
|
87
88
|
readonly voiceProviderRegistry?: VoiceProviderRegistry;
|
|
88
89
|
readonly voiceService?: VoiceService;
|
|
89
|
-
/**
|
|
90
|
+
/** Direct-command consumers (`/search`, `/image`) of already-constructed RuntimeServices. */
|
|
90
91
|
readonly webSearchService?: import('@pellux/goodvibes-sdk/platform/web-search').WebSearchService;
|
|
91
92
|
readonly mediaProviders?: import('@pellux/goodvibes-sdk/platform/media').MediaProviderRegistry;
|
|
92
93
|
readonly artifactStore?: import('@pellux/goodvibes-sdk/platform/artifacts').ArtifactStore;
|
|
@@ -139,6 +140,7 @@ export interface BootstrapCommandSectionOptions {
|
|
|
139
140
|
readonly remoteRuntime?: RemoteCommandService;
|
|
140
141
|
readonly planRuntime?: PlanRuntimeService;
|
|
141
142
|
readonly operatorClient?: OperatorClient;
|
|
143
|
+
readonly userPermissionRuleStore?: import('@pellux/goodvibes-sdk/platform/permissions').UserPermissionRuleStore;
|
|
142
144
|
readonly peerClient?: PeerClient;
|
|
143
145
|
readonly providerApi?: ProviderApi;
|
|
144
146
|
readonly knowledgeApi?: KnowledgeApi;
|
|
@@ -203,7 +205,7 @@ export function createBootstrapCommandActions(
|
|
|
203
205
|
} = options;
|
|
204
206
|
|
|
205
207
|
const showPanel = (panelId: string, pane?: 'top' | 'bottom', target?: PanelDeepLinkTarget) => {
|
|
206
|
-
//
|
|
208
|
+
// (the purge): a MIGRATE-TO-MODAL id resolves to a modal, not a panel.
|
|
207
209
|
// panelManager.open() fires the injected openModal callback and returns a
|
|
208
210
|
// no-op sentinel — so skip panelManager.show() (which would reveal an empty
|
|
209
211
|
// panel workspace behind the modal) when this id redirects. Keeps every
|
|
@@ -307,7 +309,7 @@ export function createBootstrapCommandActions(
|
|
|
307
309
|
openMemoryPanel: () => {
|
|
308
310
|
showPanel('memory');
|
|
309
311
|
},
|
|
310
|
-
//
|
|
312
|
+
// remote/subscription migrated to config-modal surfaces. open() hits
|
|
311
313
|
// the modal redirect and invokes the openModal callback — do NOT go through
|
|
312
314
|
// showPanel here, which would additionally reveal + focus an (empty) panel
|
|
313
315
|
// workspace behind the fullscreen modal.
|
|
@@ -395,13 +397,14 @@ export function createBootstrapCommandWorkspaceSection(
|
|
|
395
397
|
export function createBootstrapCommandPlatformSection(
|
|
396
398
|
options: Pick<
|
|
397
399
|
BootstrapCommandSectionOptions,
|
|
398
|
-
'configManager' | 'featureFlagManager' | 'voiceProviderRegistry' | 'voiceService' | 'webSearchService' | 'mediaProviders' | 'artifactStore'
|
|
400
|
+
'configManager' | 'pairingTokens' | 'featureFlagManager' | 'voiceProviderRegistry' | 'voiceService' | 'webSearchService' | 'mediaProviders' | 'artifactStore'
|
|
399
401
|
>,
|
|
400
402
|
shellServices: BootstrapCommandShellServices,
|
|
401
403
|
): BootstrapCommandPlatformSection {
|
|
402
404
|
return {
|
|
403
405
|
config: getConfigSnapshot(options.configManager),
|
|
404
406
|
configManager: options.configManager,
|
|
407
|
+
...(options.pairingTokens ? { pairingTokens: options.pairingTokens } : {}),
|
|
405
408
|
featureFlagManager: options.featureFlagManager,
|
|
406
409
|
voiceProviderRegistry: options.voiceProviderRegistry,
|
|
407
410
|
voiceService: options.voiceService,
|
|
@@ -435,11 +438,12 @@ export function createBootstrapCommandExtensionsSection(
|
|
|
435
438
|
export function createBootstrapCommandClientsSection(
|
|
436
439
|
options: Pick<
|
|
437
440
|
BootstrapCommandSectionOptions,
|
|
438
|
-
'operatorClient' | 'peerClient' | 'providerApi' | 'knowledgeApi' | 'memorySpine' | 'hookApi' | 'mcpApi' | 'opsApi' | 'directTransport'
|
|
441
|
+
'operatorClient' | 'userPermissionRuleStore' | 'peerClient' | 'providerApi' | 'knowledgeApi' | 'memorySpine' | 'hookApi' | 'mcpApi' | 'opsApi' | 'directTransport'
|
|
439
442
|
>,
|
|
440
443
|
): BootstrapCommandClientSection {
|
|
441
444
|
return {
|
|
442
445
|
operator: options.operatorClient,
|
|
446
|
+
userPermissionRuleStore: options.userPermissionRuleStore,
|
|
443
447
|
peer: options.peerClient,
|
|
444
448
|
providerApi: options.providerApi,
|
|
445
449
|
knowledgeApi: options.knowledgeApi,
|
|
@@ -6,6 +6,7 @@ import { ConfigManager, getConfiguredSystemPrompt } from '../config/index.ts';
|
|
|
6
6
|
import { getProviderIdFromModel } from '../config/provider-model.ts';
|
|
7
7
|
import { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
8
8
|
import { registerAllTools } from '@pellux/goodvibes-sdk/platform/tools';
|
|
9
|
+
import { createSandboxContainmentNotice } from './daemon-attach-notices.ts';
|
|
9
10
|
import { PermissionManager, createPermissionConfigReader } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
10
11
|
import { Notifier } from '@pellux/goodvibes-sdk/platform/integrations';
|
|
11
12
|
import { Compositor } from '../renderer/compositor.ts';
|
|
@@ -17,15 +18,16 @@ import type { ControlPlaneRecentEvent } from '@pellux/goodvibes-sdk/platform/con
|
|
|
17
18
|
import type { BootstrapOptions } from './context.ts';
|
|
18
19
|
import { createRuntimeStore, createDomainDispatch, type RuntimeStore } from './store/index.ts';
|
|
19
20
|
import {
|
|
20
|
-
type MutableRuntimeState, type SessionEvent, createFeatureFlagManager, RuntimeEventBus, ForensicsCollector,
|
|
21
|
+
type MutableRuntimeState, type SessionEvent, bindFeatureSettingsBridge, createFeatureFlagManager, deriveFeatureStates, RuntimeEventBus, ForensicsCollector,
|
|
21
22
|
ForensicsRegistry, generateUserSessionId, loadBootstrapSystemPrompt, syncConfiguredServices,
|
|
22
23
|
registerBootstrapHookBridge, registerBootstrapRuntimeEvents,
|
|
23
24
|
} from '@/runtime/index.ts';
|
|
24
25
|
import { readExecEnvScrubAllowlist } from '../input/exec-env-scrub-config.ts';
|
|
25
26
|
import { createSandboxExecAsk, sandboxExecAskDepsFromRuntime } from '../permissions/sandbox-exec-gate.ts';
|
|
26
27
|
import { createRuntimeServices, type RuntimeServices } from './services.ts';
|
|
28
|
+
import { createHostPowerSeam } from '@pellux/goodvibes-sdk/platform/power';
|
|
27
29
|
import { runBootMemoryFold } from './memory-fold.ts';
|
|
28
|
-
import {
|
|
30
|
+
import { wireCostPricing } from '../export/cost-utils.ts';
|
|
29
31
|
import { createUiRuntimeServices, type UiRuntimeServices } from './ui-services.ts';
|
|
30
32
|
import { join } from 'node:path';
|
|
31
33
|
import { installWrfcAgentToolGuard } from '../tools/wrfc-agent-guard.ts';
|
|
@@ -33,12 +35,10 @@ import { createWrfcPersistence, type WrfcPersistence } from './wrfc-persistence.
|
|
|
33
35
|
import type { SystemMessagePriority } from '../core/system-message-router.ts';
|
|
34
36
|
import { SessionSpineClient, SessionUnionCache, TUI_SPINE_PARTICIPANT } from '@pellux/goodvibes-sdk/platform/runtime/session-spine';
|
|
35
37
|
import { SessionInboundInputPoller, createBootstrapInboundInputPoller } from './session-inbound-inputs.ts';
|
|
36
|
-
import {
|
|
38
|
+
import { trustGatedAsk, type WorkspaceTrustLevel } from './trust/workspace-trust.ts';
|
|
37
39
|
import { syncNotifierQueueIntegrations } from './bootstrap-notifier-sync.ts';
|
|
38
40
|
|
|
39
|
-
//
|
|
40
|
-
// Pre-router buffer
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
41
|
+
// --- Pre-router buffer ---
|
|
42
42
|
|
|
43
43
|
const PRE_ROUTER_BUFFER_MAX = 100;
|
|
44
44
|
|
|
@@ -105,6 +105,7 @@ export interface BootstrapCoreState {
|
|
|
105
105
|
readonly runtimeUnsubs: Array<() => void>;
|
|
106
106
|
readonly agentStatusIntervalRef: { value: ReturnType<typeof setInterval> | null };
|
|
107
107
|
readonly permissionPromptRef: { requestPermission: PermissionRequestHandler };
|
|
108
|
+
readonly trustPromptRef: { requestTrustDecision: () => Promise<WorkspaceTrustLevel> }; // trust-at-consequence-time bridge, patched with the real modal-driving impl once the UI layer exists
|
|
108
109
|
readonly systemMessageRouterRef: { value: SystemMessageRouter | null };
|
|
109
110
|
readonly conversationFollowUpRef: { value: ((item: ConversationFollowUpItem) => void) | null };
|
|
110
111
|
/**
|
|
@@ -131,9 +132,7 @@ export interface BootstrapCoreState {
|
|
|
131
132
|
|
|
132
133
|
export type CompanionMessagePayload = Extract<SessionEvent, { type: 'COMPANION_MESSAGE_RECEIVED' }>;
|
|
133
134
|
|
|
134
|
-
//
|
|
135
|
-
// Operator narration of inbound channel events
|
|
136
|
-
// ---------------------------------------------------------------------------
|
|
135
|
+
// --- Operator narration of inbound channel events ---
|
|
137
136
|
|
|
138
137
|
/** Narrate an inbound channel event (GitHub, Slack, ntfy, etc.) that triggered an
|
|
139
138
|
* agent turn, via the SystemMessageRouter — null for internal/companion sources. */
|
|
@@ -231,10 +230,12 @@ export async function initializeBootstrapCore(
|
|
|
231
230
|
const homeDirectory = options.homeDirectory;
|
|
232
231
|
const configManager = options.configManager;
|
|
233
232
|
|
|
233
|
+
// Gate states derive from the domain settings keys; the bridge keeps live
|
|
234
|
+
// config writes flowing (honest pending-restart markers for startup-gated
|
|
235
|
+
// features). Mirrors the SDK composition root's owned-manager wiring.
|
|
234
236
|
const featureFlags = createFeatureFlagManager();
|
|
235
|
-
featureFlags.loadFromConfig({
|
|
236
|
-
|
|
237
|
-
});
|
|
237
|
+
featureFlags.loadFromConfig({ flags: deriveFeatureStates(configManager) });
|
|
238
|
+
bindFeatureSettingsBridge(configManager, featureFlags);
|
|
238
239
|
|
|
239
240
|
const userSessionId = `user-${generateUserSessionId()}`;
|
|
240
241
|
const runtimeBus = new RuntimeEventBus();
|
|
@@ -247,20 +248,19 @@ export async function initializeBootstrapCore(
|
|
|
247
248
|
runtimeBus,
|
|
248
249
|
runtimeStore: store,
|
|
249
250
|
getConversationTitle: () => getConversationTitle(),
|
|
250
|
-
workingDir,
|
|
251
|
-
|
|
252
|
-
//
|
|
253
|
-
|
|
251
|
+
workingDir, homeDirectory,
|
|
252
|
+
// Embedded topology: the in-process runtime IS the daemon and holds its own OS
|
|
253
|
+
// inhibitor, so opt into the real host seam (fork default is non-spawning). See services.ts.
|
|
254
|
+
powerSeam: createHostPowerSeam(),
|
|
254
255
|
});
|
|
255
|
-
await services.workspaceTrustManager.load(); // settle trust
|
|
256
|
+
await services.workspaceTrustManager.load(); // settle any already-persisted trust decision before any tool runs
|
|
256
257
|
const providerRegistry = services.providerRegistry;
|
|
257
258
|
providerRegistry.initModelLimits();
|
|
258
259
|
services.benchmarkStore.initBenchmarks();
|
|
259
260
|
providerRegistry.initCatalog();
|
|
260
|
-
// Wire cost-utils to the live catalog
|
|
261
|
-
// pricing from unpriced (
|
|
262
|
-
|
|
263
|
-
setPricingSource(() => providerRegistry.getRawCatalogModels());
|
|
261
|
+
// Wire cost-utils to the live catalog AND the ONE pricing resolver so every
|
|
262
|
+
// cost surface distinguishes real pricing from unpriced and names its source ("your price" vs "catalog price, as of <date>") — see cost-utils.
|
|
263
|
+
wireCostPricing(providerRegistry);
|
|
264
264
|
services.keybindingsManager.loadFromDisk();
|
|
265
265
|
domainDispatch.syncControlPlaneState({
|
|
266
266
|
enabled: Boolean(configManager.get('controlPlane.enabled')),
|
|
@@ -351,6 +351,8 @@ export async function initializeBootstrapCore(
|
|
|
351
351
|
const toolRegistry = new ToolRegistry();
|
|
352
352
|
const { fileCache, projectIndex } = registerAllTools(toolRegistry, {
|
|
353
353
|
surfaceRoot: 'tui',
|
|
354
|
+
localhostFetchApproval: services.localhostFetchApproval, // loopback-fetch ask, built once in the services composition
|
|
355
|
+
execPromptAnswerHandler: services.execPromptAnswerHandler, // terminal prompt-answer path, built once in the services composition
|
|
354
356
|
fileUndoManager: services.fileUndoManager,
|
|
355
357
|
modeManager: services.modeManager,
|
|
356
358
|
processManager: services.processManager,
|
|
@@ -373,21 +375,19 @@ export async function initializeBootstrapCore(
|
|
|
373
375
|
serviceRegistry: services.serviceRegistry,
|
|
374
376
|
overflowHandler: services.overflowHandler,
|
|
375
377
|
changeTracker: services.sessionChangeTracker,
|
|
376
|
-
//
|
|
377
|
-
// variable NAMES kept even though they look credential-bearing. See
|
|
378
|
-
// exec-env-scrub-config.ts (permissions.execEnvScrubAllowlist).
|
|
378
|
+
// Widens the allowlist of credential-looking variable NAMES kept (master switch stays on). See exec-env-scrub-config.ts.
|
|
379
379
|
credentialEnvScrub: { allowlist: readExecEnvScrubAllowlist(configManager) },
|
|
380
|
-
//
|
|
381
|
-
// registry against OUR holder rather than a fresh internal one, so the
|
|
382
|
-
// Orchestrator-backed source bound at bootstrap.ts is what the tool
|
|
383
|
-
// actually reads from. See runtime/context-accounting-source.ts.
|
|
380
|
+
// Register context_accounting against OUR holder (the Orchestrator-backed source bound at bootstrap.ts). See runtime/context-accounting-source.ts.
|
|
384
381
|
contextAccountingHolder: services.contextAccountingHolder,
|
|
382
|
+
// First contained (sandboxed) command run announces "commands now run contained" once — recorded and surfaced now.
|
|
383
|
+
onSandboxedRun: createSandboxContainmentNotice({ configManager, notify: (text) => conversation.log(`[Sandbox] ${text}`, { fg: '135' }) }),
|
|
385
384
|
});
|
|
386
|
-
// Note: installWrfcAgentToolGuard is called after routeOrBuffer is defined
|
|
387
|
-
// (further below) so the onTrace callback can route guard decisions through
|
|
388
|
-
// the pre-router buffer.
|
|
385
|
+
// Note: installWrfcAgentToolGuard is called after routeOrBuffer is defined (further below) so the onTrace callback routes guard decisions through the pre-router buffer.
|
|
389
386
|
services.agentOrchestrator.setDependencies({
|
|
390
387
|
surfaceRoot: 'tui',
|
|
388
|
+
// setDependencies is a wholesale replace: re-install the prompt-answer handler and the loopback-fetch ask here or this rewire silently drops them.
|
|
389
|
+
execPromptAnswerHandler: services.execPromptAnswerHandler,
|
|
390
|
+
localhostFetchApproval: services.localhostFetchApproval,
|
|
391
391
|
fileCache,
|
|
392
392
|
projectIndex,
|
|
393
393
|
workingDirectory: services.workingDirectory,
|
|
@@ -424,7 +424,7 @@ export async function initializeBootstrapCore(
|
|
|
424
424
|
await runBootMemoryFold(memoryStore, services.memoryEmbeddingRegistry, workingDir, logger);
|
|
425
425
|
|
|
426
426
|
const renderRequestRef = { value: (): void => {} };
|
|
427
|
-
//
|
|
427
|
+
// Coalescing render scheduler — collapses N requestRender() calls into 1 and
|
|
428
428
|
// enforces a 16ms minimum interval to cap repaints at ~60fps. renderScheduled stays
|
|
429
429
|
// set for the ENTIRE window (until run() executes), so requestRender() calls arriving
|
|
430
430
|
// on later event-loop ticks within the same 16ms window coalesce into the one
|
|
@@ -467,6 +467,9 @@ export async function initializeBootstrapCore(
|
|
|
467
467
|
const permissionPromptRef = {
|
|
468
468
|
requestPermission: (async () => ({ approved: false, remember: false })) as PermissionRequestHandler,
|
|
469
469
|
};
|
|
470
|
+
// Trust-at-consequence-time: raised by trustGatedAsk on the first non-read
|
|
471
|
+
// request in an undecided workspace; overridden once the UI layer exists — same ref-patching pattern as permissionPromptRef above.
|
|
472
|
+
const trustPromptRef = { requestTrustDecision: (async () => 'restricted') as () => Promise<WorkspaceTrustLevel> };
|
|
470
473
|
approvalBroker.start().catch((err) => logger.warn('approval broker start failed at bootstrap', { err }));
|
|
471
474
|
sharedSessionBroker.start().catch((err) => logger.warn('shared session broker start failed at bootstrap', { err }));
|
|
472
475
|
const runtimeSessionIdRef = { value: userSessionId };
|
|
@@ -663,7 +666,7 @@ export async function initializeBootstrapCore(
|
|
|
663
666
|
|
|
664
667
|
providerRegistry.startWatching(runtimeBus);
|
|
665
668
|
|
|
666
|
-
//
|
|
669
|
+
// attach the SAME WebhookNotifier instance that `/notify add|remove|clear`
|
|
667
670
|
// (notify-runtime.ts) keeps live via ctx.services.webhookNotifier, rather than
|
|
668
671
|
// constructing a second, boot-time-only instance here. Before this fix, a
|
|
669
672
|
// webhook URL added mid-session reached long-task notifications (which read
|
|
@@ -696,8 +699,7 @@ export async function initializeBootstrapCore(
|
|
|
696
699
|
await syncConfiguredServices(domainDispatch.syncIntegration, services.serviceRegistry);
|
|
697
700
|
|
|
698
701
|
const permissionManager = new PermissionManager(
|
|
699
|
-
// Composed ask layer: the workspace trust gate (outer) wraps the sandbox-aware
|
|
700
|
-
// exec gate (inner); see sandbox-exec-gate.ts. The catastrophic block is untouched.
|
|
702
|
+
// Composed ask layer: the workspace trust gate (outer) wraps the sandbox-aware exec gate (inner); see sandbox-exec-gate.ts. The catastrophic block is untouched.
|
|
701
703
|
trustGatedAsk(
|
|
702
704
|
services.workspaceTrustManager,
|
|
703
705
|
createSandboxExecAsk(
|
|
@@ -708,11 +710,13 @@ export async function initializeBootstrapCore(
|
|
|
708
710
|
localPrompt: permissionPromptRef.requestPermission,
|
|
709
711
|
}),
|
|
710
712
|
),
|
|
713
|
+
() => trustPromptRef.requestTrustDecision(), // indirection through the ref, not bound early — main.ts patches the real impl in later
|
|
711
714
|
),
|
|
712
715
|
createPermissionConfigReader(configManager),
|
|
713
716
|
policyRuntimeState,
|
|
714
717
|
services.hookDispatcher,
|
|
715
718
|
featureFlags,
|
|
719
|
+
services.userPermissionRuleStore, // durable remembered approvals (mirrors the SDK composition); permissions.rules.* lists/deletes them
|
|
716
720
|
);
|
|
717
721
|
await hookWorkbench.loadAndApplyManagedHooks();
|
|
718
722
|
|
|
@@ -757,11 +761,7 @@ export async function initializeBootstrapCore(
|
|
|
757
761
|
}, 'bootstrap.session');
|
|
758
762
|
|
|
759
763
|
runtimeUnsubs.push(
|
|
760
|
-
...registerBootstrapHookBridge({
|
|
761
|
-
runtimeBus,
|
|
762
|
-
hookDispatcher,
|
|
763
|
-
runtime,
|
|
764
|
-
}),
|
|
764
|
+
...registerBootstrapHookBridge({ runtimeBus, hookDispatcher, runtime }),
|
|
765
765
|
);
|
|
766
766
|
|
|
767
767
|
return {
|
|
@@ -783,7 +783,7 @@ export async function initializeBootstrapCore(
|
|
|
783
783
|
bootstrapUnsubs,
|
|
784
784
|
runtimeUnsubs,
|
|
785
785
|
agentStatusIntervalRef,
|
|
786
|
-
permissionPromptRef,
|
|
786
|
+
permissionPromptRef, trustPromptRef,
|
|
787
787
|
systemMessageRouterRef,
|
|
788
788
|
conversationFollowUpRef,
|
|
789
789
|
orchestratorHandleUserInputRef,
|
|
@@ -32,7 +32,7 @@ export interface ResumeSessionOptions {
|
|
|
32
32
|
readonly sessionManager: SessionManager;
|
|
33
33
|
readonly panelManager: PanelManager;
|
|
34
34
|
readonly configManager: Pick<ConfigManager, 'get' | 'getCategory'>;
|
|
35
|
-
readonly providerRegistry: Pick<ProviderRegistry, 'get' | 'getCurrentModel' | 'getForModel' | 'require'>;
|
|
35
|
+
readonly providerRegistry: Pick<ProviderRegistry, 'get' | 'getCurrentModel' | 'getForModel' | 'require' | 'resolveModelPricing'>;
|
|
36
36
|
readonly homeDirectory: string;
|
|
37
37
|
/** See CommandSessionServices.hydrateSessionUsage (command-registry.ts). */
|
|
38
38
|
readonly hydrateSessionUsage?: () => void;
|
|
@@ -93,7 +93,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
93
93
|
completeModelSelectionSideEffect,
|
|
94
94
|
} = options;
|
|
95
95
|
|
|
96
|
-
//
|
|
96
|
+
// after any resume seam replays historical messages into `conversation`,
|
|
97
97
|
// the freshly-constructed `orchestrator` still has its zeroed default usage
|
|
98
98
|
// (SDK gap — Orchestrator.usage is never persisted/reseeded). Recompute it
|
|
99
99
|
// from the replayed history so the footer doesn't show Input: 0 post-resume.
|
|
@@ -140,11 +140,11 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
140
140
|
runtimeBus,
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
-
//
|
|
143
|
+
// initial cost-budget alert threshold (USD; 0/unset = disabled).
|
|
144
144
|
// Once the session starts, the real control surface is the CostTrackerPanel
|
|
145
145
|
// itself — the in-panel 'b' key and /cost budget <usd> both call
|
|
146
146
|
// CostTrackerPanel.setBudgetThreshold() directly on the live panel instance,
|
|
147
|
-
// which
|
|
147
|
+
// which now writes through to the behavior.budgetAlertUsd config key
|
|
148
148
|
// so the background budget-breach notifier reads the same value. The env
|
|
149
149
|
// var remains a first-run convenience only: it seeds the config key when
|
|
150
150
|
// that key has never been set, so it doesn't silently override a value the
|
|
@@ -206,6 +206,12 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
206
206
|
runtimeStore,
|
|
207
207
|
openPanel: (panelId: string) => { services.panelManager.open(panelId); },
|
|
208
208
|
knowledgeApi,
|
|
209
|
+
// Fleet acts (pick / conflict / discard) surface receipts through the command
|
|
210
|
+
// context's print and reuse its one-key jump affordance — both late-bound
|
|
211
|
+
// (the command context is assigned to commandContextRef after bootstrap, and
|
|
212
|
+
// main.ts patches armFixSessionAttach onto it).
|
|
213
|
+
fleetActsNotify: (message: string) => { commandContextRef?.print?.(message); requestRender(); },
|
|
214
|
+
armFixSessionAttach: (sessionId: string) => { commandContextRef?.armFixSessionAttach?.(sessionId); },
|
|
209
215
|
});
|
|
210
216
|
services.panelManager.prewarmRegistered();
|
|
211
217
|
|
|
@@ -220,7 +226,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
220
226
|
{
|
|
221
227
|
// Suppress stale WRFC replay re-notifications for chains that can no
|
|
222
228
|
// longer act — gone (killed/removed → getChain null) or terminal
|
|
223
|
-
// (passed/failed). (
|
|
229
|
+
// (passed/failed). (item 1c.)
|
|
224
230
|
isChainTerminal: (chainId) => {
|
|
225
231
|
const chain = services.wrfcController.getChain(chainId);
|
|
226
232
|
return chain === null || chain.state === 'passed' || chain.state === 'failed';
|
|
@@ -239,6 +245,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
239
245
|
|
|
240
246
|
const commandContext: CommandContext = createBootstrapCommandContext({
|
|
241
247
|
configManager,
|
|
248
|
+
pairingTokens: services.pairingTokens,
|
|
242
249
|
providerRegistry: services.providerRegistry,
|
|
243
250
|
conversation,
|
|
244
251
|
runtime,
|
|
@@ -307,6 +314,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
307
314
|
adaptivePlanner: services.adaptivePlanner,
|
|
308
315
|
sessionOrchestration: services.sessionOrchestration,
|
|
309
316
|
operatorClient: directTransport.operator,
|
|
317
|
+
userPermissionRuleStore: services.userPermissionRuleStore,
|
|
310
318
|
peerClient: directTransport.peer,
|
|
311
319
|
knowledgeApi,
|
|
312
320
|
// /recall's browse/link/queue/export/import subcommands and the per-turn
|
|
@@ -345,7 +353,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
345
353
|
lastGitInfoRef.value = info;
|
|
346
354
|
requestRender();
|
|
347
355
|
}).catch(() => { /* non-fatal */ });
|
|
348
|
-
//
|
|
356
|
+
// FIX 2: the header's git segment otherwise only refreshes on
|
|
349
357
|
// TURN_COMPLETED/TOOL_SUCCEEDED/TOOL_FAILED (see turn-event-wiring.ts's
|
|
350
358
|
// refreshGit()) — if the user runs `git init` externally and never submits
|
|
351
359
|
// another turn, the header stays stuck on the startup-time fallback
|
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { AcpManager } from '@pellux/goodvibes-sdk/platform/acp';
|
|
|
15
15
|
import { getTierPromptSupplement, getTierForContextWindow } 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
|
+
import type { WorkspaceTrustLevel } from './trust/workspace-trust.ts';
|
|
18
19
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
19
20
|
import type { InputHistory } from '../input/input-history.ts';
|
|
20
21
|
import type { GitStatusProvider, GitHeaderInfo } from '../renderer/git-status.ts';
|
|
@@ -40,9 +41,9 @@ import { createBootstrapShell } from './bootstrap-shell.ts';
|
|
|
40
41
|
import { announceResumeState } from './resume-notice.ts';
|
|
41
42
|
import { announceInstallSelfCheck } from './install-self-check-startup.ts';
|
|
42
43
|
import { buildSharedOrchestratorCoreServices, refreshMemoryRecallSnapshot } from './orchestrator-core-services.ts';
|
|
44
|
+
import { consumeDaemonAttachNotices, consumeExternalDaemonAttachNotices } from './daemon-attach-notices.ts';
|
|
43
45
|
import { createContextAccountingSource } from './context-accounting-source.ts';
|
|
44
|
-
import {
|
|
45
|
-
import { createSafeHostServeFactory } from '../daemon/safe-serve.ts';
|
|
46
|
+
import { createEmbeddedServiceFactories } from './embedded-service-factories.ts';
|
|
46
47
|
import { buildRelayExternalServiceMethods } from './relay-reachability-bridge.ts';
|
|
47
48
|
import { startMcpConfigAutoReload } from '../mcp/runtime-reload.ts';
|
|
48
49
|
|
|
@@ -95,6 +96,8 @@ export type BootstrapContext = RuntimeContext & {
|
|
|
95
96
|
setRenderRequest: (fn: () => void) => void;
|
|
96
97
|
/** Shell-owned permission prompt bridge that main.ts patches after UI setup. */
|
|
97
98
|
permissionPromptRef: { requestPermission: PermissionRequestHandler };
|
|
99
|
+
/** Shell-owned trust-decision bridge that main.ts patches after UI setup (trust asks at consequence time). */
|
|
100
|
+
trustPromptRef: { requestTrustDecision: () => Promise<WorkspaceTrustLevel> };
|
|
98
101
|
/** Load the most recently saved conversation from disk. */
|
|
99
102
|
loadLastConversation: () => { messages: Array<Record<string, unknown>> } | null;
|
|
100
103
|
/** Write the last-session pointer file (used after session resume). */
|
|
@@ -172,7 +175,7 @@ export async function bootstrapRuntime(
|
|
|
172
175
|
bootstrapUnsubs,
|
|
173
176
|
runtimeUnsubs,
|
|
174
177
|
agentStatusIntervalRef,
|
|
175
|
-
permissionPromptRef,
|
|
178
|
+
permissionPromptRef, trustPromptRef,
|
|
176
179
|
systemMessageRouterRef,
|
|
177
180
|
conversationFollowUpRef,
|
|
178
181
|
orchestratorHandleUserInputRef,
|
|
@@ -192,9 +195,8 @@ export async function bootstrapRuntime(
|
|
|
192
195
|
pluginManager,
|
|
193
196
|
} = services;
|
|
194
197
|
|
|
195
|
-
// A liveness flip is only PAINTED once something calls requestRender();
|
|
196
|
-
//
|
|
197
|
-
// incidental activity redrew it (minutes, during an idle stretch).
|
|
198
|
+
// A liveness flip is only PAINTED once something calls requestRender(); without
|
|
199
|
+
// this, the footer's spine segment sat correct-but-undrawn until incidental activity redrew it (minutes, during an idle stretch).
|
|
198
200
|
sessionUnionCache.setOnTransition(() => requestRender());
|
|
199
201
|
|
|
200
202
|
// ── Phase 6: Orchestrator + AcpManager ───────────────────────────────────
|
|
@@ -237,7 +239,7 @@ export async function bootstrapRuntime(
|
|
|
237
239
|
logger.debug('companion handleUserInput safety catch', { error: String(err) });
|
|
238
240
|
});
|
|
239
241
|
};
|
|
240
|
-
// Shared payload (single source of truth, includes
|
|
242
|
+
// Shared payload (single source of truth, includes the memoryRegistry —
|
|
241
243
|
// see orchestrator-core-services.ts) plus this site's cacheHitTracker.
|
|
242
244
|
orchestrator.setCoreServices({
|
|
243
245
|
...buildSharedOrchestratorCoreServices({ services, configManager, providerRegistry }),
|
|
@@ -254,8 +256,7 @@ export async function bootstrapRuntime(
|
|
|
254
256
|
|
|
255
257
|
const acpManager = new AcpManager({
|
|
256
258
|
requestPermission: (request) => permissionPromptRef.requestPermission(request),
|
|
257
|
-
runtimeBus,
|
|
258
|
-
hookDispatcher: services.hookDispatcher,
|
|
259
|
+
runtimeBus, hookDispatcher: services.hookDispatcher,
|
|
259
260
|
});
|
|
260
261
|
const acpTaskAdapter = new AcpTaskAdapter(store);
|
|
261
262
|
const ACP_TASK_SYNC_INTERVAL_MS = 1_000;
|
|
@@ -265,7 +266,9 @@ export async function bootstrapRuntime(
|
|
|
265
266
|
bootstrapUnsubs.push(() => clearInterval(acpTaskSyncInterval));
|
|
266
267
|
orchestrator.registerDelegateTool(acpManager);
|
|
267
268
|
const opsTaskManager = createTaskManager(store, runtimeBus, userSessionId);
|
|
268
|
-
|
|
269
|
+
// Operator interventions ride the control-plane gateway capability
|
|
270
|
+
// (controlPlane.gateway, on by default; the old never-registered gate id shipped this dead).
|
|
271
|
+
const opsControlPlane = services.featureFlags.isEnabled('control-plane-gateway')
|
|
269
272
|
? new OpsControlPlane(opsTaskManager, runtimeBus, store, userSessionId)
|
|
270
273
|
: undefined;
|
|
271
274
|
|
|
@@ -300,7 +303,7 @@ export async function bootstrapRuntime(
|
|
|
300
303
|
wrfcPersistence.rehydrate();
|
|
301
304
|
const commandRegistry = shell.commandRegistry;
|
|
302
305
|
const commandContext = shell.commandContext;
|
|
303
|
-
// Boot resume notice (
|
|
306
|
+
// Boot resume notice (item 1): after rehydrate() so chain history is ready, before
|
|
304
307
|
// the operator can type anything. Fire-and-forget, same as main.ts's non-blocking
|
|
305
308
|
// `void workspaceCheckpointManager.init().catch(() => {})` — local file I/O only,
|
|
306
309
|
// resolves well before a human can react to the first rendered frame.
|
|
@@ -318,7 +321,7 @@ export async function bootstrapRuntime(
|
|
|
318
321
|
});
|
|
319
322
|
announceInstallSelfCheck(systemMessageRouter);
|
|
320
323
|
const { gitStatusProvider, inputHistory, lastGitInfoRef } = shell;
|
|
321
|
-
//
|
|
324
|
+
// FIX 2: dispose the header's live-repo-state poll (git-status.ts
|
|
322
325
|
// startPolling) on shutdown, same pattern as acpTaskSyncInterval above.
|
|
323
326
|
bootstrapUnsubs.push(() => gitStatusProvider.stopPolling());
|
|
324
327
|
const pluginCommandRegistry = {
|
|
@@ -475,21 +478,9 @@ export async function bootstrapRuntime(
|
|
|
475
478
|
]);
|
|
476
479
|
};
|
|
477
480
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
runtimeBus: bus,
|
|
482
|
-
userAuth,
|
|
483
|
-
runtimeServices,
|
|
484
|
-
serveFactory: createSafeHostServeFactory('Embedded daemon'),
|
|
485
|
-
}),
|
|
486
|
-
createHttpListener: (dispatcher, userAuth, configManager) => new HttpListener({
|
|
487
|
-
hookDispatcher: dispatcher,
|
|
488
|
-
userAuth,
|
|
489
|
-
configManager,
|
|
490
|
-
serveFactory: createSafeHostServeFactory('Embedded HTTP listener'),
|
|
491
|
-
}),
|
|
492
|
-
});
|
|
481
|
+
// Embedded DaemonServer/HttpListener factories (incl. the facade auto-update
|
|
482
|
+
// suppression) — see embedded-service-factories.ts.
|
|
483
|
+
const createExternalServiceFactories = createEmbeddedServiceFactories;
|
|
493
484
|
|
|
494
485
|
let externalServices: ExternalServicesHandle = {
|
|
495
486
|
daemonServer: null, httpListener: null,
|
|
@@ -505,6 +496,9 @@ export async function bootstrapRuntime(
|
|
|
505
496
|
platformExternalServices.externalServices = {
|
|
506
497
|
...buildRelayExternalServiceMethods(() => externalServices.daemonServer),
|
|
507
498
|
inspect: inspectExternalServices,
|
|
499
|
+
// Undelivered daemon receipts (update/crash/migration) for the attach-time
|
|
500
|
+
// consuming read; empty when no daemon runs. Marked delivered once served.
|
|
501
|
+
collectDaemonReceipts: () => (externalServices.daemonServer as { collectDaemonReceipts?: () => readonly { id: string; text: string; at: number }[] } | null)?.collectDaemonReceipts?.() ?? [],
|
|
508
502
|
restart: async () => {
|
|
509
503
|
if (externalServicesPromise) {
|
|
510
504
|
try {
|
|
@@ -527,10 +521,19 @@ export async function bootstrapRuntime(
|
|
|
527
521
|
externalServices = await externalServicesPromise;
|
|
528
522
|
controlPlaneRecentEventsRef.value = (limit) => externalServices.listRecentControlPlaneEvents(limit);
|
|
529
523
|
syncSessionSpineToHostStatus(externalServices.daemonStatus, companionTokenRecord.token);
|
|
524
|
+
await renderDaemonAttachNotices(companionTokenRecord.token);
|
|
530
525
|
requestRender();
|
|
531
526
|
return inspectExternalServices();
|
|
532
527
|
},
|
|
533
528
|
};
|
|
529
|
+
// The attach-time consuming read, exactly once as notices. An adopted EXTERNAL daemon has no in-process handle (daemonServer null), so read its own /status?receipts=consume over HTTP; the embedded daemon keeps the in-process fold.
|
|
530
|
+
const renderDaemonAttachNotices = async (daemonToken: string): Promise<void> => {
|
|
531
|
+
const daemonStatus = externalServices.daemonStatus;
|
|
532
|
+
const notices = daemonStatus.mode === 'external' && daemonStatus.baseUrl
|
|
533
|
+
? await consumeExternalDaemonAttachNotices({ baseUrl: daemonStatus.baseUrl, authToken: daemonToken })
|
|
534
|
+
: consumeDaemonAttachNotices({ configManager, collectReceipts: () => platformExternalServices.externalServices.collectDaemonReceipts() });
|
|
535
|
+
for (const notice of notices) systemMessageRouter.high(`[Daemon] ${notice}`);
|
|
536
|
+
};
|
|
534
537
|
deferredStartup.schedule({
|
|
535
538
|
label: 'plugins',
|
|
536
539
|
run: async () => {
|
|
@@ -591,6 +594,7 @@ export async function bootstrapRuntime(
|
|
|
591
594
|
externalServices = await externalServicesPromise;
|
|
592
595
|
controlPlaneRecentEventsRef.value = (limit) => externalServices.listRecentControlPlaneEvents(limit);
|
|
593
596
|
syncSessionSpineToHostStatus(externalServices.daemonStatus, companionTokenRecord.token);
|
|
597
|
+
await renderDaemonAttachNotices(companionTokenRecord.token);
|
|
594
598
|
requestRender();
|
|
595
599
|
},
|
|
596
600
|
onError: (error) => {
|
|
@@ -713,7 +717,7 @@ export async function bootstrapRuntime(
|
|
|
713
717
|
agentStatusIntervalRef,
|
|
714
718
|
orchestratorRefs,
|
|
715
719
|
setRenderRequest,
|
|
716
|
-
permissionPromptRef,
|
|
720
|
+
permissionPromptRef, trustPromptRef,
|
|
717
721
|
loadLastConversation: () => loadLastConversation({
|
|
718
722
|
workingDirectory: services.workingDirectory,
|
|
719
723
|
homeDirectory: services.homeDirectory,
|
|
@@ -774,10 +778,8 @@ export async function bootstrapRuntime(
|
|
|
774
778
|
},
|
|
775
779
|
};
|
|
776
780
|
|
|
777
|
-
// ── Phase 12b: Operator Control Plane wiring (
|
|
778
|
-
//
|
|
779
|
-
// The store and task manager are created unconditionally so they reflect the
|
|
780
|
-
// real runtime state (tasks registered before the flag check are visible).
|
|
781
|
+
// ── Phase 12b: Operator Control Plane wiring (capability-gated); store and
|
|
782
|
+
// task manager exist unconditionally so pre-gate tasks stay visible. ───────
|
|
781
783
|
ctx.commandContext.ops.acpManager = acpManager;
|
|
782
784
|
if (opsControlPlane) {
|
|
783
785
|
ctx.commandContext.openOpsPanel = () => {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* channel-composition — route bindings, surface registry, and channel plugin
|
|
3
|
+
* registry for the TUI composition root (split out of services.ts for the
|
|
4
|
+
* line cap).
|
|
5
|
+
*
|
|
6
|
+
* RECORDED DIVERGENCE from the SDK composition root: SurfaceRegistry and
|
|
7
|
+
* ChannelPluginRegistry are constructed WITHOUT the gate manager. The SDK's
|
|
8
|
+
* surface gate map only names six surfaces (web/slack/discord/ntfy/webhook/
|
|
9
|
+
* homeassistant) and reads every other adapter (telegram, whatsapp, signal,
|
|
10
|
+
* imessage, msteams, ...) as OFF whenever a manager is present — no settings
|
|
11
|
+
* key could re-enable them. Until the gate map covers every adapter, the
|
|
12
|
+
* honest governing switch here stays the surfaces.<id>.enabled config each
|
|
13
|
+
* adapter already reads, exactly as the feature surface's own
|
|
14
|
+
* constant-binding rule states. RouteBindingManager keeps its manager — its
|
|
15
|
+
* route-binding gate is a real registry feature.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { AutomationRouteStore } from '@pellux/goodvibes-sdk/platform/automation';
|
|
19
|
+
import { ChannelPluginRegistry, RouteBindingManager, SurfaceRegistry } from '@pellux/goodvibes-sdk/platform/channels';
|
|
20
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
21
|
+
import type { FeatureFlagManager, RuntimeEventBus } from '@/runtime/index.ts';
|
|
22
|
+
import type { RuntimeStore } from './store/index.ts';
|
|
23
|
+
|
|
24
|
+
export interface ChannelComposition {
|
|
25
|
+
readonly routeBindings: RouteBindingManager;
|
|
26
|
+
readonly surfaceRegistry: SurfaceRegistry;
|
|
27
|
+
readonly channelPlugins: ChannelPluginRegistry;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createChannelComposition(options: {
|
|
31
|
+
readonly configManager: ConfigManager;
|
|
32
|
+
readonly runtimeStore: RuntimeStore;
|
|
33
|
+
readonly runtimeBus: RuntimeEventBus;
|
|
34
|
+
readonly featureFlags: FeatureFlagManager;
|
|
35
|
+
}): ChannelComposition {
|
|
36
|
+
const routeBindings = new RouteBindingManager({
|
|
37
|
+
store: new AutomationRouteStore({ configManager: options.configManager }),
|
|
38
|
+
runtimeStore: options.runtimeStore,
|
|
39
|
+
runtimeBus: options.runtimeBus,
|
|
40
|
+
featureFlags: options.featureFlags,
|
|
41
|
+
});
|
|
42
|
+
const surfaceRegistry = new SurfaceRegistry(options.configManager, options.runtimeStore);
|
|
43
|
+
const channelPlugins = new ChannelPluginRegistry();
|
|
44
|
+
surfaceRegistry.attachPluginRegistry(channelPlugins);
|
|
45
|
+
return { routeBindings, surfaceRegistry, channelPlugins };
|
|
46
|
+
}
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
// code-index-services.ts — repo source-tree code index (TUI wiring)
|
|
3
3
|
//
|
|
4
4
|
// Constructs the TUI's repo source-tree code index: CodeIndexStore
|
|
5
|
-
// (@pellux/goodvibes-sdk/platform/state
|
|
6
|
-
// Stage A). Extracted into its own module rather than built inline in
|
|
5
|
+
// (@pellux/goodvibes-sdk/platform/state). Extracted into its own module rather than built inline in
|
|
7
6
|
// services.ts: services.ts sits at the architecture check's 800-line cap
|
|
8
7
|
// (scripts/check-architecture.ts), so any new service gets its own
|
|
9
8
|
// construction module and a single wiring call there (mirrors
|
|
@@ -28,7 +27,7 @@
|
|
|
28
27
|
// (interactive main.ts, the daemon, and every test fixture) shares one
|
|
29
28
|
// honest, user-visible on/off switch rather than needing to thread a new
|
|
30
29
|
// boolean through every call site. With it off (the default), `/codebase
|
|
31
|
-
// build` is the explicit, visible trigger — exactly the shape
|
|
30
|
+
// build` is the explicit, visible trigger — exactly the shape this design
|
|
32
31
|
// asks for.
|
|
33
32
|
//
|
|
34
33
|
// Shares memoryEmbeddingRegistry with MemoryStore (constructed in
|
|
@@ -68,7 +67,7 @@ export interface CodeIndexServicesDeps {
|
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
/**
|
|
71
|
-
* Whether
|
|
70
|
+
* Whether code auto-injection / tool-site reindex may run: the SAME
|
|
72
71
|
* storage.codeIndexEnabled switch that gates auto-build. Read live so a runtime
|
|
73
72
|
* /config toggle takes effect without restart. (The separate, default-off
|
|
74
73
|
* `agent-passive-code-injection` feature flag gates injection additionally; this
|