@myagentroam/node 0.12.4 → 0.12.6
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/dist/application/scheduled-execution-service.js +60 -0
- package/dist/connector.js +207 -261
- package/dist/marctl/package.json +1 -1
- package/dist/runner/claude-code-runner.js +4 -0
- package/dist/runner/codex-runner.js +11 -4
- package/dist/runner/mar-agent/agent-network-extension.js +2 -1
- package/dist/runner/opencode/opencode-server.js +37 -12
- package/dist/runner/opencode-runner.js +21 -7
- package/dist/service/agent-network-run-projection.js +60 -0
- package/dist/service/composer-message-input.js +1 -1
- package/dist/service/session-recent-activity.js +3 -3
- package/dist/service/skill-directory-service.js +10 -31
- package/dist/service/skill-node-operation-service.js +3 -5
- package/dist/session/native-session-projection-service.js +41 -6
- package/dist/session/session-catalog-service.js +11 -0
- package/dist/workspace/workspace-session-service.js +58 -8
- package/package.json +4 -4
package/dist/connector.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ExecutionLifecycle } from './application/execution-lifecycle.js';
|
|
|
6
6
|
import { NodeOperationAdmission } from './application/node-operation-admission.js';
|
|
7
7
|
import { normalizeMarAgentUsage } from './runner/mar-agent/conversation-normalizer.js';
|
|
8
8
|
import { NodeLifecycle } from './application/node-lifecycle.js';
|
|
9
|
+
import { ScheduledExecutionService } from './application/scheduled-execution-service.js';
|
|
9
10
|
import { isImageAttachment } from './session/attachments.js';
|
|
10
11
|
import { ModelUsageOutbox } from './service/model-usage-outbox.js';
|
|
11
12
|
import { NodeModelUsageService } from './service/model-usage-service.js';
|
|
@@ -24,7 +25,8 @@ import { CommandStateStore } from './runner-command-engine.js';
|
|
|
24
25
|
import { GoalRuntime } from './service/goal-runtime.js';
|
|
25
26
|
import { GoalContinuationCoordinator } from './service/goal-continuation-coordinator.js';
|
|
26
27
|
import { GoalMcpBridge } from './service/goal-mcp-bridge.js';
|
|
27
|
-
import { AgentNetworkObservations
|
|
28
|
+
import { AgentNetworkObservations } from './service/agent-network-observations.js';
|
|
29
|
+
import { AgentNetworkRunProjection } from './service/agent-network-run-projection.js';
|
|
28
30
|
import { createNodeAgentNetwork } from './service/agent-network-bindings.js';
|
|
29
31
|
import { agentNetworkExecutionCommand, agentNetworkInvoke } from './service/agent-network-invoke.js';
|
|
30
32
|
import { RunnerUsageReader } from './runner-usage.js';
|
|
@@ -54,7 +56,7 @@ import { SessionWatchSlotCoordinator } from './service/session-watch-slot-coordi
|
|
|
54
56
|
import { SessionContextService } from './session/session-context-service.js';
|
|
55
57
|
import { RunWorkbenchService } from './service/run-workbench-service.js';
|
|
56
58
|
import { SessionQueryService } from './session/session-query-service.js';
|
|
57
|
-
import {
|
|
59
|
+
import { marctlSessionProgress } from './service/session-recent-activity.js';
|
|
58
60
|
import { WorkspaceQueueWorkbenchService } from './workspace/workspace-queue-workbench-service.js';
|
|
59
61
|
import { ContinuousRunCoordinator } from './service/continuous-run-coordinator.js';
|
|
60
62
|
import { SessionIdentityService } from './session/session-identity-service.js';
|
|
@@ -154,6 +156,12 @@ const CONVERSATION_HOSTING_MAINTENANCE_OPERATIONS = [
|
|
|
154
156
|
export function nextReconnectDelay(attempt) {
|
|
155
157
|
return Math.min(RETRY_MAX_MS, RETRY_MIN_MS * 2 ** Math.min(Math.max(attempt, 0), 16));
|
|
156
158
|
}
|
|
159
|
+
/** Application composition and resource-lifetime root, not a domain workflow owner.
|
|
160
|
+
* Field initializers create local state/ports; the constructor creates domain owners, connects
|
|
161
|
+
* runtime event feedback, registers operations, then connects lifecycle. Callbacks for genuine
|
|
162
|
+
* Session/Workspace feedback are dormant until composition completes; start() activates resources.
|
|
163
|
+
* Session queries, Agent observations and execution preparation stay with their respective owners.
|
|
164
|
+
*/
|
|
157
165
|
export class NodeConnector {
|
|
158
166
|
usageOutbox;
|
|
159
167
|
modelUsage = new NodeModelUsageService(() => this.usageOutbox, () => this.config?.nodeId);
|
|
@@ -184,31 +192,7 @@ export class NodeConnector {
|
|
|
184
192
|
throw new Error('NODE_CONFIG_UNAVAILABLE');
|
|
185
193
|
return nodeDataDirectory(this.config, this.configPath);
|
|
186
194
|
});
|
|
187
|
-
lifecycle
|
|
188
|
-
this.continuousRunCoordinator.suspend();
|
|
189
|
-
this.goalCoordinator.freeze();
|
|
190
|
-
this.scheduledSessions.stop();
|
|
191
|
-
}, {
|
|
192
|
-
waitForRecovery: () => this.restartHandoff.wait(),
|
|
193
|
-
drainInput: async () => {
|
|
194
|
-
this.sessionMessageService.setAccepting(false);
|
|
195
|
-
await this.operationAdmission.drain();
|
|
196
|
-
await this.sessionMessageService.drain();
|
|
197
|
-
},
|
|
198
|
-
closeResume: () => this.externalSessionResumeService.close(),
|
|
199
|
-
capture: () => {
|
|
200
|
-
if (!this.config?.nodeId)
|
|
201
|
-
return;
|
|
202
|
-
return this.restartHandoff.capture();
|
|
203
|
-
},
|
|
204
|
-
dispose: () => this.disposeRuntime(),
|
|
205
|
-
publish: (snapshot) => this.restartHandoff.publish(snapshot),
|
|
206
|
-
diagnose: (stage, error) => nodeLog('node.shutdown.failed', {
|
|
207
|
-
stage,
|
|
208
|
-
errorCode: safeErrorCode(error, 'NODE_SHUTDOWN_FAILED'),
|
|
209
|
-
...(stage === 'capture' ? plannedRestartCaptureDiagnostic(error) : undefined)
|
|
210
|
-
})
|
|
211
|
-
});
|
|
195
|
+
lifecycle;
|
|
212
196
|
get stopped() {
|
|
213
197
|
return this.lifecycle.stopped;
|
|
214
198
|
}
|
|
@@ -323,24 +307,12 @@ export class NodeConnector {
|
|
|
323
307
|
runnerUsageReader;
|
|
324
308
|
terminalManager;
|
|
325
309
|
upgradeCoordinator;
|
|
326
|
-
workspaceResources
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
this.workspaceCoordinator.invalidate(workspaceId);
|
|
333
|
-
},
|
|
334
|
-
releaseWatch: (workspaceId) => this.workspaceWorkbenchService?.releaseWorkspace(workspaceId),
|
|
335
|
-
removeWatch: (watch) => this.workspaceWorkbenchService?.cancelFilePrewarm(watch),
|
|
336
|
-
temporaryRoot: () => this.attachmentTemporaryRoot(),
|
|
337
|
-
attachmentResource: (id, path) => this.runAttachmentService.fileResource(id, path)
|
|
338
|
-
});
|
|
339
|
-
workspaceWatchService = this.workspaceResources.watch;
|
|
340
|
-
workspaceSessionService = this.workspaceResources.sessions;
|
|
341
|
-
workspaceFileService = this.workspaceResources.files;
|
|
342
|
-
workspaceUploadService = this.workspaceResources.uploads;
|
|
343
|
-
invalidateWorkspaceFiles = this.workspaceResources.invalidateFiles;
|
|
310
|
+
workspaceResources;
|
|
311
|
+
workspaceWatchService;
|
|
312
|
+
workspaceSessionService;
|
|
313
|
+
workspaceFileService;
|
|
314
|
+
workspaceUploadService;
|
|
315
|
+
invalidateWorkspaceFiles;
|
|
344
316
|
directTransferService;
|
|
345
317
|
attachmentTemporaryRoot() {
|
|
346
318
|
if (this.config === undefined)
|
|
@@ -354,109 +326,13 @@ export class NodeConnector {
|
|
|
354
326
|
recentRunProjectionService = new RecentRunProjectionService((message) => this.send('recent-runs', message));
|
|
355
327
|
/** Runtime/session state is intentionally not persisted to Node SQLite. */
|
|
356
328
|
runtime = new NodeRuntimeState(() => this.config?.nodeId ?? 'runtime-node', (workspaceId) => this.database?.getWorkspace(workspaceId), Date.now, (run, session, userMessage) => this.recentRunProjectionService.record(run, session, userMessage));
|
|
357
|
-
goalCoordinator
|
|
358
|
-
goals: this.goalRuntime,
|
|
359
|
-
runners: () => this.runners,
|
|
360
|
-
runtime: this.runtime,
|
|
361
|
-
commands: this.commandStates,
|
|
362
|
-
queue: () => this.continuousRunCoordinator,
|
|
363
|
-
submit: (input) => this.sessionMessageService.submitGoal(input),
|
|
364
|
-
emitRun: (...args) => this.runEventBridge.emitRun(...args),
|
|
365
|
-
present: (session) => this.sessionPresentationService.present(session),
|
|
366
|
-
emitSession: (session) => this.emitSessionWorkbenchEvent({ session: this.sessionPresentationService.present(session) }),
|
|
367
|
-
database: () => this.database
|
|
368
|
-
});
|
|
329
|
+
goalCoordinator;
|
|
369
330
|
metrics = new NodeMetrics();
|
|
370
331
|
agentNetworkObservations = new AgentNetworkObservations();
|
|
371
|
-
|
|
372
|
-
runEventService
|
|
373
|
-
runtime: this.runtime,
|
|
374
|
-
metrics: this.metrics,
|
|
375
|
-
isBootstrapSession: (sessionId) => this.sessionIdentityService.bootstrapIds.has(sessionId),
|
|
376
|
-
presentSession: (session) => this.sessionPresentationService.present(session),
|
|
377
|
-
rejectBootstrap: (sessionId, code) => this.sessionIdentityService.reject(sessionId, code),
|
|
378
|
-
emitWorkbench: (category, payload) => this.publishWorkbenchEvent(category, payload),
|
|
379
|
-
cleanupAttachments: (runId) => this.runAttachmentService.cleanup(runId),
|
|
380
|
-
refreshAttachments: (sessionId) => this.runAttachmentService.refreshSession(sessionId),
|
|
381
|
-
expireImages: (runId) => this.runAttachmentService.expire(runId),
|
|
382
|
-
scheduleContextRefresh: (sessionId) => this.sessionContextService.schedule(sessionId),
|
|
383
|
-
refreshWorkspaceSessions: (workspaceId) => this.workspaceWorkbenchService.ensureTopicSnapshot(workspaceId, 'sessions'),
|
|
384
|
-
onTerminalRun: (run, status) => this.executionLifecycle.terminal(run, status),
|
|
385
|
-
observeAgentEvent: ({ run, executionId, eventType, payload, terminalStatus }) => {
|
|
386
|
-
const child = this.runtime.getAgentSession(run.sessionId);
|
|
387
|
-
if (!child)
|
|
388
|
-
return;
|
|
389
|
-
const parent = child.parentSessionId == null
|
|
390
|
-
? undefined
|
|
391
|
-
: this.runtime.getAgentSession(child.parentSessionId);
|
|
392
|
-
let observation = agentObservationFromRunEvent({ eventType, payload, terminalStatus });
|
|
393
|
-
if (eventType === 'approval.request') {
|
|
394
|
-
const approvals = marctlSessionDetail(this.runtime, child, 0).pendingApprovals;
|
|
395
|
-
if (approvals.length)
|
|
396
|
-
observation = {
|
|
397
|
-
kind: 'message',
|
|
398
|
-
value: JSON.stringify({
|
|
399
|
-
pendingApprovals: approvals
|
|
400
|
-
})
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
if (observation)
|
|
404
|
-
this.agentNetworkObservations.publishChild({
|
|
405
|
-
...(parent?.workspaceId === child.workspaceId ? { parentId: parent.id } : {}),
|
|
406
|
-
childId: child.id,
|
|
407
|
-
runId: run.id,
|
|
408
|
-
executionId,
|
|
409
|
-
...observation
|
|
410
|
-
});
|
|
411
|
-
if (terminalStatus !== undefined &&
|
|
412
|
-
this.transientAgentObservers.get(run.sessionId) === run.id) {
|
|
413
|
-
this.transientAgentObservers.delete(run.sessionId);
|
|
414
|
-
this.agentNetworkObservations.get(run.sessionId)?.close();
|
|
415
|
-
}
|
|
416
|
-
},
|
|
417
|
-
dispatchQueue: (sessionId, delayMs) => this.executionLifecycle.dispatchQueue(sessionId, delayMs),
|
|
418
|
-
executionStarted: (executionId) => this.continuousRunCoordinator.executionStarted(executionId),
|
|
419
|
-
acceptExecutionTerminal: (input) => this.continuousRunCoordinator.acceptExecutionTerminal(input),
|
|
420
|
-
publishGoalUpdate: ({ session, goal }) => this.goalCoordinator.publishGoalState(session, goal),
|
|
421
|
-
publishQueueChange: (sessionId) => this.continuousRunCoordinator.publish(sessionId),
|
|
422
|
-
releaseExecution: (executionId) => this.executionLifecycle.release(executionId)
|
|
423
|
-
});
|
|
332
|
+
agentNetworkProjection;
|
|
333
|
+
runEventService;
|
|
424
334
|
sessionWatchSlots = new SessionWatchSlotCoordinator();
|
|
425
|
-
nativeSessionWatchService
|
|
426
|
-
resolve: async (sessionId) => this.runtime.getAgentSession(sessionId) ??
|
|
427
|
-
this.nativeSessionProjectionService.resolveCurrent(sessionId),
|
|
428
|
-
managedActive: (session) => hasManagedActiveRun(this.runtime, session),
|
|
429
|
-
suspended: (sessionId) => this.externalSessionResumeService.transitioning(sessionId),
|
|
430
|
-
refreshActivity: (session) => this.conversationHistoryService.refreshExternalActivity(session),
|
|
431
|
-
present: (session) => this.sessionPresentationService.present(session),
|
|
432
|
-
readPage: (session, limit) => this.conversationHistoryService.read(session, { limit }),
|
|
433
|
-
readHistoryPage: (session, limit) => this.conversationHistoryService.readHistoryPage(session, { limit }),
|
|
434
|
-
projectInitialPage: (session, page, _unit, limit) => {
|
|
435
|
-
const context = this.sessionContextService.snapshot(session.id);
|
|
436
|
-
this.sessionContextService.schedule(session);
|
|
437
|
-
return {
|
|
438
|
-
kind: 'session-watch-snapshot',
|
|
439
|
-
sequence: this.workbenchEventService.snapshotSequence(),
|
|
440
|
-
session: this.sessionPresentationService.present(session),
|
|
441
|
-
runs: this.runtime.listRunsForSession(session.id, { includeTerminal: true }),
|
|
442
|
-
progress: marctlSessionProgress(this.runtime, session.id),
|
|
443
|
-
performance: this.runtime.sessionPerformance(session.id),
|
|
444
|
-
queue: this.workspaceQueueWorkbenchService.snapshot(session.id),
|
|
445
|
-
context,
|
|
446
|
-
conversation: this.conversationSegmentService.projectInitial(session, page, limit)
|
|
447
|
-
};
|
|
448
|
-
},
|
|
449
|
-
emitSession: (session) => this.emitSessionWorkbenchEvent({ session }),
|
|
450
|
-
emitPage: (session, page) => this.emitWorkbenchEvent('conversation', {
|
|
451
|
-
sessionId: session.id,
|
|
452
|
-
snapshot: this.conversationSegmentService.projectInitial(session, page, 3)
|
|
453
|
-
}),
|
|
454
|
-
nodeId: () => this.config?.nodeId ?? 'runtime-node',
|
|
455
|
-
nodeGeneration: () => this.nodeGeneration,
|
|
456
|
-
emitWatchEvent: (payload) => this.send('watch.event', payload),
|
|
457
|
-
sessionWatchSlots: this.sessionWatchSlots,
|
|
458
|
-
log: nodeLog
|
|
459
|
-
});
|
|
335
|
+
nativeSessionWatchService;
|
|
460
336
|
constructor(options = {}) {
|
|
461
337
|
this.config = options.config;
|
|
462
338
|
this.configPath = options.configPath;
|
|
@@ -1076,6 +952,100 @@ export class NodeConnector {
|
|
|
1076
952
|
goal: (input) => this.goalCoordinator.start(input),
|
|
1077
953
|
clearGoal: (session) => this.goalCoordinator.clear(session)
|
|
1078
954
|
});
|
|
955
|
+
this.nativeSessionWatchService = new NativeSessionWatchService({
|
|
956
|
+
resolve: async (sessionId) => this.runtime.getAgentSession(sessionId) ??
|
|
957
|
+
this.nativeSessionProjectionService.resolveCurrent(sessionId),
|
|
958
|
+
managedActive: (session) => hasManagedActiveRun(this.runtime, session),
|
|
959
|
+
suspended: (sessionId) => this.externalSessionResumeService.transitioning(sessionId),
|
|
960
|
+
refreshActivity: (session) => this.conversationHistoryService.refreshExternalActivity(session),
|
|
961
|
+
present: (session) => this.sessionPresentationService.present(session),
|
|
962
|
+
readPage: (session, limit) => this.conversationHistoryService.read(session, { limit }),
|
|
963
|
+
readHistoryPage: (session, limit) => this.conversationHistoryService.readHistoryPage(session, { limit }),
|
|
964
|
+
projectInitialPage: (session, page, _unit, limit) => {
|
|
965
|
+
const context = this.sessionContextService.snapshot(session.id);
|
|
966
|
+
this.sessionContextService.schedule(session);
|
|
967
|
+
return {
|
|
968
|
+
kind: 'session-watch-snapshot',
|
|
969
|
+
sequence: this.workbenchEventService.snapshotSequence(),
|
|
970
|
+
session: this.sessionPresentationService.present(session),
|
|
971
|
+
runs: this.runtime.listRunsForSession(session.id, { includeTerminal: true }),
|
|
972
|
+
progress: marctlSessionProgress(this.runtime, session.id),
|
|
973
|
+
performance: this.runtime.sessionPerformance(session.id),
|
|
974
|
+
queue: this.workspaceQueueWorkbenchService.snapshot(session.id),
|
|
975
|
+
context,
|
|
976
|
+
conversation: this.conversationSegmentService.projectInitial(session, page, limit)
|
|
977
|
+
};
|
|
978
|
+
},
|
|
979
|
+
emitSession: (session) => this.emitSessionWorkbenchEvent({ session }),
|
|
980
|
+
emitPage: (session, page) => this.emitWorkbenchEvent('conversation', {
|
|
981
|
+
sessionId: session.id,
|
|
982
|
+
snapshot: this.conversationSegmentService.projectInitial(session, page, 3)
|
|
983
|
+
}),
|
|
984
|
+
nodeId: () => this.config?.nodeId ?? 'runtime-node',
|
|
985
|
+
nodeGeneration: () => this.nodeGeneration,
|
|
986
|
+
emitWatchEvent: (payload) => this.send('watch.event', payload),
|
|
987
|
+
sessionWatchSlots: this.sessionWatchSlots,
|
|
988
|
+
log: nodeLog
|
|
989
|
+
});
|
|
990
|
+
// Create the Session query owner, then connect its Workspace cache/observation ports below.
|
|
991
|
+
this.sessionCatalogService = new SessionCatalogService({
|
|
992
|
+
resolveExecutionDirectory,
|
|
993
|
+
database: () => {
|
|
994
|
+
if (this.database === undefined)
|
|
995
|
+
throw new Error('NODE_DATABASE_UNAVAILABLE');
|
|
996
|
+
return this.database;
|
|
997
|
+
},
|
|
998
|
+
nodeId: () => this.config?.nodeId ?? 'recorded-session',
|
|
999
|
+
runtime: this.runtime,
|
|
1000
|
+
runners: this.runners,
|
|
1001
|
+
runnerAvailable: (runner) => this.runners.require(runner).available(this.capabilities),
|
|
1002
|
+
projection: this.nativeSessionProjectionService,
|
|
1003
|
+
cachedNative: () => this.nativeSessionProjectionService.cachedNative(),
|
|
1004
|
+
cachedWorkspace: (workspaceId) => this.workspaceSessionService.cached(workspaceId),
|
|
1005
|
+
discoveryPending: (workspaceId) => this.workspaceSessionService.discoveryPending(workspaceId),
|
|
1006
|
+
discoverWorkspace: (workspaceId, cleanup) => this.nativeSessionProjectionService.discoverWorkspace(workspaceId, undefined, cleanup),
|
|
1007
|
+
present: (session) => this.sessionPresentationService.present(session),
|
|
1008
|
+
nativeIds: (session) => this.nativeSessionProjectionService.nativeIds(session),
|
|
1009
|
+
forget: (session, nativeIds) => {
|
|
1010
|
+
this.nativeSessionProjectionService.forget(session, nativeIds);
|
|
1011
|
+
this.promptCompletion.invalidateSession(session.workspaceId, session.id);
|
|
1012
|
+
void this.runAttachmentService.releaseSession(session.id);
|
|
1013
|
+
},
|
|
1014
|
+
refreshActivity: (session) => this.conversationHistoryService.refreshExternalActivity(session),
|
|
1015
|
+
externalActivity: (sessionId) => this.externalSessionResumeService.activity(sessionId),
|
|
1016
|
+
isWatching: (sessionId) => this.nativeSessionWatchService.isWatching(sessionId),
|
|
1017
|
+
isRecovering: (sessionId) => this.restartHandoff.blocks(sessionId),
|
|
1018
|
+
history: (session, input) => this.conversationHistoryService.read(session, input),
|
|
1019
|
+
invalidateHistory: (sessionId, workspaceId) => {
|
|
1020
|
+
this.nativeSessionWatchService.invalidate(sessionId);
|
|
1021
|
+
this.promptCompletion.invalidateSession(workspaceId, sessionId);
|
|
1022
|
+
},
|
|
1023
|
+
invalidateWorkspaceSessions: (workspaceId) => {
|
|
1024
|
+
this.workspaceSessionService.invalidateCache(workspaceId);
|
|
1025
|
+
void this.workspaceWorkbenchService?.invalidateTopic(workspaceId, 'sessions');
|
|
1026
|
+
},
|
|
1027
|
+
emitSession: (session) => this.emitSessionWorkbenchEvent({
|
|
1028
|
+
session: this.sessionPresentationService.present(session)
|
|
1029
|
+
})
|
|
1030
|
+
});
|
|
1031
|
+
this.workspaceResources = composeWorkspaceResources({
|
|
1032
|
+
discover: (workspaceId, onRunnerDiscovered, signal) => this.discoverWorkspaceSessions(workspaceId, onRunnerDiscovered, signal),
|
|
1033
|
+
listPage: (workspaceId, group) => this.sessionCatalogService.listWorkspacePage(workspaceId, group),
|
|
1034
|
+
invalidateSessions: (workspaceId) => void this.workspaceWorkbenchService?.invalidateTopic(workspaceId, 'sessions'),
|
|
1035
|
+
invalidateFiles: (workspaceId) => {
|
|
1036
|
+
this.workspaceWorkbenchService?.invalidateWorkspaceFiles(workspaceId);
|
|
1037
|
+
this.workspaceCoordinator.invalidate(workspaceId);
|
|
1038
|
+
},
|
|
1039
|
+
releaseWatch: (workspaceId) => this.workspaceWorkbenchService?.releaseWorkspace(workspaceId),
|
|
1040
|
+
removeWatch: (watch) => this.workspaceWorkbenchService?.cancelFilePrewarm(watch),
|
|
1041
|
+
temporaryRoot: () => this.attachmentTemporaryRoot(),
|
|
1042
|
+
attachmentResource: (id, path) => this.runAttachmentService.fileResource(id, path)
|
|
1043
|
+
});
|
|
1044
|
+
this.workspaceWatchService = this.workspaceResources.watch;
|
|
1045
|
+
this.workspaceSessionService = this.workspaceResources.sessions;
|
|
1046
|
+
this.workspaceFileService = this.workspaceResources.files;
|
|
1047
|
+
this.workspaceUploadService = this.workspaceResources.uploads;
|
|
1048
|
+
this.invalidateWorkspaceFiles = this.workspaceResources.invalidateFiles;
|
|
1079
1049
|
this.sessionMessageService = new SessionMessageService({
|
|
1080
1050
|
resolveExecutionDirectory,
|
|
1081
1051
|
runtime: this.runtime,
|
|
@@ -1098,6 +1068,21 @@ export class NodeConnector {
|
|
|
1098
1068
|
prepareGoalInsertion: (sessionId, submissionId, goal) => this.goalCoordinator.prepareInsertion(sessionId, submissionId, goal),
|
|
1099
1069
|
goalPreparationFailed: (session, goal, activated) => this.goalCoordinator.handleGoalPreparationFailed(session, goal, activated)
|
|
1100
1070
|
});
|
|
1071
|
+
this.goalCoordinator = new GoalContinuationCoordinator({
|
|
1072
|
+
goals: this.goalRuntime,
|
|
1073
|
+
runners: () => this.runners,
|
|
1074
|
+
runtime: this.runtime,
|
|
1075
|
+
commands: this.commandStates,
|
|
1076
|
+
queue: () => this.continuousRunCoordinator,
|
|
1077
|
+
submit: (input) => this.sessionMessageService.submitGoal(input),
|
|
1078
|
+
emitRun: (...args) => this.runEventBridge.emitRun(...args),
|
|
1079
|
+
present: (session) => this.sessionPresentationService.present(session),
|
|
1080
|
+
emitSession: (session) => this.emitSessionWorkbenchEvent({
|
|
1081
|
+
session: this.sessionPresentationService.present(session)
|
|
1082
|
+
}),
|
|
1083
|
+
database: () => this.database
|
|
1084
|
+
});
|
|
1085
|
+
this.agentNetworkProjection = new AgentNetworkRunProjection(this.runtime, this.agentNetworkObservations);
|
|
1101
1086
|
this.agentNetworkService = createNodeAgentNetwork({
|
|
1102
1087
|
runtime: this.runtime,
|
|
1103
1088
|
database: () => this.database,
|
|
@@ -1110,27 +1095,9 @@ export class NodeConnector {
|
|
|
1110
1095
|
goals: this.goalRuntime,
|
|
1111
1096
|
runs: this.runWorkbenchService,
|
|
1112
1097
|
observations: this.agentNetworkObservations,
|
|
1113
|
-
ensureObservations:
|
|
1114
|
-
const existing = this.agentNetworkObservations.get(actor.observationId ?? actor.sessionId);
|
|
1115
|
-
if (existing)
|
|
1116
|
-
return existing;
|
|
1117
|
-
const run = actor.runId === undefined ? undefined : this.runtime.getRun(actor.runId);
|
|
1118
|
-
if (!run ||
|
|
1119
|
-
run.sessionId !== actor.sessionId ||
|
|
1120
|
-
this.runtime.activeSessionRun(actor.sessionId)?.id !== run.id)
|
|
1121
|
-
throw new Error('AGENT_ACTOR_NOT_ACTIVE');
|
|
1122
|
-
const observer = this.agentNetworkObservations.attach(actor.sessionId);
|
|
1123
|
-
this.transientAgentObservers.set(actor.sessionId, run.id);
|
|
1124
|
-
return observer;
|
|
1125
|
-
},
|
|
1098
|
+
ensureObservations: this.agentNetworkProjection.ensureObservations,
|
|
1126
1099
|
withGrant: (actor, work) => this.modelUsage.withGrant(actor.usageGrant, work)
|
|
1127
1100
|
});
|
|
1128
|
-
this.operationRouter.register('agent.network', agentNetworkExecutionCommand({
|
|
1129
|
-
runtime: this.runtime,
|
|
1130
|
-
coordinator: this.continuousRunCoordinator,
|
|
1131
|
-
service: this.agentNetworkService,
|
|
1132
|
-
observations: this.agentNetworkObservations
|
|
1133
|
-
}));
|
|
1134
1101
|
const inputState = (entry, message) => this.marAgentClient.restartInputState(entry.session.id, message.clientMessageId);
|
|
1135
1102
|
const restorer = new RestartSessionRestorer({
|
|
1136
1103
|
runtime: this.runtime,
|
|
@@ -1187,46 +1154,7 @@ export class NodeConnector {
|
|
|
1187
1154
|
restore: (entry, id) => restorer.restore(entry, id),
|
|
1188
1155
|
diagnose: (code, sessionId, errorCode) => nodeLog('node.restart.diagnostic', { code, sessionId, errorCode })
|
|
1189
1156
|
});
|
|
1190
|
-
|
|
1191
|
-
resolveExecutionDirectory,
|
|
1192
|
-
database: () => {
|
|
1193
|
-
if (this.database === undefined)
|
|
1194
|
-
throw new Error('NODE_DATABASE_UNAVAILABLE');
|
|
1195
|
-
return this.database;
|
|
1196
|
-
},
|
|
1197
|
-
nodeId: () => this.config?.nodeId ?? 'recorded-session',
|
|
1198
|
-
runtime: this.runtime,
|
|
1199
|
-
runners: this.runners,
|
|
1200
|
-
runnerAvailable: (runner) => this.runners.require(runner).available(this.capabilities),
|
|
1201
|
-
projection: this.nativeSessionProjectionService,
|
|
1202
|
-
cachedNative: () => this.nativeSessionProjectionService.cachedNative(),
|
|
1203
|
-
cachedWorkspace: (workspaceId) => this.workspaceCoordinator.cachedSessions(workspaceId),
|
|
1204
|
-
discoveryPending: (workspaceId) => this.workspaceSessionService.discoveryPending(workspaceId),
|
|
1205
|
-
discoverWorkspace: (workspaceId, cleanup) => this.nativeSessionProjectionService.discoverWorkspace(workspaceId, undefined, cleanup),
|
|
1206
|
-
present: (session) => this.sessionPresentationService.present(session),
|
|
1207
|
-
nativeIds: (session) => this.nativeSessionProjectionService.nativeIds(session),
|
|
1208
|
-
forget: (session, nativeIds) => {
|
|
1209
|
-
this.nativeSessionProjectionService.forget(session, nativeIds);
|
|
1210
|
-
this.promptCompletion.invalidateSession(session.workspaceId, session.id);
|
|
1211
|
-
void this.runAttachmentService.releaseSession(session.id);
|
|
1212
|
-
},
|
|
1213
|
-
refreshActivity: (session) => this.conversationHistoryService.refreshExternalActivity(session),
|
|
1214
|
-
externalActivity: (sessionId) => this.externalSessionResumeService.activity(sessionId),
|
|
1215
|
-
isWatching: (sessionId) => this.nativeSessionWatchService.isWatching(sessionId),
|
|
1216
|
-
isRecovering: (sessionId) => this.restartHandoff.blocks(sessionId),
|
|
1217
|
-
history: (session, input) => this.conversationHistoryService.read(session, input),
|
|
1218
|
-
invalidateHistory: (sessionId, workspaceId) => {
|
|
1219
|
-
this.nativeSessionWatchService.invalidate(sessionId);
|
|
1220
|
-
this.promptCompletion.invalidateSession(workspaceId, sessionId);
|
|
1221
|
-
},
|
|
1222
|
-
invalidateWorkspaceSessions: (workspaceId) => {
|
|
1223
|
-
this.workspaceSessionService.invalidateCache(workspaceId);
|
|
1224
|
-
void this.workspaceWorkbenchService?.invalidateTopic(workspaceId, 'sessions');
|
|
1225
|
-
},
|
|
1226
|
-
emitSession: (session) => this.emitSessionWorkbenchEvent({
|
|
1227
|
-
session: this.sessionPresentationService.present(session)
|
|
1228
|
-
})
|
|
1229
|
-
});
|
|
1157
|
+
// Connect Runner control feedback after Session owners and Workspace resources exist.
|
|
1230
1158
|
this.codexClient.bindControl({
|
|
1231
1159
|
start: (envelope) => this.codexRunController.start(envelope),
|
|
1232
1160
|
cancel: (runId, intent) => {
|
|
@@ -1428,11 +1356,7 @@ export class NodeConnector {
|
|
|
1428
1356
|
terminals: this.terminalManager,
|
|
1429
1357
|
resources: this.workspaceResources,
|
|
1430
1358
|
changes: this.workspaceChangeService,
|
|
1431
|
-
listSessions: (workspaceId, sessionGroup) => this.
|
|
1432
|
-
workspaceId,
|
|
1433
|
-
limit: 30,
|
|
1434
|
-
...(sessionGroup === undefined ? {} : { sessionGroup })
|
|
1435
|
-
}),
|
|
1359
|
+
listSessions: (workspaceId, sessionGroup) => this.workspaceSessionService.listPage(workspaceId, sessionGroup),
|
|
1436
1360
|
sessionNavigation: async (workspaceId, query) => this.sessionCatalogService.navigation({ workspaceId, ...query }),
|
|
1437
1361
|
invalidatePrompt: (id) => this.promptCompletion?.invalidateWorkspace(id),
|
|
1438
1362
|
nodeId: () => this.config?.nodeId ?? 'runtime-node',
|
|
@@ -1445,6 +1369,28 @@ export class NodeConnector {
|
|
|
1445
1369
|
this.workspaceService = workspaceApplication.workspace;
|
|
1446
1370
|
this.workspaceWorkbenchService = workspaceApplication.workbench;
|
|
1447
1371
|
this.publishWorkspaceSession = workspaceApplication.publishSession;
|
|
1372
|
+
// Connect normalized event projection and terminal feedback; no execution starts here.
|
|
1373
|
+
this.runEventService = new RunEventService({
|
|
1374
|
+
runtime: this.runtime,
|
|
1375
|
+
metrics: this.metrics,
|
|
1376
|
+
isBootstrapSession: (sessionId) => this.sessionIdentityService.bootstrapIds.has(sessionId),
|
|
1377
|
+
presentSession: (session) => this.sessionPresentationService.present(session),
|
|
1378
|
+
rejectBootstrap: (sessionId, code) => this.sessionIdentityService.reject(sessionId, code),
|
|
1379
|
+
emitWorkbench: (category, payload) => this.publishWorkbenchEvent(category, payload),
|
|
1380
|
+
cleanupAttachments: (runId) => this.runAttachmentService.cleanup(runId),
|
|
1381
|
+
refreshAttachments: (sessionId) => this.runAttachmentService.refreshSession(sessionId),
|
|
1382
|
+
expireImages: (runId) => this.runAttachmentService.expire(runId),
|
|
1383
|
+
scheduleContextRefresh: (sessionId) => this.sessionContextService.schedule(sessionId),
|
|
1384
|
+
refreshWorkspaceSessions: (workspaceId) => this.workspaceWorkbenchService.ensureTopicSnapshot(workspaceId, 'sessions'),
|
|
1385
|
+
onTerminalRun: (run, status) => this.executionLifecycle.terminal(run, status),
|
|
1386
|
+
observeAgentEvent: this.agentNetworkProjection.accept,
|
|
1387
|
+
dispatchQueue: (sessionId, delayMs) => this.executionLifecycle.dispatchQueue(sessionId, delayMs),
|
|
1388
|
+
executionStarted: (executionId) => this.continuousRunCoordinator.executionStarted(executionId),
|
|
1389
|
+
acceptExecutionTerminal: (input) => this.continuousRunCoordinator.acceptExecutionTerminal(input),
|
|
1390
|
+
publishGoalUpdate: ({ session, goal }) => this.goalCoordinator.publishGoalState(session, goal),
|
|
1391
|
+
publishQueueChange: (sessionId) => this.continuousRunCoordinator.publish(sessionId),
|
|
1392
|
+
releaseExecution: (executionId) => this.executionLifecycle.release(executionId)
|
|
1393
|
+
});
|
|
1448
1394
|
this.runEventBridge = new NodeRunEventBridge({
|
|
1449
1395
|
bindModelUsage: (runId) => {
|
|
1450
1396
|
const run = this.runtime.getRun(runId);
|
|
@@ -1497,62 +1443,22 @@ export class NodeConnector {
|
|
|
1497
1443
|
return this.database;
|
|
1498
1444
|
};
|
|
1499
1445
|
this.scheduledRunAuthorization = new RunAuthorizationControl((envelope) => this.controlChannel.sendEnvelope(envelope));
|
|
1446
|
+
const scheduledExecution = new ScheduledExecutionService({
|
|
1447
|
+
runtime: this.runtime,
|
|
1448
|
+
projection: this.nativeSessionProjectionService,
|
|
1449
|
+
authorization: this.scheduledRunAuthorization,
|
|
1450
|
+
runners: this.runners,
|
|
1451
|
+
git: this.gitOperationService,
|
|
1452
|
+
messages: this.sessionMessageService
|
|
1453
|
+
});
|
|
1500
1454
|
this.scheduledSessions = new ScheduledSessionCoordinator({
|
|
1501
1455
|
store: () => new ScheduledSessionStore(requireDatabase().raw),
|
|
1502
1456
|
busy: (task) => this.stopped ||
|
|
1503
1457
|
this.restartHandoff.blocks(task.sessionId) ||
|
|
1504
1458
|
this.runtime.activeSessionRun(task.sessionId) !== undefined ||
|
|
1505
1459
|
this.runtime.sessionQueue(task.sessionId).itemIds.length > 0,
|
|
1506
|
-
authorize:
|
|
1507
|
-
|
|
1508
|
-
(await this.nativeSessionProjectionService.resolveCurrent(task.sessionId));
|
|
1509
|
-
if (session === undefined ||
|
|
1510
|
-
session.workspaceId !== task.workspaceId ||
|
|
1511
|
-
session.runner !== task.runner)
|
|
1512
|
-
throw new Error('SCHEDULE_SESSION_NOT_FOUND');
|
|
1513
|
-
const configuredSession = this.nativeSessionProjectionService.ensureResumedConfiguration(session);
|
|
1514
|
-
const context = await this.scheduledRunAuthorization.authorize({
|
|
1515
|
-
taskId: task.id,
|
|
1516
|
-
revision: task.revision,
|
|
1517
|
-
occurrenceId,
|
|
1518
|
-
sessionId: task.sessionId,
|
|
1519
|
-
workspaceId: task.workspaceId,
|
|
1520
|
-
ownerUserId: task.ownerUserId,
|
|
1521
|
-
runner: task.runner,
|
|
1522
|
-
modelId: configuredSession.modelId
|
|
1523
|
-
});
|
|
1524
|
-
return {
|
|
1525
|
-
...(context.gitConfiguration === undefined
|
|
1526
|
-
? {}
|
|
1527
|
-
: { gitConfiguration: context.gitConfiguration }),
|
|
1528
|
-
secretEnvironment: context.secretEnvironment,
|
|
1529
|
-
personalInstructions: context.personalInstructions,
|
|
1530
|
-
usageGrant: context.usageGrant,
|
|
1531
|
-
executionContext: this.runners.require(task.runner).prepareExecutionContext(context)
|
|
1532
|
-
};
|
|
1533
|
-
},
|
|
1534
|
-
submit: async (task, occurrenceId, context) => {
|
|
1535
|
-
const result = (await this.gitOperationService.execute('session.message', {
|
|
1536
|
-
sessionId: task.sessionId,
|
|
1537
|
-
workspaceId: task.workspaceId,
|
|
1538
|
-
__requestUserId: task.ownerUserId,
|
|
1539
|
-
secretEnvironment: context.secretEnvironment,
|
|
1540
|
-
...(context.gitConfiguration === undefined
|
|
1541
|
-
? {}
|
|
1542
|
-
: { gitConfiguration: context.gitConfiguration })
|
|
1543
|
-
}, async (data) => this.sessionMessageService.submitScheduled({
|
|
1544
|
-
sessionId: task.sessionId,
|
|
1545
|
-
occurrenceId,
|
|
1546
|
-
objective: task.objective,
|
|
1547
|
-
initiatedByUserId: task.ownerUserId,
|
|
1548
|
-
secretEnvironment: data
|
|
1549
|
-
.secretEnvironment,
|
|
1550
|
-
personalInstructions: context.personalInstructions,
|
|
1551
|
-
...(context.usageGrant === undefined ? {} : { usageGrant: context.usageGrant }),
|
|
1552
|
-
executionContext: context.executionContext
|
|
1553
|
-
})));
|
|
1554
|
-
return { runId: result.run.id };
|
|
1555
|
-
},
|
|
1460
|
+
authorize: scheduledExecution.authorize,
|
|
1461
|
+
submit: scheduledExecution.submit,
|
|
1556
1462
|
sessionTitle: (sessionId) => {
|
|
1557
1463
|
const session = this.runtime.getAgentSession(sessionId);
|
|
1558
1464
|
return session?.customTitle ?? session?.runnerTitle ?? sessionId;
|
|
@@ -1562,6 +1468,8 @@ export class NodeConnector {
|
|
|
1562
1468
|
{}),
|
|
1563
1469
|
emitNotification: (payload) => this.emitWorkbenchEvent('conversation', payload)
|
|
1564
1470
|
});
|
|
1471
|
+
this.executionLifecycle = new ExecutionLifecycle(() => this.database !== undefined, this.scheduledSessions, this.continuousRunCoordinator, this.goalCoordinator, this.modelUsage, this.goalMcpBridge, this.scheduleMcpBridge, this.notificationMcpBridge, this.runEventBridge, this.upgradeCoordinator);
|
|
1472
|
+
// Register public operations only after domain workflows are connected.
|
|
1565
1473
|
this.runnerService = new RunnerService(requireDatabase, () => this.capabilities, this.runners, this.runnerUsageReader);
|
|
1566
1474
|
this.workbenchManifestService = new WorkbenchManifestService({
|
|
1567
1475
|
capabilities: () => this.capabilities,
|
|
@@ -1616,6 +1524,12 @@ export class NodeConnector {
|
|
|
1616
1524
|
readPage: (input, actor, signal) => completionWorkspace.readPage(input, actor, signal),
|
|
1617
1525
|
references: (workspaceId, _actor, signal) => completionWorkspace.references(workspaceId, signal)
|
|
1618
1526
|
});
|
|
1527
|
+
this.operationRouter.register('agent.network', agentNetworkExecutionCommand({
|
|
1528
|
+
runtime: this.runtime,
|
|
1529
|
+
coordinator: this.continuousRunCoordinator,
|
|
1530
|
+
service: this.agentNetworkService,
|
|
1531
|
+
observations: this.agentNetworkObservations
|
|
1532
|
+
}));
|
|
1619
1533
|
this.operationRouter.registerAll(this.promptCompletion.operations());
|
|
1620
1534
|
for (const operation of CONVERSATION_TEMPLATE_OPERATIONS)
|
|
1621
1535
|
this.operationRouter.register(operation, (data) => {
|
|
@@ -1704,8 +1618,35 @@ export class NodeConnector {
|
|
|
1704
1618
|
manifest: await this.workbenchManifestService.read(),
|
|
1705
1619
|
binaryTerminal: true
|
|
1706
1620
|
}));
|
|
1707
|
-
this.executionLifecycle = new ExecutionLifecycle(() => this.database !== undefined, this.scheduledSessions, this.continuousRunCoordinator, this.goalCoordinator, this.modelUsage, this.goalMcpBridge, this.scheduleMcpBridge, this.notificationMcpBridge, this.runEventBridge, this.upgradeCoordinator);
|
|
1708
1621
|
this.operationAdmission = new NodeOperationAdmission(() => this.stopped, () => this.database !== undefined, () => this.config?.nodeId, this.restartHandoff, this.upgradeCoordinator, this.gitOperationService, this.operationRouter);
|
|
1622
|
+
// Lifecycle is connected last; start() is the only resource activation boundary.
|
|
1623
|
+
this.lifecycle = new NodeLifecycle(() => this.startResources(), () => {
|
|
1624
|
+
this.continuousRunCoordinator.suspend();
|
|
1625
|
+
this.goalCoordinator.freeze();
|
|
1626
|
+
this.scheduledSessions.stop();
|
|
1627
|
+
void this.workspaceSessionService.stop();
|
|
1628
|
+
}, {
|
|
1629
|
+
waitForRecovery: () => this.restartHandoff.wait(),
|
|
1630
|
+
drainInput: async () => {
|
|
1631
|
+
this.sessionMessageService.setAccepting(false);
|
|
1632
|
+
await this.operationAdmission.drain();
|
|
1633
|
+
await this.sessionMessageService.drain();
|
|
1634
|
+
await this.workspaceSessionService.stop();
|
|
1635
|
+
},
|
|
1636
|
+
closeResume: () => this.externalSessionResumeService.close(),
|
|
1637
|
+
capture: () => {
|
|
1638
|
+
if (!this.config?.nodeId)
|
|
1639
|
+
return;
|
|
1640
|
+
return this.restartHandoff.capture();
|
|
1641
|
+
},
|
|
1642
|
+
dispose: () => this.disposeRuntime(),
|
|
1643
|
+
publish: (snapshot) => this.restartHandoff.publish(snapshot),
|
|
1644
|
+
diagnose: (stage, error) => nodeLog('node.shutdown.failed', {
|
|
1645
|
+
stage,
|
|
1646
|
+
errorCode: safeErrorCode(error, 'NODE_SHUTDOWN_FAILED'),
|
|
1647
|
+
...(stage === 'capture' ? plannedRestartCaptureDiagnostic(error) : undefined)
|
|
1648
|
+
})
|
|
1649
|
+
});
|
|
1709
1650
|
}
|
|
1710
1651
|
projectComputerUseCapability(capabilities) {
|
|
1711
1652
|
return {
|
|
@@ -1717,6 +1658,7 @@ export class NodeConnector {
|
|
|
1717
1658
|
return this.lifecycle.start();
|
|
1718
1659
|
}
|
|
1719
1660
|
async startResources() {
|
|
1661
|
+
this.workspaceSessionService.resume();
|
|
1720
1662
|
this.continuousRunCoordinator.resumeScheduling();
|
|
1721
1663
|
this.sessionMessageService.setAccepting(true);
|
|
1722
1664
|
this.config ??= await loadNodeConfig(this.configPath);
|
|
@@ -1820,6 +1762,8 @@ export class NodeConnector {
|
|
|
1820
1762
|
return this.lifecycle.stop(options.handoff === true);
|
|
1821
1763
|
}
|
|
1822
1764
|
disposeRuntime() {
|
|
1765
|
+
// Earlier shutdown stages may fail; disposal must still join internal reads before DB release.
|
|
1766
|
+
const workspaceSessionDrain = this.workspaceSessionService.stop();
|
|
1823
1767
|
this.recentRunProjectionService.dispose();
|
|
1824
1768
|
this.upgradeCoordinator.stop();
|
|
1825
1769
|
this.connectionLifecycle.stop();
|
|
@@ -1831,6 +1775,7 @@ export class NodeConnector {
|
|
|
1831
1775
|
this.gitOperationService.clear();
|
|
1832
1776
|
this.goalCoordinator.dispose();
|
|
1833
1777
|
this.runEventService.clear();
|
|
1778
|
+
this.agentNetworkProjection.dispose();
|
|
1834
1779
|
this.sessionContextService.dispose();
|
|
1835
1780
|
this.runAttachmentService.dispose();
|
|
1836
1781
|
this.modelResourcePublicationService.dispose();
|
|
@@ -1863,6 +1808,7 @@ export class NodeConnector {
|
|
|
1863
1808
|
this.controlChannel.stop();
|
|
1864
1809
|
const database = this.database;
|
|
1865
1810
|
const drains = Promise.allSettled([
|
|
1811
|
+
workspaceSessionDrain,
|
|
1866
1812
|
scheduledDrain,
|
|
1867
1813
|
marAgentDrain,
|
|
1868
1814
|
runnerDrain,
|
|
@@ -1909,7 +1855,7 @@ export class NodeConnector {
|
|
|
1909
1855
|
};
|
|
1910
1856
|
emitSessionWorkbenchEvent = (payload) => this.publishWorkspaceSession(payload);
|
|
1911
1857
|
emitWorkbenchEvent = (category, payload) => this.workbenchEventService.dispatch(category, payload);
|
|
1912
|
-
discoverWorkspaceSessions = (workspaceId, onRunnerDiscovered) => this.nativeSessionProjectionService.discoverWorkspace(workspaceId, onRunnerDiscovered);
|
|
1858
|
+
discoverWorkspaceSessions = (workspaceId, onRunnerDiscovered, signal) => this.nativeSessionProjectionService.discoverWorkspace(workspaceId, onRunnerDiscovered, false, signal);
|
|
1913
1859
|
invalidateWorkspaceWatchTopics = (workspaceId) => this.workspaceCoordinator.invalidate(workspaceId);
|
|
1914
1860
|
startCapabilityRefresh = () => this.connectionLifecycle.startCapabilityRefresh();
|
|
1915
1861
|
refreshCapabilities = () => this.connectionLifecycle.refreshCapabilities();
|
package/dist/marctl/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"0.12.
|
|
1
|
+
{"type":"module","version":"0.12.6"}
|
|
@@ -124,16 +124,20 @@ export class ClaudeCodeRunner extends AbstractRunner {
|
|
|
124
124
|
async discoverSessions(context, workspace) {
|
|
125
125
|
const sessions = [];
|
|
126
126
|
for (const target of workspace === undefined ? context.workspaces : [workspace]) {
|
|
127
|
+
context.signal?.throwIfAborted();
|
|
127
128
|
let official = [];
|
|
128
129
|
try {
|
|
129
130
|
official = await this.listSessions(target.path);
|
|
130
131
|
}
|
|
131
132
|
catch (error) {
|
|
133
|
+
context.signal?.throwIfAborted();
|
|
132
134
|
if (context.cleanup)
|
|
133
135
|
throw error;
|
|
134
136
|
// Native transcripts remain authoritative when SDK listing is unavailable.
|
|
135
137
|
}
|
|
138
|
+
context.signal?.throwIfAborted();
|
|
136
139
|
const native = await discoverNativeSessions(this.name, target.path);
|
|
140
|
+
context.signal?.throwIfAborted();
|
|
137
141
|
sessions.push(...this.projectDiscoveredSessions(context, target, [
|
|
138
142
|
...official.flatMap((value) => {
|
|
139
143
|
const parsed = claudeDiscoveredSession(value, target.path);
|