@pellux/goodvibes-tui 1.17.0 → 1.19.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 +208 -0
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +5025 -1636
- package/package.json +7 -7
- package/src/cli/endpoints.ts +50 -4
- package/src/cli/help.ts +29 -2
- package/src/cli/management-commands.ts +99 -23
- package/src/cli/management.ts +0 -2
- package/src/cli/service-posture.ts +5 -3
- package/src/cli/status.ts +27 -6
- package/src/cli/surface-command.ts +29 -15
- package/src/core/consolidation-receipt.ts +41 -0
- package/src/core/conversation-rendering.ts +14 -5
- package/src/core/memory-diagnostics-gateway.ts +99 -0
- package/src/core/memory-provenance.ts +67 -0
- package/src/core/memory-status.ts +118 -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 +21 -0
- package/src/core/turn-budget-outcome.ts +60 -0
- package/src/core/turn-cancellation.ts +39 -0
- package/src/core/turn-event-wiring.ts +6 -0
- package/src/core/voice-provision-gateway.ts +202 -0
- package/src/core/voice-provision-status.ts +197 -0
- package/src/daemon/cli.ts +127 -60
- package/src/input/command-registry.ts +21 -0
- package/src/input/commands/acp-runtime.ts +72 -0
- package/src/input/commands/devices-runtime.ts +109 -0
- package/src/input/commands/experience-runtime.ts +25 -4
- 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 +15 -1
- package/src/input/commands/operator-rpc.ts +32 -11
- package/src/input/commands/power-runtime.ts +56 -0
- package/src/input/commands/qrcode-runtime.ts +14 -19
- package/src/input/commands/queue-runtime.ts +70 -0
- package/src/input/commands/workstream-attempts.ts +6 -1
- package/src/input/commands/workstream-runtime.ts +44 -25
- package/src/input/commands/worktree-runtime.ts +35 -8
- package/src/input/commands.ts +10 -0
- package/src/input/config-modal-types.ts +11 -0
- package/src/input/config-modal.ts +65 -2
- package/src/input/handler-shortcuts.ts +23 -0
- package/src/input/keybindings.ts +19 -1
- package/src/input/settings-modal-data.ts +31 -37
- package/src/input/settings-modal-types.ts +5 -2
- package/src/input/tts-settings-actions.ts +27 -8
- package/src/input/voice-local-settings.ts +52 -0
- package/src/main.ts +42 -42
- package/src/panels/builtin/operations.ts +54 -1
- package/src/panels/builtin/shared.ts +12 -0
- package/src/panels/builtin-modals.ts +49 -32
- package/src/panels/diff-panel.ts +34 -1
- package/src/panels/fleet-acts.ts +446 -0
- package/src/panels/fleet-gateway.ts +117 -0
- package/src/panels/fleet-observed-render.ts +128 -0
- package/src/panels/fleet-panel-format.ts +120 -4
- package/src/panels/fleet-panel-worktree-detail.ts +14 -0
- package/src/panels/fleet-panel.ts +60 -44
- package/src/panels/fleet-read-model.ts +34 -3
- package/src/panels/fleet-spawn.ts +266 -0
- package/src/panels/fleet-stop.ts +38 -2
- package/src/panels/fleet-tabs.ts +2 -2
- package/src/panels/memory-consolidation-gateway.ts +94 -0
- package/src/panels/modals/devices-modal.ts +161 -0
- package/src/panels/modals/memory-modal.ts +149 -5
- package/src/panels/modals/pairing-modal.ts +198 -68
- package/src/panels/modals/security-modal.ts +6 -0
- package/src/panels/workstream-graph-render.ts +123 -0
- package/src/renderer/composer-fragments.ts +69 -0
- package/src/renderer/settings-modal-helpers.ts +9 -0
- package/src/renderer/settings-modal.ts +4 -2
- package/src/renderer/shell-surface.ts +3 -0
- package/src/renderer/tool-call.ts +12 -6
- package/src/renderer/ui-factory.ts +32 -0
- package/src/runtime/bootstrap-command-context.ts +3 -1
- package/src/runtime/bootstrap-command-parts.ts +3 -1
- package/src/runtime/bootstrap-core.ts +6 -6
- package/src/runtime/bootstrap-shell.ts +7 -0
- package/src/runtime/code-index-services.ts +15 -1
- package/src/runtime/durability-services.ts +36 -1
- package/src/runtime/fleet-services.ts +41 -0
- package/src/runtime/idle-power-services.ts +85 -0
- package/src/runtime/index.ts +2 -0
- package/src/runtime/interaction-seams.ts +109 -0
- package/src/runtime/knowledge-services.ts +94 -0
- package/src/runtime/legacy-daemon-migration.ts +38 -6
- package/src/runtime/legacy-daemon-reconcile.ts +439 -0
- package/src/runtime/memory-governance-services.ts +79 -0
- package/src/runtime/notification-dispatch.ts +28 -0
- package/src/runtime/power-keepawake-remote.ts +75 -0
- package/src/runtime/process-lifecycle.ts +3 -1
- package/src/runtime/services.ts +105 -107
- package/src/runtime/ui-services.ts +3 -0
- package/src/runtime/voice-setup-services.ts +104 -0
- package/src/shell/blocking-input.ts +21 -141
- package/src/shell/recovery-input-helpers.ts +53 -166
- package/src/version.ts +11 -2
package/src/runtime/services.ts
CHANGED
|
@@ -4,33 +4,28 @@ import { ConfigManager, ServiceRegistry, SubscriptionManager, ToolLLM } from '@p
|
|
|
4
4
|
import { SecretsManager } from '../config/secrets.ts';
|
|
5
5
|
import { AutomationDeliveryManager, AutomationManager } from '@pellux/goodvibes-sdk/platform/automation';
|
|
6
6
|
import { ChannelDeliveryRouter, ChannelPolicyManager, type ChannelPluginRegistry, type RouteBindingManager, type SurfaceRegistry } from '@pellux/goodvibes-sdk/platform/channels';
|
|
7
|
-
import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
7
|
+
import { ApprovalBroker, GatewayMethodCatalog, SessionLiveTurnControlsHolder, SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
8
|
+
import type { PowerManager } from '@pellux/goodvibes-sdk/platform/power';
|
|
9
|
+
import { wireIdlePowerAndLiveTurn } from './idle-power-services.ts';
|
|
8
10
|
import { StepUpService } from '@pellux/goodvibes-sdk/daemon';
|
|
9
|
-
import {
|
|
11
|
+
import { PairingTokenManager } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
12
|
+
import { resolvePairingWebOrigin } from '../core/pairing-origin.ts';
|
|
13
|
+
import { attachWsOnlyGatewayVerbHandlers } from '@pellux/goodvibes-terminal-shell';
|
|
10
14
|
import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
|
|
11
15
|
import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
HOME_GRAPH_KNOWLEDGE_EXTENSION,
|
|
16
|
-
KnowledgeService,
|
|
17
|
-
KnowledgeSemanticService,
|
|
18
|
-
KnowledgeStore,
|
|
19
|
-
ProjectPlanningService,
|
|
20
|
-
createProviderBackedKnowledgeSemanticLlm,
|
|
21
|
-
createWebKnowledgeGapRepairer,
|
|
22
|
-
projectPlanningProjectIdFromPath,
|
|
23
|
-
} from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
16
|
+
import { createWebKnowledgeGapRepairer } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
17
|
+
import type { HomeGraphService, KnowledgeService, ProjectPlanningService } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
18
|
+
import { createKnowledgeServices } from './knowledge-services.ts';
|
|
24
19
|
import { MediaProviderRegistry, ensureBuiltinMediaProviders } from '@pellux/goodvibes-sdk/platform/media';
|
|
25
20
|
import { MultimodalService } from '@pellux/goodvibes-sdk/platform/multimodal';
|
|
26
21
|
import { AgentMessageBus, AgentOrchestrator, ArchetypeLoader, WrfcController } from '@pellux/goodvibes-sdk/platform/agents';
|
|
27
22
|
import { AgentManager, ContextAccountingHolder, OverflowHandler, ProcessManager, createWorkflowServices, type WorkflowServices } from '@pellux/goodvibes-sdk/platform/tools';
|
|
28
|
-
import { FileStateCache, FileUndoManager, MemoryEmbeddingProviderRegistry, MemoryRegistry, MemoryStore, ModeManager, ProjectIndex, resolveCanonicalMemoryDbPath, type CodeIndexStore, type CodeIndexReindexScheduler } from '@pellux/goodvibes-sdk/platform/state';
|
|
23
|
+
import { FileStateCache, FileUndoManager, MemoryConsolidationScheduler, MemoryEmbeddingProviderRegistry, MemoryRegistry, MemoryStore, ModeManager, ProjectIndex, resolveCanonicalMemoryDbPath, type CodeIndexStore, type CodeIndexReindexScheduler } from '@pellux/goodvibes-sdk/platform/state';
|
|
29
24
|
import type { StoreSnapshotScheduler } from '@pellux/goodvibes-sdk/platform/state/store-snapshots';
|
|
30
25
|
import type { UserPermissionRuleStore } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
31
26
|
import { buildExecPromptAnswerHandler } from '@pellux/goodvibes-sdk/platform/runtime/permissions/exec-prompt-wiring';
|
|
32
27
|
import { buildLocalhostFetchApproval } from '@pellux/goodvibes-sdk/platform/runtime/permissions/localhost-fetch-approval';
|
|
33
|
-
import { createNotificationDispatcher, wireRuntimeNotificationBridge, type NotificationDispatcher } from './notification-dispatch.ts';
|
|
28
|
+
import { createNotificationDispatcher, wireRuntimeNotificationBridge, wireMemoryPressureNotice, type NotificationDispatcher } from './notification-dispatch.ts';
|
|
34
29
|
import { createDurabilityServices } from './durability-services.ts';
|
|
35
30
|
import { MemorySpineClient, createLocalMemoryAccess } from '@pellux/goodvibes-sdk/platform/runtime/memory-spine';
|
|
36
31
|
import { WorkspaceCheckpointManager } from '@pellux/goodvibes-sdk/platform/workspace';
|
|
@@ -44,6 +39,9 @@ import {
|
|
|
44
39
|
type ShellPathService, type FeatureFlagManager, createFeatureFlagManager, PolicyRuntimeState,
|
|
45
40
|
} from '@/runtime/index.ts';
|
|
46
41
|
import { VoiceProviderRegistry, VoiceService, ensureBuiltinVoiceProviders } from '@pellux/goodvibes-sdk/platform/voice';
|
|
42
|
+
import { CacheRegistry, PauseController, type MemoryGovernor } from '@pellux/goodvibes-sdk/platform/runtime/memory';
|
|
43
|
+
import { wireMemoryGovernance } from './memory-governance-services.ts';
|
|
44
|
+
import { wireVoiceSetup } from './voice-setup-services.ts';
|
|
47
45
|
import { WebSearchProviderRegistry, WebSearchService } from '@pellux/goodvibes-sdk/platform/web-search';
|
|
48
46
|
import { PanelManager } from '../panels/panel-manager.ts';
|
|
49
47
|
import { HookActivityTracker } from '@pellux/goodvibes-sdk/platform/hooks';
|
|
@@ -55,17 +53,18 @@ import { SessionManager, CrossSessionTaskRegistry, SessionChangeTracker } from '
|
|
|
55
53
|
import { ApiTokenAuditor, UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
|
|
56
54
|
import { WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
|
|
57
55
|
import { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
58
|
-
import { BenchmarkStore, CacheHitTracker,
|
|
56
|
+
import { BenchmarkStore, CacheHitTracker, FavoritesStore, ModelLimitsService, ProviderCapabilityRegistry, ProviderOptimizer, ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
|
|
59
57
|
import { KeybindingsManager } from '../input/keybindings.ts';
|
|
60
58
|
import { AdaptivePlanner, DeterministicReplayEngine, ExecutionPlanManager, SessionLineageTracker, SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
|
|
61
59
|
import { deriveFeatureStates, bindFeatureSettingsBridge } from '@pellux/goodvibes-sdk/platform/runtime/state';
|
|
62
60
|
import { createChannelComposition } from './channel-composition.ts';
|
|
63
61
|
import { applyProviderOptimizerConfigMode, bindProviderOptimizerFeatureFlag } from './provider-optimizer-wiring.ts';
|
|
64
62
|
import { type ArchivableProcessRegistry } from '@pellux/goodvibes-sdk/platform/runtime/fleet';
|
|
63
|
+
import { createFleetServices } from './fleet-services.ts';
|
|
65
64
|
import { createWorkstreamServices, type OrchestrationEngine, type WorkstreamCommandService } from './workstream-services.ts';
|
|
66
65
|
import { wireFleetNeedsInputPush } from './fleet-needs-input-push.ts';
|
|
67
66
|
import { codeIndexDbPath, createCodeIndexServices, isCodeInjectionSettingEnabled } from './code-index-services.ts';
|
|
68
|
-
import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
|
|
67
|
+
import type { WorkPlanStore } from '../work-plans/work-plan-store.ts';
|
|
69
68
|
import { registerDaemonHandlers, type DaemonHandlerSurfaces } from '../daemon/handlers/index.ts';
|
|
70
69
|
import type { HandlerContext, HandlerLogger } from '../daemon/handlers/context.ts';
|
|
71
70
|
import { createDaemonCredentialStore } from '../daemon/handlers/credentials.ts';
|
|
@@ -79,8 +78,6 @@ import { registerRemoteSurface } from '../daemon/handlers/remote/index.ts';
|
|
|
79
78
|
import { WorkspaceTrustManager } from './trust/workspace-trust.ts';
|
|
80
79
|
import { ensureConfiguredModelIsRoutable } from './provider-fallback.ts';
|
|
81
80
|
|
|
82
|
-
const REGULAR_KNOWLEDGE_DB_FILE = 'knowledge-wiki.sqlite';
|
|
83
|
-
const HOME_GRAPH_KNOWLEDGE_DB_FILE = 'knowledge-home-graph.sqlite';
|
|
84
81
|
export interface RuntimeServicesOptions {
|
|
85
82
|
readonly runtimeBus: RuntimeEventBus;
|
|
86
83
|
readonly runtimeStore: RuntimeStore;
|
|
@@ -90,6 +87,13 @@ export interface RuntimeServicesOptions {
|
|
|
90
87
|
readonly getConversationTitle?: () => string | undefined;
|
|
91
88
|
readonly workingDir: string;
|
|
92
89
|
readonly homeDirectory: string;
|
|
90
|
+
/** Opt-in (daemon-side only): fold host-observed external coding-agent sessions
|
|
91
|
+
* into the fleet as 'observed-external' rows. Interactive leaves it off and reads
|
|
92
|
+
* the daemon snapshot. Mirrors the SDK's own createRuntimeServices option. */
|
|
93
|
+
readonly observeExternalAgents?: boolean | undefined;
|
|
94
|
+
/** Host power seam opt-in. Fork mirrors the SDK: non-spawning unavailable-seam
|
|
95
|
+
* default (idle-power-services.ts); daemon + embedded runtime pass createHostPowerSeam(). */
|
|
96
|
+
readonly powerSeam?: Parameters<typeof wireIdlePowerAndLiveTurn>[0]['powerSeam'];
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
export interface RuntimeServices {
|
|
@@ -135,6 +139,7 @@ export interface RuntimeServices {
|
|
|
135
139
|
readonly serviceRegistry: ServiceRegistry;
|
|
136
140
|
readonly secretsManager: SecretsManager;
|
|
137
141
|
readonly stepUpService: StepUpService;
|
|
142
|
+
readonly pairingTokens: PairingTokenManager; // backs pairing.tokens.* verbs + the settings device surface (mirrors the SDK composition)
|
|
138
143
|
readonly subscriptionManager: SubscriptionManager;
|
|
139
144
|
readonly localUserAuthManager: UserAuthManager;
|
|
140
145
|
readonly profileManager: ProfileManager;
|
|
@@ -198,6 +203,15 @@ export interface RuntimeServices {
|
|
|
198
203
|
readonly codeIndexReindexScheduler: CodeIndexReindexScheduler; // tool-site reindex
|
|
199
204
|
/** Daily snapshots of every SQLite store this runtime writes, with bounded retention; unref'd timers (mirrors the SDK composition — hosts that tear down a runtime stop() it themselves). */
|
|
200
205
|
readonly storeSnapshotScheduler: StoreSnapshotScheduler;
|
|
206
|
+
readonly memoryConsolidationScheduler: MemoryConsolidationScheduler;
|
|
207
|
+
readonly powerManager: PowerManager;
|
|
208
|
+
/** The daemon's memory governor (default ON). Backs ops.memory.get and defends the daemon's footprint by tier. */
|
|
209
|
+
readonly memoryGovernor: MemoryGovernor;
|
|
210
|
+
/** Registry of every retained cache the governor can shrink (knowledge stores + shared session broker). */
|
|
211
|
+
readonly cacheRegistry: CacheRegistry;
|
|
212
|
+
/** Controller the governor uses to pause/resume the deferrable background jobs under pressure. */
|
|
213
|
+
readonly pauseController: PauseController;
|
|
214
|
+
readonly sessionLiveTurnControls: SessionLiveTurnControlsHolder;
|
|
201
215
|
/** Unified live process registry (agents, WRFC chains, workflows, watchers, background processes) backing the Fleet panel; archive-aware — finished subtrees can be moved to the session archive view. */
|
|
202
216
|
readonly processRegistry: ArchivableProcessRegistry;
|
|
203
217
|
readonly modeManager: ModeManager;
|
|
@@ -227,6 +241,19 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
227
241
|
bindFeatureSettingsBridge(configManager, featureFlags);
|
|
228
242
|
}
|
|
229
243
|
const runtimeDispatch = createDomainDispatch(options.runtimeStore);
|
|
244
|
+
// Memory governance seams built EARLY (mirrors the SDK's own createRuntimeServices)
|
|
245
|
+
// so the scheduler gates and the knowledge background jobs can consult the pause
|
|
246
|
+
// controller before the MemoryGovernor (constructed at the composition tail)
|
|
247
|
+
// drives it. The admission gate is late-bound: expensive entry points capture
|
|
248
|
+
// this closure now and the governor binds into it at the tail — until then
|
|
249
|
+
// everything is admitted (the daemon is still booting).
|
|
250
|
+
const cacheRegistry = new CacheRegistry();
|
|
251
|
+
const pauseController = new PauseController();
|
|
252
|
+
const MEMORY_BACKGROUND_JOB_IDS = ['knowledge-self-improvement', 'memory-consolidation', 'code-index-reindex'];
|
|
253
|
+
const admitExpensiveWorkRef: { current: ((label: string) => { allowed: boolean; reason?: string | undefined }) | null } = { current: null };
|
|
254
|
+
const admitExpensiveWork = (label: string): { allowed: boolean; reason?: string | undefined } =>
|
|
255
|
+
admitExpensiveWorkRef.current?.(label) ?? { allowed: true };
|
|
256
|
+
const isKnowledgeBackgroundPaused = (): boolean => pauseController.isPaused('knowledge-self-improvement');
|
|
230
257
|
const gatewayMethods = new GatewayMethodCatalog();
|
|
231
258
|
const panelManager = new PanelManager();
|
|
232
259
|
// (the purge): MIGRATE-TO-MODAL surface + redirect registration moved to
|
|
@@ -249,6 +276,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
249
276
|
});
|
|
250
277
|
// Step-up (WebAuthn) ceremony service, shared between the ceremony gateway verbs and the relay gate's verifier.
|
|
251
278
|
const stepUpService = new StepUpService({ secrets: secretsManager });
|
|
279
|
+
const pairingTokens = new PairingTokenManager(shellPaths.resolveUserPath('control-plane', 'pairing-tokens.json'));
|
|
252
280
|
const subscriptionManager = new SubscriptionManager(shellPaths.resolveUserPath('tui', 'subscriptions.json'));
|
|
253
281
|
const serviceRegistry = new ServiceRegistry(shellPaths.resolveProjectPath('tui', 'services.json'), {
|
|
254
282
|
secretsManager,
|
|
@@ -414,61 +442,15 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
414
442
|
return record.id;
|
|
415
443
|
},
|
|
416
444
|
});
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
});
|
|
425
|
-
const homeGraphKnowledgeStore = new KnowledgeStore({
|
|
426
|
-
configManager,
|
|
427
|
-
dbFileName: HOME_GRAPH_KNOWLEDGE_DB_FILE,
|
|
428
|
-
});
|
|
429
|
-
const knowledgeSemanticLlm = createProviderBackedKnowledgeSemanticLlm(providerRegistry, {
|
|
430
|
-
timeoutMs: 20_000,
|
|
431
|
-
maxConcurrent: 1,
|
|
432
|
-
});
|
|
433
|
-
const knowledgeSemanticService = new KnowledgeSemanticService(knowledgeStore, {
|
|
434
|
-
llm: knowledgeSemanticLlm,
|
|
435
|
-
maxLlmSourcesPerReindex: 3,
|
|
436
|
-
});
|
|
437
|
-
const homeGraphSemanticService = new KnowledgeSemanticService(homeGraphKnowledgeStore, {
|
|
438
|
-
llm: knowledgeSemanticLlm,
|
|
439
|
-
maxLlmSourcesPerReindex: 3,
|
|
440
|
-
objectProfiles: HOME_GRAPH_KNOWLEDGE_EXTENSION.objectProfiles,
|
|
441
|
-
});
|
|
442
|
-
const agentKnowledgeSemanticService = new KnowledgeSemanticService(agentKnowledgeStore, {
|
|
443
|
-
llm: knowledgeSemanticLlm,
|
|
444
|
-
maxLlmSourcesPerReindex: 3,
|
|
445
|
-
});
|
|
446
|
-
const knowledgeService = new KnowledgeService(knowledgeStore, artifactStore, undefined, {
|
|
447
|
-
memoryRegistry,
|
|
448
|
-
runtimeBus: options.runtimeBus,
|
|
449
|
-
semanticService: knowledgeSemanticService,
|
|
450
|
-
});
|
|
451
|
-
knowledgeService.attachRuntimeBus(options.runtimeBus);
|
|
452
|
-
const agentKnowledgeService = new KnowledgeService(agentKnowledgeStore, artifactStore, undefined, {
|
|
453
|
-
memoryRegistry,
|
|
454
|
-
runtimeBus: options.runtimeBus,
|
|
455
|
-
semanticService: agentKnowledgeSemanticService,
|
|
456
|
-
});
|
|
457
|
-
agentKnowledgeService.attachRuntimeBus(options.runtimeBus);
|
|
458
|
-
const homeGraphService = new HomeGraphService(homeGraphKnowledgeStore, artifactStore, {
|
|
459
|
-
semanticService: homeGraphSemanticService,
|
|
460
|
-
});
|
|
461
|
-
const projectPlanningProjectId = projectPlanningProjectIdFromPath(workingDirectory);
|
|
462
|
-
const projectPlanningService = new ProjectPlanningService(knowledgeStore, {
|
|
463
|
-
defaultProjectId: projectPlanningProjectId,
|
|
464
|
-
});
|
|
465
|
-
const workPlanStore = new WorkPlanStore({
|
|
466
|
-
homeDirectory,
|
|
467
|
-
projectId: projectPlanningProjectId,
|
|
468
|
-
projectRoot: workingDirectory,
|
|
469
|
-
});
|
|
445
|
+
// Knowledge/wiki + home-graph stack (governor backpressure wired in) — see knowledge-services.ts.
|
|
446
|
+
const {
|
|
447
|
+
knowledgeStore, agentKnowledgeStore, homeGraphKnowledgeStore,
|
|
448
|
+
knowledgeSemanticService, homeGraphSemanticService, agentKnowledgeSemanticService,
|
|
449
|
+
knowledgeService, agentKnowledgeService, homeGraphService,
|
|
450
|
+
projectPlanningService, projectPlanningProjectId, workPlanStore,
|
|
451
|
+
} = createKnowledgeServices({ configManager, providerRegistry, artifactStore, memoryRegistry, runtimeBus: options.runtimeBus, workingDirectory, homeDirectory, isBackgroundPaused: isKnowledgeBackgroundPaused, admitExpensiveWork });
|
|
470
452
|
const voiceProviders = new VoiceProviderRegistry();
|
|
471
|
-
ensureBuiltinVoiceProviders(voiceProviders);
|
|
453
|
+
ensureBuiltinVoiceProviders(voiceProviders, { readConfig: (key) => configManager.get(key as Parameters<typeof configManager.get>[0]) });
|
|
472
454
|
const voiceService = new VoiceService(voiceProviders);
|
|
473
455
|
const webSearchProviders = new WebSearchProviderRegistry({
|
|
474
456
|
env: process.env,
|
|
@@ -478,18 +460,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
478
460
|
serviceRegistry,
|
|
479
461
|
featureFlags,
|
|
480
462
|
});
|
|
481
|
-
knowledgeSemanticService
|
|
482
|
-
searchService: webSearchService,
|
|
483
|
-
|
|
484
|
-
}));
|
|
485
|
-
agentKnowledgeSemanticService.setGapRepairer(createWebKnowledgeGapRepairer({
|
|
486
|
-
searchService: webSearchService,
|
|
487
|
-
ingestService: agentKnowledgeService,
|
|
488
|
-
}));
|
|
489
|
-
homeGraphSemanticService.setGapRepairer(createWebKnowledgeGapRepairer({
|
|
490
|
-
searchService: webSearchService,
|
|
491
|
-
ingestService: homeGraphService,
|
|
492
|
-
}));
|
|
463
|
+
for (const [semantic, ingest] of [[knowledgeSemanticService, knowledgeService], [agentKnowledgeSemanticService, agentKnowledgeService], [homeGraphSemanticService, homeGraphService]] as const) {
|
|
464
|
+
semantic.setGapRepairer(createWebKnowledgeGapRepairer({ searchService: webSearchService, ingestService: ingest }));
|
|
465
|
+
}
|
|
493
466
|
const mediaProviders = new MediaProviderRegistry();
|
|
494
467
|
ensureBuiltinMediaProviders(mediaProviders, artifactStore, providerRegistry);
|
|
495
468
|
const multimodalService = new MultimodalService(artifactStore, mediaProviders, voiceService, knowledgeService);
|
|
@@ -587,40 +560,55 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
587
560
|
// Repo source-tree code index, sharing memoryEmbeddingRegistry
|
|
588
561
|
// with MemoryStore above. Auto-build is config-gated (default off) — see
|
|
589
562
|
// code-index-services.ts's header doc.
|
|
590
|
-
const { codeIndexStore, codeIndexReindexScheduler } = createCodeIndexServices({ workingDirectory, configManager, memoryEmbeddingRegistry });
|
|
563
|
+
const { codeIndexStore, codeIndexReindexScheduler } = createCodeIndexServices({ workingDirectory, configManager, memoryEmbeddingRegistry, isReindexPaused: () => pauseController.isPaused('code-index-reindex'), admitExpensiveWork });
|
|
591
564
|
// Store snapshots + durable remembered-approval rules + the live credential
|
|
592
565
|
// chain, mirroring the SDK composition — see durability-services.ts.
|
|
593
566
|
const { storeSnapshotScheduler, userPermissionRuleStore } = createDurabilityServices({
|
|
594
|
-
configManager, secretsManager, providerRegistry, memoryDbPath, codeIndexDbPath: codeIndexDbPath(workingDirectory),
|
|
567
|
+
configManager, secretsManager, providerRegistry, memoryDbPath, codeIndexDbPath: codeIndexDbPath(workingDirectory), workingDirectory, surfaceRoot: 'tui', homeDirectory, shellPaths, // + retention-sweep roots & live config watch (mirrors the SDK)
|
|
595
568
|
});
|
|
596
569
|
const codeInjectionOrchestratorDeps = { codeIndex: codeIndexStore, isCodeInjectionSettingEnabled: () => isCodeInjectionSettingEnabled(configManager), codeIndexReindexScheduler }; // Code-injection seam (agent here; main via orchestrator-core-services.ts)
|
|
597
|
-
// Shared
|
|
598
|
-
|
|
599
|
-
agentManager,
|
|
600
|
-
wrfcController,
|
|
570
|
+
const { processRegistry } = createFleetServices({ // Shared archive-aware fleet registry (+ daemon observed rows) — see fleet-services.ts
|
|
571
|
+
agentManager, wrfcController,
|
|
601
572
|
orchestrationEngine, // Folds workstream/phase/work-item nodes into the fleet
|
|
602
573
|
codeIndexService: codeIndexStore, // Folds a single 'code-index' node into the fleet
|
|
603
|
-
processManager,
|
|
604
|
-
watcherRegistry,
|
|
605
|
-
workflow,
|
|
606
|
-
approvalBroker,
|
|
607
|
-
sessionBroker,
|
|
574
|
+
processManager, watcherRegistry, workflow, approvalBroker, sessionBroker,
|
|
608
575
|
messageBus: agentMessageBus, // Backs steer()/`steerable` (the Fleet steer composer builds on top)
|
|
609
576
|
automationManager, // Folds /schedule AutomationJobs into the fleet as 'schedule' nodes
|
|
610
577
|
runtimeBus: options.runtimeBus,
|
|
611
|
-
|
|
612
|
-
// -> catalog -> unknown); unknown/subscription yields null, never $0. Mirrors the SDK composition.
|
|
613
|
-
priceUsage: (model, usage) => (model ? computeUsageCostUsd(providerRegistry.resolveModelPricing(model), usage) : null),
|
|
578
|
+
observeExternalAgents: options.observeExternalAgents, providerRegistry, // observeExternalAgents is daemon-side only
|
|
614
579
|
});
|
|
615
|
-
const modeManager = new ModeManager();
|
|
616
|
-
const fileUndoManager = new FileUndoManager();
|
|
580
|
+
const modeManager = new ModeManager(); const fileUndoManager = new FileUndoManager();
|
|
617
581
|
const workspaceCheckpointManager = createWorkspaceCheckpointing({ workspaceRoot: workingDirectory, runtimeBus: options.runtimeBus, configManager });
|
|
582
|
+
// memory-consolidation honors governor backpressure: it ticks only when idle
|
|
583
|
+
// AND the 'memory-consolidation' job is not paused AND expensive work is
|
|
584
|
+
// admitted (mirrors the SDK's own createRuntimeServices idle gate).
|
|
585
|
+
const { memoryConsolidationScheduler, powerManager, sessionLiveTurnControls } = wireIdlePowerAndLiveTurn({ configManager, memoryRegistry, runtimeBus: options.runtimeBus, isIdle: () => sessionBroker.countBusySessions() === 0 && !pauseController.isPaused('memory-consolidation') && admitExpensiveWork('memory consolidation').allowed, snapshotTick: () => storeSnapshotScheduler.tick(), heartbeat: async () => { await automationManager.triggerHeartbeat({ source: 'wake-catchup' }); }, powerSeam: options.powerSeam });
|
|
586
|
+
|
|
587
|
+
// Construct + start the MemoryGovernor (default ON — a safety feature) with
|
|
588
|
+
// the standard KNOWN cache adapters (knowledge stores + shared session
|
|
589
|
+
// broker), then late-bind the admission gate the expensive entry points
|
|
590
|
+
// captured earlier. Mirrors the SDK's own createRuntimeServices composition tail.
|
|
591
|
+
const { memoryGovernor } = wireMemoryGovernance({
|
|
592
|
+
configManager,
|
|
593
|
+
runtimeBus: options.runtimeBus,
|
|
594
|
+
cacheRegistry,
|
|
595
|
+
pauseController,
|
|
596
|
+
jobIds: MEMORY_BACKGROUND_JOB_IDS,
|
|
597
|
+
receiptPath: shellPaths.resolveProjectPath('tui', 'memory', 'tripwire-receipt.json'),
|
|
598
|
+
knowledgeStores: [knowledgeStore, agentKnowledgeStore, homeGraphKnowledgeStore],
|
|
599
|
+
sessionBroker,
|
|
600
|
+
// Graceful tripwire shutdown flushes in-flight state via ASYNC store
|
|
601
|
+
// snapshots so the governor's 10s shutdown ceiling stays enforceable.
|
|
602
|
+
onTripwireShutdown: async () => { await storeSnapshotScheduler.snapshotAllAsync('tripwire'); },
|
|
603
|
+
});
|
|
604
|
+
admitExpensiveWorkRef.current = (label) => memoryGovernor.admitExpensiveWork(label);
|
|
605
|
+
|
|
606
|
+
// Managed local-voice provisioning (voice.local.status/install) — single-flight
|
|
607
|
+
// one-act install + no-network status; see voice-setup-services.ts.
|
|
608
|
+
const { voiceSetup } = wireVoiceSetup({ configManager, shellPaths, voiceProviders, admitExpensiveWork });
|
|
618
609
|
|
|
619
|
-
//
|
|
620
|
-
|
|
621
|
-
// channelDeliveryRouter/providerRegistry/automationManager/sessionLister ALL present; fleet needs-input push gated by
|
|
622
|
-
// runtimeBus/sessionPresence (fleet-needs-input-push.ts). conversationRewindPort serves conversation-scope rewind live.
|
|
623
|
-
attachWsOnlyGatewayVerbHandlers(gatewayMethods, { processRegistry, workspaceCheckpointManager, conversationRewindPort: createSessionConversationRewindPort(), sessionBroker, secretsManager, stepUpService, approvalBroker, requestApproval: (input) => approvalBroker.requestApproval(input), watcherRegistry, userPermissionRuleStore, shellPaths, configManager, runtimeStore: options.runtimeStore, channelDeliveryRouter, providerRegistry, automationManager, sessionLister: sessionBroker, sessionIntake: sessionBroker, workingDirectory, memoryRegistry, ...wireFleetNeedsInputPush({ registry: processRegistry, runtimeBus: options.runtimeBus, sessionBroker }) });
|
|
610
|
+
// Terminal-shell wrapper over the SDK registerGatewayVerbGroups (gateway-verbs.ts); checkin.*/fleet-needs-input/pairing.* register only when their deps are present. memoryGovernor lights up ops.memory.get; voiceSetup lights up voice.local.status/install.
|
|
611
|
+
attachWsOnlyGatewayVerbHandlers(gatewayMethods, { processRegistry, workspaceCheckpointManager, conversationRewindPort: createSessionConversationRewindPort(), sessionBroker, secretsManager, stepUpService, approvalBroker, requestApproval: (input) => approvalBroker.requestApproval(input), watcherRegistry, userPermissionRuleStore, shellPaths, configManager, runtimeStore: options.runtimeStore, channelDeliveryRouter, providerRegistry, automationManager, sessionLister: sessionBroker, sessionIntake: sessionBroker, workingDirectory, memoryRegistry, pairingTokens, sessionLiveTurnControls, powerManager, memoryGovernor, voiceSetup, relayAvailable: () => configManager.get('relay.enabled') === true, pairingWebOrigin: () => resolvePairingWebOrigin(configManager).origin, ...wireFleetNeedsInputPush({ registry: processRegistry, runtimeBus: options.runtimeBus, sessionBroker }) });
|
|
624
612
|
const integrationHelpers = new IntegrationHelperService({
|
|
625
613
|
workingDirectory,
|
|
626
614
|
homeDirectory,
|
|
@@ -683,6 +671,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
683
671
|
// panel feed (panel_only and burst-collapsed decisions land there).
|
|
684
672
|
const notificationDispatcher = createNotificationDispatcher(configManager);
|
|
685
673
|
wireRuntimeNotificationBridge(options.runtimeBus, notificationDispatcher);
|
|
674
|
+
// OPS_MEMORY_PRESSURE is lifted into the notice feed on its own targeted
|
|
675
|
+
// bridge (the high-churn 'ops' domain stays out of the wholesale allowlist).
|
|
676
|
+
wireMemoryPressureNotice(options.runtimeBus, notificationDispatcher);
|
|
686
677
|
|
|
687
678
|
return {
|
|
688
679
|
workingDirectory,
|
|
@@ -723,6 +714,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
723
714
|
serviceRegistry,
|
|
724
715
|
secretsManager,
|
|
725
716
|
stepUpService,
|
|
717
|
+
pairingTokens,
|
|
726
718
|
subscriptionManager,
|
|
727
719
|
localUserAuthManager,
|
|
728
720
|
profileManager,
|
|
@@ -782,6 +774,12 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
782
774
|
codeIndexStore,
|
|
783
775
|
codeIndexReindexScheduler,
|
|
784
776
|
storeSnapshotScheduler,
|
|
777
|
+
memoryConsolidationScheduler,
|
|
778
|
+
powerManager,
|
|
779
|
+
memoryGovernor,
|
|
780
|
+
cacheRegistry,
|
|
781
|
+
pauseController,
|
|
782
|
+
sessionLiveTurnControls,
|
|
785
783
|
processRegistry,
|
|
786
784
|
modeManager,
|
|
787
785
|
fileUndoManager,
|
|
@@ -59,6 +59,8 @@ export interface UiPlatformServices {
|
|
|
59
59
|
readonly surfaceRegistry: RuntimeServices['surfaceRegistry'];
|
|
60
60
|
readonly subscriptionManager: RuntimeServices['subscriptionManager'];
|
|
61
61
|
readonly secretsManager: SecretsManager;
|
|
62
|
+
/** Per-device pairing tokens — backs the pairing modal QR and the settings device surface. */
|
|
63
|
+
readonly pairingTokens: RuntimeServices['pairingTokens'];
|
|
62
64
|
readonly tokenAuditor: RuntimeServices['tokenAuditor'];
|
|
63
65
|
readonly replayEngine: RuntimeServices['replayEngine'];
|
|
64
66
|
readonly webhookNotifier: RuntimeServices['webhookNotifier'];
|
|
@@ -188,6 +190,7 @@ export function createUiRuntimeServices(
|
|
|
188
190
|
surfaceRegistry: runtimeServices.surfaceRegistry,
|
|
189
191
|
subscriptionManager: runtimeServices.subscriptionManager,
|
|
190
192
|
secretsManager: runtimeServices.secretsManager,
|
|
193
|
+
pairingTokens: runtimeServices.pairingTokens,
|
|
191
194
|
tokenAuditor: runtimeServices.tokenAuditor,
|
|
192
195
|
replayEngine: runtimeServices.replayEngine,
|
|
193
196
|
webhookNotifier: runtimeServices.webhookNotifier,
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// voice-setup-services.ts — managed local-voice provisioning composition (TUI wiring)
|
|
3
|
+
//
|
|
4
|
+
// Backs the daemon's voice.local.status / voice.local.install verbs. Extracted
|
|
5
|
+
// into its own module rather than built inline in services.ts, which sits at
|
|
6
|
+
// the architecture check's 800-line cap (scripts/check-architecture.ts) — new
|
|
7
|
+
// service construction gets its own module and a single wiring call there.
|
|
8
|
+
//
|
|
9
|
+
// Mirrors the SDK's own createRuntimeServices voiceSetup: a single-flight
|
|
10
|
+
// one-act install that provisions the piper engine + a default voice (and
|
|
11
|
+
// whisper STT where a bundle is published) and pre-configures the voice.local.*
|
|
12
|
+
// keys with ownership awareness (values THIS installer previously wrote update
|
|
13
|
+
// to the new managed paths; genuinely user-set values still win; a user-cleared
|
|
14
|
+
// installer value stays cleared). status() is a no-network read.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
createVoiceInstallProgressTracker,
|
|
19
|
+
localVoiceRuntimeStatus,
|
|
20
|
+
preconfigureLocalVoiceKeys,
|
|
21
|
+
provisionLocalVoiceRuntime,
|
|
22
|
+
readVoiceInstallStamp,
|
|
23
|
+
writeVoiceInstallStamp,
|
|
24
|
+
type VoiceProviderRegistry,
|
|
25
|
+
} from '@pellux/goodvibes-sdk/platform/voice';
|
|
26
|
+
import { singleFlight } from '@pellux/goodvibes-sdk/platform/utils';
|
|
27
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
28
|
+
import type { ShellPathService } from '@/runtime/index.ts';
|
|
29
|
+
import type { VoiceLocalInstallResult } from '../core/voice-provision-status.ts';
|
|
30
|
+
|
|
31
|
+
export interface VoiceSetupServicesDeps {
|
|
32
|
+
readonly configManager: ConfigManager;
|
|
33
|
+
readonly shellPaths: Pick<ShellPathService, 'resolveUserPath'>;
|
|
34
|
+
readonly voiceProviders: VoiceProviderRegistry;
|
|
35
|
+
/** Critical-tier admission gate — a provision run allocates archive + model buffers. */
|
|
36
|
+
readonly admitExpensiveWork: (label: string) => { allowed: boolean; reason?: string | undefined };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The narrow provisioning slice the voice.local.* gateway verbs consume. */
|
|
40
|
+
export interface VoiceSetupService {
|
|
41
|
+
status(): unknown;
|
|
42
|
+
install(): Promise<VoiceLocalInstallResult>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Compose the managed-voice single-flight install + no-network status read. */
|
|
46
|
+
export function wireVoiceSetup(deps: VoiceSetupServicesDeps): { voiceSetup: VoiceSetupService } {
|
|
47
|
+
const { configManager, voiceProviders } = deps;
|
|
48
|
+
const managedVoiceRoot = deps.shellPaths.resolveUserPath('voice');
|
|
49
|
+
// Live install progress: the install verb is plain request/response, so during
|
|
50
|
+
// a multi-hundred-MB provision a surface would otherwise only see busy→receipt.
|
|
51
|
+
// The tracker folds the provisioner's onProgress stream into a poll-able
|
|
52
|
+
// snapshot that status() carries as `installInProgress` WHILE (and only while)
|
|
53
|
+
// an install runs — surfaces poll status during install (mirrors the SDK).
|
|
54
|
+
const progress = createVoiceInstallProgressTracker();
|
|
55
|
+
// Single-flight: concurrent installs join the in-progress promise instead of
|
|
56
|
+
// starting parallel multi-hundred-MB downloads.
|
|
57
|
+
const runVoiceInstall = singleFlight(async () => {
|
|
58
|
+
progress.begin();
|
|
59
|
+
try {
|
|
60
|
+
const provision = await provisionLocalVoiceRuntime({ managedRoot: managedVoiceRoot, onProgress: (p) => progress.onProgress(p) });
|
|
61
|
+
let configured: { set: { key: string; value: string }[]; skipped: { key: string; reason: string }[] } = { set: [], skipped: [] };
|
|
62
|
+
if (provision.tts.state === 'provisioned' && provision.tts.binaryPath && provision.tts.modelPath) {
|
|
63
|
+
const stamp = readVoiceInstallStamp(managedVoiceRoot);
|
|
64
|
+
const receipt = preconfigureLocalVoiceKeys({
|
|
65
|
+
getConfig: (k) => String(configManager.get(k as Parameters<typeof configManager.get>[0]) ?? ''),
|
|
66
|
+
setConfig: (k, v) => configManager.setDynamic(k as Parameters<typeof configManager.setDynamic>[0], v),
|
|
67
|
+
ttsEngine: provision.tts.engine,
|
|
68
|
+
ttsBinary: provision.tts.binaryPath,
|
|
69
|
+
ttsModelPath: provision.tts.modelPath,
|
|
70
|
+
...(provision.stt.state === 'provisioned' && provision.stt.binaryPath && provision.stt.modelPath
|
|
71
|
+
? { sttEngine: provision.stt.engine, sttBinary: provision.stt.binaryPath, sttModelPath: provision.stt.modelPath }
|
|
72
|
+
: {}),
|
|
73
|
+
priorInstallWrites: stamp?.configWrites,
|
|
74
|
+
});
|
|
75
|
+
configured = { set: [...receipt.set], skipped: [...receipt.skipped] };
|
|
76
|
+
if (stamp) {
|
|
77
|
+
writeVoiceInstallStamp(managedVoiceRoot, { ...stamp, configWrites: { ...stamp.configWrites, ...receipt.installWrites } });
|
|
78
|
+
}
|
|
79
|
+
// A successful (re-)install clears any tripped local-engine breaker.
|
|
80
|
+
voiceProviders.get('local')?.resetEngineFailureState?.();
|
|
81
|
+
}
|
|
82
|
+
return { provisioned: provision.tts.state === 'provisioned', platform: provision.platform, tts: provision.tts, stt: provision.stt, components: provision.components, configured };
|
|
83
|
+
} finally {
|
|
84
|
+
progress.end();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const voiceSetup: VoiceSetupService = {
|
|
88
|
+
status: () => {
|
|
89
|
+
const base = localVoiceRuntimeStatus({ managedRoot: managedVoiceRoot });
|
|
90
|
+
const snapshot = progress.snapshot();
|
|
91
|
+
// Carry live per-component progress ONLY while an install is active.
|
|
92
|
+
return snapshot ? { ...base, installInProgress: snapshot } : base;
|
|
93
|
+
},
|
|
94
|
+
install: async () => {
|
|
95
|
+
// Critical-tier admission: refuse honestly instead of piling onto pressure.
|
|
96
|
+
const admission = deps.admitExpensiveWork('voice runtime install');
|
|
97
|
+
if (!admission.allowed) {
|
|
98
|
+
throw new Error(admission.reason ?? 'voice runtime install refused: daemon is under critical memory pressure.');
|
|
99
|
+
}
|
|
100
|
+
return runVoiceInstall();
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
return { voiceSetup };
|
|
104
|
+
}
|