@pellux/goodvibes-tui 1.23.0 → 1.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- package/package.json +3 -3
- package/src/cli/bundle-command.ts +4 -0
- package/src/cli/help.ts +5 -0
- package/src/cli/management-utils.ts +4 -0
- package/src/cluster/commands.ts +382 -0
- package/src/cluster/remote-daemon-target.ts +225 -0
- package/src/cluster/render.ts +268 -0
- package/src/core/conversation-line-cache.ts +11 -6
- package/src/core/conversation-render-context.ts +122 -0
- package/src/core/conversation-rendering.ts +86 -89
- package/src/daemon/cli.ts +73 -2
- package/src/daemon/handlers/inbox/cursor-store.ts +12 -1
- package/src/daemon/handlers/inbox/index.ts +63 -3
- package/src/daemon/handlers/inbox/poller.ts +66 -10
- package/src/daemon/handlers/index.ts +9 -0
- package/src/input/command-args-hint.ts +2 -0
- package/src/input/commands/cluster-runtime.ts +53 -0
- package/src/input/commands.ts +2 -0
- package/src/input/settings-modal-data.ts +6 -0
- package/src/main.ts +3 -0
- package/src/renderer/conversation-surface.ts +23 -6
- package/src/renderer/conversation-tree.ts +142 -93
- package/src/renderer/tool-call.ts +13 -12
- package/src/runtime/agent-graph-composition.ts +78 -0
- package/src/runtime/bootstrap.ts +6 -1
- package/src/runtime/cluster-composition.ts +124 -0
- package/src/runtime/cluster-group-composition.ts +284 -0
- package/src/runtime/daemon-handler-composition.ts +80 -0
- package/src/runtime/disposal-wiring.ts +83 -0
- package/src/runtime/durability-services.ts +7 -3
- package/src/runtime/embedded-service-factories.ts +19 -1
- package/src/runtime/process-lifecycle.ts +9 -1
- package/src/runtime/remote-execution-composition.ts +62 -0
- package/src/runtime/services.ts +73 -76
- package/src/verification/verification-ledger.ts +38 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remote-execution-composition.ts — running work somewhere other than here.
|
|
3
|
+
*
|
|
4
|
+
* Four collaborators that only make sense together, so they are built together
|
|
5
|
+
* rather than as four unrelated lines in the middle of the runtime composition:
|
|
6
|
+
*
|
|
7
|
+
* - RemoteRunnerRegistry knows which remote runners exist and how to reach
|
|
8
|
+
* them; RemoteSupervisor drives them and is meaningless without it.
|
|
9
|
+
*
|
|
10
|
+
* - SandboxSessionRegistry owns the sandboxes a tool call can be confined to,
|
|
11
|
+
* and McpRegistry is the thing that confines them — an MCP server started
|
|
12
|
+
* without the sandbox registry runs its tools directly on the host.
|
|
13
|
+
*
|
|
14
|
+
* The pairing in each case is the point: handing the supervisor a registry it
|
|
15
|
+
* did not build, or the MCP registry a sandbox runtime it does not share with
|
|
16
|
+
* the session registry, produces a runtime that looks wired and quietly is not.
|
|
17
|
+
*/
|
|
18
|
+
import { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
19
|
+
import {
|
|
20
|
+
RemoteRunnerRegistry,
|
|
21
|
+
RemoteSupervisor,
|
|
22
|
+
SandboxSessionRegistry,
|
|
23
|
+
type RuntimeEventBus,
|
|
24
|
+
} from '@/runtime/index.ts';
|
|
25
|
+
import type { AgentManager } from '@pellux/goodvibes-sdk/platform/tools';
|
|
26
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
27
|
+
import type { HookDispatcher } from '@pellux/goodvibes-sdk/platform/hooks';
|
|
28
|
+
|
|
29
|
+
export interface RemoteExecutionServices {
|
|
30
|
+
readonly remoteRunnerRegistry: RemoteRunnerRegistry;
|
|
31
|
+
readonly remoteSupervisor: RemoteSupervisor;
|
|
32
|
+
readonly sandboxSessionRegistry: SandboxSessionRegistry;
|
|
33
|
+
readonly mcpRegistry: McpRegistry;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Build the remote-execution and sandboxing seam.
|
|
38
|
+
*
|
|
39
|
+
* Constructing these opens no connection and starts no server: a runner is
|
|
40
|
+
* reached when something asks for it, and an MCP server starts when a session
|
|
41
|
+
* requests it. Composing a runtime in a test therefore executes nothing.
|
|
42
|
+
*/
|
|
43
|
+
export function createRemoteExecutionServices(options: {
|
|
44
|
+
readonly agentManager: AgentManager;
|
|
45
|
+
readonly workingDirectory: string;
|
|
46
|
+
readonly hookDispatcher: HookDispatcher;
|
|
47
|
+
readonly configManager: ConfigManager;
|
|
48
|
+
readonly runtimeBus: RuntimeEventBus;
|
|
49
|
+
}): RemoteExecutionServices {
|
|
50
|
+
const remoteRunnerRegistry = new RemoteRunnerRegistry(options.agentManager);
|
|
51
|
+
const remoteSupervisor = new RemoteSupervisor(remoteRunnerRegistry);
|
|
52
|
+
const sandboxSessionRegistry = new SandboxSessionRegistry(options.workingDirectory);
|
|
53
|
+
const mcpRegistry = new McpRegistry({
|
|
54
|
+
hookDispatcher: options.hookDispatcher,
|
|
55
|
+
sandboxSessions: sandboxSessionRegistry,
|
|
56
|
+
});
|
|
57
|
+
mcpRegistry.setRuntimeBus(options.runtimeBus);
|
|
58
|
+
// The SAME sandbox registry the session registry above owns, so a tool call
|
|
59
|
+
// confined by one is confined by the other.
|
|
60
|
+
mcpRegistry.setSandboxRuntime(options.configManager, sandboxSessionRegistry);
|
|
61
|
+
return { remoteRunnerRegistry, remoteSupervisor, sandboxSessionRegistry, mcpRegistry };
|
|
62
|
+
}
|
package/src/runtime/services.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { StepUpService } from '@pellux/goodvibes-sdk/daemon';
|
|
|
11
11
|
import { PairingTokenManager } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
12
12
|
import { resolvePairingWebOrigin } from '../core/pairing-origin.ts';
|
|
13
13
|
import { attachWsOnlyGatewayVerbHandlers } from '@pellux/goodvibes-terminal-shell';
|
|
14
|
+
import { createDisposalScope, registerSurfaceRuntimePollers } from './disposal-wiring.ts';
|
|
14
15
|
import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
|
|
15
16
|
import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
|
|
16
17
|
import { createWebKnowledgeGapRepairer } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
@@ -19,7 +20,7 @@ import { createKnowledgeServices } from './knowledge-services.ts';
|
|
|
19
20
|
import { MediaProviderRegistry, ensureBuiltinMediaProviders } from '@pellux/goodvibes-sdk/platform/media';
|
|
20
21
|
import { MultimodalService } from '@pellux/goodvibes-sdk/platform/multimodal';
|
|
21
22
|
import { AgentMessageBus, AgentOrchestrator, ArchetypeLoader, WrfcController } from '@pellux/goodvibes-sdk/platform/agents';
|
|
22
|
-
import { AgentManager, ContextAccountingHolder, OverflowHandler, ProcessManager, createWorkflowServices, type WorkflowServices } from '@pellux/goodvibes-sdk/platform/tools';
|
|
23
|
+
import { AgentManager, ContextAccountingHolder, OverflowHandler, ProcessManager, cancelAllAgentRuns, createWorkflowServices, type WorkflowServices } from '@pellux/goodvibes-sdk/platform/tools';
|
|
23
24
|
import { FileStateCache, FileUndoManager, MemoryConsolidationScheduler, MemoryEmbeddingProviderRegistry, MemoryRegistry, MemoryStore, ModeManager, ProjectIndex, resolveCanonicalMemoryDbPath, type CodeIndexStore, type CodeIndexReindexScheduler } from '@pellux/goodvibes-sdk/platform/state';
|
|
24
25
|
import type { StoreSnapshotScheduler } from '@pellux/goodvibes-sdk/platform/state/store-snapshots';
|
|
25
26
|
import type { UserPermissionRuleStore } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
@@ -36,8 +37,7 @@ import type { DomainDispatch, RuntimeStore } from './store/index.ts';
|
|
|
36
37
|
import {
|
|
37
38
|
type RuntimeEventBus, DistributedRuntimeManager, RemoteRunnerRegistry, RemoteSupervisor, IntegrationHelperService,
|
|
38
39
|
IdempotencyStore, ComponentHealthMonitor, WorktreeRegistry, SandboxSessionRegistry, createShellPathService,
|
|
39
|
-
type ShellPathService, type FeatureFlagManager, createFeatureFlagManager, PolicyRuntimeState,
|
|
40
|
-
type SessionSurface,
|
|
40
|
+
type ShellPathService, type FeatureFlagManager, createFeatureFlagManager, PolicyRuntimeState, type SessionSurface,
|
|
41
41
|
} from '@/runtime/index.ts';
|
|
42
42
|
import { createSessionStorageServices } from './session-storage-services.ts';
|
|
43
43
|
import { VoiceProviderRegistry, VoiceService, ensureBuiltinVoiceProviders } from '@pellux/goodvibes-sdk/platform/voice';
|
|
@@ -55,6 +55,8 @@ import { SessionManager, CrossSessionTaskRegistry, SessionChangeTracker } from '
|
|
|
55
55
|
import { ApiTokenAuditor, UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
|
|
56
56
|
import { WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
|
|
57
57
|
import { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
58
|
+
import { createRemoteExecutionServices } from './remote-execution-composition.ts';
|
|
59
|
+
import { createAgentGraph } from './agent-graph-composition.ts';
|
|
58
60
|
import { BenchmarkStore, CacheHitTracker, FavoritesStore, ModelLimitsService, ProviderCapabilityRegistry, ProviderOptimizer, ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
|
|
59
61
|
import { KeybindingsManager } from '../input/keybindings.ts';
|
|
60
62
|
import { AdaptivePlanner, DeterministicReplayEngine, ExecutionPlanManager, SessionLineageTracker, SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
|
|
@@ -67,16 +69,10 @@ import { createWorkstreamServices, type OrchestrationEngine, type WorkstreamComm
|
|
|
67
69
|
import { wireFleetNeedsInputPush } from './fleet-needs-input-push.ts';
|
|
68
70
|
import { codeIndexDbPath, createCodeIndexServices, createStoreRerooter, isCodeInjectionSettingEnabled } from './code-index-services.ts';
|
|
69
71
|
import type { WorkPlanStore } from '../work-plans/work-plan-store.ts';
|
|
70
|
-
import {
|
|
71
|
-
import
|
|
72
|
-
import {
|
|
73
|
-
import {
|
|
74
|
-
import { registerInboxMethods } from '../daemon/handlers/inbox/index.ts';
|
|
75
|
-
import { registerTriagedInbox } from '../daemon/handlers/triage/index.ts';
|
|
76
|
-
import { registerDraftMethods } from '../daemon/handlers/drafts/index.ts';
|
|
77
|
-
import { registerCalendar } from '../daemon/handlers/calendar/index.ts';
|
|
78
|
-
import { registerEmailMethods } from '../daemon/handlers/email/index.ts';
|
|
79
|
-
import { registerRemoteSurface } from '../daemon/handlers/remote/index.ts';
|
|
72
|
+
import type { DaemonHandlerSurfaces } from '../daemon/handlers/index.ts';
|
|
73
|
+
import { createDaemonHandlerComposition } from './daemon-handler-composition.ts';
|
|
74
|
+
import { createClusterServices, startClusterServices, type ClusterGroupComposition } from './cluster-group-composition.ts';
|
|
75
|
+
import type { ClusterCoordinator } from '@pellux/goodvibes-sdk/platform/cluster';
|
|
80
76
|
import { WorkspaceTrustManager } from './trust/workspace-trust.ts';
|
|
81
77
|
import { ensureConfiguredModelIsRoutable } from './provider-fallback.ts';
|
|
82
78
|
|
|
@@ -184,6 +180,12 @@ export interface RuntimeServices {
|
|
|
184
180
|
readonly toolLLM: ToolLLM;
|
|
185
181
|
readonly distributedRuntime: DistributedRuntimeManager;
|
|
186
182
|
readonly daemonHandlers: DaemonHandlerSurfaces;
|
|
183
|
+
/** Elects the one node on this network that consumes inbound messages; hand it to the DaemonServer so its consumers share this leadership instead of holding a second election. */
|
|
184
|
+
readonly clusterCoordinator: ClusterCoordinator;
|
|
185
|
+
/** LAN group membership: identity, keys, roster, and the `cluster` verbs. */
|
|
186
|
+
readonly clusterGroup: ClusterGroupComposition;
|
|
187
|
+
/** Start the group layer and then the election, in that order. Idempotent. */
|
|
188
|
+
readonly startCluster: () => Promise<void>;
|
|
187
189
|
readonly remoteRunnerRegistry: RemoteRunnerRegistry;
|
|
188
190
|
readonly remoteSupervisor: RemoteSupervisor;
|
|
189
191
|
readonly sessionMemoryStore: SessionMemoryStore;
|
|
@@ -231,10 +233,20 @@ export interface RuntimeServices {
|
|
|
231
233
|
readonly integrationHelpers: IntegrationHelperService;
|
|
232
234
|
/** Re-root path-bound stores (MemoryStore, ProjectIndex) to a new working directory, called by WorkspaceSwapManager after verification; stores needing a process restart just warn-log and keep serving the old path until the daemon restarts with the new --working-dir. */
|
|
233
235
|
rerootStores(newWorkingDir: string): Promise<void>;
|
|
236
|
+
/**
|
|
237
|
+
* Cancel the agent runs this graph is hosting, returning how many.
|
|
238
|
+
*
|
|
239
|
+
* Required by the SDK's RuntimePollerOwners: by dispose() time the fleet
|
|
240
|
+
* registry, orchestration engine, process registry and bus these runs report
|
|
241
|
+
* through are already down, so a run still described as "running" is orphaned
|
|
242
|
+
* rather than preserved.
|
|
243
|
+
*/
|
|
244
|
+
cancelHostedAgentRuns(): number;
|
|
245
|
+
dispose(): void; // Stop every poller this graph started; best-effort, total, idempotent. This surface owns its graph — see disposal-wiring.ts.
|
|
234
246
|
}
|
|
235
247
|
|
|
236
248
|
export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeServices {
|
|
237
|
-
const workingDirectory = options.workingDir;
|
|
249
|
+
const disposalScope = createDisposalScope('RuntimeServices'); const workingDirectory = options.workingDir; // disposal seam: see ./disposal-wiring.ts
|
|
238
250
|
const homeDirectory = options.homeDirectory;
|
|
239
251
|
const shellPaths = createShellPathService({
|
|
240
252
|
workingDirectory,
|
|
@@ -340,34 +352,14 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
340
352
|
runtimeStore: options.runtimeStore,
|
|
341
353
|
runtimeBus: options.runtimeBus,
|
|
342
354
|
});
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const agentManager = new AgentManager({
|
|
351
|
-
archetypeLoader,
|
|
352
|
-
messageBus: agentMessageBus,
|
|
353
|
-
executor: agentOrchestrator,
|
|
354
|
-
configManager,
|
|
355
|
-
// The live registry lets a bare model id in a spawn() override resolve
|
|
356
|
-
// through the shared resolver instead of being rejected as unqualified.
|
|
357
|
-
providerRegistry,
|
|
358
|
-
});
|
|
359
|
-
const contextAccountingHolder = new ContextAccountingHolder();
|
|
360
|
-
agentOrchestrator.setConversationSink({ // Conversation-snapshot bridge (mirrors the SDK's own createRuntimeServices)
|
|
361
|
-
register: (agentId, source) => agentManager.registerConversationSource(agentId, source),
|
|
362
|
-
release: (agentId) => agentManager.releaseConversationSource(agentId),
|
|
363
|
-
});
|
|
364
|
-
agentManager.setRuntimeBus(options.runtimeBus);
|
|
365
|
-
const wrfcController = new WrfcController(options.runtimeBus, agentMessageBus, {
|
|
366
|
-
agentManager,
|
|
367
|
-
configManager,
|
|
368
|
-
projectRoot: workingDirectory,
|
|
355
|
+
// The agent-execution graph, wired in both directions; see
|
|
356
|
+
// agent-graph-composition.ts for why the six are built as one.
|
|
357
|
+
const {
|
|
358
|
+
agentMessageBus, archetypeLoader, agentOrchestrator,
|
|
359
|
+
agentManager, contextAccountingHolder, wrfcController,
|
|
360
|
+
} = createAgentGraph({
|
|
361
|
+
runtimeBus: options.runtimeBus, workingDirectory, configManager, providerRegistry,
|
|
369
362
|
});
|
|
370
|
-
agentManager.setWrfcController(wrfcController);
|
|
371
363
|
const hookDispatcher = new HookDispatcher({ agentManager, toolLLM, projectRoot: workingDirectory }, hookActivityTracker);
|
|
372
364
|
configManager.attachHookDispatcher(hookDispatcher);
|
|
373
365
|
const hookWorkbench = createHookWorkbench({
|
|
@@ -419,6 +411,12 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
419
411
|
const memorySpine = new MemorySpineClient({ local: createLocalMemoryAccess(memoryRegistry) });
|
|
420
412
|
const deliveryManager = new AutomationDeliveryManager({
|
|
421
413
|
configManager,
|
|
414
|
+
// This manager builds the delivery router the daemon actually replies
|
|
415
|
+
// through (bootstrap.ts hands it to the daemon facade). Without the
|
|
416
|
+
// secrets manager it cannot resolve a goodvibes://secrets/... credential,
|
|
417
|
+
// so Telegram accepted every inbound message and dropped every reply with
|
|
418
|
+
// "Missing Telegram bot token" while ntfy — which needs no secret — worked.
|
|
419
|
+
secretsManager,
|
|
422
420
|
serviceRegistry,
|
|
423
421
|
runtimeBus: options.runtimeBus,
|
|
424
422
|
runtimeStore: options.runtimeStore,
|
|
@@ -498,43 +496,30 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
498
496
|
automationBridge: automationManager,
|
|
499
497
|
});
|
|
500
498
|
|
|
501
|
-
//
|
|
502
|
-
//
|
|
503
|
-
//
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
credentials: createDaemonCredentialStore(secretsManager),
|
|
499
|
+
// Which machines on this network are "us", and which of them reads the
|
|
500
|
+
// shared inbox. Both inert until startCluster() — no socket, no key material
|
|
501
|
+
// read; see cluster-group-composition.ts for why they are built together.
|
|
502
|
+
const { clusterGroup, clusterCoordinator } = createClusterServices({
|
|
503
|
+
configManager, shellPaths, secretsManager,
|
|
504
|
+
});
|
|
505
|
+
// Daemon handler surfaces (see daemon-handler-composition.ts); the inbox
|
|
506
|
+
// poller registers itself with the coordinator rather than starting eagerly.
|
|
507
|
+
const daemonHandlers = createDaemonHandlerComposition({
|
|
508
|
+
gatewayMethods,
|
|
509
|
+
secretsManager,
|
|
513
510
|
configManager,
|
|
514
511
|
workingDirectory,
|
|
515
512
|
homeDirectory,
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const daemonHandlers = registerDaemonHandlers(handlerContext, {
|
|
519
|
-
registerRouting,
|
|
520
|
-
registerInbox: (ctx, routing) =>
|
|
521
|
-
registerTriagedInbox(ctx, (inboxCtx) => registerInboxMethods(inboxCtx, routing))
|
|
522
|
-
.unregister,
|
|
523
|
-
registerDrafts: (ctx) => registerDraftMethods(ctx),
|
|
524
|
-
registerCalendar,
|
|
525
|
-
registerEmail: (ctx) => registerEmailMethods(ctx),
|
|
526
|
-
registerRemote: (ctx) => registerRemoteSurface(ctx, { manager: distributedRuntime }),
|
|
513
|
+
distributedRuntime,
|
|
514
|
+
clusterCoordinator,
|
|
527
515
|
});
|
|
528
516
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const sandboxSessionRegistry
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
});
|
|
536
|
-
mcpRegistry.setRuntimeBus(options.runtimeBus);
|
|
537
|
-
mcpRegistry.setSandboxRuntime(configManager, sandboxSessionRegistry);
|
|
517
|
+
// Remote runners and the sandboxes tool calls are confined to; see
|
|
518
|
+
// remote-execution-composition.ts for why the four are built as one.
|
|
519
|
+
const { remoteRunnerRegistry, remoteSupervisor, sandboxSessionRegistry, mcpRegistry }
|
|
520
|
+
= createRemoteExecutionServices({
|
|
521
|
+
agentManager, workingDirectory, hookDispatcher, configManager, runtimeBus: options.runtimeBus,
|
|
522
|
+
});
|
|
538
523
|
const tokenAuditor = new ApiTokenAuditor({ managed: false });
|
|
539
524
|
const componentHealthMonitor = new ComponentHealthMonitor();
|
|
540
525
|
const worktreeRegistry = new WorktreeRegistry(workingDirectory);
|
|
@@ -572,7 +557,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
572
557
|
// code-index-services.ts's header doc.
|
|
573
558
|
const { codeIndexStore, codeIndexReindexScheduler } = createCodeIndexServices({ workingDirectory, configManager, memoryEmbeddingRegistry, isReindexPaused: () => pauseController.isPaused('code-index-reindex'), admitExpensiveWork });
|
|
574
559
|
// Store snapshots, the periodic append-only sweep, durable remembered-approval rules + the live credential chain — see durability-services.ts.
|
|
575
|
-
const { storeSnapshotScheduler, appendOnlyRetentionScheduler, userPermissionRuleStore, stopDurabilityHousekeeping } = createDurabilityServices({
|
|
560
|
+
const { storeSnapshotScheduler, appendOnlyRetentionScheduler, userPermissionRuleStore, stopDurabilityHousekeeping, stopConfigWatch } = createDurabilityServices({
|
|
576
561
|
configManager, secretsManager, providerRegistry, memoryDbPath, codeIndexDbPath: codeIndexDbPath(workingDirectory), surface, shellPaths, // + retention-sweep roots & live config watch (mirrors the SDK)
|
|
577
562
|
...(options.currentSessionId ? { currentSessionId: options.currentSessionId } : {}), // exempts the running session from crash-residue reaping
|
|
578
563
|
});
|
|
@@ -618,7 +603,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
618
603
|
const { voiceSetup } = wireVoiceSetup({ configManager, shellPaths, voiceProviders, admitExpensiveWork });
|
|
619
604
|
|
|
620
605
|
// 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.
|
|
621
|
-
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 }) });
|
|
606
|
+
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, disposal: disposalScope.registry, ...wireFleetNeedsInputPush({ registry: processRegistry, runtimeBus: options.runtimeBus, sessionBroker }) });
|
|
622
607
|
const integrationHelpers = new IntegrationHelperService({
|
|
623
608
|
surface, // surface-scoped: continuity's recovery-file check must read the SAME paths the app writes with, not the unscoped legacy pair.
|
|
624
609
|
runtimeStore: options.runtimeStore,
|
|
@@ -684,7 +669,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
684
669
|
// bridge (the high-churn 'ops' domain stays out of the wholesale allowlist).
|
|
685
670
|
wireMemoryPressureNotice(options.runtimeBus, notificationDispatcher);
|
|
686
671
|
|
|
687
|
-
|
|
672
|
+
const services: RuntimeServices = {
|
|
688
673
|
workingDirectory,
|
|
689
674
|
homeDirectory,
|
|
690
675
|
surface,
|
|
@@ -762,6 +747,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
762
747
|
toolLLM,
|
|
763
748
|
distributedRuntime,
|
|
764
749
|
daemonHandlers,
|
|
750
|
+
clusterCoordinator,
|
|
751
|
+
clusterGroup,
|
|
752
|
+
startCluster: () => startClusterServices({ clusterGroup, clusterCoordinator }),
|
|
765
753
|
remoteRunnerRegistry,
|
|
766
754
|
remoteSupervisor,
|
|
767
755
|
sessionMemoryStore,
|
|
@@ -796,5 +784,14 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
796
784
|
workspaceCheckpointManager,
|
|
797
785
|
integrationHelpers,
|
|
798
786
|
rerootStores: createStoreRerooter({ codeIndexStore, projectIndex }),
|
|
787
|
+
// Cancels the agent runs this graph was hosting. By dispose() time the
|
|
788
|
+
// fleet registry, orchestration engine, process registry and bus these runs
|
|
789
|
+
// report through are already down, so a run still described as "running" is
|
|
790
|
+
// orphaned rather than preserved — and this is the only shutdown-reachable
|
|
791
|
+
// way to abort its in-flight provider call instead of letting it sleep out
|
|
792
|
+
// a retry backoff nobody is waiting on.
|
|
793
|
+
cancelHostedAgentRuns: () => cancelAllAgentRuns(agentManager),
|
|
794
|
+
dispose: (): void => disposalScope.dispose(),
|
|
799
795
|
};
|
|
796
|
+
registerSurfaceRuntimePollers(disposalScope.registry, services, { stopConfigWatch }); return services;
|
|
800
797
|
}
|
|
@@ -206,9 +206,47 @@ const ENABLEMENT_KEYS_BEHAVIOR_VERIFIED = new Set(
|
|
|
206
206
|
).size;
|
|
207
207
|
|
|
208
208
|
/** Settings with real local behavior verification: the authored baseline plus the persistence-tested feature-knob, device/trigger, and enablement keys. */
|
|
209
|
+
/**
|
|
210
|
+
* Config keys added by the LAN group-key layer: the automatic group-key
|
|
211
|
+
* rotation interval, the dual-generation acceptance window around a rotation,
|
|
212
|
+
* the discovery beacon interval, and the roster gossip interval.
|
|
213
|
+
*
|
|
214
|
+
* THIS CONSTANT IS NOT A DIAL, for the same reason as the two above. Each key
|
|
215
|
+
* is counted because a test that exercises it was actually written:
|
|
216
|
+
* `src/test/verification/cluster-group-settings-persistence.test.ts` runs the
|
|
217
|
+
* same four-part persistence contract — schema default exposure, `set()`
|
|
218
|
+
* through the key's own validator to disk, reload into a fresh ConfigManager
|
|
219
|
+
* with read-back equality, and reset-to-default that survives reload.
|
|
220
|
+
*
|
|
221
|
+
* PER-KEY EVIDENCE. All four have a LIVE consumer in this build, which is more
|
|
222
|
+
* than several of the keys counted above can claim:
|
|
223
|
+
* cluster.keyRotationHours — read by resolveClusterGroupSettings and
|
|
224
|
+
* compared against the current key's age in
|
|
225
|
+
* the group runtime's rotation check.
|
|
226
|
+
* cluster.keyRotationGraceMinutes — sets how long the previous generation
|
|
227
|
+
* stays accepted after a scheduled
|
|
228
|
+
* rotation; drives the keyring's accepted
|
|
229
|
+
* generation set.
|
|
230
|
+
* cluster.beaconSeconds — the discovery beacon timer interval, and
|
|
231
|
+
* the basis of the "recently heard from"
|
|
232
|
+
* window that decides which member mints a
|
|
233
|
+
* rotation.
|
|
234
|
+
* cluster.rosterGossipSeconds — how often the member list is shared.
|
|
235
|
+
*
|
|
236
|
+
* `cluster.enabled` is NOT here: it is a feature enablement key and the ledger
|
|
237
|
+
* counts those in its own set.
|
|
238
|
+
*/
|
|
239
|
+
export const CLUSTER_GROUP_LOCAL_SETTINGS = [
|
|
240
|
+
'cluster.keyRotationHours',
|
|
241
|
+
'cluster.keyRotationGraceMinutes',
|
|
242
|
+
'cluster.beaconSeconds',
|
|
243
|
+
'cluster.rosterGossipSeconds',
|
|
244
|
+
] as const;
|
|
245
|
+
|
|
209
246
|
const SETTINGS_BEHAVIOR_VERIFIED = SETTINGS_BEHAVIOR_BASELINE
|
|
210
247
|
+ FEATURE_KNOB_LOCAL_SETTINGS.length
|
|
211
248
|
+ DEVICE_AND_TRIGGER_LOCAL_SETTINGS.length
|
|
249
|
+
+ CLUSTER_GROUP_LOCAL_SETTINGS.length
|
|
212
250
|
+ ENABLEMENT_KEYS_BEHAVIOR_VERIFIED;
|
|
213
251
|
|
|
214
252
|
const EXTERNAL_SLASH_COMMANDS = new Set([
|
package/src/version.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'node:path';
|
|
|
6
6
|
// The prebuild script updates the fallback value before compilation.
|
|
7
7
|
// Uses import.meta.dir (Bun) to locate package.json relative to this file,
|
|
8
8
|
// which is correct regardless of the process working directory.
|
|
9
|
-
let _version = '1.
|
|
9
|
+
let _version = '1.24.1';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
|
|
12
12
|
// Only trust a version read from OUR OWN package.json. A Bun single-file
|