@myagentroam/node 0.11.35 → 0.11.37
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/execution-lifecycle.js +54 -0
- package/dist/application/node-lifecycle.js +104 -0
- package/dist/application/node-operation-admission.js +51 -0
- package/dist/application/node-operation-contracts.js +1 -0
- package/dist/application/runner-composition.js +22 -0
- package/dist/application/session-projection-composition.js +26 -0
- package/dist/application/workspace-application.js +61 -0
- package/dist/application/workspace-composition.js +21 -0
- package/dist/capabilities.js +2 -2
- package/dist/codex-app-server.js +1 -471
- package/dist/connection/authorization.js +26 -0
- package/dist/{service → connection}/direct-transfer-service.js +1 -1
- package/dist/connection/endpoints.js +32 -0
- package/dist/connector.js +144 -252
- package/dist/database.js +34 -14
- package/dist/git-askpass.js +1 -1
- package/dist/git-execution-helper.js +1 -1
- package/dist/hosting/hosted-conversation-file-identity.js +27 -0
- package/dist/hosting/hosted-conversation-file-operations.js +44 -0
- package/dist/hosting/hosted-conversation-node-service.js +974 -0
- package/dist/hosting/hosted-conversation-runs.js +599 -0
- package/dist/hosting/hosted-conversation-templates.js +280 -0
- package/dist/hosting/hosted-conversation-uploads.js +344 -0
- package/dist/hosting/hosted-conversation-watch.js +194 -0
- package/dist/hosting/runtime-contracts.js +1 -0
- package/dist/marctl-guidance.js +1 -1
- package/dist/runner/abstract-runner.js +4 -13
- package/dist/{claude-agent-sdk.js → runner/claude/claude-agent-sdk.js} +2 -2
- package/dist/runner/claude/conversation-parser.js +2 -1
- package/dist/runner/claude/managed-run-controller.js +6 -7
- package/dist/runner/claude/message-parsers.js +2 -1
- package/dist/runner/claude/native-transcript.js +2 -1
- package/dist/runner/claude/tool-normalizer.js +1 -1
- package/dist/runner/claude-code-runner.js +2 -2
- package/dist/runner/codex/codex-app-server.js +471 -0
- package/dist/runner/codex/conversation-parser.js +4 -2
- package/dist/runner/codex/managed-run-controller.js +7 -9
- package/dist/runner/codex/native-transcript.js +1 -1
- package/dist/runner/codex/tool-normalizer.js +1 -1
- package/dist/runner/codex-runner.js +9 -27
- package/dist/runner/contracts.js +1 -0
- package/dist/runner/mar-agent/conversation-normalizer.js +2 -2
- package/dist/runner/mar-agent/history-projection.js +1 -1
- package/dist/runner/mar-agent/hosted-conversation-runtime.js +6 -10
- package/dist/runner/mar-agent/managed-run-controller.js +85 -61
- package/dist/runner/mar-agent-runner.js +1 -1
- package/dist/runner/normalization.js +42 -0
- package/dist/runner/opencode/conversation-parser.js +1 -1
- package/dist/runner/opencode/managed-run-controller.js +6 -7
- package/dist/{opencode-server.js → runner/opencode/opencode-server.js} +2 -2
- package/dist/runner/opencode/tool-normalizer.js +1 -1
- package/dist/runner/opencode-runner.js +4 -5
- package/dist/runner/runner-registry.js +4 -1
- package/dist/runtime-state.js +48 -372
- package/dist/service/computer-use-enablement-service.js +1 -1
- package/dist/service/continuous-run-coordinator.js +52 -7
- package/dist/service/conversation-history-service.js +4 -4
- package/dist/service/conversation-hosting-capability-service.js +1 -1
- package/dist/service/conversation-hosting-enablement-service.js +1 -1
- package/dist/service/conversation-hosting-lifecycle-service.js +3 -3
- package/dist/service/conversation-hosting-maintenance-service.js +1 -1
- package/dist/service/conversation-observation.js +1 -1
- package/dist/service/conversation-segment-service.js +1 -1
- package/dist/service/external-session-resume-service.js +47 -27
- package/dist/service/fake-managed-run-service.js +3 -7
- package/dist/service/git-operation-service.js +1 -1
- package/dist/service/goal-continuation-coordinator.js +14 -7
- package/dist/service/mar-agent-model-transport-test-service.js +1 -1
- package/dist/service/native-session-watch-service.js +1 -1
- package/dist/service/node-control-channel.js +1 -5
- package/dist/service/node-request-service.js +1 -1
- package/dist/service/node-terminal-channel.js +2 -1
- package/dist/service/node-workspace-coordinator.js +3 -2
- package/dist/service/notification-mcp-bridge.js +6 -2
- package/dist/service/recent-run-projection-service.js +1 -1
- package/dist/service/restart-session-restorer.js +1 -1
- package/dist/service/run-event-service.js +49 -42
- package/dist/service/run-workbench-service.js +3 -3
- package/dist/service/runner-interaction-service.js +6 -5
- package/dist/service/runner-service.js +1 -1
- package/dist/service/session-recent-activity.js +2 -1
- package/dist/service/skill-directory-service.js +1 -1
- package/dist/service/skill-install-service.js +2 -2
- package/dist/service/terminal-service.js +1 -1
- package/dist/service/workbench-event-projection.js +3 -2
- package/dist/service/workbench-event-service.js +1 -1
- package/dist/service/workspace-service.js +3 -2
- package/dist/session/attachments.js +110 -0
- package/dist/session/contracts.js +1 -0
- package/dist/{util → session}/conversation-identity.js +1 -1
- package/dist/session/input-validation.js +15 -0
- package/dist/{service → session}/native-session-projection-service.js +40 -11
- package/dist/session/pagination.js +77 -0
- package/dist/{util → session}/runner-native-session-parsers.js +2 -1
- package/dist/session/runtime/approvals.js +90 -0
- package/dist/session/runtime/conversation-projection.js +310 -0
- package/dist/session/runtime/type-guards.js +19 -0
- package/dist/{service → session}/session-catalog-service.js +5 -4
- package/dist/{service → session}/session-command-service.js +3 -3
- package/dist/{service → session}/session-identity-service.js +1 -1
- package/dist/{service → session}/session-lifecycle-service.js +18 -7
- package/dist/{service → session}/session-message-service.js +6 -5
- package/dist/{service → session}/session-presentation-service.js +1 -1
- package/dist/{service → session}/session-query-service.js +2 -2
- package/dist/{service → session}/session-schedule-service.js +2 -2
- package/dist/util/records.js +3 -0
- package/dist/workspace/contracts.js +1 -0
- package/dist/workspace/file-index.js +534 -0
- package/dist/workspace/files.js +466 -0
- package/dist/workspace/git.js +991 -0
- package/dist/workspace/path-access.js +184 -0
- package/dist/workspace/utf8.js +12 -0
- package/dist/{service → workspace}/workspace-change-service.js +45 -21
- package/dist/{service → workspace}/workspace-code-navigation-service.js +6 -6
- package/dist/{service → workspace}/workspace-file-manager-service.js +1 -1
- package/dist/{service → workspace}/workspace-file-service.js +16 -16
- package/dist/{service → workspace}/workspace-git-exclude-service.js +1 -1
- package/dist/{service → workspace}/workspace-queue-workbench-service.js +3 -2
- package/dist/{service → workspace}/workspace-session-service.js +45 -40
- package/dist/{service → workspace}/workspace-upload-service.js +28 -28
- package/dist/{service → workspace}/workspace-watch-service.js +29 -28
- package/dist/{service → workspace}/workspace-workbench-service.js +4 -3
- package/package.json +4 -4
- package/dist/service/hosted-conversation-node-service.js +0 -2252
- package/dist/service/run-domain-state.js +0 -4
- package/dist/service/session-domain-state.js +0 -9
- package/dist/service/workspace-domain-state.js +0 -41
- package/dist/util/node-operation-parsers.js +0 -320
- package/dist/workspace.js +0 -2168
- /package/dist/{connector → application}/node-connector-options.js +0 -0
- /package/dist/{util → connection}/node-operation-data.js +0 -0
- /package/dist/{connector → connection}/node-operation-router.js +0 -0
- /package/dist/{service → hosting}/hosted-conversation-sandbox-profile.js +0 -0
- /package/dist/{service → hosting}/hosted-conversation-store.js +0 -0
- /package/dist/{util → mcp}/secret-environment.js +0 -0
- /package/dist/{claude-channel.js → runner/claude/claude-channel.js} +0 -0
- /package/dist/{util → runner}/personal-instructions.js +0 -0
- /package/dist/{util → runner}/runner-error.js +0 -0
- /package/dist/{service/conversation-work-process.js → session/runtime/work-process.js} +0 -0
- /package/dist/{service → session}/session-context-service.js +0 -0
- /package/dist/{util → workspace}/git-credential-client.js +0 -0
- /package/dist/{service → workspace}/workspace-content-search-service.js +0 -0
- /package/dist/{service → workspace}/workspace-watch-snapshot-service.js +0 -0
package/dist/connector.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { composeWorkspaceApplication } from './application/workspace-application.js';
|
|
2
|
+
import { composeSessionProjection } from './application/session-projection-composition.js';
|
|
3
|
+
import { composeWorkspaceResources } from './application/workspace-composition.js';
|
|
4
|
+
import { composeRunners } from './application/runner-composition.js';
|
|
5
|
+
import { ExecutionLifecycle } from './application/execution-lifecycle.js';
|
|
6
|
+
import { NodeOperationAdmission } from './application/node-operation-admission.js';
|
|
1
7
|
import { normalizeMarAgentUsage } from './runner/mar-agent/conversation-normalizer.js';
|
|
2
|
-
import {
|
|
8
|
+
import { NodeLifecycle } from './application/node-lifecycle.js';
|
|
9
|
+
import { isImageAttachment } from './session/attachments.js';
|
|
3
10
|
import { ModelUsageOutbox } from './service/model-usage-outbox.js';
|
|
4
11
|
import { NodeModelUsageService } from './service/model-usage-service.js';
|
|
5
12
|
import { dirname, resolve } from 'node:path';
|
|
@@ -7,7 +14,7 @@ import { createEnvelope, directNodeCommandSchema } from '@myagentroam/protocol';
|
|
|
7
14
|
import { loadNodeConfig, computerUseRuntimeExecutable, directTransferUdpPortRange, nodeDataDirectory, nodeDatabasePath } from './config.js';
|
|
8
15
|
import { NodeMetrics, nodeLog } from './operational.js';
|
|
9
16
|
import { assertLocalSqlitePath } from './storage.js';
|
|
10
|
-
import { resolveWorkspaceExecutionDirectory } from './workspace.js';
|
|
17
|
+
import { resolveWorkspaceExecutionDirectory } from './workspace/path-access.js';
|
|
11
18
|
import { detectCapabilitiesAsync, unavailableCapabilities } from './capabilities.js';
|
|
12
19
|
import { NodeDatabase } from './database.js';
|
|
13
20
|
import { TerminalManager } from './terminal.js';
|
|
@@ -17,59 +24,43 @@ import { GoalRuntime } from './service/goal-runtime.js';
|
|
|
17
24
|
import { GoalContinuationCoordinator } from './service/goal-continuation-coordinator.js';
|
|
18
25
|
import { GoalMcpBridge } from './service/goal-mcp-bridge.js';
|
|
19
26
|
import { RunnerUsageReader } from './runner-usage.js';
|
|
20
|
-
import { ClaudeCodeRunner } from './runner/claude-code-runner.js';
|
|
21
27
|
import { ClaudeManagedRunController } from './runner/claude/managed-run-controller.js';
|
|
22
|
-
import { CodexRunner } from './runner/codex-runner.js';
|
|
23
28
|
import { CodexManagedRunController } from './runner/codex/managed-run-controller.js';
|
|
24
|
-
import { FakeTestRunner } from './runner/fake-test-runner.js';
|
|
25
|
-
import { RunnerRegistry } from './runner/runner-registry.js';
|
|
26
|
-
import { OpenCodeRunner } from './runner/opencode-runner.js';
|
|
27
|
-
import { MarAgentRunner } from './runner/mar-agent-runner.js';
|
|
28
29
|
import { MarAgentManagedRunController } from './runner/mar-agent/managed-run-controller.js';
|
|
29
30
|
import { PyAutoGuiComputerUseProvider } from './runner/mar-agent/computer-use.js';
|
|
30
31
|
import { ManagedComputerUseRuntime } from './computer-use-runtime.js';
|
|
31
32
|
import { OpenCodeManagedRunController } from './runner/opencode/managed-run-controller.js';
|
|
32
|
-
import { NodeOperationRouter } from './
|
|
33
|
+
import { NodeOperationRouter } from './connection/node-operation-router.js';
|
|
33
34
|
import { SkillNodeOperationService } from './service/skill-node-operation-service.js';
|
|
34
35
|
import { McpNodeOperationService } from './service/mcp-node-operation-service.js';
|
|
35
36
|
import { RunnerService } from './service/runner-service.js';
|
|
36
37
|
import { TerminalService } from './service/terminal-service.js';
|
|
37
38
|
import { GitExecutionService } from './service/git-execution-service.js';
|
|
38
39
|
import { GitOperationService } from './service/git-operation-service.js';
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import { WorkspaceFileService } from './service/workspace-file-service.js';
|
|
42
|
-
import { WorkspaceUploadService } from './service/workspace-upload-service.js';
|
|
43
|
-
import { DirectTransferService } from './service/direct-transfer-service.js';
|
|
44
|
-
import { WorkspaceChangeService } from './service/workspace-change-service.js';
|
|
45
|
-
import { WorkspaceSessionService } from './service/workspace-session-service.js';
|
|
40
|
+
import { DirectTransferService } from './connection/direct-transfer-service.js';
|
|
41
|
+
import { WorkspaceChangeService } from './workspace/workspace-change-service.js';
|
|
46
42
|
import { WorkbenchEventService } from './service/workbench-event-service.js';
|
|
47
|
-
import { RunDomainState } from './service/run-domain-state.js';
|
|
48
43
|
import { RecentRunProjectionService } from './service/recent-run-projection-service.js';
|
|
49
44
|
import { sessionGroupChangedSchema } from '@myagentroam/protocol';
|
|
50
|
-
import { SessionDomainState } from './service/session-domain-state.js';
|
|
51
45
|
import { RunEventService } from './service/run-event-service.js';
|
|
52
46
|
import { RunAttachmentService } from './service/run-attachment-service.js';
|
|
53
47
|
import { NodeTerminalChannel } from './service/node-terminal-channel.js';
|
|
54
|
-
import { WorkspaceWorkbenchService } from './service/workspace-workbench-service.js';
|
|
55
48
|
import { NativeSessionWatchService } from './service/native-session-watch-service.js';
|
|
56
49
|
import { SessionWatchSlotCoordinator } from './service/session-watch-slot-coordinator.js';
|
|
57
|
-
import { SessionContextService } from './
|
|
58
|
-
import { WorkspaceDomainState } from './service/workspace-domain-state.js';
|
|
50
|
+
import { SessionContextService } from './session/session-context-service.js';
|
|
59
51
|
import { RunWorkbenchService } from './service/run-workbench-service.js';
|
|
60
|
-
import { SessionQueryService } from './
|
|
52
|
+
import { SessionQueryService } from './session/session-query-service.js';
|
|
61
53
|
import { marctlSessionProgress } from './service/session-recent-activity.js';
|
|
62
|
-
import { WorkspaceQueueWorkbenchService } from './
|
|
54
|
+
import { WorkspaceQueueWorkbenchService } from './workspace/workspace-queue-workbench-service.js';
|
|
63
55
|
import { ContinuousRunCoordinator } from './service/continuous-run-coordinator.js';
|
|
64
|
-
import { SessionIdentityService } from './
|
|
65
|
-
import { NativeSessionProjectionService } from './service/native-session-projection-service.js';
|
|
56
|
+
import { SessionIdentityService } from './session/session-identity-service.js';
|
|
66
57
|
import { ConversationHistoryService, hasManagedActiveRun } from './service/conversation-history-service.js';
|
|
67
58
|
import { ConversationSegmentService } from './service/conversation-segment-service.js';
|
|
68
59
|
import { RunnerInteractionService } from './service/runner-interaction-service.js';
|
|
69
|
-
import { SessionLifecycleService } from './
|
|
60
|
+
import { SessionLifecycleService } from './session/session-lifecycle-service.js';
|
|
70
61
|
import { ExternalSessionResumeService } from './service/external-session-resume-service.js';
|
|
71
|
-
import { SessionMessageService } from './
|
|
72
|
-
import { SessionScheduleService } from './
|
|
62
|
+
import { SessionMessageService } from './session/session-message-service.js';
|
|
63
|
+
import { SessionScheduleService } from './session/session-schedule-service.js';
|
|
73
64
|
import { ScheduledSessionCoordinator } from './service/scheduled-session-coordinator.js';
|
|
74
65
|
import { ScheduledSessionStore } from './service/scheduled-session-store.js';
|
|
75
66
|
import { RunAuthorizationControl } from './service/run-authorization-control.js';
|
|
@@ -78,20 +69,20 @@ import { RestartSessionRestorer } from './service/restart-session-restorer.js';
|
|
|
78
69
|
import { ScheduleMcpBridge } from './service/schedule-mcp-bridge.js';
|
|
79
70
|
import { MailNotificationControl } from './service/mail-notification-control.js';
|
|
80
71
|
import { NotificationMcpBridge, resolveNotificationCapability } from './service/notification-mcp-bridge.js';
|
|
81
|
-
import { SessionCatalogService } from './
|
|
82
|
-
import { SessionCommandService } from './
|
|
83
|
-
import {
|
|
84
|
-
import { isPlainRecord
|
|
72
|
+
import { SessionCatalogService } from './session/session-catalog-service.js';
|
|
73
|
+
import { SessionCommandService } from './session/session-command-service.js';
|
|
74
|
+
import { sessionGroup } from './session/session-presentation-service.js';
|
|
75
|
+
import { isPlainRecord } from './util/records.js';
|
|
76
|
+
import { isRunnerImageAttachment, parseRunnerImageAttachments } from './session/attachments.js';
|
|
85
77
|
import { WebToolService } from './service/web-tool-service.js';
|
|
86
78
|
import { ModelResourcePublicationService } from './service/model-resource-publication-service.js';
|
|
87
|
-
export { nodeConnectEndpoint, validatedCapabilities } from './
|
|
79
|
+
export { nodeConnectEndpoint, validatedCapabilities } from './connection/endpoints.js';
|
|
88
80
|
import { NodeControlChannel } from './service/node-control-channel.js';
|
|
89
81
|
import { NodeControlMessageService } from './service/node-control-message-service.js';
|
|
90
82
|
import { NodeRequestService } from './service/node-request-service.js';
|
|
91
83
|
import { WorkbenchManifestService } from './service/workbench-manifest-service.js';
|
|
92
84
|
import { NodeRunEventBridge } from './service/node-run-event-bridge.js';
|
|
93
85
|
import { workbenchPayloadSessionId } from './service/workbench-event-projection.js';
|
|
94
|
-
import { NodeWorkspaceCoordinator } from './service/node-workspace-coordinator.js';
|
|
95
86
|
import { FakeManagedRunService } from './service/fake-managed-run-service.js';
|
|
96
87
|
import { RunnerChannelMessageService } from './service/runner-channel-message-service.js';
|
|
97
88
|
import { ManagedRunnerSessionService } from './service/managed-runner-session-service.js';
|
|
@@ -175,7 +166,8 @@ export class NodeConnector {
|
|
|
175
166
|
scheduledRunAuthorization;
|
|
176
167
|
restartAuthorization;
|
|
177
168
|
restartHandoff;
|
|
178
|
-
|
|
169
|
+
operationAdmission;
|
|
170
|
+
executionLifecycle;
|
|
179
171
|
pendingSessionGroups = new Map();
|
|
180
172
|
mailNotificationControl = new MailNotificationControl((envelope) => this.sendEnvelope(envelope));
|
|
181
173
|
scheduledSessions;
|
|
@@ -194,12 +186,25 @@ export class NodeConnector {
|
|
|
194
186
|
throw new Error('NODE_CONFIG_UNAVAILABLE');
|
|
195
187
|
return nodeDataDirectory(this.config, this.configPath);
|
|
196
188
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
this.
|
|
189
|
+
lifecycle = new NodeLifecycle(() => this.startResources(), () => {
|
|
190
|
+
this.continuousRunCoordinator.suspend();
|
|
191
|
+
this.goalCoordinator.freeze();
|
|
192
|
+
this.scheduledSessions.stop();
|
|
193
|
+
}, {
|
|
194
|
+
waitForRecovery: () => this.restartHandoff.wait(),
|
|
195
|
+
drainInput: async () => {
|
|
196
|
+
this.sessionMessageService.setAccepting(false);
|
|
197
|
+
await this.operationAdmission.drain();
|
|
198
|
+
await this.sessionMessageService.drain();
|
|
199
|
+
},
|
|
200
|
+
closeResume: () => this.externalSessionResumeService.close(),
|
|
201
|
+
capture: () => (this.config?.nodeId ? this.restartHandoff.capture() : undefined),
|
|
202
|
+
dispose: () => this.disposeRuntime(),
|
|
203
|
+
publish: (snapshot) => this.restartHandoff.publish(snapshot)
|
|
204
|
+
});
|
|
205
|
+
get stopped() {
|
|
206
|
+
return this.lifecycle.stopped;
|
|
200
207
|
}
|
|
201
|
-
stopped = false;
|
|
202
|
-
stopping;
|
|
203
208
|
config;
|
|
204
209
|
capabilitiesProvided;
|
|
205
210
|
capabilities;
|
|
@@ -224,10 +229,8 @@ export class NodeConnector {
|
|
|
224
229
|
});
|
|
225
230
|
fakeRunner;
|
|
226
231
|
fakeScript;
|
|
227
|
-
runState = new RunDomainState();
|
|
228
232
|
runEventBridge;
|
|
229
233
|
workspaceCoordinator;
|
|
230
|
-
sessionState = new SessionDomainState();
|
|
231
234
|
sessionIdentityService;
|
|
232
235
|
nativeSessionProjectionService;
|
|
233
236
|
conversationHistoryService;
|
|
@@ -311,30 +314,33 @@ export class NodeConnector {
|
|
|
311
314
|
runnerUsageReader;
|
|
312
315
|
terminalManager;
|
|
313
316
|
upgradeCoordinator;
|
|
314
|
-
|
|
315
|
-
workspaceWatchService = new WorkspaceWatchService(this.workspaceState, (workspaceId) => this.workspaceSessionService.ensureWatch(workspaceId), (workspaceId) => this.workspaceSessionService.stopWatch(workspaceId), (workspaceId) => this.workspaceWorkbenchService?.releaseWorkspace(workspaceId), (watch) => this.workspaceWorkbenchService?.cancelFilePrewarm(watch));
|
|
316
|
-
workspaceSessionService = new WorkspaceSessionService(this.workspaceState, {
|
|
317
|
+
workspaceResources = composeWorkspaceResources({
|
|
317
318
|
discover: (workspaceId, onRunnerDiscovered) => this.discoverWorkspaceSessions(workspaceId, onRunnerDiscovered),
|
|
318
319
|
listPage: (workspaceId) => this.executeNodeOperation('session.list', { workspaceId, limit: 30 }),
|
|
319
|
-
|
|
320
|
-
|
|
320
|
+
invalidateSessions: (workspaceId) => void this.workspaceWorkbenchService?.invalidateTopic(workspaceId, 'sessions'),
|
|
321
|
+
invalidateFiles: (workspaceId) => {
|
|
322
|
+
this.workspaceWorkbenchService?.invalidateWorkspaceFiles(workspaceId);
|
|
323
|
+
this.workspaceCoordinator.invalidate(workspaceId);
|
|
324
|
+
},
|
|
325
|
+
releaseWatch: (workspaceId) => this.workspaceWorkbenchService?.releaseWorkspace(workspaceId),
|
|
326
|
+
removeWatch: (watch) => this.workspaceWorkbenchService?.cancelFilePrewarm(watch),
|
|
327
|
+
temporaryRoot: () => this.attachmentTemporaryRoot(),
|
|
328
|
+
attachmentResource: (id, path) => this.runAttachmentService.fileResource(id, path)
|
|
321
329
|
});
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
workspaceFileService = new WorkspaceFileService(this.workspaceState, this.invalidateWorkspaceFiles, {}, (workspaceId, resourcePath) => this.workspaceUploadService.fileResource(workspaceId, resourcePath) ??
|
|
328
|
-
this.runAttachmentService.fileResource(workspaceId, resourcePath));
|
|
329
|
-
workspaceUploadService = new WorkspaceUploadService(this.workspaceState, this.invalidateWorkspaceFiles, () => this.attachmentTemporaryRoot());
|
|
330
|
+
workspaceWatchService = this.workspaceResources.watch;
|
|
331
|
+
workspaceSessionService = this.workspaceResources.sessions;
|
|
332
|
+
workspaceFileService = this.workspaceResources.files;
|
|
333
|
+
workspaceUploadService = this.workspaceResources.uploads;
|
|
334
|
+
invalidateWorkspaceFiles = this.workspaceResources.invalidateFiles;
|
|
330
335
|
directTransferService;
|
|
331
336
|
attachmentTemporaryRoot() {
|
|
332
337
|
if (this.config === undefined)
|
|
333
338
|
throw new Error('NODE_CONFIG_UNAVAILABLE');
|
|
334
339
|
return resolve(nodeDataDirectory(this.config, this.configPath), 'temp-files');
|
|
335
340
|
}
|
|
336
|
-
workspaceChangeService = new WorkspaceChangeService(
|
|
341
|
+
workspaceChangeService = new WorkspaceChangeService();
|
|
337
342
|
workspaceWorkbenchService;
|
|
343
|
+
publishWorkspaceSession;
|
|
338
344
|
database;
|
|
339
345
|
recentRunProjectionService = new RecentRunProjectionService((message) => this.send('recent-runs', message));
|
|
340
346
|
/** Runtime/session state is intentionally not persisted to Node SQLite. */
|
|
@@ -355,53 +361,23 @@ export class NodeConnector {
|
|
|
355
361
|
runEventService = new RunEventService({
|
|
356
362
|
runtime: this.runtime,
|
|
357
363
|
metrics: this.metrics,
|
|
358
|
-
state: this.runState,
|
|
359
364
|
isBootstrapSession: (sessionId) => this.sessionIdentityService.bootstrapIds.has(sessionId),
|
|
360
365
|
presentSession: (session) => this.sessionPresentationService.present(session),
|
|
361
366
|
rejectBootstrap: (sessionId, code) => this.sessionIdentityService.reject(sessionId, code),
|
|
362
|
-
emitWorkbench: (category, payload) =>
|
|
363
|
-
if (category === 'conversation' && isPlainRecord(payload) && 'turn' in payload)
|
|
364
|
-
this.emitConversationTurn(payload.turn);
|
|
365
|
-
else
|
|
366
|
-
this.publishWorkbenchEvent(category, payload);
|
|
367
|
-
},
|
|
367
|
+
emitWorkbench: (category, payload) => this.publishWorkbenchEvent(category, payload),
|
|
368
368
|
cleanupAttachments: (runId) => this.runAttachmentService.cleanup(runId),
|
|
369
369
|
refreshAttachments: (sessionId) => this.runAttachmentService.refreshSession(sessionId),
|
|
370
370
|
expireImages: (runId) => this.runAttachmentService.expire(runId),
|
|
371
371
|
scheduleContextRefresh: (sessionId) => this.sessionContextService.schedule(sessionId),
|
|
372
372
|
refreshWorkspaceSessions: (workspaceId) => this.workspaceWorkbenchService.ensureTopicSnapshot(workspaceId, 'sessions'),
|
|
373
|
-
onTerminalRun: (run, status) =>
|
|
374
|
-
|
|
375
|
-
this.scheduledSessions.executionTerminated(run, status);
|
|
376
|
-
this.continuousRunCoordinator.runTerminated(run.sessionId);
|
|
377
|
-
},
|
|
378
|
-
dispatchQueue: async (sessionId, delayMs = 0) => {
|
|
379
|
-
if (this.upgradeCoordinator.pending())
|
|
380
|
-
return;
|
|
381
|
-
if (delayMs > 0) {
|
|
382
|
-
this.continuousRunCoordinator.schedule(sessionId, delayMs);
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
await this.continuousRunCoordinator.dispatch(sessionId);
|
|
386
|
-
},
|
|
373
|
+
onTerminalRun: (run, status) => this.executionLifecycle.terminal(run, status),
|
|
374
|
+
dispatchQueue: (sessionId, delayMs) => this.executionLifecycle.dispatchQueue(sessionId, delayMs),
|
|
387
375
|
executionStarted: (executionId) => this.continuousRunCoordinator.executionStarted(executionId),
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
},
|
|
393
|
-
releaseExecution: (executionId) => {
|
|
394
|
-
this.modelUsage.release(executionId);
|
|
395
|
-
this.goalCoordinator.releaseExecution(executionId);
|
|
396
|
-
this.revokeExecutionMcps(executionId);
|
|
397
|
-
this.continuousRunCoordinator.remove(executionId);
|
|
398
|
-
}
|
|
376
|
+
acceptExecutionTerminal: (input) => this.continuousRunCoordinator.acceptExecutionTerminal(input),
|
|
377
|
+
publishGoalUpdate: ({ session, goal }) => this.goalCoordinator.publishGoalState(session, goal),
|
|
378
|
+
publishQueueChange: (sessionId) => this.continuousRunCoordinator.publish(sessionId),
|
|
379
|
+
releaseExecution: (executionId) => this.executionLifecycle.release(executionId)
|
|
399
380
|
});
|
|
400
|
-
revokeExecutionMcps(executionId) {
|
|
401
|
-
this.goalMcpBridge.revoke(executionId);
|
|
402
|
-
this.scheduleMcpBridge.revoke(executionId);
|
|
403
|
-
this.notificationMcpBridge.revoke(executionId);
|
|
404
|
-
}
|
|
405
381
|
sessionWatchSlots = new SessionWatchSlotCoordinator();
|
|
406
382
|
nativeSessionWatchService = new NativeSessionWatchService({
|
|
407
383
|
resolve: async (sessionId) => this.runtime.getAgentSession(sessionId) ??
|
|
@@ -483,7 +459,7 @@ export class NodeConnector {
|
|
|
483
459
|
if (this.config === undefined)
|
|
484
460
|
throw new Error('NODE_CONFIG_UNAVAILABLE');
|
|
485
461
|
return nodeUpgradeRequestPath(nodeDatabasePath(this.config, this.configPath));
|
|
486
|
-
}, () => this.
|
|
462
|
+
}, () => this.runtime.activeExecutionCount(), (status) => {
|
|
487
463
|
this.capabilities = {
|
|
488
464
|
...this.capabilities,
|
|
489
465
|
metadata: upgradeMetadata(this.capabilities.metadata, status)
|
|
@@ -506,8 +482,8 @@ export class NodeConnector {
|
|
|
506
482
|
}));
|
|
507
483
|
};
|
|
508
484
|
this.reconnect = options.reconnect ?? true;
|
|
509
|
-
|
|
510
|
-
|
|
485
|
+
const composedRunners = composeRunners(options);
|
|
486
|
+
this.fakeRunner = composedRunners.fake;
|
|
511
487
|
this.fakeScript = options.fakeScript;
|
|
512
488
|
this.runAttachmentService = new RunAttachmentService((session) => this.runners.require(session.runner).nativeImageRoots(session), (sessionId) => this.runtime.activeSessionRun(sessionId) !== undefined ||
|
|
513
489
|
this.runtime.sessionQueue(sessionId).itemIds.length > 0, () => this.attachmentTemporaryRoot());
|
|
@@ -525,18 +501,17 @@ export class NodeConnector {
|
|
|
525
501
|
return url.protocol === 'http:' || url.protocol === 'https:' ? url.origin : undefined;
|
|
526
502
|
}
|
|
527
503
|
});
|
|
528
|
-
this.codexClient =
|
|
504
|
+
this.codexClient = composedRunners.codex;
|
|
529
505
|
this.codexRunController = new CodexManagedRunController(this.codexClient, {
|
|
530
506
|
available: () => this.capabilities.codex.available,
|
|
531
507
|
intercepted: () => this.fakeRunner !== undefined,
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
removeActive: (runId) => this.runState.active.delete(runId),
|
|
508
|
+
isExecutionActive: (runId) => this.runtime.isExecutionActive(runId),
|
|
509
|
+
executionAccepted: (runId) => this.runtime.executionAccepted(runId),
|
|
535
510
|
adopt: (input) => this.runtime.adoptRun(input),
|
|
536
511
|
session: (sessionId) => this.runtime.getAgentSession(sessionId),
|
|
537
512
|
runStatus: (runId) => this.runtime.getRun(runId)?.status,
|
|
538
513
|
run: (runId) => this.runtime.getRun(runId),
|
|
539
|
-
interrupted: (runId) => this.
|
|
514
|
+
interrupted: (runId) => this.runtime.isExecutionInterruptRequested(runId),
|
|
540
515
|
parseAttachments: parseRunnerImageAttachments,
|
|
541
516
|
materialize: (runId, attachments) => this.runAttachmentService.materializeCodex(runId, attachments),
|
|
542
517
|
completeCancelled: (runId) => this.runnerInteractionService.completeCancelledRun(runId),
|
|
@@ -562,9 +537,9 @@ export class NodeConnector {
|
|
|
562
537
|
})
|
|
563
538
|
});
|
|
564
539
|
this.codexClient.onNotification((notification) => this.codexRunController.handleNotification(notification));
|
|
565
|
-
this.claudeClient =
|
|
566
|
-
this.openCodeClient =
|
|
567
|
-
this.marAgentClient =
|
|
540
|
+
this.claudeClient = composedRunners.claude;
|
|
541
|
+
this.openCodeClient = composedRunners.openCode;
|
|
542
|
+
this.marAgentClient = composedRunners.marAgent;
|
|
568
543
|
this.marAgentClient.setGeneratedImageRegistrar((session, images) => this.runAttachmentService.registerNative(session, images));
|
|
569
544
|
this.computerUseProvider = new PyAutoGuiComputerUseProvider(() => {
|
|
570
545
|
if (this.config?.computerUse?.enabled !== true)
|
|
@@ -588,7 +563,8 @@ export class NodeConnector {
|
|
|
588
563
|
this.marAgentRunController = new MarAgentManagedRunController(this.marAgentClient, {
|
|
589
564
|
createApproval: (input) => this.runtime.createApproval(input),
|
|
590
565
|
publishApproval: (input) => this.runnerInteractionService.publishApproval(input),
|
|
591
|
-
|
|
566
|
+
isExecutionActive: (runId) => this.runtime.isExecutionActive(runId),
|
|
567
|
+
executionAccepted: (runId) => this.runtime.executionAccepted(runId),
|
|
592
568
|
adopt: (input) => this.runtime.adoptRun(input),
|
|
593
569
|
promote: (sessionId, nativeSessionId) => this.sessionIdentityService.promote(sessionId, nativeSessionId),
|
|
594
570
|
customTitle: (sessionId) => this.runtime.getAgentSession(sessionId)?.customTitle,
|
|
@@ -632,7 +608,8 @@ export class NodeConnector {
|
|
|
632
608
|
this.marAgentClient.setSessionResourceReleaser((sessionId) => this.marAgentRunController.releaseSession(sessionId));
|
|
633
609
|
this.openCodeRunController = new OpenCodeManagedRunController(this.openCodeClient, {
|
|
634
610
|
intercepted: () => this.fakeRunner !== undefined,
|
|
635
|
-
|
|
611
|
+
isExecutionActive: (runId) => this.runtime.isExecutionActive(runId),
|
|
612
|
+
executionAccepted: (runId) => this.runtime.executionAccepted(runId),
|
|
636
613
|
parseAttachments: parseRunnerImageAttachments,
|
|
637
614
|
persistAttachments: async (_cwd, runId, attachments) => {
|
|
638
615
|
const run = this.runtime.getRun(runId);
|
|
@@ -668,7 +645,8 @@ export class NodeConnector {
|
|
|
668
645
|
}, this.claudeApprovalTimeoutMs);
|
|
669
646
|
this.claudeRunController = new ClaudeManagedRunController(this.claudeClient, {
|
|
670
647
|
intercepted: () => this.fakeRunner !== undefined,
|
|
671
|
-
|
|
648
|
+
isExecutionActive: (runId) => this.runtime.isExecutionActive(runId),
|
|
649
|
+
executionAccepted: (runId) => this.runtime.executionAccepted(runId),
|
|
672
650
|
parseAttachments: parseRunnerImageAttachments,
|
|
673
651
|
emit: (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status),
|
|
674
652
|
adopt: (input) => this.runtime.adoptRun(input),
|
|
@@ -689,19 +667,12 @@ export class NodeConnector {
|
|
|
689
667
|
clearCommandState: (sessionId, commandId) => this.commandStates.clear(sessionId, commandId),
|
|
690
668
|
commandStates: (sessionId) => this.commandStates.list(sessionId)
|
|
691
669
|
});
|
|
692
|
-
this.runners =
|
|
693
|
-
this.openCodeClient,
|
|
694
|
-
this.marAgentClient,
|
|
695
|
-
this.codexClient,
|
|
696
|
-
this.claudeClient,
|
|
697
|
-
...(this.fakeRunner === undefined ? [] : [this.fakeRunner])
|
|
698
|
-
]);
|
|
670
|
+
this.runners = composedRunners.registry;
|
|
699
671
|
this.managedRunnerSessions = new ManagedRunnerSessionService(this.runtime, this.runners, (session) => this.emitSessionWorkbenchEvent({
|
|
700
672
|
session: this.sessionPresentationService.present(session)
|
|
701
673
|
}));
|
|
702
674
|
this.runnerInteractionService = new RunnerInteractionService({
|
|
703
675
|
runtime: this.runtime,
|
|
704
|
-
state: this.runState,
|
|
705
676
|
codex: () => this.codexClient,
|
|
706
677
|
settleCodexUsage: (runId, turnId) => this.codexRunController.settleUsage(runId, turnId),
|
|
707
678
|
claude: () => this.claudeClient,
|
|
@@ -715,26 +686,17 @@ export class NodeConnector {
|
|
|
715
686
|
interactions: this.runnerInteractionService,
|
|
716
687
|
send: (type, payload, replyTo) => this.send(type, payload, replyTo)
|
|
717
688
|
});
|
|
718
|
-
|
|
719
|
-
database: () => this.database,
|
|
720
|
-
runtime: this.runtime,
|
|
721
|
-
commands: this.commandStates,
|
|
722
|
-
runners: this.runners,
|
|
723
|
-
capabilities: () => this.capabilities,
|
|
724
|
-
hasManagedActiveRun: (session) => hasManagedActiveRun(this.runtime, session),
|
|
725
|
-
projectionForNative: (session) => this.nativeSessionProjectionService.projectionForNative(session)
|
|
726
|
-
});
|
|
727
|
-
this.nativeSessionProjectionService = new NativeSessionProjectionService({
|
|
689
|
+
const sessionProjection = composeSessionProjection({
|
|
728
690
|
database: () => this.database,
|
|
729
691
|
nodeId: () => this.config?.nodeId ?? 'recorded-session',
|
|
730
692
|
runtime: this.runtime,
|
|
731
693
|
runners: this.runners,
|
|
732
694
|
capabilities: () => this.capabilities,
|
|
733
|
-
state: this.sessionState,
|
|
734
695
|
commands: this.commandStates,
|
|
735
|
-
releaseResumeState: (directIds, projectionIds) => this.externalSessionResumeService.forgetSessions(directIds, projectionIds)
|
|
736
|
-
present: (session) => this.sessionPresentationService.present(session)
|
|
696
|
+
releaseResumeState: (directIds, projectionIds) => this.externalSessionResumeService.forgetSessions(directIds, projectionIds)
|
|
737
697
|
});
|
|
698
|
+
this.sessionPresentationService = sessionProjection.presentation;
|
|
699
|
+
this.nativeSessionProjectionService = sessionProjection.native;
|
|
738
700
|
this.conversationHistoryService = new ConversationHistoryService({
|
|
739
701
|
runtime: this.runtime,
|
|
740
702
|
runners: this.runners,
|
|
@@ -765,7 +727,7 @@ export class NodeConnector {
|
|
|
765
727
|
},
|
|
766
728
|
emitRun: (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status),
|
|
767
729
|
control: (operation, payload) => this.controlMessages.handle(JSON.stringify(createEnvelope(operation, payload))),
|
|
768
|
-
markInterrupted: (runId) => this.
|
|
730
|
+
markInterrupted: (runId) => this.runtime.requestExecutionInterrupt(runId)
|
|
769
731
|
});
|
|
770
732
|
this.sessionQueryService = new SessionQueryService({
|
|
771
733
|
queuedCount: (sessionId) => this.workspaceQueueWorkbenchService.queuedCount(sessionId),
|
|
@@ -843,7 +805,12 @@ export class NodeConnector {
|
|
|
843
805
|
emitConversation: (turn) => this.emitConversationTurn(turn),
|
|
844
806
|
control: (operation, payload) => this.controlMessages.handle(JSON.stringify(createEnvelope(operation, payload))),
|
|
845
807
|
stopped: () => this.stopped,
|
|
846
|
-
markInterrupted: (runId) => this.
|
|
808
|
+
markInterrupted: (runId) => this.runtime.requestExecutionInterrupt(runId),
|
|
809
|
+
keepRunActive: (sessionId) => this.goalCoordinator.keepRunActive(sessionId),
|
|
810
|
+
executionTerminating: (executionId, status, permissionStop) => {
|
|
811
|
+
this.gitOperationService.executionFinished(executionId);
|
|
812
|
+
return this.goalCoordinator.executionTerminating(executionId, status, permissionStop);
|
|
813
|
+
},
|
|
847
814
|
mcps: (workspaceId) => this.database?.effectiveMcpInstallations(workspaceId) ?? [],
|
|
848
815
|
retainEnvironment: (environment) => this.gitExecution().retain(environment),
|
|
849
816
|
goalCurrent: (input) => input.goal === undefined ||
|
|
@@ -860,7 +827,7 @@ export class NodeConnector {
|
|
|
860
827
|
code: safeErrorCode(error, 'GOAL_EXECUTION_START_FAILED')
|
|
861
828
|
});
|
|
862
829
|
},
|
|
863
|
-
revokeExecutionMcps: (executionId) => this.
|
|
830
|
+
revokeExecutionMcps: (executionId) => this.executionLifecycle.revokeMcps(executionId),
|
|
864
831
|
goalMcp: async (input) => {
|
|
865
832
|
if (input.goal === undefined)
|
|
866
833
|
throw new Error('GOAL_NOT_ACTIVE');
|
|
@@ -979,7 +946,6 @@ export class NodeConnector {
|
|
|
979
946
|
resolveExecutionDirectory,
|
|
980
947
|
runtime: this.runtime,
|
|
981
948
|
runners: this.runners,
|
|
982
|
-
state: this.sessionState,
|
|
983
949
|
available: (runner) => this.runners.require(runner).available(this.capabilities),
|
|
984
950
|
projectionFor: (session) => this.nativeSessionProjectionService.projectionForNative(session),
|
|
985
951
|
managedAliasFor: (session) => this.nativeSessionProjectionService.managedForNative(session),
|
|
@@ -1078,7 +1044,7 @@ export class NodeConnector {
|
|
|
1078
1044
|
runners: this.runners,
|
|
1079
1045
|
runnerAvailable: (runner) => this.runners.require(runner).available(this.capabilities),
|
|
1080
1046
|
projection: this.nativeSessionProjectionService,
|
|
1081
|
-
cachedNative: () =>
|
|
1047
|
+
cachedNative: () => this.nativeSessionProjectionService.cachedNative(),
|
|
1082
1048
|
cachedWorkspace: (workspaceId) => this.workspaceCoordinator.cachedSessions(workspaceId),
|
|
1083
1049
|
discoveryPending: (workspaceId) => this.workspaceSessionService.discoveryPending(workspaceId),
|
|
1084
1050
|
discoverWorkspace: (workspaceId, cleanup) => this.nativeSessionProjectionService.discoverWorkspace(workspaceId, undefined, cleanup),
|
|
@@ -1090,7 +1056,7 @@ export class NodeConnector {
|
|
|
1090
1056
|
void this.runAttachmentService.releaseSession(session.id);
|
|
1091
1057
|
},
|
|
1092
1058
|
refreshActivity: (session) => this.conversationHistoryService.refreshExternalActivity(session),
|
|
1093
|
-
externalActivity: (sessionId) => this.
|
|
1059
|
+
externalActivity: (sessionId) => this.externalSessionResumeService.activity(sessionId),
|
|
1094
1060
|
isWatching: (sessionId) => this.nativeSessionWatchService.isWatching(sessionId),
|
|
1095
1061
|
isRecovering: (sessionId) => this.restartHandoff.blocks(sessionId),
|
|
1096
1062
|
history: (session, input) => this.conversationHistoryService.read(session, input),
|
|
@@ -1154,7 +1120,6 @@ export class NodeConnector {
|
|
|
1154
1120
|
script: this.fakeScript,
|
|
1155
1121
|
runners: this.runners,
|
|
1156
1122
|
runtime: this.runtime,
|
|
1157
|
-
state: this.runState,
|
|
1158
1123
|
emitRun: (runId, type, payload, status) => this.runEventBridge.emitRun(runId, type, payload, status),
|
|
1159
1124
|
publishApproval: (input) => this.runnerInteractionService.publishApproval(input),
|
|
1160
1125
|
disconnect: () => this.controlChannel.close(4010, 'FAKE_RUNNER_DISCONNECT')
|
|
@@ -1278,15 +1243,29 @@ export class NodeConnector {
|
|
|
1278
1243
|
execute: (operation, data) => this.modelUsage.withGrant(isPlainRecord(data) ? data.__usageGrant : undefined, () => this.executeNodeOperation(operation, data)),
|
|
1279
1244
|
send: (type, payload, replyTo) => this.send(type, payload, replyTo)
|
|
1280
1245
|
});
|
|
1281
|
-
|
|
1246
|
+
const workspaceApplication = composeWorkspaceApplication({
|
|
1282
1247
|
config: () => this.config,
|
|
1283
1248
|
database: () => this.database,
|
|
1284
|
-
|
|
1285
|
-
|
|
1249
|
+
runtime: this.runtime,
|
|
1250
|
+
terminals: this.terminalManager,
|
|
1251
|
+
resources: this.workspaceResources,
|
|
1286
1252
|
changes: this.workspaceChangeService,
|
|
1287
|
-
|
|
1288
|
-
|
|
1253
|
+
listSessions: (workspaceId, sessionGroup) => this.executeNodeOperation('session.list', {
|
|
1254
|
+
workspaceId,
|
|
1255
|
+
limit: 30,
|
|
1256
|
+
...(sessionGroup === undefined ? {} : { sessionGroup })
|
|
1257
|
+
}),
|
|
1258
|
+
invalidatePrompt: (id) => this.promptCompletion?.invalidateWorkspace(id),
|
|
1259
|
+
nodeId: () => this.config?.nodeId ?? 'runtime-node',
|
|
1260
|
+
nodeGeneration: () => this.nodeGeneration,
|
|
1261
|
+
send: (type, payload, replyTo) => this.send(type, payload, replyTo),
|
|
1262
|
+
emitWatchEvent: (payload) => this.send('watch.event', payload),
|
|
1263
|
+
publishSession: (payload) => this.emitWorkbenchEvent('session', payload)
|
|
1289
1264
|
});
|
|
1265
|
+
this.workspaceCoordinator = workspaceApplication.coordinator;
|
|
1266
|
+
this.workspaceService = workspaceApplication.workspace;
|
|
1267
|
+
this.workspaceWorkbenchService = workspaceApplication.workbench;
|
|
1268
|
+
this.publishWorkspaceSession = workspaceApplication.publishSession;
|
|
1290
1269
|
this.runEventBridge = new NodeRunEventBridge({
|
|
1291
1270
|
bindModelUsage: (runId) => {
|
|
1292
1271
|
const run = this.runtime.getRun(runId);
|
|
@@ -1401,43 +1380,12 @@ export class NodeConnector {
|
|
|
1401
1380
|
terminals: this.terminalManager
|
|
1402
1381
|
});
|
|
1403
1382
|
this.terminalService = new TerminalService(requireDatabase, this.terminalManager, (environment) => this.gitExecution().retain(environment));
|
|
1404
|
-
this.workspaceService = new WorkspaceService(requireDatabase, () => {
|
|
1405
|
-
if (this.config === undefined)
|
|
1406
|
-
throw new Error('NODE_CONFIG_UNAVAILABLE');
|
|
1407
|
-
return this.config;
|
|
1408
|
-
}, this.runtime, (workspaceId) => {
|
|
1409
|
-
this.terminalManager.removeWorkspaceAssociation(workspaceId);
|
|
1410
|
-
this.workspaceFileService.dispose(workspaceId);
|
|
1411
|
-
this.workspaceCoordinator.invalidateChanges(workspaceId);
|
|
1412
|
-
this.workspaceSessionService.invalidate(workspaceId);
|
|
1413
|
-
this.workspaceCoordinator.clearWatches(workspaceId);
|
|
1414
|
-
this.workspaceWorkbenchService.clearWorkspace(workspaceId);
|
|
1415
|
-
this.promptCompletion?.invalidateWorkspace(workspaceId);
|
|
1416
|
-
}, (workspaceId) => this.workspaceCoordinator.gitPolicyChanged(workspaceId));
|
|
1417
|
-
this.workspaceWorkbenchService = new WorkspaceWorkbenchService({
|
|
1418
|
-
requireWorkspace: (workspaceId) => this.workspaceCoordinator.require(workspaceId),
|
|
1419
|
-
inspectWorkspace: (workspace) => this.workspaceCoordinator.inspectMetadata(workspace),
|
|
1420
|
-
commitWorkspace: (workspace, inspection) => this.workspaceCoordinator.commitMetadata(workspace, inspection),
|
|
1421
|
-
watch: this.workspaceWatchService,
|
|
1422
|
-
files: this.workspaceFileService,
|
|
1423
|
-
uploads: this.workspaceUploadService,
|
|
1424
|
-
changes: this.workspaceChangeService,
|
|
1425
|
-
listSessions: (workspaceId, sessionGroup) => this.executeNodeOperation('session.list', {
|
|
1426
|
-
workspaceId,
|
|
1427
|
-
limit: 30,
|
|
1428
|
-
...(sessionGroup === undefined ? {} : { sessionGroup })
|
|
1429
|
-
}),
|
|
1430
|
-
invalidate: this.invalidateWorkspaceFiles,
|
|
1431
|
-
nodeId: () => this.config?.nodeId ?? 'runtime-node',
|
|
1432
|
-
nodeGeneration: () => this.nodeGeneration,
|
|
1433
|
-
emitWatchEvent: (payload) => this.send('watch.event', payload)
|
|
1434
|
-
});
|
|
1435
1383
|
const completionWorkspace = new PromptCompletionWorkspaceSource({
|
|
1436
1384
|
requireWorkspace: (workspaceId) => this.workspaceCoordinator.require(workspaceId),
|
|
1437
1385
|
observesWorkspace: (workspaceId, actor, connectionId) => this.workspaceWatchService.observes(workspaceId, actor.sessionHash, connectionId),
|
|
1438
1386
|
observesSession: (workspaceId, sessionId, actor, connectionId) => this.nativeSessionWatchService.observes(actor.sessionHash, connectionId, workspaceId, sessionId),
|
|
1439
1387
|
resolveSession: (sessionId) => this.nativeSessionProjectionService.resolve(sessionId),
|
|
1440
|
-
cachedSessions: (workspaceId) => this.
|
|
1388
|
+
cachedSessions: (workspaceId) => this.workspaceSessionService.cachedSnapshot(workspaceId),
|
|
1441
1389
|
readHistory: (session, limit) => this.conversationHistoryService.read(session, { limit })
|
|
1442
1390
|
});
|
|
1443
1391
|
this.promptCompletion = new PromptCompletionNodeService({
|
|
@@ -1555,7 +1503,7 @@ export class NodeConnector {
|
|
|
1555
1503
|
this.operationRouter.register('node.metrics', () => ({
|
|
1556
1504
|
metrics: {
|
|
1557
1505
|
...this.metrics.snapshot(),
|
|
1558
|
-
activeRuns: this.
|
|
1506
|
+
activeRuns: this.runtime.activeExecutionCount(),
|
|
1559
1507
|
workspaceLeases: this.runtime.activeWorkspaceLeaseCount()
|
|
1560
1508
|
}
|
|
1561
1509
|
}));
|
|
@@ -1565,6 +1513,8 @@ export class NodeConnector {
|
|
|
1565
1513
|
manifest: await this.workbenchManifestService.read(),
|
|
1566
1514
|
binaryTerminal: true
|
|
1567
1515
|
}));
|
|
1516
|
+
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);
|
|
1517
|
+
this.operationAdmission = new NodeOperationAdmission(() => this.stopped, () => this.database !== undefined, () => this.config?.nodeId, this.restartHandoff, this.upgradeCoordinator, this.gitOperationService, this.operationRouter);
|
|
1568
1518
|
}
|
|
1569
1519
|
projectComputerUseCapability(capabilities) {
|
|
1570
1520
|
return {
|
|
@@ -1572,11 +1522,10 @@ export class NodeConnector {
|
|
|
1572
1522
|
computerUse: this.computerUseEnablement.capability()
|
|
1573
1523
|
};
|
|
1574
1524
|
}
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
this.stopped = false;
|
|
1525
|
+
start() {
|
|
1526
|
+
return this.lifecycle.start();
|
|
1527
|
+
}
|
|
1528
|
+
async startResources() {
|
|
1580
1529
|
this.continuousRunCoordinator.resumeScheduling();
|
|
1581
1530
|
this.sessionMessageService.setAccepting(true);
|
|
1582
1531
|
this.config ??= await loadNodeConfig(this.configPath);
|
|
@@ -1677,30 +1626,7 @@ export class NodeConnector {
|
|
|
1677
1626
|
return this.directTransferService?.handleTerminal(command) ?? false;
|
|
1678
1627
|
}
|
|
1679
1628
|
stop(options = {}) {
|
|
1680
|
-
|
|
1681
|
-
return this.stopping;
|
|
1682
|
-
this.stopped = true;
|
|
1683
|
-
this.continuousRunCoordinator.suspend();
|
|
1684
|
-
this.goalCoordinator.freeze();
|
|
1685
|
-
this.scheduledSessions.stop();
|
|
1686
|
-
this.stopping = (async () => {
|
|
1687
|
-
let snapshot;
|
|
1688
|
-
try {
|
|
1689
|
-
// In-flight recovery must rebuild accepted inputs before preparation closes.
|
|
1690
|
-
await this.restartHandoff.wait();
|
|
1691
|
-
this.sessionMessageService.setAccepting(false);
|
|
1692
|
-
await Promise.allSettled([...this.inFlightOperations]);
|
|
1693
|
-
await this.sessionMessageService.drain();
|
|
1694
|
-
if (options.handoff && this.config?.nodeId)
|
|
1695
|
-
snapshot = this.restartHandoff.capture();
|
|
1696
|
-
}
|
|
1697
|
-
finally {
|
|
1698
|
-
await this.disposeRuntime();
|
|
1699
|
-
}
|
|
1700
|
-
if (snapshot !== undefined)
|
|
1701
|
-
await this.restartHandoff.publish(snapshot);
|
|
1702
|
-
})();
|
|
1703
|
-
return this.stopping;
|
|
1629
|
+
return this.lifecycle.stop(options.handoff === true);
|
|
1704
1630
|
}
|
|
1705
1631
|
disposeRuntime() {
|
|
1706
1632
|
this.recentRunProjectionService.dispose();
|
|
@@ -1756,19 +1682,20 @@ export class NodeConnector {
|
|
|
1756
1682
|
webToolDrain
|
|
1757
1683
|
]);
|
|
1758
1684
|
return (async () => {
|
|
1759
|
-
|
|
1685
|
+
const hosting = await Promise.allSettled([conversationHostingDrain]);
|
|
1686
|
+
const results = await drains;
|
|
1687
|
+
this.database = undefined;
|
|
1688
|
+
const git = await Promise.allSettled([this.gitExecutionService?.close()]);
|
|
1689
|
+
this.usageOutbox?.disconnected();
|
|
1690
|
+
this.usageOutbox = undefined;
|
|
1691
|
+
this.modelUsage.clear();
|
|
1692
|
+
const failed = [...hosting, ...results, ...git].find((result) => result.status === 'rejected');
|
|
1760
1693
|
try {
|
|
1761
|
-
await conversationHostingDrain;
|
|
1762
|
-
}
|
|
1763
|
-
finally {
|
|
1764
|
-
const results = await drains;
|
|
1765
|
-
this.database = undefined;
|
|
1766
|
-
await this.gitExecutionService?.close();
|
|
1767
|
-
this.usageOutbox?.disconnected();
|
|
1768
|
-
this.usageOutbox = undefined;
|
|
1769
|
-
this.modelUsage.clear();
|
|
1770
1694
|
database?.close();
|
|
1771
|
-
|
|
1695
|
+
}
|
|
1696
|
+
catch (error) {
|
|
1697
|
+
if (failed === undefined)
|
|
1698
|
+
throw error;
|
|
1772
1699
|
}
|
|
1773
1700
|
if (failed !== undefined)
|
|
1774
1701
|
throw failed.reason;
|
|
@@ -1777,10 +1704,7 @@ export class NodeConnector {
|
|
|
1777
1704
|
/** @internal Thin compatibility delegates; all behavior remains in the extracted services. */
|
|
1778
1705
|
handleMessage = (raw) => this.controlMessages.handle(raw);
|
|
1779
1706
|
emitRunEvent = (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status);
|
|
1780
|
-
emitConversationItem = (runId, item) =>
|
|
1781
|
-
this.goalCoordinator.executionProgress(runId, item);
|
|
1782
|
-
this.runEventBridge.emitConversationItem(runId, item);
|
|
1783
|
-
};
|
|
1707
|
+
emitConversationItem = (runId, item) => this.executionLifecycle.emitItem(runId, item);
|
|
1784
1708
|
emitConversationTurn = (turn) => {
|
|
1785
1709
|
this.emitWorkbenchEvent('conversation', { turn });
|
|
1786
1710
|
};
|
|
@@ -1791,46 +1715,14 @@ export class NodeConnector {
|
|
|
1791
1715
|
}
|
|
1792
1716
|
this.emitWorkbenchEvent(category, payload);
|
|
1793
1717
|
};
|
|
1794
|
-
emitSessionWorkbenchEvent = (payload) =>
|
|
1795
|
-
if (isPlainRecord(payload) && isPlainRecord(payload.session)) {
|
|
1796
|
-
const workspaceId = payload.session.workspaceId;
|
|
1797
|
-
if (typeof workspaceId === 'string') {
|
|
1798
|
-
this.workspaceSessionService.markCacheStale(workspaceId);
|
|
1799
|
-
void this.workspaceWorkbenchService?.invalidateTopic(workspaceId, 'sessions');
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
this.emitWorkbenchEvent('session', payload);
|
|
1803
|
-
};
|
|
1718
|
+
emitSessionWorkbenchEvent = (payload) => this.publishWorkspaceSession(payload);
|
|
1804
1719
|
emitWorkbenchEvent = (category, payload) => this.workbenchEventService.dispatch(category, payload);
|
|
1805
1720
|
discoverWorkspaceSessions = (workspaceId, onRunnerDiscovered) => this.nativeSessionProjectionService.discoverWorkspace(workspaceId, onRunnerDiscovered);
|
|
1806
1721
|
invalidateWorkspaceWatchTopics = (workspaceId) => this.workspaceCoordinator.invalidate(workspaceId);
|
|
1807
1722
|
startCapabilityRefresh = () => this.connectionLifecycle.startCapabilityRefresh();
|
|
1808
1723
|
refreshCapabilities = () => this.connectionLifecycle.refreshCapabilities();
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
throw new Error('NODE_STOPPED');
|
|
1812
|
-
const input = isPlainRecord(data) ? data : {};
|
|
1813
|
-
const sessionId = typeof input.sessionId === 'string' ? input.sessionId : undefined;
|
|
1814
|
-
if (this.restartHandoff.blocksOperation(operation, input))
|
|
1815
|
-
throw new Error('SESSION_RESTART_PENDING');
|
|
1816
|
-
if (this.database === undefined)
|
|
1817
|
-
throw new Error('NODE_DATABASE_UNAVAILABLE');
|
|
1818
|
-
if (this.upgradeCoordinator.blocks(operation))
|
|
1819
|
-
throw new Error('NODE_UPGRADE_PENDING');
|
|
1820
|
-
nodeLog('node.operation', { nodeId: this.config?.nodeId, operation });
|
|
1821
|
-
const task = this.gitOperationService.execute(operation, data, (input) => this.operationRouter.execute(operation, input));
|
|
1822
|
-
this.inFlightOperations.add(task);
|
|
1823
|
-
try {
|
|
1824
|
-
const result = await task;
|
|
1825
|
-
if ((operation === 'session.command.execute' || operation === 'session.message') &&
|
|
1826
|
-
sessionId !== undefined &&
|
|
1827
|
-
Number.isSafeInteger(input.__requestUserId))
|
|
1828
|
-
this.restartHandoff.rememberUser(sessionId, input.__requestUserId);
|
|
1829
|
-
return result;
|
|
1830
|
-
}
|
|
1831
|
-
finally {
|
|
1832
|
-
this.inFlightOperations.delete(task);
|
|
1833
|
-
}
|
|
1724
|
+
executeNodeOperation(operation, data) {
|
|
1725
|
+
return this.operationAdmission.execute(operation, data);
|
|
1834
1726
|
}
|
|
1835
1727
|
gitExecution() {
|
|
1836
1728
|
this.gitExecutionService ??= new GitExecutionService({
|