@moxt-ai/mobius 0.0.5 → 0.0.7

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.
Files changed (87) hide show
  1. package/dist/acp/activity.d.ts +7 -2
  2. package/dist/acp/activity.d.ts.map +1 -1
  3. package/dist/acp/activity.js +95 -7
  4. package/dist/acp/activity.js.map +1 -1
  5. package/dist/acp/native-session.d.ts +30 -0
  6. package/dist/acp/native-session.d.ts.map +1 -0
  7. package/dist/acp/native-session.js +25 -0
  8. package/dist/acp/native-session.js.map +1 -0
  9. package/dist/acp/session-history.d.ts +9 -0
  10. package/dist/acp/session-history.d.ts.map +1 -0
  11. package/dist/acp/session-history.js +69 -0
  12. package/dist/acp/session-history.js.map +1 -0
  13. package/dist/acp/session-manager.d.ts +16 -5
  14. package/dist/acp/session-manager.d.ts.map +1 -1
  15. package/dist/acp/session-manager.js +210 -25
  16. package/dist/acp/session-manager.js.map +1 -1
  17. package/dist/acp/session-store.d.ts +9 -0
  18. package/dist/acp/session-store.d.ts.map +1 -1
  19. package/dist/acp/session-store.js +43 -0
  20. package/dist/acp/session-store.js.map +1 -1
  21. package/dist/agent-catalog/discover-local-agents.d.ts +1 -1
  22. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  23. package/dist/agent-catalog/discover-local-agents.js +19 -30
  24. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  25. package/dist/agent-installation/automatic-adapter-provisioner.d.ts +1 -1
  26. package/dist/agent-installation/automatic-adapter-provisioner.d.ts.map +1 -1
  27. package/dist/agent-installation/automatic-adapter-provisioner.js +1 -1
  28. package/dist/agent-installation/automatic-adapter-provisioner.js.map +1 -1
  29. package/dist/agent-installation/fixed-installation-executor.d.ts +1 -1
  30. package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
  31. package/dist/agent-installation/fixed-installation-executor.js +9 -18
  32. package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
  33. package/dist/agent-installation/installation-grants.d.ts.map +1 -1
  34. package/dist/agent-installation/installation-grants.js +1 -2
  35. package/dist/agent-installation/installation-grants.js.map +1 -1
  36. package/dist/agent-installation/managed-adapter-installer.d.ts +0 -1
  37. package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
  38. package/dist/agent-installation/managed-adapter-installer.js +1 -3
  39. package/dist/agent-installation/managed-adapter-installer.js.map +1 -1
  40. package/dist/authorization/local-authorization-error.d.ts +5 -0
  41. package/dist/authorization/local-authorization-error.d.ts.map +1 -0
  42. package/dist/authorization/local-authorization-error.js +8 -0
  43. package/dist/authorization/local-authorization-error.js.map +1 -0
  44. package/dist/authorization/workspace-directory.d.ts +16 -5
  45. package/dist/authorization/workspace-directory.d.ts.map +1 -1
  46. package/dist/authorization/workspace-directory.js +109 -119
  47. package/dist/authorization/workspace-directory.js.map +1 -1
  48. package/dist/cli.js +2881 -739
  49. package/dist/cli.js.map +4 -4
  50. package/dist/config.d.ts +3 -3
  51. package/dist/config.d.ts.map +1 -1
  52. package/dist/config.js +8 -6
  53. package/dist/config.js.map +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +2895 -788
  57. package/dist/index.js.map +4 -4
  58. package/dist/native-sessions/codex-history.d.ts +11 -0
  59. package/dist/native-sessions/codex-history.d.ts.map +1 -0
  60. package/dist/native-sessions/codex-history.js +223 -0
  61. package/dist/native-sessions/codex-history.js.map +1 -0
  62. package/dist/native-sessions/service.d.ts +14 -0
  63. package/dist/native-sessions/service.d.ts.map +1 -0
  64. package/dist/native-sessions/service.js +254 -0
  65. package/dist/native-sessions/service.js.map +1 -0
  66. package/dist/pairing/pair-local-machine.d.ts.map +1 -1
  67. package/dist/pairing/pair-local-machine.js +41 -31
  68. package/dist/pairing/pair-local-machine.js.map +1 -1
  69. package/dist/process/executable.d.ts +1 -1
  70. package/dist/process/executable.d.ts.map +1 -1
  71. package/dist/process/executable.js +3 -11
  72. package/dist/process/executable.js.map +1 -1
  73. package/dist/relay-connection/liveness.d.ts.map +1 -1
  74. package/dist/relay-connection/liveness.js +1 -2
  75. package/dist/relay-connection/liveness.js.map +1 -1
  76. package/dist/relay-connection/session-event-outbox.d.ts +19 -0
  77. package/dist/relay-connection/session-event-outbox.d.ts.map +1 -0
  78. package/dist/relay-connection/session-event-outbox.js +182 -0
  79. package/dist/relay-connection/session-event-outbox.js.map +1 -0
  80. package/dist/run-daemon.d.ts.map +1 -1
  81. package/dist/run-daemon.js +340 -244
  82. package/dist/run-daemon.js.map +1 -1
  83. package/package.json +3 -2
  84. package/dist/authorization/authorize-binding.d.ts +0 -6
  85. package/dist/authorization/authorize-binding.d.ts.map +0 -1
  86. package/dist/authorization/authorize-binding.js +0 -30
  87. package/dist/authorization/authorize-binding.js.map +0 -1
@@ -1,6 +1,5 @@
1
- import { randomUUID } from "node:crypto";
2
1
  import { basename } from "node:path";
3
- import { AGENT_ACTIVITY_KIND, AGENT_INSTALL_AWAITING_APPROVAL_KIND, AGENT_INSTALL_CANCEL_KIND, AGENT_INSTALL_CANCELLED_KIND, AGENT_INSTALL_COMPLETED_KIND, AGENT_INSTALL_FAILED_KIND, AGENT_INSTALL_PROGRESS_KIND, AGENT_INSTALL_REQUEST_KIND, AGENT_INSTALL_STARTED_KIND, AGENT_MESSAGE_DELTA_KIND, decodeAgentInstallCancelCommand, decodeAgentInstallRequestCommand, decodeMessageKind, decodeRuntimeHeartbeatAckEvent, decodeRuntimeLivenessReadyEvent, decodeSessionCancelCommand, decodeSessionConfigureCommand, decodeSessionElicitationRespondCommand, decodeSessionPermissionRespondCommand, decodeSessionPrepareCommand, decodeSessionPromptCommand, decodeWorkspaceListCommand, encodeAgentActivityEvent, encodeAgentContentEvent, encodeAgentInstallAwaitingApprovalEvent, encodeAgentInstallCancelledEvent, encodeAgentInstallCompletedEvent, encodeAgentInstallFailedEvent, encodeAgentInstallProgressEvent, encodeAgentInstallStartedEvent, encodeAgentMessageDeltaEvent, encodeSessionCommandsUpdatedEvent, encodeSessionCompletedEvent, encodeSessionConfigUpdatedEvent, encodeSessionElicitationRequestedEvent, encodeSessionElicitationResolvedEvent, encodeSessionFailedEvent, encodeSessionInfoUpdatedEvent, encodeSessionOperationFailedEvent, encodeSessionPermissionRequestedEvent, encodeSessionPermissionResolvedEvent, encodeSessionReadyEvent, encodeSessionStartedEvent, encodeSessionUsageUpdatedEvent, encodeWorkspaceEntriesEvent, MOBIUS_PROTOCOL_VERSION, RUNTIME_HEARTBEAT_ACK_KIND, RUNTIME_LIVENESS_READY_KIND, SESSION_CANCEL_KIND, SESSION_COMPLETED_KIND, SESSION_CONFIGURE_KIND, SESSION_ELICITATION_RESPOND_KIND, SESSION_FAILED_KIND, SESSION_PERMISSION_RESPOND_KIND, SESSION_PREPARE_KIND, SESSION_PROMPT_KIND, SESSION_STARTED_KIND, WORKSPACE_LIST_KIND, } from "@moxt-ai/mobius-protocol";
2
+ import { AGENT_ACTIVITY_KIND, AGENT_INSTALL_AWAITING_APPROVAL_KIND, AGENT_INSTALL_CANCEL_KIND, AGENT_INSTALL_CANCELLED_KIND, AGENT_INSTALL_COMPLETED_KIND, AGENT_INSTALL_FAILED_KIND, AGENT_INSTALL_PROGRESS_KIND, AGENT_INSTALL_REQUEST_KIND, AGENT_INSTALL_STARTED_KIND, AGENT_MESSAGE_DELTA_KIND, decodeAgentInstallCancelCommand, decodeAgentInstallRequestCommand, decodeMessageKind, decodeNativeSessionCancel, decodeNativeSessionCommand, decodeRuntimeHeartbeatAckEvent, decodeRuntimeLivenessReadyEvent, decodeSessionCancelCommand, decodeSessionConfigureCommand, decodeSessionElicitationRespondCommand, decodeSessionEventAcknowledgement, decodeSessionPermissionRespondCommand, decodeSessionPrepareCommand, decodeSessionPromptCommand, decodeWorkspaceListCommand, encodeAgentActivityEvent, encodeAgentContentEvent, encodeAgentInstallAwaitingApprovalEvent, encodeAgentInstallCancelledEvent, encodeAgentInstallCompletedEvent, encodeAgentInstallFailedEvent, encodeAgentInstallProgressEvent, encodeAgentInstallStartedEvent, encodeAgentMessageDeltaEvent, encodeNativeSessionResult, encodeSessionCommandsUpdatedEvent, encodeSessionCompletedEvent, encodeSessionConfigUpdatedEvent, encodeSessionElicitationRequestedEvent, encodeSessionElicitationResolvedEvent, encodeSessionFailedEvent, encodeSessionInfoUpdatedEvent, encodeSessionOperationFailedEvent, encodeSessionPermissionRequestedEvent, encodeSessionPermissionResolvedEvent, encodeSessionReadyEvent, encodeSessionStartedEvent, encodeSessionUsageUpdatedEvent, encodeWorkspaceEntriesEvent, NATIVE_SESSION_CANCEL_KIND, NATIVE_SESSION_REQUEST_KIND, RUNTIME_HEARTBEAT_ACK_KIND, RUNTIME_LIVENESS_READY_KIND, SESSION_CANCEL_KIND, SESSION_COMPLETED_KIND, SESSION_CONFIGURE_KIND, SESSION_ELICITATION_RESPOND_KIND, SESSION_EVENT_ACK_KIND, SESSION_FAILED_KIND, SESSION_PERMISSION_RESPOND_KIND, SESSION_PREPARE_KIND, SESSION_PROMPT_KIND, SESSION_STARTED_KIND, WORKSPACE_LIST_KIND, } from "@moxt-ai/mobius-protocol";
4
3
  import { WebSocket } from "undici";
5
4
  import { AcpExecutionError, AcpSessionManager, NullAcpSessionObserver, } from "./acp/session-manager.js";
6
5
  import { SqliteAcpSessionStore } from "./acp/session-store.js";
@@ -12,10 +11,12 @@ import { AutomaticAdapterProvisioner } from "./agent-installation/automatic-adap
12
11
  import { FixedInstallationExecutor } from "./agent-installation/fixed-installation-executor.js";
13
12
  import { ConsoleInstallationAuthorizer } from "./agent-installation/local-installation-authorizer.js";
14
13
  import { ManagedAdapterInstaller } from "./agent-installation/managed-adapter-installer.js";
15
- import { LocalAuthorizationError } from "./authorization/authorize-binding.js";
14
+ import { LocalAuthorizationError } from "./authorization/local-authorization-error.js";
16
15
  import { WorkspaceDirectoryService } from "./authorization/workspace-directory.js";
16
+ import { NativeSessionService } from "./native-sessions/service.js";
17
17
  import { connectRelay } from "./relay-connection/connect.js";
18
18
  import { RelayConnectionLiveness } from "./relay-connection/liveness.js";
19
+ import { SessionEventOutbox } from "./relay-connection/session-event-outbox.js";
19
20
  import { systemDaemonTimer, } from "./relay-connection/timer.js";
20
21
  import { readStateDirectory } from "./storage/state-directory.js";
21
22
  const RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
@@ -71,44 +72,44 @@ class RelayConnectionRefresh {
71
72
  };
72
73
  }
73
74
  class DaemonAcpObserver {
74
- #socket;
75
- constructor(socket) {
76
- this.#socket = socket;
75
+ #record;
76
+ constructor(record) {
77
+ this.#record = record;
77
78
  }
78
79
  onCommands = (event) => {
79
- send(this.#socket, encodeSessionCommandsUpdatedEvent(event));
80
+ this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
80
81
  return Promise.resolve();
81
82
  };
82
83
  onConfig = (event) => {
83
- send(this.#socket, encodeSessionConfigUpdatedEvent(event));
84
+ this.#record(event.sessionId, encodeSessionConfigUpdatedEvent(event));
84
85
  return Promise.resolve();
85
86
  };
86
87
  onContent = (event) => {
87
- send(this.#socket, encodeAgentContentEvent(event));
88
+ this.#record(event.sessionId, encodeAgentContentEvent(event));
88
89
  return Promise.resolve();
89
90
  };
90
91
  onElicitation = (event) => {
91
- send(this.#socket, encodeSessionElicitationRequestedEvent(event));
92
+ this.#record(event.sessionId, encodeSessionElicitationRequestedEvent(event));
92
93
  return Promise.resolve();
93
94
  };
94
95
  onElicitationResolved = (event) => {
95
- send(this.#socket, encodeSessionElicitationResolvedEvent(event));
96
+ this.#record(event.sessionId, encodeSessionElicitationResolvedEvent(event));
96
97
  return Promise.resolve();
97
98
  };
98
99
  onInfo = (event) => {
99
- send(this.#socket, encodeSessionInfoUpdatedEvent(event));
100
+ this.#record(event.sessionId, encodeSessionInfoUpdatedEvent(event));
100
101
  return Promise.resolve();
101
102
  };
102
103
  onPermission = (event) => {
103
- send(this.#socket, encodeSessionPermissionRequestedEvent(event));
104
+ this.#record(event.sessionId, encodeSessionPermissionRequestedEvent(event));
104
105
  return Promise.resolve();
105
106
  };
106
107
  onPermissionResolved = (event) => {
107
- send(this.#socket, encodeSessionPermissionResolvedEvent(event));
108
+ this.#record(event.sessionId, encodeSessionPermissionResolvedEvent(event));
108
109
  return Promise.resolve();
109
110
  };
110
111
  onUsage = (event) => {
111
- send(this.#socket, encodeSessionUsageUpdatedEvent(event));
112
+ this.#record(event.sessionId, encodeSessionUsageUpdatedEvent(event));
112
113
  return Promise.resolve();
113
114
  };
114
115
  }
@@ -159,7 +160,6 @@ class DaemonInstallationObserver {
159
160
  this.#send(socket, encodeAgentInstallAwaitingApprovalEvent({
160
161
  agentId: state.agentId,
161
162
  kind: AGENT_INSTALL_AWAITING_APPROVAL_KIND,
162
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
163
163
  requestId: state.requestId,
164
164
  }));
165
165
  return Promise.resolve();
@@ -170,14 +170,12 @@ class DaemonInstallationObserver {
170
170
  this.#send(socket, encodeAgentInstallStartedEvent({
171
171
  agentId: state.agentId,
172
172
  kind: AGENT_INSTALL_STARTED_KIND,
173
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
174
173
  requestId: state.requestId,
175
174
  }));
176
175
  }
177
176
  this.#send(socket, encodeAgentInstallProgressEvent({
178
177
  agentId: state.agentId,
179
178
  kind: AGENT_INSTALL_PROGRESS_KIND,
180
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
181
179
  requestId: state.requestId,
182
180
  stage: state.stage,
183
181
  }));
@@ -188,7 +186,6 @@ class DaemonInstallationObserver {
188
186
  agentId: state.agentId,
189
187
  authenticationMayBeRequired: state.authenticationMayBeRequired,
190
188
  kind: AGENT_INSTALL_COMPLETED_KIND,
191
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
192
189
  requestId: state.requestId,
193
190
  }));
194
191
  return Promise.resolve();
@@ -199,7 +196,6 @@ class DaemonInstallationObserver {
199
196
  code: state.code,
200
197
  kind: AGENT_INSTALL_FAILED_KIND,
201
198
  message: state.message,
202
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
203
199
  requestId: state.requestId,
204
200
  }));
205
201
  return Promise.resolve();
@@ -208,7 +204,6 @@ class DaemonInstallationObserver {
208
204
  this.#send(socket, encodeAgentInstallCancelledEvent({
209
205
  agentId: state.agentId,
210
206
  kind: AGENT_INSTALL_CANCELLED_KIND,
211
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
212
207
  requestId: state.requestId,
213
208
  }));
214
209
  return Promise.resolve();
@@ -256,18 +251,20 @@ function send(socket, message) {
256
251
  }
257
252
  socket.send(message);
258
253
  }
259
- function reportFailure(socket, command, code, message) {
260
- if (socket.readyState !== WebSocket.OPEN) {
261
- return;
254
+ function recordSessionEvent(outbox, socket, sessionId, payload, attemptId = null) {
255
+ const envelope = outbox.enqueue(sessionId, payload, attemptId);
256
+ if (socket.readyState === WebSocket.OPEN) {
257
+ socket.send(envelope);
262
258
  }
263
- send(socket, encodeSessionFailedEvent({
259
+ }
260
+ function reportFailure(outbox, socket, command, code, message, attemptId = null) {
261
+ recordSessionEvent(outbox, socket, command.sessionId, encodeSessionFailedEvent({
264
262
  code,
265
263
  commandId: command.commandId,
266
264
  kind: SESSION_FAILED_KIND,
267
265
  message,
268
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
269
266
  sessionId: command.sessionId,
270
- }));
267
+ }), attemptId);
271
268
  }
272
269
  function operationErrorCode(error) {
273
270
  if (error instanceof AcpExecutionError ||
@@ -293,18 +290,17 @@ function reportOperationFailure(socket, requestId, sessionId, error) {
293
290
  code: operationErrorCode(error),
294
291
  kind: "session.operation.failed",
295
292
  message: operationErrorMessage(error),
296
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
297
293
  requestId,
298
294
  sessionId,
299
295
  }));
300
296
  }
301
- async function resolveSessionDirectories(directories, bindingId, directoryId, additionalDirectoryIds) {
302
- const cwd = await directories.resolve(bindingId, directoryId);
297
+ async function resolveSessionDirectories(directories, bindingId, directoryId, additionalDirectoryIds, signal) {
298
+ const cwd = await directories.resolve(bindingId, directoryId, signal);
303
299
  const additionalDirectories = [];
304
300
  const additionalDirectoryEntries = [];
305
301
  const unique = new Set([cwd]);
306
302
  for (const additionalDirectoryId of additionalDirectoryIds) {
307
- const directory = await directories.resolve(bindingId, additionalDirectoryId);
303
+ const directory = await directories.resolve(bindingId, additionalDirectoryId, signal);
308
304
  if (unique.has(directory)) {
309
305
  throw new LocalAuthorizationError("Workspace directories must resolve to distinct locations");
310
306
  }
@@ -317,9 +313,9 @@ async function resolveSessionDirectories(directories, bindingId, directoryId, ad
317
313
  }
318
314
  return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
319
315
  }
320
- async function executeWorkspaceList(socket, command, directories, audit) {
316
+ async function executeWorkspaceList(socket, command, directories, audit, signal) {
321
317
  try {
322
- const listing = await directories.list(command.bindingId, command.directoryId);
318
+ const listing = await directories.list(command.bindingId, command.directoryId, signal);
323
319
  audit.record({
324
320
  commandId: command.requestId,
325
321
  event: "workspace_list_authorized",
@@ -332,7 +328,6 @@ async function executeWorkspaceList(socket, command, directories, audit) {
332
328
  entries: listing.entries,
333
329
  kind: "workspace.entries",
334
330
  parentDirectoryId: listing.parentDirectoryId,
335
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
336
331
  requestId: command.requestId,
337
332
  }));
338
333
  }
@@ -340,9 +335,9 @@ async function executeWorkspaceList(socket, command, directories, audit) {
340
335
  reportOperationFailure(socket, command.requestId, "", error);
341
336
  }
342
337
  }
343
- async function executeSessionPrepare(socket, command, config, directories, audit, sessions, signal) {
338
+ async function executeSessionPrepare(outbox, socket, command, config, directories, audit, sessions, signal) {
344
339
  try {
345
- const resolved = await resolveSessionDirectories(directories, command.bindingId, command.directoryId, command.additionalDirectoryIds);
340
+ const resolved = await resolveSessionDirectories(directories, config.bindingId, command.directoryId, command.additionalDirectoryIds, signal);
346
341
  const agent = config.catalog.find(command.agentId);
347
342
  const prepared = await sessions.prepareSession({
348
343
  additionalDirectories: resolved.additionalDirectories,
@@ -351,13 +346,13 @@ async function executeSessionPrepare(socket, command, config, directories, audit
351
346
  sessionId: command.sessionId,
352
347
  signal,
353
348
  });
354
- const listing = await directories.list(command.bindingId, command.directoryId);
349
+ const listing = await directories.list(config.bindingId, command.directoryId, signal);
355
350
  audit.record({
356
351
  commandId: command.requestId,
357
352
  event: "session_prepared",
358
353
  sessionId: command.sessionId,
359
354
  });
360
- send(socket, encodeSessionReadyEvent({
355
+ recordSessionEvent(outbox, socket, command.sessionId, encodeSessionReadyEvent({
361
356
  additionalDirectories: resolved.additionalDirectoryEntries,
362
357
  agentId: command.agentId,
363
358
  agentName: prepared.agentName,
@@ -368,7 +363,6 @@ async function executeSessionPrepare(socket, command, config, directories, audit
368
363
  directoryId: command.directoryId,
369
364
  directoryLabel: listing.directoryLabel,
370
365
  kind: "session.ready",
371
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
372
366
  requestId: command.requestId,
373
367
  restored: prepared.restored,
374
368
  sessionId: command.sessionId,
@@ -378,9 +372,9 @@ async function executeSessionPrepare(socket, command, config, directories, audit
378
372
  reportOperationFailure(socket, command.requestId, command.sessionId, error);
379
373
  }
380
374
  }
381
- async function executeSessionConfigure(socket, command, config, directories, audit, sessions, signal) {
375
+ async function executeSessionConfigure(outbox, socket, command, config, directories, audit, sessions, signal) {
382
376
  try {
383
- const resolved = await resolveSessionDirectories(directories, command.bindingId, command.directoryId, command.additionalDirectoryIds);
377
+ const resolved = await resolveSessionDirectories(directories, config.bindingId, command.directoryId, command.additionalDirectoryIds, signal);
384
378
  const configOptions = await sessions.configureSession({
385
379
  additionalDirectories: resolved.additionalDirectories,
386
380
  agent: config.catalog.find(command.agentId),
@@ -398,10 +392,9 @@ async function executeSessionConfigure(socket, command, config, directories, aud
398
392
  event: "session_configured",
399
393
  sessionId: command.sessionId,
400
394
  });
401
- send(socket, encodeSessionConfigUpdatedEvent({
395
+ recordSessionEvent(outbox, socket, command.sessionId, encodeSessionConfigUpdatedEvent({
402
396
  configOptions,
403
397
  kind: "session.config.updated",
404
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
405
398
  requestId: command.requestId,
406
399
  sessionId: command.sessionId,
407
400
  }));
@@ -410,23 +403,22 @@ async function executeSessionConfigure(socket, command, config, directories, aud
410
403
  reportOperationFailure(socket, command.requestId, command.sessionId, error);
411
404
  }
412
405
  }
413
- async function executePrompt(socket, command, config, directories, audit, sessions, signal) {
406
+ async function executePrompt(outbox, socket, command, config, directories, audit, sessions, attemptId, signal) {
414
407
  try {
415
- const resolved = await resolveSessionDirectories(directories, command.bindingId, command.directoryId, command.additionalDirectoryIds);
408
+ const resolved = await resolveSessionDirectories(directories, config.bindingId, command.directoryId, command.additionalDirectoryIds, signal);
416
409
  const agent = config.catalog.find(command.agentId);
417
- const processAttemptId = randomUUID();
418
410
  audit.record({
419
411
  commandId: command.commandId,
420
412
  event: "session_authorized",
421
413
  sessionId: command.sessionId,
422
414
  });
423
- send(socket, encodeSessionStartedEvent({
415
+ outbox.transitionExecution(command.commandId, "running");
416
+ recordSessionEvent(outbox, socket, command.sessionId, encodeSessionStartedEvent({
424
417
  commandId: command.commandId,
425
418
  kind: SESSION_STARTED_KIND,
426
- processAttemptId,
427
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
419
+ attemptId,
428
420
  sessionId: command.sessionId,
429
- }));
421
+ }), attemptId);
430
422
  const result = await sessions.runPrompt({
431
423
  additionalDirectories: resolved.additionalDirectories,
432
424
  agent,
@@ -434,33 +426,32 @@ async function executePrompt(socket, command, config, directories, audit, sessio
434
426
  cwd: resolved.cwd,
435
427
  images: command.images,
436
428
  onActivity: (activity) => {
437
- send(socket, encodeAgentActivityEvent({
429
+ recordSessionEvent(outbox, socket, command.sessionId, encodeAgentActivityEvent({
438
430
  activityId: activity.activityId,
439
431
  activityType: activity.activityType,
440
432
  commandId: command.commandId,
441
433
  content: activity.content,
434
+ detail: activity.detail,
442
435
  input: activity.input,
443
436
  kind: AGENT_ACTIVITY_KIND,
444
437
  locations: activity.locations,
445
438
  name: activity.name,
446
439
  output: activity.output,
447
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
448
440
  sequence: activity.sequence,
449
441
  sessionId: command.sessionId,
450
442
  status: activity.status,
451
443
  title: activity.title,
452
444
  toolKind: activity.toolKind,
453
- }));
445
+ }), attemptId);
454
446
  return Promise.resolve();
455
447
  },
456
448
  onText: (text) => {
457
- send(socket, encodeAgentMessageDeltaEvent({
449
+ recordSessionEvent(outbox, socket, command.sessionId, encodeAgentMessageDeltaEvent({
458
450
  commandId: command.commandId,
459
451
  kind: AGENT_MESSAGE_DELTA_KIND,
460
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
461
452
  sessionId: command.sessionId,
462
453
  text,
463
- }));
454
+ }), attemptId);
464
455
  return Promise.resolve();
465
456
  },
466
457
  prompt: command.prompt,
@@ -468,13 +459,13 @@ async function executePrompt(socket, command, config, directories, audit, sessio
468
459
  sessionId: command.sessionId,
469
460
  signal,
470
461
  });
471
- send(socket, encodeSessionCompletedEvent({
462
+ recordSessionEvent(outbox, socket, command.sessionId, encodeSessionCompletedEvent({
472
463
  commandId: command.commandId,
473
464
  kind: SESSION_COMPLETED_KIND,
474
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
475
465
  sessionId: command.sessionId,
476
466
  stopReason: result.stopReason,
477
- }));
467
+ }), attemptId);
468
+ outbox.transitionExecution(command.commandId, result.stopReason === "cancelled" ? "cancelled" : "succeeded");
478
469
  audit.record({
479
470
  commandId: command.commandId,
480
471
  event: result.stopReason === "cancelled"
@@ -490,9 +481,10 @@ async function executePrompt(socket, command, config, directories, audit, sessio
490
481
  sessionId: command.sessionId,
491
482
  });
492
483
  const code = operationErrorCode(error);
493
- reportFailure(socket, command, code === "session_operation_failed" ? "agent_execution_failed" : code, code === "session_operation_failed"
484
+ reportFailure(outbox, socket, command, code === "session_operation_failed" ? "agent_execution_failed" : code, code === "session_operation_failed"
494
485
  ? "The local agent could not complete the request"
495
- : operationErrorMessage(error));
486
+ : operationErrorMessage(error), attemptId);
487
+ outbox.transitionExecution(command.commandId, "failed");
496
488
  console.error("Mobius daemon command failed", error);
497
489
  }
498
490
  }
@@ -510,215 +502,313 @@ function waitForRelayRetry(signal, timer) {
510
502
  signal.addEventListener("abort", finish, { once: true });
511
503
  });
512
504
  }
513
- async function runRelayConnection(config, directories, audit, sessions, installations, installationObserver, signal, timer) {
505
+ async function runRelayConnection(config, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, signal, timer) {
514
506
  const relayUrl = new URL(config.relayUrl);
515
507
  relayUrl.searchParams.set("liveness", "1");
516
508
  const socket = await connectRelay(relayUrl, signal);
517
509
  const activeTurns = new Map();
510
+ const activeAttemptIds = new Map();
518
511
  const connectionController = new AbortController();
519
- sessions.setObserver(new DaemonAcpObserver(socket));
512
+ const nativeRequests = new Map();
513
+ const record = (sessionId, payload) => {
514
+ recordSessionEvent(outbox, socket, sessionId, payload, activeAttemptIds.get(sessionId) ?? null);
515
+ };
516
+ sessions.setObserver(new DaemonAcpObserver(record));
520
517
  installationObserver.connect(socket);
521
- await new Promise((resolve, reject) => {
522
- let finished = false;
523
- const cleanup = () => {
524
- connectionRefresh.close();
525
- connectionLiveness.close();
526
- signal.removeEventListener("abort", stop);
527
- socket.removeEventListener("close", handleClose);
528
- socket.removeEventListener("error", handleError);
529
- socket.removeEventListener("message", handleMessage);
530
- installationObserver.disconnect(socket);
531
- connectionController.abort();
532
- for (const turn of activeTurns.values()) {
533
- turn.abortConnection();
534
- }
535
- activeTurns.clear();
536
- };
537
- const resolveConnection = () => {
538
- if (finished) {
539
- return;
540
- }
541
- finished = true;
542
- cleanup();
543
- resolve();
544
- };
545
- const rejectConnection = () => {
546
- if (finished) {
547
- return;
548
- }
549
- finished = true;
550
- cleanup();
551
- reject(new Error("Relay WebSocket failed"));
552
- };
553
- const stop = () => {
554
- socket.close(1000, "Daemon stopped");
555
- resolveConnection();
556
- };
557
- const refreshConnection = () => {
558
- socket.close(1000, "Refreshing idle relay connection");
559
- resolveConnection();
560
- };
561
- const connectionLiveness = new RelayConnectionLiveness(timer, {
562
- send: (message) => send(socket, message),
563
- unresponsive: () => {
564
- socket.close(4001, "Relay liveness check timed out");
518
+ for (const pending of outbox.pending()) {
519
+ send(socket, pending);
520
+ }
521
+ try {
522
+ await new Promise((resolve, reject) => {
523
+ let finished = false;
524
+ const cleanup = () => {
525
+ connectionRefresh.close();
526
+ connectionLiveness.close();
527
+ signal.removeEventListener("abort", stop);
528
+ socket.removeEventListener("close", handleClose);
529
+ socket.removeEventListener("error", handleError);
530
+ socket.removeEventListener("message", handleMessage);
531
+ installationObserver.disconnect(socket);
532
+ connectionController.abort();
533
+ for (const turn of activeTurns.values()) {
534
+ turn.abortConnection();
535
+ }
536
+ activeTurns.clear();
537
+ };
538
+ const resolveConnection = () => {
539
+ if (finished) {
540
+ return;
541
+ }
542
+ finished = true;
543
+ cleanup();
544
+ resolve();
545
+ };
546
+ const rejectConnection = () => {
547
+ if (finished) {
548
+ return;
549
+ }
550
+ finished = true;
551
+ cleanup();
552
+ reject(new Error("Relay WebSocket failed"));
553
+ };
554
+ const stop = () => {
555
+ socket.close(1000, "Daemon stopped");
565
556
  resolveConnection();
566
- },
567
- });
568
- const connectionRefresh = new RelayConnectionRefresh(timer, () => activeTurns.size === 0, refreshConnection);
569
- signal.addEventListener("abort", stop, { once: true });
570
- const handleClose = () => {
571
- resolveConnection();
572
- };
573
- const handleError = () => {
574
- if (signal.aborted) {
557
+ };
558
+ const refreshConnection = () => {
559
+ socket.close(1000, "Refreshing idle relay connection");
575
560
  resolveConnection();
576
- return;
577
- }
578
- rejectConnection();
579
- };
580
- const handleMessage = (event) => {
581
- const encoded = event.data;
582
- if (typeof encoded !== "string") {
583
- socket.close(4003, "Text message required");
584
- rejectConnection();
585
- return;
586
- }
587
- try {
588
- const kind = decodeMessageKind(encoded);
589
- if (kind === RUNTIME_LIVENESS_READY_KIND) {
590
- decodeRuntimeLivenessReadyEvent(encoded);
591
- connectionLiveness.start();
561
+ };
562
+ const connectionLiveness = new RelayConnectionLiveness(timer, {
563
+ send: (message) => send(socket, message),
564
+ unresponsive: () => {
565
+ socket.close(4001, "Relay liveness check timed out");
566
+ resolveConnection();
567
+ },
568
+ });
569
+ const connectionRefresh = new RelayConnectionRefresh(timer, () => activeTurns.size === 0, refreshConnection);
570
+ signal.addEventListener("abort", stop, { once: true });
571
+ const handleClose = () => {
572
+ resolveConnection();
573
+ };
574
+ const handleError = () => {
575
+ if (signal.aborted) {
576
+ resolveConnection();
592
577
  return;
593
578
  }
594
- if (kind === RUNTIME_HEARTBEAT_ACK_KIND) {
595
- connectionLiveness.acknowledge(decodeRuntimeHeartbeatAckEvent(encoded));
579
+ rejectConnection();
580
+ };
581
+ const handleMessage = (event) => {
582
+ const encoded = event.data;
583
+ if (typeof encoded !== "string") {
584
+ socket.close(4003, "Text message required");
585
+ rejectConnection();
596
586
  return;
597
587
  }
598
- if (kind === SESSION_CANCEL_KIND) {
599
- const cancellation = decodeSessionCancelCommand(encoded);
600
- const turn = activeTurns.get(cancellation.commandId);
601
- if (turn === undefined || !turn.matches(cancellation)) {
602
- console.warn("Mobius daemon ignored cancellation for an inactive turn");
588
+ try {
589
+ const kind = decodeMessageKind(encoded);
590
+ if (kind === SESSION_EVENT_ACK_KIND) {
591
+ outbox.acknowledge(decodeSessionEventAcknowledgement(encoded));
603
592
  return;
604
593
  }
605
- if (!turn.requestCancellation()) {
594
+ if (kind === NATIVE_SESSION_CANCEL_KIND) {
595
+ const command = decodeNativeSessionCancel(encoded);
596
+ const pending = nativeRequests.get(command.requestId);
597
+ if (pending?.sessionId === command.sessionId)
598
+ pending.controller.abort(new AcpExecutionError("Native session operation cancelled", {}, "native_session_cancelled"));
606
599
  return;
607
600
  }
608
- audit.record({
609
- commandId: cancellation.commandId,
610
- event: "session_cancellation_requested",
611
- sessionId: cancellation.sessionId,
612
- });
613
- void sessions.cancelPrompt(cancellation.sessionId).catch((error) => {
614
- console.error("Mobius daemon could not cancel the agent turn", error);
615
- });
616
- return;
617
- }
618
- if (kind === WORKSPACE_LIST_KIND) {
619
- const command = decodeWorkspaceListCommand(encoded);
620
- void executeWorkspaceList(socket, command, directories, audit);
621
- return;
622
- }
623
- if (kind === SESSION_PREPARE_KIND) {
624
- const command = decodeSessionPrepareCommand(encoded);
625
- void executeSessionPrepare(socket, command, config, directories, audit, sessions, connectionController.signal);
626
- return;
627
- }
628
- if (kind === SESSION_CONFIGURE_KIND) {
629
- const command = decodeSessionConfigureCommand(encoded);
630
- void executeSessionConfigure(socket, command, config, directories, audit, sessions, connectionController.signal);
631
- return;
632
- }
633
- if (kind === SESSION_PERMISSION_RESPOND_KIND) {
634
- const command = decodeSessionPermissionRespondCommand(encoded);
635
- void sessions
636
- .respondPermission(command)
637
- .then(() => {
638
- audit.record({
639
- commandId: command.interactionId,
640
- event: "session_permission_resolved",
601
+ if (kind === NATIVE_SESSION_REQUEST_KIND) {
602
+ const command = decodeNativeSessionCommand(encoded);
603
+ const previous = [...nativeRequests.values()].filter((request) => request.agentId === command.agentId);
604
+ if (nativeRequests.has(command.requestId) ||
605
+ nativeRequests.size >= 4 ||
606
+ previous.some((request) => !request.controller.signal.aborted)) {
607
+ reportOperationFailure(socket, command.requestId, command.sessionId, new AcpExecutionError("Another native session operation is running", {}, "native_session_busy"));
608
+ return;
609
+ }
610
+ const controller = new AbortController();
611
+ const operationSignal = AbortSignal.any([
612
+ connectionController.signal,
613
+ controller.signal,
614
+ ]);
615
+ const timeout = timer.schedule(() => controller.abort(new AcpExecutionError("Native session operation timed out", {}, "native_session_timeout")), 90_000);
616
+ const completion = (async () => {
617
+ try {
618
+ operationSignal.throwIfAborted();
619
+ if (previous.length > 0) {
620
+ await new Promise((resolve, reject) => {
621
+ const cancel = () => reject(operationSignal.reason);
622
+ operationSignal.addEventListener("abort", cancel, {
623
+ once: true,
624
+ });
625
+ void Promise.all(previous.map((request) => request.completion)).then(() => {
626
+ operationSignal.removeEventListener("abort", cancel);
627
+ resolve();
628
+ }, (error) => {
629
+ operationSignal.removeEventListener("abort", cancel);
630
+ reject(error);
631
+ });
632
+ });
633
+ }
634
+ operationSignal.throwIfAborted();
635
+ const result = await nativeSessions.execute(command, operationSignal);
636
+ if (socket.readyState === WebSocket.OPEN)
637
+ send(socket, encodeNativeSessionResult(result));
638
+ }
639
+ catch (error) {
640
+ const failure = operationSignal.aborted
641
+ ? (controller.signal.reason ??
642
+ new AcpExecutionError("Native session operation cancelled", {}, "native_session_cancelled"))
643
+ : error;
644
+ audit.record({
645
+ commandId: command.requestId,
646
+ sessionId: command.sessionId,
647
+ event: "native_session_operation_failed",
648
+ details: { code: operationErrorCode(failure) },
649
+ });
650
+ reportOperationFailure(socket, command.requestId, command.sessionId, failure);
651
+ }
652
+ finally {
653
+ timeout.cancel();
654
+ nativeRequests.delete(command.requestId);
655
+ }
656
+ })();
657
+ nativeRequests.set(command.requestId, {
658
+ agentId: command.agentId,
641
659
  sessionId: command.sessionId,
660
+ controller,
661
+ completion,
642
662
  });
643
- })
644
- .catch((error) => {
645
- reportOperationFailure(socket, command.interactionId, command.sessionId, error);
646
- });
647
- return;
648
- }
649
- if (kind === SESSION_ELICITATION_RESPOND_KIND) {
650
- const command = decodeSessionElicitationRespondCommand(encoded);
651
- void sessions
652
- .respondElicitation(command)
653
- .then(() => {
663
+ return;
664
+ }
665
+ if (kind === RUNTIME_LIVENESS_READY_KIND) {
666
+ decodeRuntimeLivenessReadyEvent(encoded);
667
+ connectionLiveness.start();
668
+ return;
669
+ }
670
+ if (kind === RUNTIME_HEARTBEAT_ACK_KIND) {
671
+ connectionLiveness.acknowledge(decodeRuntimeHeartbeatAckEvent(encoded));
672
+ return;
673
+ }
674
+ if (kind === SESSION_CANCEL_KIND) {
675
+ const cancellation = decodeSessionCancelCommand(encoded);
676
+ const turn = activeTurns.get(cancellation.commandId);
677
+ if (turn === undefined || !turn.matches(cancellation)) {
678
+ console.warn("Mobius daemon ignored cancellation for an inactive turn");
679
+ return;
680
+ }
681
+ if (!turn.requestCancellation()) {
682
+ return;
683
+ }
654
684
  audit.record({
655
- commandId: command.interactionId,
656
- event: "session_elicitation_resolved",
657
- sessionId: command.sessionId,
685
+ commandId: cancellation.commandId,
686
+ event: "session_cancellation_requested",
687
+ sessionId: cancellation.sessionId,
658
688
  });
659
- })
660
- .catch((error) => {
661
- reportOperationFailure(socket, command.interactionId, command.sessionId, error);
662
- });
663
- return;
664
- }
665
- if (kind === AGENT_INSTALL_REQUEST_KIND) {
666
- const command = decodeAgentInstallRequestCommand(encoded);
667
- void installations
668
- .request(command, signal)
669
- .catch((error) => {
670
- console.error("Mobius Agent installation failed", error);
671
- });
672
- return;
673
- }
674
- if (kind === AGENT_INSTALL_CANCEL_KIND) {
675
- const command = decodeAgentInstallCancelCommand(encoded);
676
- void installations
677
- .cancel(command.requestId)
689
+ void sessions
690
+ .cancelPrompt(cancellation.sessionId)
691
+ .catch((error) => {
692
+ console.error("Mobius daemon could not cancel the agent turn", error);
693
+ });
694
+ return;
695
+ }
696
+ if (kind === WORKSPACE_LIST_KIND) {
697
+ const command = decodeWorkspaceListCommand(encoded);
698
+ void executeWorkspaceList(socket, command, directories, audit, connectionController.signal);
699
+ return;
700
+ }
701
+ if (kind === SESSION_PREPARE_KIND) {
702
+ const command = decodeSessionPrepareCommand(encoded);
703
+ void executeSessionPrepare(outbox, socket, command, config, directories, audit, sessions, connectionController.signal);
704
+ return;
705
+ }
706
+ if (kind === SESSION_CONFIGURE_KIND) {
707
+ const command = decodeSessionConfigureCommand(encoded);
708
+ void executeSessionConfigure(outbox, socket, command, config, directories, audit, sessions, connectionController.signal);
709
+ return;
710
+ }
711
+ if (kind === SESSION_PERMISSION_RESPOND_KIND) {
712
+ const command = decodeSessionPermissionRespondCommand(encoded);
713
+ void sessions
714
+ .respondPermission(command)
715
+ .then(() => {
716
+ audit.record({
717
+ commandId: command.interactionId,
718
+ event: "session_permission_resolved",
719
+ sessionId: command.sessionId,
720
+ });
721
+ })
722
+ .catch((error) => {
723
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error);
724
+ });
725
+ return;
726
+ }
727
+ if (kind === SESSION_ELICITATION_RESPOND_KIND) {
728
+ const command = decodeSessionElicitationRespondCommand(encoded);
729
+ void sessions
730
+ .respondElicitation(command)
731
+ .then(() => {
732
+ audit.record({
733
+ commandId: command.interactionId,
734
+ event: "session_elicitation_resolved",
735
+ sessionId: command.sessionId,
736
+ });
737
+ })
738
+ .catch((error) => {
739
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error);
740
+ });
741
+ return;
742
+ }
743
+ if (kind === AGENT_INSTALL_REQUEST_KIND) {
744
+ const command = decodeAgentInstallRequestCommand(encoded);
745
+ void installations
746
+ .request(command, signal)
747
+ .catch((error) => {
748
+ console.error("Mobius Agent installation failed", error);
749
+ });
750
+ return;
751
+ }
752
+ if (kind === AGENT_INSTALL_CANCEL_KIND) {
753
+ const command = decodeAgentInstallCancelCommand(encoded);
754
+ void installations
755
+ .cancel(command.requestId)
756
+ .catch((error) => {
757
+ reportOperationFailure(socket, command.requestId, "", error);
758
+ });
759
+ return;
760
+ }
761
+ if (kind !== SESSION_PROMPT_KIND) {
762
+ throw new Error("Unsupported protocol message");
763
+ }
764
+ const command = decodeSessionPromptCommand(encoded);
765
+ if (activeTurns.has(command.commandId)) {
766
+ return;
767
+ }
768
+ const receipt = outbox.claimExecution(command.commandId, command.sessionId, encoded);
769
+ if (receipt.kind === "duplicate") {
770
+ return;
771
+ }
772
+ const turn = new ActiveDaemonTurn(command, new AbortController());
773
+ activeTurns.set(command.commandId, turn);
774
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
775
+ void executePrompt(outbox, socket, command, config, directories, audit, sessions, receipt.attemptId, turn.signal)
678
776
  .catch((error) => {
679
- reportOperationFailure(socket, command.requestId, "", error);
777
+ console.error("Mobius daemon turn failed", error);
778
+ })
779
+ .finally(() => {
780
+ activeTurns.delete(command.commandId);
781
+ if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
782
+ activeAttemptIds.delete(command.sessionId);
783
+ }
784
+ connectionRefresh.afterTurnFinished();
680
785
  });
681
- return;
682
786
  }
683
- if (kind !== SESSION_PROMPT_KIND) {
684
- throw new Error("Unsupported protocol message");
787
+ catch (error) {
788
+ console.error("Mobius daemon rejected a message", error);
789
+ socket.close(4008, "Invalid protocol message");
790
+ rejectConnection();
685
791
  }
686
- const command = decodeSessionPromptCommand(encoded);
687
- if (activeTurns.has(command.commandId)) {
688
- reportFailure(socket, command, "duplicate_command", "The command is already running");
689
- return;
690
- }
691
- const turn = new ActiveDaemonTurn(command, new AbortController());
692
- activeTurns.set(command.commandId, turn);
693
- void executePrompt(socket, command, config, directories, audit, sessions, turn.signal)
694
- .catch((error) => {
695
- console.error("Mobius daemon turn failed", error);
696
- })
697
- .finally(() => {
698
- activeTurns.delete(command.commandId);
699
- connectionRefresh.afterTurnFinished();
700
- });
701
- }
702
- catch (error) {
703
- console.error("Mobius daemon rejected a message", error);
704
- socket.close(4008, "Invalid protocol message");
705
- rejectConnection();
792
+ };
793
+ socket.addEventListener("close", handleClose);
794
+ socket.addEventListener("error", handleError);
795
+ socket.addEventListener("message", handleMessage);
796
+ if (signal.aborted) {
797
+ stop();
706
798
  }
707
- };
708
- socket.addEventListener("close", handleClose);
709
- socket.addEventListener("error", handleError);
710
- socket.addEventListener("message", handleMessage);
711
- if (signal.aborted) {
712
- stop();
713
- }
714
- });
799
+ });
800
+ }
801
+ finally {
802
+ connectionController.abort();
803
+ await Promise.all([...nativeRequests.values()].map((request) => request.completion));
804
+ }
715
805
  }
716
806
  export async function runDaemon(config, audit, signal, timer = systemDaemonTimer) {
717
807
  const installationAudit = new AuditInstallationEvents(audit);
718
808
  const stateDirectory = readStateDirectory();
719
809
  const specifications = supportedLocalAgentSpecifications();
720
810
  const installationExecutor = new FixedInstallationExecutor({
721
- approvedRoot: config.approvedRoot,
811
+ defaultWorkspace: config.defaultWorkspace,
722
812
  audit: installationAudit,
723
813
  catalog: config.catalog,
724
814
  environment: process.env,
@@ -726,26 +816,27 @@ export async function runDaemon(config, audit, signal, timer = systemDaemonTimer
726
816
  stateDirectory,
727
817
  });
728
818
  await new AutomaticAdapterProvisioner({
729
- approvedRoot: config.approvedRoot,
819
+ defaultWorkspace: config.defaultWorkspace,
730
820
  audit: installationAudit,
731
821
  catalog: config.catalog,
732
822
  environment: process.env,
733
823
  }, new ManagedAdapterInstaller({
734
- approvedRoot: config.approvedRoot,
735
824
  environment: process.env,
736
825
  stateDirectory,
737
826
  }), specifications).prepare(signal);
738
827
  const sessionStore = new SqliteAcpSessionStore(config.auditDatabasePath);
828
+ const outbox = new SessionEventOutbox(config.auditDatabasePath);
739
829
  const sessions = new AcpSessionManager(new NullAcpSessionObserver(), sessionStore);
740
- const directories = new WorkspaceDirectoryService(config.bindingId, config.approvedRoot);
830
+ const directories = new WorkspaceDirectoryService(config.bindingId, config.defaultWorkspace);
741
831
  const installationObserver = new DaemonInstallationObserver();
832
+ const nativeSessions = new NativeSessionService(config, directories, sessions, audit);
742
833
  const installations = new AgentInstallationManager(specifications, new ConsoleInstallationAuthorizer(stateDirectory), installationExecutor, installationObserver, installationAudit);
743
834
  let retryAnnounced = false;
744
835
  try {
745
836
  while (!signal.aborted) {
746
837
  try {
747
838
  await publishAgentCatalog(config, signal);
748
- await runRelayConnection(config, directories, audit, sessions, installations, installationObserver, signal, timer);
839
+ await runRelayConnection(config, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, signal, timer);
749
840
  retryAnnounced = false;
750
841
  }
751
842
  catch {
@@ -769,7 +860,12 @@ export async function runDaemon(config, audit, signal, timer = systemDaemonTimer
769
860
  await sessions.close();
770
861
  }
771
862
  finally {
772
- sessionStore.close();
863
+ try {
864
+ sessionStore.close();
865
+ }
866
+ finally {
867
+ outbox.close();
868
+ }
773
869
  }
774
870
  }
775
871
  }