@moxt-ai/mobius 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/acp/native-session.d.ts +30 -0
  2. package/dist/acp/native-session.d.ts.map +1 -0
  3. package/dist/acp/native-session.js +25 -0
  4. package/dist/acp/native-session.js.map +1 -0
  5. package/dist/acp/session-history.d.ts +9 -0
  6. package/dist/acp/session-history.d.ts.map +1 -0
  7. package/dist/acp/session-history.js +69 -0
  8. package/dist/acp/session-history.js.map +1 -0
  9. package/dist/acp/session-manager.d.ts +16 -5
  10. package/dist/acp/session-manager.d.ts.map +1 -1
  11. package/dist/acp/session-manager.js +211 -12
  12. package/dist/acp/session-manager.js.map +1 -1
  13. package/dist/acp/session-store.d.ts +9 -0
  14. package/dist/acp/session-store.d.ts.map +1 -1
  15. package/dist/acp/session-store.js +43 -0
  16. package/dist/acp/session-store.js.map +1 -1
  17. package/dist/agent-catalog/discover-local-agents.d.ts +1 -1
  18. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  19. package/dist/agent-catalog/discover-local-agents.js +19 -30
  20. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  21. package/dist/agent-installation/automatic-adapter-provisioner.d.ts +1 -1
  22. package/dist/agent-installation/automatic-adapter-provisioner.d.ts.map +1 -1
  23. package/dist/agent-installation/automatic-adapter-provisioner.js +1 -1
  24. package/dist/agent-installation/automatic-adapter-provisioner.js.map +1 -1
  25. package/dist/agent-installation/fixed-installation-executor.d.ts +1 -1
  26. package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
  27. package/dist/agent-installation/fixed-installation-executor.js +9 -18
  28. package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
  29. package/dist/agent-installation/managed-adapter-installer.d.ts +0 -1
  30. package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
  31. package/dist/agent-installation/managed-adapter-installer.js +1 -3
  32. package/dist/agent-installation/managed-adapter-installer.js.map +1 -1
  33. package/dist/authorization/local-authorization-error.d.ts +5 -0
  34. package/dist/authorization/local-authorization-error.d.ts.map +1 -0
  35. package/dist/authorization/local-authorization-error.js +8 -0
  36. package/dist/authorization/local-authorization-error.js.map +1 -0
  37. package/dist/authorization/workspace-directory.d.ts +16 -5
  38. package/dist/authorization/workspace-directory.d.ts.map +1 -1
  39. package/dist/authorization/workspace-directory.js +109 -119
  40. package/dist/authorization/workspace-directory.js.map +1 -1
  41. package/dist/cli.js +1851 -543
  42. package/dist/cli.js.map +4 -4
  43. package/dist/config.d.ts +3 -3
  44. package/dist/config.d.ts.map +1 -1
  45. package/dist/config.js +7 -5
  46. package/dist/config.js.map +1 -1
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +1866 -593
  50. package/dist/index.js.map +4 -4
  51. package/dist/native-sessions/codex-history.d.ts +11 -0
  52. package/dist/native-sessions/codex-history.d.ts.map +1 -0
  53. package/dist/native-sessions/codex-history.js +223 -0
  54. package/dist/native-sessions/codex-history.js.map +1 -0
  55. package/dist/native-sessions/service.d.ts +14 -0
  56. package/dist/native-sessions/service.d.ts.map +1 -0
  57. package/dist/native-sessions/service.js +249 -0
  58. package/dist/native-sessions/service.js.map +1 -0
  59. package/dist/pairing/pair-local-machine.d.ts.map +1 -1
  60. package/dist/pairing/pair-local-machine.js +29 -26
  61. package/dist/pairing/pair-local-machine.js.map +1 -1
  62. package/dist/process/executable.d.ts +1 -1
  63. package/dist/process/executable.d.ts.map +1 -1
  64. package/dist/process/executable.js +3 -11
  65. package/dist/process/executable.js.map +1 -1
  66. package/dist/run-daemon.d.ts.map +1 -1
  67. package/dist/run-daemon.js +274 -193
  68. package/dist/run-daemon.js.map +1 -1
  69. package/package.json +3 -2
  70. package/dist/authorization/authorize-binding.d.ts +0 -6
  71. package/dist/authorization/authorize-binding.d.ts.map +0 -1
  72. package/dist/authorization/authorize-binding.js +0 -30
  73. package/dist/authorization/authorize-binding.js.map +0 -1
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ var createAcpClient = (handler) => client({ name: "mobius" }).onRequest(
22
22
  });
23
23
 
24
24
  // src/config.ts
25
+ import { join as join3 } from "node:path";
25
26
  import { fileURLToPath } from "node:url";
26
27
 
27
28
  // src/agent-catalog/local-agent.ts
@@ -31,7 +32,7 @@ import { realpathSync, statSync } from "node:fs";
31
32
  import { spawn } from "node:child_process";
32
33
  import { constants } from "node:fs";
33
34
  import { access, realpath, stat } from "node:fs/promises";
34
- import { isAbsolute, join, relative, resolve } from "node:path";
35
+ import { join, resolve } from "node:path";
35
36
  var DEFAULT_OUTPUT_LIMIT_BYTES = 16 * 1024;
36
37
  var PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS = 1e3;
37
38
  var PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS = 5e3;
@@ -55,9 +56,9 @@ var ExecutableIdentity = class {
55
56
  var ResolvedExecutable = class {
56
57
  identity;
57
58
  path;
58
- constructor(identity) {
59
- this.identity = identity;
60
- this.path = identity.realPath;
59
+ constructor(identity2) {
60
+ this.identity = identity2;
61
+ this.path = identity2.realPath;
61
62
  }
62
63
  };
63
64
  var ProcessExecutionError = class extends Error {
@@ -76,10 +77,6 @@ var ProcessResult = class {
76
77
  this.stdout = stdout;
77
78
  }
78
79
  };
79
- function isInside(root, candidate) {
80
- const difference = relative(root, candidate);
81
- return difference.length === 0 || !difference.startsWith("..") && !isAbsolute(difference);
82
- }
83
80
  function executableExtensions(executableName, environment, platform) {
84
81
  if (platform !== "win32") {
85
82
  return [""];
@@ -118,10 +115,9 @@ async function resolveExecutablePath(requestedPath, platform = process.platform)
118
115
  return null;
119
116
  }
120
117
  }
121
- async function findExecutableOnPath(executableName, environment, approvedRoot, platform = process.platform) {
118
+ async function findExecutableOnPath(executableName, environment, platform = process.platform) {
122
119
  const encodedPath = environment["PATH"] ?? "";
123
120
  const separator = platform === "win32" ? ";" : ":";
124
- const approvedRealPath = await realpath(resolve(approvedRoot));
125
121
  const extensions = executableExtensions(
126
122
  executableName,
127
123
  environment,
@@ -136,16 +132,16 @@ async function findExecutableOnPath(executableName, environment, approvedRoot, p
136
132
  join(entry, `${executableName}${extension}`)
137
133
  );
138
134
  const executable = await resolveExecutablePath(requestedPath, platform);
139
- if (executable !== null && !isInside(approvedRealPath, requestedPath) && !isInside(approvedRealPath, executable.path)) {
135
+ if (executable !== null) {
140
136
  return executable;
141
137
  }
142
138
  }
143
139
  }
144
140
  return null;
145
141
  }
146
- async function revalidateExecutable(identity, platform = process.platform) {
147
- const current = await resolveExecutablePath(identity.requestedPath, platform);
148
- return current !== null && identity.matches(current.identity);
142
+ async function revalidateExecutable(identity2, platform = process.platform) {
143
+ const current = await resolveExecutablePath(identity2.requestedPath, platform);
144
+ return current !== null && identity2.matches(current.identity);
149
145
  }
150
146
  function appendBounded(chunks, chunk, currentBytes, limitBytes) {
151
147
  const nextBytes = currentBytes + chunk.byteLength;
@@ -369,8 +365,8 @@ async function runBoundedProcess(options) {
369
365
  }
370
366
 
371
367
  // src/agent-catalog/local-agent.ts
372
- function readTrustedIdentity(path) {
373
- const resolvedPath = realpathSync(path);
368
+ function readTrustedIdentity(path2) {
369
+ const resolvedPath = realpathSync(path2);
374
370
  const metadata = statSync(resolvedPath);
375
371
  return new ExecutableIdentity(
376
372
  resolvedPath,
@@ -467,14 +463,26 @@ var LocalAgentCatalog = class {
467
463
  };
468
464
  };
469
465
 
466
+ // src/storage/state-directory.ts
467
+ import { homedir } from "node:os";
468
+ import { join as join2, resolve as resolve2 } from "node:path";
469
+ function readStateDirectory(environment = process.env) {
470
+ const configured = environment["MOBIUS_STATE_DIRECTORY"]?.trim();
471
+ if (configured !== void 0 && configured.length > 0) {
472
+ return resolve2(configured);
473
+ }
474
+ return join2(homedir(), ".mobius");
475
+ }
476
+
470
477
  // src/config.ts
471
- function loadApprovedRoot() {
472
- return process.env["MOBIUS_APPROVED_ROOT"] ?? process.cwd();
478
+ function loadDefaultWorkspace() {
479
+ const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = process.env;
480
+ return configuredWorkspace ?? join3(readStateDirectory(), "workspace");
473
481
  }
474
482
  function createDaemonConfig(connection, agents = [], installableAgents = []) {
475
483
  return {
476
484
  agents,
477
- approvedRoot: connection.approvedRoot,
485
+ defaultWorkspace: connection.defaultWorkspace,
478
486
  auditDatabasePath: connection.auditDatabasePath,
479
487
  bindingId: "workspace",
480
488
  catalog: new LocalAgentCatalog(agents, installableAgents),
@@ -498,7 +506,7 @@ function loadDaemonConfig() {
498
506
  }
499
507
  return createDaemonConfig(
500
508
  {
501
- approvedRoot: loadApprovedRoot(),
509
+ defaultWorkspace: loadDefaultWorkspace(),
502
510
  auditDatabasePath: (
503
511
  // biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
504
512
  process.env["MOBIUS_AUDIT_DATABASE"] ?? fileURLToPath(
@@ -1266,10 +1274,10 @@ function mergeDefs(...defs) {
1266
1274
  function cloneDef(schema) {
1267
1275
  return mergeDefs(schema._zod.def);
1268
1276
  }
1269
- function getElementAtPath(obj, path) {
1270
- if (!path)
1277
+ function getElementAtPath(obj, path2) {
1278
+ if (!path2)
1271
1279
  return obj;
1272
- return path.reduce((acc, key) => acc?.[key], obj);
1280
+ return path2.reduce((acc, key) => acc?.[key], obj);
1273
1281
  }
1274
1282
  function promiseAllObject(promisesObj) {
1275
1283
  const keys = Object.keys(promisesObj);
@@ -1681,11 +1689,11 @@ function explicitlyAborted(x, startIndex = 0) {
1681
1689
  }
1682
1690
  return false;
1683
1691
  }
1684
- function prefixIssues(path, issues) {
1692
+ function prefixIssues(path2, issues) {
1685
1693
  return issues.map((iss) => {
1686
1694
  var _a3;
1687
1695
  (_a3 = iss).path ?? (_a3.path = []);
1688
- iss.path.unshift(path);
1696
+ iss.path.unshift(path2);
1689
1697
  return iss;
1690
1698
  });
1691
1699
  }
@@ -2118,16 +2126,16 @@ function flattenError(error61, mapper = (issue2) => issue2.message) {
2118
2126
  }
2119
2127
  function formatError(error61, mapper = (issue2) => issue2.message) {
2120
2128
  const fieldErrors = { _errors: [] };
2121
- const processError = (error62, path = []) => {
2129
+ const processError = (error62, path2 = []) => {
2122
2130
  for (const issue2 of error62.issues) {
2123
2131
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2124
- issue2.errors.map((issues) => processError({ issues }, [...path, ...issue2.path]));
2132
+ issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path]));
2125
2133
  } else if (issue2.code === "invalid_key") {
2126
- processError({ issues: issue2.issues }, [...path, ...issue2.path]);
2134
+ processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
2127
2135
  } else if (issue2.code === "invalid_element") {
2128
- processError({ issues: issue2.issues }, [...path, ...issue2.path]);
2136
+ processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
2129
2137
  } else {
2130
- const fullpath = [...path, ...issue2.path];
2138
+ const fullpath = [...path2, ...issue2.path];
2131
2139
  if (fullpath.length === 0) {
2132
2140
  fieldErrors._errors.push(mapper(issue2));
2133
2141
  } else {
@@ -2166,17 +2174,17 @@ function formatError(error61, mapper = (issue2) => issue2.message) {
2166
2174
  }
2167
2175
  function treeifyError(error61, mapper = (issue2) => issue2.message) {
2168
2176
  const result = { errors: [] };
2169
- const processError = (error62, path = []) => {
2177
+ const processError = (error62, path2 = []) => {
2170
2178
  var _a3;
2171
2179
  for (const issue2 of error62.issues) {
2172
2180
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2173
- issue2.errors.map((issues) => processError({ issues }, [...path, ...issue2.path]));
2181
+ issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path]));
2174
2182
  } else if (issue2.code === "invalid_key") {
2175
- processError({ issues: issue2.issues }, [...path, ...issue2.path]);
2183
+ processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
2176
2184
  } else if (issue2.code === "invalid_element") {
2177
- processError({ issues: issue2.issues }, [...path, ...issue2.path]);
2185
+ processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
2178
2186
  } else {
2179
- const fullpath = [...path, ...issue2.path];
2187
+ const fullpath = [...path2, ...issue2.path];
2180
2188
  if (fullpath.length === 0) {
2181
2189
  result.errors.push(mapper(issue2));
2182
2190
  continue;
@@ -2215,8 +2223,8 @@ function treeifyError(error61, mapper = (issue2) => issue2.message) {
2215
2223
  }
2216
2224
  function toDotPath(_path) {
2217
2225
  const segs = [];
2218
- const path = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2219
- for (const seg of path) {
2226
+ const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2227
+ for (const seg of path2) {
2220
2228
  if (typeof seg === "number")
2221
2229
  segs.push(`[${seg}]`);
2222
2230
  else if (typeof seg === "symbol")
@@ -18726,13 +18734,13 @@ function resolveRef(ref, ctx) {
18726
18734
  if (!ref.startsWith("#")) {
18727
18735
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
18728
18736
  }
18729
- const path = ref.slice(1).split("/").filter(Boolean);
18730
- if (path.length === 0) {
18737
+ const path2 = ref.slice(1).split("/").filter(Boolean);
18738
+ if (path2.length === 0) {
18731
18739
  return ctx.rootSchema;
18732
18740
  }
18733
18741
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
18734
- if (path[0] === defsKey) {
18735
- const key = path[1] === void 0 ? void 0 : decodeJSONPointerSegment(path[1]);
18742
+ if (path2[0] === defsKey) {
18743
+ const key = path2[1] === void 0 ? void 0 : decodeJSONPointerSegment(path2[1]);
18736
18744
  if (!key || !ctx.defs[key]) {
18737
18745
  throw new Error(`Reference not found: ${ref}`);
18738
18746
  }
@@ -19388,6 +19396,56 @@ function date4(params) {
19388
19396
  return _coercedDate(ZodDate, params);
19389
19397
  }
19390
19398
 
19399
+ // ../protocol/src/prompt-usage.ts
19400
+ var TOKEN_COUNT = external_exports.number().int().nonnegative();
19401
+ var promptUsageSchema = external_exports.object({
19402
+ cachedReadTokens: TOKEN_COUNT.nullish(),
19403
+ cachedWriteTokens: TOKEN_COUNT.nullish(),
19404
+ inputTokens: TOKEN_COUNT,
19405
+ outputTokens: TOKEN_COUNT,
19406
+ thoughtTokens: TOKEN_COUNT.nullish(),
19407
+ totalTokens: TOKEN_COUNT
19408
+ }).readonly();
19409
+ var quotaTokenCountSchema = external_exports.object({
19410
+ cachedInputTokens: TOKEN_COUNT,
19411
+ cachedWriteTokens: TOKEN_COUNT.optional(),
19412
+ inputTokens: TOKEN_COUNT,
19413
+ outputTokens: TOKEN_COUNT,
19414
+ reasoningOutputTokens: TOKEN_COUNT,
19415
+ totalTokens: TOKEN_COUNT
19416
+ }).readonly();
19417
+ var promptMetadataSchema = external_exports.object({
19418
+ quota: external_exports.object({
19419
+ model_usage: external_exports.array(
19420
+ external_exports.object({
19421
+ model: external_exports.string().min(1).max(255),
19422
+ token_count: quotaTokenCountSchema
19423
+ }).readonly()
19424
+ ).max(100).readonly(),
19425
+ token_count: quotaTokenCountSchema.nullable()
19426
+ }).readonly().optional()
19427
+ }).readonly();
19428
+ var agentPromptResponseSchema = external_exports.object({
19429
+ _meta: promptMetadataSchema.nullish(),
19430
+ stopReason: external_exports.enum([
19431
+ "end_turn",
19432
+ "max_tokens",
19433
+ "max_turn_requests",
19434
+ "refusal",
19435
+ "cancelled"
19436
+ ]),
19437
+ usage: promptUsageSchema.nullish()
19438
+ }).readonly();
19439
+ function decodeAgentPromptResponse(value) {
19440
+ const result = agentPromptResponseSchema.safeParse(value);
19441
+ if (!result.success) {
19442
+ throw new ProtocolMessageError("Invalid agent prompt response", {
19443
+ cause: result.error
19444
+ });
19445
+ }
19446
+ return result.data;
19447
+ }
19448
+
19391
19449
  // ../protocol/src/version.ts
19392
19450
  var MOBIUS_PROTOCOL_VERSION = 1;
19393
19451
 
@@ -19454,7 +19512,8 @@ var sessionCapabilitiesSchema = external_exports.strictObject({
19454
19512
  imagePrompt: external_exports.boolean(),
19455
19513
  listSessions: external_exports.boolean(),
19456
19514
  loadSession: external_exports.boolean(),
19457
- resumeSession: external_exports.boolean()
19515
+ resumeSession: external_exports.boolean(),
19516
+ unstableForkSession: external_exports.boolean().default(false)
19458
19517
  }).readonly();
19459
19518
  var sessionCommandSchema = external_exports.strictObject({
19460
19519
  description: SHORT_TEXT,
@@ -19595,7 +19654,7 @@ var sessionConfigUpdatedEventSchema = external_exports.strictObject({
19595
19654
  requestId: IDENTIFIER,
19596
19655
  sessionId: IDENTIFIER
19597
19656
  }).readonly();
19598
- var sessionUsageUpdatedEventSchema = external_exports.strictObject({
19657
+ var sessionContextUsageUpdatedEventSchema = external_exports.strictObject({
19599
19658
  costAmount: external_exports.number().finite().nonnegative(),
19600
19659
  costCurrency: external_exports.string().max(16),
19601
19660
  hasCost: external_exports.boolean(),
@@ -19603,8 +19662,22 @@ var sessionUsageUpdatedEventSchema = external_exports.strictObject({
19603
19662
  protocolVersion: PROTOCOL_VERSION,
19604
19663
  sessionId: IDENTIFIER,
19605
19664
  size: external_exports.number().int().nonnegative(),
19665
+ source: external_exports.literal("context").default("context"),
19606
19666
  used: external_exports.number().int().nonnegative()
19607
19667
  }).readonly();
19668
+ var sessionPromptUsageUpdatedEventSchema = external_exports.strictObject({
19669
+ _meta: promptMetadataSchema.nullable(),
19670
+ commandId: IDENTIFIER,
19671
+ kind: external_exports.literal(SESSION_USAGE_UPDATED_KIND),
19672
+ protocolVersion: PROTOCOL_VERSION,
19673
+ sessionId: IDENTIFIER,
19674
+ source: external_exports.literal("prompt"),
19675
+ usage: promptUsageSchema.nullable()
19676
+ }).refine((event) => event.usage !== null || event._meta?.quota !== void 0).readonly();
19677
+ var sessionUsageUpdatedEventSchema = external_exports.union([
19678
+ sessionContextUsageUpdatedEventSchema,
19679
+ sessionPromptUsageUpdatedEventSchema
19680
+ ]);
19608
19681
  var sessionCommandsUpdatedEventSchema = external_exports.strictObject({
19609
19682
  commands: external_exports.array(sessionCommandSchema).max(500).readonly(),
19610
19683
  kind: external_exports.literal(SESSION_COMMANDS_UPDATED_KIND),
@@ -19615,7 +19688,7 @@ var sessionInfoUpdatedEventSchema = external_exports.strictObject({
19615
19688
  kind: external_exports.literal(SESSION_INFO_UPDATED_KIND),
19616
19689
  protocolVersion: PROTOCOL_VERSION,
19617
19690
  sessionId: IDENTIFIER,
19618
- title: external_exports.string().max(500),
19691
+ title: external_exports.string().max(500).nullable(),
19619
19692
  updatedAt: external_exports.string().max(128)
19620
19693
  }).readonly();
19621
19694
  var sessionPermissionRequestedEventSchema = external_exports.strictObject({
@@ -20192,6 +20265,160 @@ function encodeSessionFailedEvent(message) {
20192
20265
  return JSON.stringify(decodeSessionFailedEvent(JSON.stringify(message)));
20193
20266
  }
20194
20267
 
20268
+ // ../protocol/src/session-history.ts
20269
+ var SESSION_HISTORY_CHARACTER_LIMIT = 256e3;
20270
+ var SESSION_HISTORY_MESSAGE_LIMIT = 1e3;
20271
+ var SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT = 10;
20272
+ var SESSION_HISTORY_IMAGE_CHARACTER_LIMIT = 4e6;
20273
+ var historyImage = external_exports.strictObject({
20274
+ data: external_exports.string().min(4).max(SESSION_HISTORY_IMAGE_CHARACTER_LIMIT).refine(
20275
+ (data) => data.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(data)
20276
+ ),
20277
+ mimeType: external_exports.enum(["image/png", "image/jpeg", "image/gif", "image/webp"]),
20278
+ name: external_exports.string().min(1).max(500)
20279
+ }).readonly();
20280
+ function parseNativeHistoryText(text) {
20281
+ const images = [];
20282
+ let imageCharacters = 0;
20283
+ const plainText = text.replace(
20284
+ /\[@image\]\(([^)\r\n]*)(?:\)|$)/g,
20285
+ (_marker, uri) => {
20286
+ const header = /^data:(image\/[a-z+]+);base64,/.exec(uri);
20287
+ if (header === null) return "[Image unavailable]";
20288
+ const parsed = historyImage.safeParse({
20289
+ data: uri.slice(header[0].length),
20290
+ mimeType: header[1],
20291
+ name: `Image ${(images.length + 1).toString()}`
20292
+ });
20293
+ if (!parsed.success || images.length >= 8 || imageCharacters + parsed.data.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT)
20294
+ return "[Image unavailable]";
20295
+ images.push(parsed.data);
20296
+ imageCharacters += parsed.data.data.length;
20297
+ return "";
20298
+ }
20299
+ );
20300
+ return { text: plainText, images };
20301
+ }
20302
+ var historyMessage = external_exports.strictObject({
20303
+ role: external_exports.enum(["user", "assistant"]),
20304
+ text: external_exports.string().max(SESSION_HISTORY_CHARACTER_LIMIT),
20305
+ images: external_exports.array(historyImage).max(8).readonly().optional()
20306
+ }).readonly();
20307
+ var sessionHistorySchema = external_exports.discriminatedUnion("status", [
20308
+ external_exports.strictObject({
20309
+ status: external_exports.literal("available"),
20310
+ messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
20311
+ truncated: external_exports.boolean(),
20312
+ coveredCommandIds: external_exports.array(external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/)).max(1e4).readonly()
20313
+ }).readonly(),
20314
+ external_exports.strictObject({ status: external_exports.literal("unavailable") }).readonly()
20315
+ ]).refine(
20316
+ (history) => history.status === "unavailable" || history.messages.reduce(
20317
+ (total, message) => total + message.text.length,
20318
+ 0
20319
+ ) <= SESSION_HISTORY_CHARACTER_LIMIT && history.messages.reduce(
20320
+ (total, message) => total + (message.images ?? []).reduce(
20321
+ (size, image) => size + image.data.length,
20322
+ 0
20323
+ ),
20324
+ 0
20325
+ ) <= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT
20326
+ );
20327
+
20328
+ // ../protocol/src/native-sessions.ts
20329
+ var NATIVE_SESSION_REQUEST_KIND = "native.session.request";
20330
+ var NATIVE_SESSION_RESULT_KIND = "native.session.result";
20331
+ var NATIVE_SESSION_CANCEL_KIND = "native.session.cancel";
20332
+ var identifier = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/);
20333
+ var directoryId = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/);
20334
+ var envelope = {
20335
+ protocolVersion: external_exports.literal(MOBIUS_PROTOCOL_VERSION),
20336
+ requestId: identifier,
20337
+ sessionId: identifier
20338
+ };
20339
+ var identity = {
20340
+ ...envelope,
20341
+ kind: external_exports.literal(NATIVE_SESSION_REQUEST_KIND),
20342
+ additionalDirectoryIds: external_exports.array(directoryId).max(16).readonly(),
20343
+ agentId: identifier,
20344
+ bindingId: identifier,
20345
+ directoryId
20346
+ };
20347
+ var nativeSessionCommandSchema = external_exports.discriminatedUnion("action", [
20348
+ external_exports.strictObject({
20349
+ ...identity,
20350
+ action: external_exports.literal("list"),
20351
+ cursor: identifier.nullable()
20352
+ }).readonly(),
20353
+ external_exports.strictObject({
20354
+ ...identity,
20355
+ action: external_exports.enum(["import", "fork"]),
20356
+ entryId: identifier,
20357
+ targetSessionId: identifier
20358
+ }).readonly(),
20359
+ external_exports.strictObject({
20360
+ ...identity,
20361
+ action: external_exports.literal("delete"),
20362
+ entryId: identifier
20363
+ }).readonly()
20364
+ ]);
20365
+ var nativeSessionEntrySchema = external_exports.strictObject({
20366
+ entryId: identifier,
20367
+ title: external_exports.string().max(500),
20368
+ directoryId,
20369
+ directoryLabel: external_exports.string().min(1).max(2048),
20370
+ updatedAt: external_exports.iso.datetime({ offset: true }).nullable(),
20371
+ additionalDirectories: external_exports.array(
20372
+ external_exports.strictObject({ directoryId, name: external_exports.string().min(1).max(255) }).readonly()
20373
+ ).max(16).readonly()
20374
+ }).readonly();
20375
+ var resultEnvelope = {
20376
+ ...envelope,
20377
+ kind: external_exports.literal(NATIVE_SESSION_RESULT_KIND)
20378
+ };
20379
+ var nativeSessionResultSchema = external_exports.discriminatedUnion("action", [
20380
+ external_exports.strictObject({
20381
+ ...resultEnvelope,
20382
+ action: external_exports.literal("list"),
20383
+ capabilities: sessionCapabilitiesSchema,
20384
+ entries: external_exports.array(nativeSessionEntrySchema).max(500).readonly(),
20385
+ nextCursor: identifier.nullable()
20386
+ }).readonly(),
20387
+ external_exports.strictObject({
20388
+ ...resultEnvelope,
20389
+ action: external_exports.enum(["import", "fork"]),
20390
+ ready: sessionReadyEventSchema,
20391
+ history: sessionHistorySchema,
20392
+ title: external_exports.string().max(500)
20393
+ }).readonly(),
20394
+ external_exports.strictObject({
20395
+ ...resultEnvelope,
20396
+ action: external_exports.literal("preview"),
20397
+ entryId: identifier,
20398
+ reason: external_exports.literal("continuation_unavailable"),
20399
+ history: sessionHistorySchema,
20400
+ title: external_exports.string().max(500)
20401
+ }).readonly(),
20402
+ external_exports.strictObject({
20403
+ ...resultEnvelope,
20404
+ action: external_exports.literal("delete"),
20405
+ entryId: identifier,
20406
+ deletedSessionIds: external_exports.array(identifier).max(500).readonly()
20407
+ }).readonly()
20408
+ ]);
20409
+ var nativeSessionCancelSchema = external_exports.strictObject({ ...envelope, kind: external_exports.literal(NATIVE_SESSION_CANCEL_KIND) }).readonly();
20410
+ function decode4(schema, encoded) {
20411
+ try {
20412
+ const value = JSON.parse(encoded);
20413
+ return schema.parse(value);
20414
+ } catch (cause) {
20415
+ throw new ProtocolMessageError("Invalid native session message", { cause });
20416
+ }
20417
+ }
20418
+ var decodeNativeSessionCommand = (encoded) => decode4(nativeSessionCommandSchema, encoded);
20419
+ var encodeNativeSessionResult = (value) => JSON.stringify(nativeSessionResultSchema.parse(value));
20420
+ var decodeNativeSessionCancel = (encoded) => decode4(nativeSessionCancelSchema, encoded);
20421
+
20195
20422
  // src/acp/activity.ts
20196
20423
  var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
20197
20424
  function isRecord2(value) {
@@ -20430,15 +20657,15 @@ var AcpActivityTracker = class {
20430
20657
  await this.finishNarrative();
20431
20658
  }
20432
20659
  const previous = this.#activities.get(key);
20433
- const identity = this.#identity(key);
20660
+ const identity2 = this.#identity(key);
20434
20661
  const activity = new AcpActivity(
20435
- identity.id,
20662
+ identity2.id,
20436
20663
  activityType,
20437
20664
  "",
20438
20665
  [],
20439
20666
  "",
20440
20667
  truncate(`${previous?.output ?? ""}${text}`, AGENT_ACTIVITY_DETAIL_LIMIT),
20441
- identity.sequence,
20668
+ identity2.sequence,
20442
20669
  "running",
20443
20670
  activityType === "reasoning" ? "Reasoning" : "Progress update",
20444
20671
  activityType === "reasoning" ? "think" : ""
@@ -20458,18 +20685,18 @@ var AcpActivityTracker = class {
20458
20685
  await this.#recordPlanEntries(key, plan.entries);
20459
20686
  return;
20460
20687
  }
20461
- const identity = this.#identity(key);
20688
+ const identity2 = this.#identity(key);
20462
20689
  const output2 = plan.type === "markdown" ? plan.content : `Plan file: ${plan.uri}`;
20463
20690
  await this.#record(
20464
20691
  key,
20465
20692
  new AcpActivity(
20466
- identity.id,
20693
+ identity2.id,
20467
20694
  "plan",
20468
20695
  "",
20469
20696
  [],
20470
20697
  "",
20471
20698
  truncate(output2, AGENT_ACTIVITY_DETAIL_LIMIT),
20472
- identity.sequence,
20699
+ identity2.sequence,
20473
20700
  "running",
20474
20701
  "Plan",
20475
20702
  ""
@@ -20502,18 +20729,18 @@ var AcpActivityTracker = class {
20502
20729
  recordToolCall = async (update) => {
20503
20730
  await this.finishNarrative();
20504
20731
  const key = `tool:${update.toolCallId}`;
20505
- const identity = this.#identity(key);
20732
+ const identity2 = this.#identity(key);
20506
20733
  const output2 = update.rawOutput === void 0 ? readContentOutput(update.content) : formatUnknown(update.rawOutput);
20507
20734
  await this.#record(
20508
20735
  key,
20509
20736
  new AcpActivity(
20510
- identity.id,
20737
+ identity2.id,
20511
20738
  "tool",
20512
20739
  update.rawInput === void 0 ? "" : formatUnknown(update.rawInput),
20513
20740
  normalizeLocations(update.locations ?? []),
20514
20741
  truncate(update.name ?? "", 128),
20515
20742
  output2,
20516
- identity.sequence,
20743
+ identity2.sequence,
20517
20744
  normalizeToolStatus(update.status ?? "pending", "pending"),
20518
20745
  normalizeTitle(update.title, "Tool call"),
20519
20746
  update.kind ?? "other",
@@ -20525,19 +20752,19 @@ var AcpActivityTracker = class {
20525
20752
  await this.finishNarrative();
20526
20753
  const key = `tool:${update.toolCallId}`;
20527
20754
  const previous = this.#activities.get(key);
20528
- const identity = this.#identity(key);
20755
+ const identity2 = this.#identity(key);
20529
20756
  const output2 = update.rawOutput !== void 0 ? formatUnknown(update.rawOutput) : update.content !== void 0 && update.content !== null ? readContentOutput(update.content) : previous?.output ?? "";
20530
20757
  const content = update.content === void 0 || update.content === null ? previous?.content ?? [] : normalizeToolContent(update.content);
20531
20758
  await this.#record(
20532
20759
  key,
20533
20760
  new AcpActivity(
20534
- identity.id,
20761
+ identity2.id,
20535
20762
  "tool",
20536
20763
  update.rawInput === void 0 ? previous?.input ?? "" : formatUnknown(update.rawInput),
20537
20764
  update.locations === void 0 || update.locations === null ? previous?.locations ?? [] : normalizeLocations(update.locations),
20538
20765
  update.name === void 0 || update.name === null ? previous?.name ?? "" : truncate(update.name, 128),
20539
20766
  output2,
20540
- identity.sequence,
20767
+ identity2.sequence,
20541
20768
  update.status === void 0 || update.status === null ? previous?.status ?? "pending" : normalizeToolStatus(update.status, previous?.status ?? "pending"),
20542
20769
  update.title === void 0 || update.title === null ? previous?.title ?? "Tool call" : normalizeTitle(update.title, "Tool call"),
20543
20770
  update.kind === void 0 || update.kind === null ? previous?.toolKind ?? "other" : update.kind,
@@ -20577,30 +20804,30 @@ var AcpActivityTracker = class {
20577
20804
  if (existing !== void 0) {
20578
20805
  return existing;
20579
20806
  }
20580
- const identity = new ActivityIdentity(
20807
+ const identity2 = new ActivityIdentity(
20581
20808
  `activity-${crypto.randomUUID()}`,
20582
20809
  this.#nextSequence
20583
20810
  );
20584
20811
  this.#nextSequence += 1;
20585
- this.#identities.set(key, identity);
20586
- return identity;
20812
+ this.#identities.set(key, identity2);
20813
+ return identity2;
20587
20814
  };
20588
20815
  #record = async (key, activity) => {
20589
20816
  this.#activities.set(key, activity);
20590
20817
  await this.#onActivity(activity);
20591
20818
  };
20592
20819
  #recordPlanEntries = async (key, entries) => {
20593
- const identity = this.#identity(key);
20820
+ const identity2 = this.#identity(key);
20594
20821
  await this.#record(
20595
20822
  key,
20596
20823
  new AcpActivity(
20597
- identity.id,
20824
+ identity2.id,
20598
20825
  "plan",
20599
20826
  "",
20600
20827
  [],
20601
20828
  "",
20602
20829
  formatPlanEntries(entries),
20603
- identity.sequence,
20830
+ identity2.sequence,
20604
20831
  planStatus(entries),
20605
20832
  "Plan",
20606
20833
  ""
@@ -20609,6 +20836,88 @@ var AcpActivityTracker = class {
20609
20836
  };
20610
20837
  };
20611
20838
 
20839
+ // src/acp/native-session.ts
20840
+ var path = external_exports.string().min(1).max(2048).refine((value) => !value.includes("\0"));
20841
+ var nativeSessionIdSchema = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,255}$/);
20842
+ var nativeSessionInfoSchema = external_exports.object({
20843
+ sessionId: nativeSessionIdSchema,
20844
+ cwd: path,
20845
+ additionalDirectories: external_exports.array(path).max(16).default([]).readonly(),
20846
+ title: external_exports.string().max(500).nullish(),
20847
+ updatedAt: external_exports.iso.datetime({ offset: true }).nullish()
20848
+ }).readonly();
20849
+ var nativeSessionPageSchema = external_exports.object({
20850
+ sessions: external_exports.array(nativeSessionInfoSchema).max(500).readonly(),
20851
+ nextCursor: external_exports.string().min(1).max(4096).nullish()
20852
+ }).readonly();
20853
+
20854
+ // src/acp/session-history.ts
20855
+ var AcpHistoryReplay = class {
20856
+ #messages = [];
20857
+ #lastMessageId = null;
20858
+ #characters = 0;
20859
+ #imageCharacters = 0;
20860
+ #truncated = false;
20861
+ record = (update) => {
20862
+ if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk")
20863
+ return;
20864
+ if (update.sessionUpdate === "agent_message_chunk" && isProgressMessage(update))
20865
+ return;
20866
+ const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
20867
+ const content = update.content;
20868
+ const parsed = parseNativeHistoryText(
20869
+ content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
20870
+ );
20871
+ const text = parsed.text;
20872
+ if (text.length === 0 && parsed.images.length === 0) return;
20873
+ const previous = this.#messages.at(-1);
20874
+ const id = update.messageId ?? null;
20875
+ const continuation = previous?.role === role && id === this.#lastMessageId;
20876
+ const combined = continuation ? `${previous.text}${text}` : text;
20877
+ const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
20878
+ const images = allImages.slice(0, 8);
20879
+ this.#truncated ||= images.length < allImages.length;
20880
+ if (continuation) {
20881
+ this.#messages.pop();
20882
+ this.#characters -= previous.text.length;
20883
+ this.#imageCharacters -= (previous.images ?? []).reduce(
20884
+ (size, image) => size + image.data.length,
20885
+ 0
20886
+ );
20887
+ }
20888
+ const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
20889
+ this.#truncated ||= bounded.length < combined.length;
20890
+ this.#messages.push({
20891
+ role,
20892
+ text: bounded,
20893
+ ...images.length > 0 ? { images } : {}
20894
+ });
20895
+ this.#characters += bounded.length;
20896
+ this.#imageCharacters += images.reduce(
20897
+ (size, image) => size + image.data.length,
20898
+ 0
20899
+ );
20900
+ this.#lastMessageId = id;
20901
+ while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT || this.#imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
20902
+ const removed = this.#messages.shift();
20903
+ if (removed !== void 0) {
20904
+ this.#characters -= removed.text.length;
20905
+ this.#imageCharacters -= (removed.images ?? []).reduce(
20906
+ (size, image) => size + image.data.length,
20907
+ 0
20908
+ );
20909
+ }
20910
+ this.#truncated = true;
20911
+ }
20912
+ };
20913
+ snapshot = () => ({
20914
+ status: "available",
20915
+ messages: [...this.#messages],
20916
+ truncated: this.#truncated,
20917
+ coveredCommandIds: []
20918
+ });
20919
+ };
20920
+
20612
20921
  // src/acp/session-store.ts
20613
20922
  import { mkdirSync } from "node:fs";
20614
20923
  import { dirname } from "node:path";
@@ -20642,6 +20951,9 @@ var FoundAcpStoredSession = class extends AcpStoredSessionLookup {
20642
20951
  this.session = session;
20643
20952
  }
20644
20953
  };
20954
+ var DeletedAcpStoredSession = class extends AcpStoredSessionLookup {
20955
+ found = false;
20956
+ };
20645
20957
  function readString2(value, field) {
20646
20958
  if (typeof value !== "string" || value.length === 0) {
20647
20959
  throw new Error(`Stored ACP session has an invalid ${field}`);
@@ -20682,7 +20994,22 @@ function decodeSessionRow(row) {
20682
20994
  }
20683
20995
  var MemoryAcpSessionStore = class {
20684
20996
  #sessions = /* @__PURE__ */ new Map();
20997
+ #deleted = /* @__PURE__ */ new Set();
20998
+ findNative = (agentId, nativeSessionId) => [...this.#sessions.values()].filter(
20999
+ (session) => session.agentId === agentId && session.nativeSessionId === nativeSessionId
21000
+ );
21001
+ markDeleted = (agentId, nativeSessionId) => {
21002
+ const ids = this.findNative(agentId, nativeSessionId).map(
21003
+ (session) => session.sessionId
21004
+ );
21005
+ for (const id of ids) {
21006
+ this.#sessions.delete(id);
21007
+ this.#deleted.add(id);
21008
+ }
21009
+ return ids;
21010
+ };
20685
21011
  read = (sessionId) => {
21012
+ if (this.#deleted.has(sessionId)) return new DeletedAcpStoredSession();
20686
21013
  const session = this.#sessions.get(sessionId);
20687
21014
  return session === void 0 ? new MissingAcpStoredSession() : new FoundAcpStoredSession(session);
20688
21015
  };
@@ -20695,10 +21022,11 @@ var MemoryAcpSessionStore = class {
20695
21022
  };
20696
21023
  var SqliteAcpSessionStore = class {
20697
21024
  #database;
20698
- constructor(path) {
20699
- mkdirSync(dirname(path), { recursive: true });
20700
- this.#database = new DatabaseSync(path);
21025
+ constructor(path2) {
21026
+ mkdirSync(dirname(path2), { recursive: true });
21027
+ this.#database = new DatabaseSync(path2);
20701
21028
  this.#database.exec(`
21029
+ CREATE TABLE IF NOT EXISTS acp_deleted_sessions (session_id TEXT PRIMARY KEY) STRICT;
20702
21030
  CREATE TABLE IF NOT EXISTS acp_sessions (
20703
21031
  session_id TEXT PRIMARY KEY,
20704
21032
  agent_id TEXT NOT NULL,
@@ -20721,6 +21049,10 @@ var SqliteAcpSessionStore = class {
20721
21049
  }
20722
21050
  }
20723
21051
  read = (sessionId) => {
21052
+ if (this.#database.prepare(
21053
+ "SELECT session_id FROM acp_deleted_sessions WHERE session_id = ?"
21054
+ ).get(sessionId) !== void 0)
21055
+ return new DeletedAcpStoredSession();
20724
21056
  const row = this.#database.prepare(
20725
21057
  `
20726
21058
  SELECT
@@ -20739,6 +21071,28 @@ var SqliteAcpSessionStore = class {
20739
21071
  remove = (sessionId) => {
20740
21072
  this.#database.prepare("DELETE FROM acp_sessions WHERE session_id = ?").run(sessionId);
20741
21073
  };
21074
+ findNative = (agentId, nativeSessionId) => this.#database.prepare(
21075
+ "SELECT * FROM acp_sessions WHERE agent_id = ? AND native_session_id = ?"
21076
+ ).all(agentId, nativeSessionId).map(decodeSessionRow);
21077
+ markDeleted = (agentId, nativeSessionId) => {
21078
+ const ids = this.findNative(agentId, nativeSessionId).map(
21079
+ (session) => session.sessionId
21080
+ );
21081
+ this.#database.exec("BEGIN");
21082
+ try {
21083
+ for (const id of ids) {
21084
+ this.#database.prepare(
21085
+ "INSERT OR IGNORE INTO acp_deleted_sessions (session_id) VALUES (?)"
21086
+ ).run(id);
21087
+ this.remove(id);
21088
+ }
21089
+ this.#database.exec("COMMIT");
21090
+ return ids;
21091
+ } catch (error61) {
21092
+ this.#database.exec("ROLLBACK");
21093
+ throw error61;
21094
+ }
21095
+ };
20742
21096
  write = (session) => {
20743
21097
  this.#database.prepare(
20744
21098
  `
@@ -20868,7 +21222,7 @@ function createWritableAcpStream(output2) {
20868
21222
  if (outputFailure !== void 0) {
20869
21223
  return Promise.reject(outputFailure);
20870
21224
  }
20871
- return new Promise((resolve6, reject) => {
21225
+ return new Promise((resolve5, reject) => {
20872
21226
  pendingWriteFailures.add(reject);
20873
21227
  output2.write(chunk, (error61) => {
20874
21228
  pendingWriteFailures.delete(reject);
@@ -20881,7 +21235,7 @@ function createWritableAcpStream(output2) {
20881
21235
  reject(outputFailure);
20882
21236
  return;
20883
21237
  }
20884
- resolve6();
21238
+ resolve5();
20885
21239
  });
20886
21240
  });
20887
21241
  }
@@ -21042,7 +21396,8 @@ function normalizeCapabilities(capabilities) {
21042
21396
  imagePrompt: prompt?.image === true,
21043
21397
  listSessions: session?.list != null,
21044
21398
  loadSession: capabilities.loadSession === true,
21045
- resumeSession: session?.resume != null
21399
+ resumeSession: session?.resume != null,
21400
+ unstableForkSession: session?.fork != null
21046
21401
  };
21047
21402
  }
21048
21403
  function elicitationFieldType(value) {
@@ -21390,15 +21745,18 @@ var AcpProcessSession = class _AcpProcessSession {
21390
21745
  imagePrompt: false,
21391
21746
  listSessions: false,
21392
21747
  loadSession: false,
21393
- resumeSession: false
21748
+ resumeSession: false,
21749
+ unstableForkSession: false
21394
21750
  };
21395
21751
  #commands = [];
21396
21752
  #configOptions = [];
21397
21753
  #nativeSessionId = "";
21398
21754
  #prompted = false;
21399
- #replaying = false;
21755
+ #replay = {
21756
+ kind: "idle"
21757
+ };
21400
21758
  #restored = false;
21401
- #sessionTitle = "";
21759
+ #sessionTitle = null;
21402
21760
  #sessionUpdatedAt = "";
21403
21761
  #turn = new IdleAcpTurn();
21404
21762
  #updateTail = Promise.resolve();
@@ -21427,9 +21785,9 @@ var AcpProcessSession = class _AcpProcessSession {
21427
21785
  stderr.on("data", (chunk) => {
21428
21786
  process.stderr.write(`[${agent.id}-acp] ${chunk}`);
21429
21787
  });
21430
- this.#processExit = new Promise((resolve6) => {
21431
- this.#child.once("error", resolve6);
21432
- this.#child.once("exit", resolve6);
21788
+ this.#processExit = new Promise((resolve5) => {
21789
+ this.#child.once("error", resolve5);
21790
+ this.#child.once("exit", resolve5);
21433
21791
  });
21434
21792
  const stream = ndJsonStream(
21435
21793
  createWritableAcpStream(stdin),
@@ -21460,10 +21818,11 @@ var AcpProcessSession = class _AcpProcessSession {
21460
21818
  store
21461
21819
  );
21462
21820
  try {
21463
- await runtime.initialize(options.signal);
21821
+ await runtime.initialize(options.signal, options.origin);
21464
21822
  return runtime;
21465
21823
  } catch (error61) {
21466
21824
  await runtime.closeProcess();
21825
+ options.signal.throwIfAborted();
21467
21826
  if (error61 instanceof AcpExecutionError) {
21468
21827
  throw error61;
21469
21828
  }
@@ -21482,7 +21841,33 @@ var AcpProcessSession = class _AcpProcessSession {
21482
21841
  this.#configOptions,
21483
21842
  this.#restored
21484
21843
  );
21485
- initialize = async (signal) => {
21844
+ loadHistory = async (signal) => {
21845
+ if (!this.#capabilities.loadSession) return { status: "unavailable" };
21846
+ const history = new AcpHistoryReplay();
21847
+ this.#replay = { kind: "capture", history };
21848
+ try {
21849
+ await this.race(
21850
+ this.#connection.agent.request(
21851
+ methods2.agent.session.load,
21852
+ {
21853
+ additionalDirectories: [...this.#additionalDirectories],
21854
+ cwd: this.#cwd,
21855
+ mcpServers: [],
21856
+ sessionId: this.#nativeSessionId
21857
+ },
21858
+ { cancellationSignal: signal }
21859
+ ),
21860
+ "ACP agent exited while loading history",
21861
+ signal
21862
+ );
21863
+ await this.#updateTail;
21864
+ signal.throwIfAborted();
21865
+ return history.snapshot();
21866
+ } finally {
21867
+ this.#replay = { kind: "idle" };
21868
+ }
21869
+ };
21870
+ initialize = async (signal, origin) => {
21486
21871
  const initialized = await this.race(
21487
21872
  this.#connection.agent.request(
21488
21873
  methods2.agent.initialize,
@@ -21514,9 +21899,56 @@ var AcpProcessSession = class _AcpProcessSession {
21514
21899
  255
21515
21900
  );
21516
21901
  this.#agentVersion = truncate2(initialized.agentInfo?.version ?? "", 128);
21517
- const stored = this.#store.read(this.#mobiusSessionId);
21902
+ const stored = origin?.kind === "import" ? new FoundAcpStoredSession(
21903
+ new AcpStoredSession(
21904
+ this.#mobiusSessionId,
21905
+ this.#agentId,
21906
+ nativeSessionIdSchema.parse(origin.nativeSessionId),
21907
+ this.#cwd,
21908
+ this.#additionalDirectories,
21909
+ true
21910
+ )
21911
+ ) : this.#store.read(this.#mobiusSessionId);
21912
+ if (stored instanceof DeletedAcpStoredSession)
21913
+ throw new AcpExecutionError(
21914
+ "The native Agent session was deleted. Start a new chat.",
21915
+ {},
21916
+ "native_session_deleted"
21917
+ );
21518
21918
  let lifecycleResponse;
21519
- if (stored instanceof FoundAcpStoredSession && stored.session.agentId === this.#agentId && stored.session.cwd === this.#cwd && arraysEqual(
21919
+ if (origin?.kind === "fork") {
21920
+ if (!this.#capabilities.unstableForkSession)
21921
+ throw new AcpExecutionError(
21922
+ "This Agent does not support session forking",
21923
+ {},
21924
+ "native_session_unsupported"
21925
+ );
21926
+ const forked = await this.race(
21927
+ this.#connection.agent.request(
21928
+ methods2.agent.session.fork,
21929
+ {
21930
+ sessionId: nativeSessionIdSchema.parse(origin.nativeSessionId),
21931
+ cwd: this.#cwd,
21932
+ additionalDirectories: [...this.#additionalDirectories],
21933
+ mcpServers: []
21934
+ },
21935
+ { cancellationSignal: signal }
21936
+ ),
21937
+ "ACP agent exited while forking a session",
21938
+ signal
21939
+ );
21940
+ this.#nativeSessionId = nativeSessionIdSchema.parse(forked.sessionId);
21941
+ if (this.#nativeSessionId === origin.nativeSessionId || this.#store.findNative(this.#agentId, this.#nativeSessionId).length > 0) {
21942
+ throw new AcpExecutionError(
21943
+ "The Agent did not create an independent fork",
21944
+ {},
21945
+ "invalid_native_session_response"
21946
+ );
21947
+ }
21948
+ this.#prompted = true;
21949
+ this.#restored = true;
21950
+ lifecycleResponse = forked;
21951
+ } else if (stored instanceof FoundAcpStoredSession && stored.session.agentId === this.#agentId && stored.session.cwd === this.#cwd && arraysEqual(
21520
21952
  stored.session.additionalDirectories,
21521
21953
  this.#additionalDirectories
21522
21954
  )) {
@@ -21539,7 +21971,7 @@ var AcpProcessSession = class _AcpProcessSession {
21539
21971
  signal
21540
21972
  );
21541
21973
  } else if (this.#capabilities.loadSession) {
21542
- this.#replaying = true;
21974
+ this.#replay = { kind: "discard" };
21543
21975
  try {
21544
21976
  lifecycleResponse = await this.race(
21545
21977
  this.#connection.agent.request(
@@ -21556,7 +21988,8 @@ var AcpProcessSession = class _AcpProcessSession {
21556
21988
  signal
21557
21989
  );
21558
21990
  } finally {
21559
- this.#replaying = false;
21991
+ await this.#updateTail;
21992
+ this.#replay = { kind: "idle" };
21560
21993
  }
21561
21994
  } else {
21562
21995
  throw new AcpExecutionError(
@@ -21609,7 +22042,60 @@ var AcpProcessSession = class _AcpProcessSession {
21609
22042
  );
21610
22043
  await this.#updateTail;
21611
22044
  signal.throwIfAborted();
22045
+ this.#store.write(
22046
+ new AcpStoredSession(
22047
+ this.#mobiusSessionId,
22048
+ this.#agentId,
22049
+ this.#nativeSessionId,
22050
+ this.#cwd,
22051
+ this.#additionalDirectories,
22052
+ this.#prompted
22053
+ )
22054
+ );
22055
+ };
22056
+ listNativeSessions = async (cursor, signal) => {
22057
+ if (!this.#capabilities.listSessions)
22058
+ throw new AcpExecutionError(
22059
+ "This Agent does not support native session listing",
22060
+ {},
22061
+ "native_session_unsupported"
22062
+ );
22063
+ const response = await this.race(
22064
+ this.#connection.agent.request(
22065
+ methods2.agent.session.list,
22066
+ cursor === null ? {} : { cursor },
22067
+ { cancellationSignal: signal }
22068
+ ),
22069
+ "ACP agent exited while listing sessions",
22070
+ signal
22071
+ );
22072
+ const decoded = nativeSessionPageSchema.safeParse(response);
22073
+ if (!decoded.success)
22074
+ throw new AcpExecutionError(
22075
+ "The Agent returned an invalid native session list",
22076
+ { cause: decoded.error },
22077
+ "invalid_native_session_response"
22078
+ );
22079
+ return decoded.data;
21612
22080
  };
22081
+ deleteNativeSession = async (nativeSessionId, signal) => {
22082
+ if (!this.#capabilities.deleteSession || !this.#capabilities.listSessions)
22083
+ throw new AcpExecutionError(
22084
+ "This Agent does not support native session deletion",
22085
+ {},
22086
+ "native_session_unsupported"
22087
+ );
22088
+ await this.race(
22089
+ this.#connection.agent.request(
22090
+ methods2.agent.session.delete,
22091
+ { sessionId: nativeSessionIdSchema.parse(nativeSessionId) },
22092
+ { cancellationSignal: signal }
22093
+ ),
22094
+ "ACP agent exited while deleting a session",
22095
+ signal
22096
+ );
22097
+ };
22098
+ nativeSessionId = () => this.#nativeSessionId;
21613
22099
  configure = async (options) => {
21614
22100
  const existing = this.#configOptions.find(
21615
22101
  (option) => option.id === options.configId
@@ -21772,7 +22258,28 @@ var AcpProcessSession = class _AcpProcessSession {
21772
22258
  );
21773
22259
  await this.#updateTail;
21774
22260
  await running.activities.finish();
21775
- return { stopReason: response.stopReason };
22261
+ let result;
22262
+ try {
22263
+ result = decodeAgentPromptResponse(response);
22264
+ } catch (cause) {
22265
+ throw new AcpExecutionError(
22266
+ "ACP agent returned an invalid prompt response",
22267
+ { cause },
22268
+ "acp_invalid_prompt_response"
22269
+ );
22270
+ }
22271
+ if (result.usage != null || result._meta?.quota !== void 0) {
22272
+ await this.#getObserver().onUsage({
22273
+ _meta: result._meta ?? null,
22274
+ commandId: options.commandId,
22275
+ kind: SESSION_USAGE_UPDATED_KIND,
22276
+ protocolVersion: MOBIUS_PROTOCOL_VERSION,
22277
+ sessionId: this.#mobiusSessionId,
22278
+ source: "prompt",
22279
+ usage: result.usage ?? null
22280
+ });
22281
+ }
22282
+ return result;
21776
22283
  } catch (error61) {
21777
22284
  await running.activities.finish();
21778
22285
  if (error61 instanceof AcpExecutionError) {
@@ -21992,7 +22499,8 @@ var AcpProcessSession = class _AcpProcessSession {
21992
22499
  processUpdate = async (notification) => {
21993
22500
  this.assertNativeSession(notification.sessionId);
21994
22501
  const update = notification.update;
21995
- if (this.#replaying && (update.sessionUpdate === "user_message_chunk" || update.sessionUpdate === "agent_message_chunk" || update.sessionUpdate === "agent_thought_chunk" || update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update" || update.sessionUpdate === "plan" || update.sessionUpdate === "plan_update" || update.sessionUpdate === "plan_removed")) {
22502
+ if (this.#replay.kind === "capture") this.#replay.history.record(update);
22503
+ if (this.#replay.kind !== "idle" && (update.sessionUpdate === "user_message_chunk" || update.sessionUpdate === "agent_message_chunk" || update.sessionUpdate === "agent_thought_chunk" || update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update" || update.sessionUpdate === "plan" || update.sessionUpdate === "plan_update" || update.sessionUpdate === "plan_removed")) {
21996
22504
  return;
21997
22505
  }
21998
22506
  if (update.sessionUpdate === "agent_message_chunk") {
@@ -22106,6 +22614,7 @@ var AcpProcessSession = class _AcpProcessSession {
22106
22614
  protocolVersion: MOBIUS_PROTOCOL_VERSION,
22107
22615
  sessionId: this.#mobiusSessionId,
22108
22616
  size: Math.max(0, Math.trunc(update.size)),
22617
+ source: "context",
22109
22618
  used: Math.max(0, Math.trunc(update.used))
22110
22619
  });
22111
22620
  }
@@ -22227,6 +22736,7 @@ var AcpProcessSession = class _AcpProcessSession {
22227
22736
  };
22228
22737
  };
22229
22738
  var AcpSessionManager = class {
22739
+ #nativeOperations = /* @__PURE__ */ new Set();
22230
22740
  #activeSessionIds = /* @__PURE__ */ new Set();
22231
22741
  #cancellationRequests = /* @__PURE__ */ new Set();
22232
22742
  #preparing = /* @__PURE__ */ new Map();
@@ -22278,6 +22788,21 @@ var AcpSessionManager = class {
22278
22788
  return await operation;
22279
22789
  }
22280
22790
  prepareSession = async (options) => {
22791
+ const stored = this.#store.read(options.sessionId);
22792
+ if (stored instanceof DeletedAcpStoredSession)
22793
+ throw new AcpExecutionError(
22794
+ "The native Agent session was deleted. Start a new chat.",
22795
+ {},
22796
+ "native_session_deleted"
22797
+ );
22798
+ if (stored instanceof FoundAcpStoredSession && this.#nativeOperations.has(
22799
+ `${stored.session.agentId}:${stored.session.nativeSessionId}`
22800
+ ))
22801
+ throw new AcpExecutionError(
22802
+ "The native session is being managed",
22803
+ {},
22804
+ "session_busy"
22805
+ );
22281
22806
  const pending = this.#preparing.get(options.sessionId);
22282
22807
  if (pending !== void 0) {
22283
22808
  const runtime2 = await pending;
@@ -22324,6 +22849,16 @@ var AcpSessionManager = class {
22324
22849
  }
22325
22850
  };
22326
22851
  runPrompt = async (options) => {
22852
+ const stored = this.#store.read(options.sessionId);
22853
+ if (stored instanceof FoundAcpStoredSession && this.#nativeOperations.has(
22854
+ `${stored.session.agentId}:${stored.session.nativeSessionId}`
22855
+ )) {
22856
+ throw new AcpExecutionError(
22857
+ "The native session is being managed",
22858
+ {},
22859
+ "session_busy"
22860
+ );
22861
+ }
22327
22862
  if (this.#activeSessionIds.has(options.sessionId)) {
22328
22863
  throw new AcpExecutionError(
22329
22864
  "Another prompt is already running in this conversation",
@@ -22337,6 +22872,14 @@ var AcpSessionManager = class {
22337
22872
  return { stopReason: "cancelled" };
22338
22873
  }
22339
22874
  const runtime = await this.ensureSession(options);
22875
+ if (this.#nativeOperations.has(
22876
+ `${options.agent.id}:${runtime.nativeSessionId()}`
22877
+ ))
22878
+ throw new AcpExecutionError(
22879
+ "The native session is being managed",
22880
+ {},
22881
+ "session_busy"
22882
+ );
22340
22883
  if (this.#cancellationRequests.has(options.sessionId)) {
22341
22884
  return { stopReason: "cancelled" };
22342
22885
  }
@@ -22408,6 +22951,124 @@ var AcpSessionManager = class {
22408
22951
  }
22409
22952
  return started;
22410
22953
  };
22954
+ listNativeSessions = async (options, cursor) => await (await this.ensureSession(options)).listNativeSessions(
22955
+ cursor,
22956
+ options.signal
22957
+ );
22958
+ openNativeSession = async (options, origin) => {
22959
+ const key = `${options.agent.id}:${origin.nativeSessionId}`;
22960
+ if (this.#nativeOperations.has(key))
22961
+ throw new AcpExecutionError(
22962
+ "The native session is being managed",
22963
+ {},
22964
+ "session_busy"
22965
+ );
22966
+ const linked = this.#store.findNative(
22967
+ options.agent.id,
22968
+ origin.nativeSessionId
22969
+ );
22970
+ if (linked.some(
22971
+ (entry) => this.#activeSessionIds.has(entry.sessionId) || this.#preparing.has(entry.sessionId)
22972
+ ))
22973
+ throw new AcpExecutionError(
22974
+ "Wait for the native session's running operation to finish",
22975
+ {},
22976
+ "session_busy"
22977
+ );
22978
+ const existing = linked[0];
22979
+ if (origin.kind === "import" && existing !== void 0) {
22980
+ const runtime = await this.ensureSession({
22981
+ ...options,
22982
+ sessionId: existing.sessionId
22983
+ });
22984
+ if (this.#activeSessionIds.has(existing.sessionId) || this.#nativeOperations.has(key))
22985
+ throw new AcpExecutionError(
22986
+ "Wait for the native session's running operation to finish",
22987
+ {},
22988
+ "session_busy"
22989
+ );
22990
+ this.#nativeOperations.add(key);
22991
+ try {
22992
+ const history = await runtime.loadHistory(options.signal);
22993
+ return {
22994
+ prepared: runtime.prepared(),
22995
+ sessionId: existing.sessionId,
22996
+ history
22997
+ };
22998
+ } catch (error61) {
22999
+ this.#sessions.delete(existing.sessionId);
23000
+ await runtime.closeProcess();
23001
+ throw error61;
23002
+ } finally {
23003
+ this.#nativeOperations.delete(key);
23004
+ }
23005
+ }
23006
+ if (this.#sessions.has(options.sessionId) || this.#preparing.has(options.sessionId) || this.#store.read(options.sessionId) instanceof FoundAcpStoredSession || this.#store.read(options.sessionId) instanceof DeletedAcpStoredSession)
23007
+ throw new AcpExecutionError(
23008
+ "The destination conversation already exists",
23009
+ {},
23010
+ "session_identity_mismatch"
23011
+ );
23012
+ this.#nativeOperations.add(key);
23013
+ try {
23014
+ const runtime = await this.#startPreparation({ ...options, origin });
23015
+ const openedKey = `${options.agent.id}:${runtime.nativeSessionId()}`;
23016
+ this.#nativeOperations.add(openedKey);
23017
+ try {
23018
+ const history = await runtime.loadHistory(options.signal);
23019
+ return {
23020
+ sessionId: options.sessionId,
23021
+ prepared: runtime.prepared(),
23022
+ history
23023
+ };
23024
+ } catch (error61) {
23025
+ this.#sessions.delete(options.sessionId);
23026
+ this.#store.remove(options.sessionId);
23027
+ await runtime.closeProcess();
23028
+ throw error61;
23029
+ } finally {
23030
+ this.#nativeOperations.delete(openedKey);
23031
+ }
23032
+ } finally {
23033
+ this.#nativeOperations.delete(key);
23034
+ }
23035
+ };
23036
+ deleteNativeSession = async (options, nativeSessionId) => {
23037
+ const runtime = await this.ensureSession(options);
23038
+ const key = `${options.agent.id}:${nativeSessionId}`;
23039
+ const linked = this.#store.findNative(options.agent.id, nativeSessionId);
23040
+ if (this.#nativeOperations.has(key) || linked.some(
23041
+ (entry) => this.#activeSessionIds.has(entry.sessionId) || this.#preparing.has(entry.sessionId)
23042
+ ))
23043
+ throw new AcpExecutionError(
23044
+ "Wait for the native session's running operation to finish",
23045
+ {},
23046
+ "session_busy"
23047
+ );
23048
+ this.#nativeOperations.add(key);
23049
+ try {
23050
+ for (const entry of linked) {
23051
+ const active = this.#sessions.get(entry.sessionId);
23052
+ if (active !== void 0 && active !== runtime) {
23053
+ this.#sessions.delete(entry.sessionId);
23054
+ await active.close();
23055
+ }
23056
+ }
23057
+ options.signal.throwIfAborted();
23058
+ await runtime.deleteNativeSession(nativeSessionId, options.signal);
23059
+ const deleted = this.#store.markDeleted(
23060
+ options.agent.id,
23061
+ nativeSessionId
23062
+ );
23063
+ if (runtime.nativeSessionId() === nativeSessionId) {
23064
+ this.#sessions.delete(options.sessionId);
23065
+ await runtime.close();
23066
+ }
23067
+ return deleted;
23068
+ } finally {
23069
+ this.#nativeOperations.delete(key);
23070
+ }
23071
+ };
22411
23072
  };
22412
23073
 
22413
23074
  // src/acp/run-prompt.ts
@@ -22443,9 +23104,9 @@ import { dirname as dirname2 } from "node:path";
22443
23104
  import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
22444
23105
  var AuditStore = class {
22445
23106
  database;
22446
- constructor(path) {
22447
- mkdirSync2(dirname2(path), { recursive: true });
22448
- this.database = new DatabaseSync2(path);
23107
+ constructor(path2) {
23108
+ mkdirSync2(dirname2(path2), { recursive: true });
23109
+ this.database = new DatabaseSync2(path2);
22449
23110
  this.database.exec(`
22450
23111
  CREATE TABLE IF NOT EXISTS audit_events (
22451
23112
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -22487,8 +23148,7 @@ var AuditStore = class {
22487
23148
  }
22488
23149
  };
22489
23150
 
22490
- // src/authorization/authorize-binding.ts
22491
- import { realpath as realpath2, stat as stat2 } from "node:fs/promises";
23151
+ // src/authorization/local-authorization-error.ts
22492
23152
  var LocalAuthorizationError = class extends Error {
22493
23153
  code = "local_authorization_failed";
22494
23154
  constructor(message, options = {}) {
@@ -22496,45 +23156,24 @@ var LocalAuthorizationError = class extends Error {
22496
23156
  this.name = "LocalAuthorizationError";
22497
23157
  }
22498
23158
  };
22499
- async function authorizeBinding(requestedBindingId, approvedBindingId, approvedRoot) {
22500
- if (requestedBindingId !== approvedBindingId) {
22501
- throw new LocalAuthorizationError("The runtime binding is not authorized");
22502
- }
22503
- try {
22504
- const resolvedRoot = await realpath2(approvedRoot);
22505
- const metadata = await stat2(resolvedRoot);
22506
- if (!metadata.isDirectory()) {
22507
- throw new LocalAuthorizationError("The approved root is not a directory");
22508
- }
22509
- return resolvedRoot;
22510
- } catch (error61) {
22511
- if (error61 instanceof LocalAuthorizationError) {
22512
- throw error61;
22513
- }
22514
- throw new LocalAuthorizationError("The approved root cannot be resolved", {
22515
- cause: error61
22516
- });
22517
- }
22518
- }
22519
23159
 
22520
23160
  // src/pairing/pair-local-machine.ts
22521
23161
  import { randomUUID } from "node:crypto";
22522
23162
  import {
22523
23163
  mkdir as mkdir2,
22524
23164
  open as open4,
22525
- realpath as realpath5,
23165
+ realpath as realpath3,
22526
23166
  rename as rename2,
22527
- stat as stat4,
23167
+ stat as stat3,
22528
23168
  writeFile
22529
23169
  } from "node:fs/promises";
22530
23170
  import { hostname as hostname3 } from "node:os";
22531
- import { basename, join as join6, resolve as resolve4 } from "node:path";
23171
+ import { basename, join as join7, resolve as resolve3 } from "node:path";
22532
23172
  import { fetch } from "undici";
22533
23173
 
22534
23174
  // src/agent-catalog/discover-local-agents.ts
22535
23175
  import { spawn as spawn3 } from "node:child_process";
22536
- import { realpath as realpath4 } from "node:fs/promises";
22537
- import { isAbsolute as isAbsolute2, join as join5, relative as relative3, resolve as resolve3 } from "node:path";
23176
+ import { isAbsolute, join as join6 } from "node:path";
22538
23177
  import {
22539
23178
  methods as methods3,
22540
23179
  ndJsonStream as ndJsonStream2,
@@ -22543,17 +23182,17 @@ import {
22543
23182
 
22544
23183
  // src/agent-installation/installation-grants.ts
22545
23184
  import { open as open2 } from "node:fs/promises";
22546
- import { join as join2 } from "node:path";
23185
+ import { join as join4 } from "node:path";
22547
23186
  var MAX_GRANT_FILE_LENGTH = 16 * 1024;
22548
23187
  var AGENT_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22549
23188
  function isRecord4(value) {
22550
23189
  return typeof value === "object" && value !== null && !Array.isArray(value);
22551
23190
  }
22552
23191
  async function readGrantedAgents(stateDirectory) {
22553
- const path = join2(stateDirectory, "installation-grants.json");
23192
+ const path2 = join4(stateDirectory, "installation-grants.json");
22554
23193
  let handle;
22555
23194
  try {
22556
- handle = await open2(path, "r");
23195
+ handle = await open2(path2, "r");
22557
23196
  } catch (error61) {
22558
23197
  if (error61 instanceof Error && "code" in error61 && error61.code === "ENOENT") {
22559
23198
  return /* @__PURE__ */ new Set();
@@ -22588,12 +23227,12 @@ import {
22588
23227
  mkdir,
22589
23228
  mkdtemp,
22590
23229
  open as open3,
22591
- realpath as realpath3,
23230
+ realpath as realpath2,
22592
23231
  rename,
22593
23232
  rm,
22594
- stat as stat3
23233
+ stat as stat2
22595
23234
  } from "node:fs/promises";
22596
- import { delimiter, dirname as dirname3, join as join3, relative as relative2 } from "node:path";
23235
+ import { delimiter, dirname as dirname3, join as join5, relative } from "node:path";
22597
23236
  var ADAPTER_INSTALL_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3;
22598
23237
  var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
22599
23238
  var ManagedAdapterInstallError = class extends Error {
@@ -22608,10 +23247,10 @@ function isRecord5(value) {
22608
23247
  return typeof value === "object" && value !== null && !Array.isArray(value);
22609
23248
  }
22610
23249
  function packagePath(root, packageName) {
22611
- return join3(root, "node_modules", ...packageName.split("/"));
23250
+ return join5(root, "node_modules", ...packageName.split("/"));
22612
23251
  }
22613
- async function readPackageJson(path) {
22614
- const handle = await open3(path, "r");
23252
+ async function readPackageJson(path2) {
23253
+ const handle = await open3(path2, "r");
22615
23254
  try {
22616
23255
  const metadata = await handle.stat();
22617
23256
  if (!metadata.isFile() || metadata.size > PACKAGE_METADATA_LIMIT_BYTES) {
@@ -22648,18 +23287,18 @@ function readBinPath(packageMetadata, executableName) {
22648
23287
  );
22649
23288
  }
22650
23289
  async function validateManagedAdapter(root, specification) {
22651
- const rootPath = await realpath3(root);
22652
- const packageRoot = await realpath3(
23290
+ const rootPath = await realpath2(root);
23291
+ const packageRoot = await realpath2(
22653
23292
  packagePath(rootPath, specification.adapterPackage)
22654
23293
  );
22655
- const packageDifference = relative2(rootPath, packageRoot);
23294
+ const packageDifference = relative(rootPath, packageRoot);
22656
23295
  if (packageDifference.startsWith("..") || packageDifference.length === 0) {
22657
23296
  throw new ManagedAdapterInstallError(
22658
23297
  "adapter_verification_failed",
22659
23298
  "The managed adapter package escaped its private cache"
22660
23299
  );
22661
23300
  }
22662
- const metadata = await readPackageJson(join3(packageRoot, "package.json"));
23301
+ const metadata = await readPackageJson(join5(packageRoot, "package.json"));
22663
23302
  if (metadata["name"] !== specification.adapterPackage || metadata["version"] !== specification.adapterVersion) {
22664
23303
  throw new ManagedAdapterInstallError(
22665
23304
  "adapter_verification_failed",
@@ -22668,7 +23307,7 @@ async function validateManagedAdapter(root, specification) {
22668
23307
  }
22669
23308
  const declaredBin = readBinPath(metadata, specification.adapterExecutable);
22670
23309
  const executable = await resolveExecutablePath(
22671
- join3(packageRoot, declaredBin)
23310
+ join5(packageRoot, declaredBin)
22672
23311
  );
22673
23312
  if (executable === null) {
22674
23313
  throw new ManagedAdapterInstallError(
@@ -22676,7 +23315,7 @@ async function validateManagedAdapter(root, specification) {
22676
23315
  "The managed adapter executable is invalid"
22677
23316
  );
22678
23317
  }
22679
- const executableDifference = relative2(rootPath, executable.path);
23318
+ const executableDifference = relative(rootPath, executable.path);
22680
23319
  if (executableDifference.startsWith("..") || executableDifference.length === 0) {
22681
23320
  throw new ManagedAdapterInstallError(
22682
23321
  "adapter_verification_failed",
@@ -22686,20 +23325,18 @@ async function validateManagedAdapter(root, specification) {
22686
23325
  return executable;
22687
23326
  }
22688
23327
  var ManagedAdapterInstaller = class {
22689
- #approvedRoot;
22690
23328
  #environment;
22691
23329
  #stateDirectory;
22692
23330
  constructor(options) {
22693
- this.#approvedRoot = options.approvedRoot;
22694
23331
  this.#environment = options.environment;
22695
23332
  this.#stateDirectory = options.stateDirectory;
22696
23333
  }
22697
23334
  install = async (specification, signal) => {
22698
23335
  signal.throwIfAborted();
22699
- const agentCache = join3(this.#stateDirectory, "adapters", specification.id);
22700
- const published = join3(agentCache, specification.adapterVersion);
23336
+ const agentCache = join5(this.#stateDirectory, "adapters", specification.id);
23337
+ const published = join5(agentCache, specification.adapterVersion);
22701
23338
  try {
22702
- const metadata = await stat3(published);
23339
+ const metadata = await stat2(published);
22703
23340
  if (metadata.isDirectory()) {
22704
23341
  return await validateManagedAdapter(published, specification);
22705
23342
  }
@@ -22710,13 +23347,12 @@ var ManagedAdapterInstaller = class {
22710
23347
  }
22711
23348
  await mkdir(agentCache, { mode: 448, recursive: true });
22712
23349
  const staging = await mkdtemp(
22713
- join3(agentCache, `.${specification.adapterVersion}.staging-`)
23350
+ join5(agentCache, `.${specification.adapterVersion}.staging-`)
22714
23351
  );
22715
23352
  try {
22716
23353
  const npm = await findExecutableOnPath(
22717
23354
  process.platform === "win32" ? "npm.cmd" : "npm",
22718
- this.#environment,
22719
- this.#approvedRoot
23355
+ this.#environment
22720
23356
  );
22721
23357
  if (npm === null) {
22722
23358
  throw new ManagedAdapterInstallError(
@@ -22741,7 +23377,7 @@ var ManagedAdapterInstaller = class {
22741
23377
  command: npm.path,
22742
23378
  cwd: staging,
22743
23379
  environment: {
22744
- HOME: join3(staging, "home"),
23380
+ HOME: join5(staging, "home"),
22745
23381
  NPM_CONFIG_AUDIT: "false",
22746
23382
  NPM_CONFIG_FUND: "false",
22747
23383
  NPM_CONFIG_IGNORE_SCRIPTS: "true",
@@ -22786,17 +23422,6 @@ var ManagedAdapterInstaller = class {
22786
23422
  };
22787
23423
  };
22788
23424
 
22789
- // src/storage/state-directory.ts
22790
- import { homedir } from "node:os";
22791
- import { join as join4, resolve as resolve2 } from "node:path";
22792
- function readStateDirectory(environment = process.env) {
22793
- const configured = environment["MOBIUS_STATE_DIRECTORY"]?.trim();
22794
- if (configured !== void 0 && configured.length > 0) {
22795
- return resolve2(configured);
22796
- }
22797
- return join4(homedir(), ".mobius");
22798
- }
22799
-
22800
23425
  // src/agent-catalog/discover-local-agents.ts
22801
23426
  var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
22802
23427
  var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
@@ -22960,29 +23585,17 @@ var DiscoveryAcpHandler = class {
22960
23585
  onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
22961
23586
  onUpdate = (_notification) => Promise.resolve();
22962
23587
  };
22963
- async function authorizeManagedExecutable(managed, options) {
22964
- const approvedRoot = await realpath4(resolve3(options.approvedRoot));
22965
- const requestedDifference = relative3(
22966
- approvedRoot,
22967
- managed.identity.requestedPath
22968
- );
22969
- const resolvedDifference = relative3(approvedRoot, managed.path);
22970
- const requestedInside = requestedDifference.length === 0 || !requestedDifference.startsWith("..") && !isAbsolute2(requestedDifference);
22971
- const resolvedInside = resolvedDifference.length === 0 || !resolvedDifference.startsWith("..") && !isAbsolute2(resolvedDifference);
22972
- return requestedInside || resolvedInside ? null : managed;
22973
- }
22974
23588
  async function resolveManagedExecutable(managedExecutablePath, options) {
22975
- const managed = await resolveExecutablePath(
22976
- join5(readStateDirectory(options.environment), ...managedExecutablePath),
23589
+ return await resolveExecutablePath(
23590
+ join6(readStateDirectory(options.environment), ...managedExecutablePath),
22977
23591
  options.platform
22978
23592
  );
22979
- return managed === null ? null : await authorizeManagedExecutable(managed, options);
22980
23593
  }
22981
23594
  async function resolveManagedAdapterExecutable(specification, options) {
22982
23595
  let managed;
22983
23596
  try {
22984
23597
  managed = await validateManagedAdapter(
22985
- join5(
23598
+ join6(
22986
23599
  readStateDirectory(options.environment),
22987
23600
  "adapters",
22988
23601
  specification.id,
@@ -22993,12 +23606,12 @@ async function resolveManagedAdapterExecutable(specification, options) {
22993
23606
  } catch {
22994
23607
  return null;
22995
23608
  }
22996
- return await authorizeManagedExecutable(managed, options);
23609
+ return managed;
22997
23610
  }
22998
23611
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, options) {
22999
23612
  const override = options.environment[overrideVariable];
23000
23613
  if (override !== void 0) {
23001
- if (override.length === 0 || !isAbsolute2(override)) {
23614
+ if (override.length === 0 || !isAbsolute(override)) {
23002
23615
  return [];
23003
23616
  }
23004
23617
  const executable = await resolveExecutablePath(override, options.platform);
@@ -23007,7 +23620,6 @@ async function resolveSpecificationExecutables(executableName, overrideVariable,
23007
23620
  const external = await findExecutableOnPath(
23008
23621
  executableName,
23009
23622
  options.environment,
23010
- options.approvedRoot,
23011
23623
  options.platform
23012
23624
  );
23013
23625
  const managed = await resolveManaged();
@@ -23049,11 +23661,11 @@ async function resolveAdapterExecutable(specification, options) {
23049
23661
  function normalizedVersion(output2) {
23050
23662
  return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
23051
23663
  }
23052
- async function probeVersion(executable, environment, approvedRoot, signal) {
23664
+ async function probeVersion(executable, environment, defaultWorkspace, signal) {
23053
23665
  const result = await runBoundedProcess({
23054
23666
  arguments: ["--version"],
23055
23667
  command: executable.path,
23056
- cwd: approvedRoot,
23668
+ cwd: defaultWorkspace,
23057
23669
  environment,
23058
23670
  signal,
23059
23671
  timeoutMilliseconds: VERSION_PROBE_TIMEOUT_MILLISECONDS
@@ -23082,7 +23694,7 @@ async function findVerifiedAgentExecutable(specification, options) {
23082
23694
  const version2 = await probeVersion(
23083
23695
  executable,
23084
23696
  options.environment,
23085
- options.approvedRoot,
23697
+ options.defaultWorkspace,
23086
23698
  options.signal
23087
23699
  );
23088
23700
  return new VerifiedAgentExecutable(executable, version2);
@@ -23149,7 +23761,7 @@ function writableAcpStream(output2) {
23149
23761
  }
23150
23762
  });
23151
23763
  }
23152
- async function probeAcp(agent, environment, approvedRoot, signal) {
23764
+ async function probeAcp(agent, environment, defaultWorkspace, signal) {
23153
23765
  signal.throwIfAborted();
23154
23766
  const controller = new AbortController();
23155
23767
  let timedOut = false;
@@ -23163,13 +23775,19 @@ async function probeAcp(agent, environment, approvedRoot, signal) {
23163
23775
  abort();
23164
23776
  }
23165
23777
  const child = spawn3(agent.adapterPath, [...agent.arguments], {
23166
- cwd: approvedRoot,
23778
+ cwd: defaultWorkspace,
23167
23779
  detached: process.platform !== "win32",
23168
23780
  env: { ...environment, ...agent.environment },
23169
23781
  shell: false,
23170
23782
  stdio: ["pipe", "pipe", "pipe"]
23171
23783
  });
23172
- const stdin = child.stdin;
23784
+ const processExit = new Promise((_resolve, reject) => {
23785
+ const rejectExit = () => reject(new Error("ACP adapter exited during initialization"));
23786
+ child.once("error", reject);
23787
+ child.once("exit", rejectExit);
23788
+ if (child.exitCode !== null || child.signalCode !== null) rejectExit();
23789
+ });
23790
+ const stdin = child.stdin;
23173
23791
  const stdout = child.stdout;
23174
23792
  const stderr = child.stderr;
23175
23793
  if (stdin === null || stdout === null || stderr === null) {
@@ -23190,13 +23808,6 @@ async function probeAcp(agent, environment, approvedRoot, signal) {
23190
23808
  const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
23191
23809
  ndJsonStream2(writableAcpStream(stdin), readableAcpStream(stdout))
23192
23810
  );
23193
- const processExit = new Promise((_resolve, reject) => {
23194
- child.once("error", (error61) => reject(error61));
23195
- child.once(
23196
- "exit",
23197
- () => reject(new Error("ACP adapter exited during initialization"))
23198
- );
23199
- });
23200
23811
  try {
23201
23812
  const initialized = await Promise.race([
23202
23813
  connection.agent.request(
@@ -23281,7 +23892,7 @@ async function discoverSpecification(specification, options) {
23281
23892
  agentVersion = await probeVersion(
23282
23893
  agent,
23283
23894
  options.environment,
23284
- options.approvedRoot,
23895
+ options.defaultWorkspace,
23285
23896
  options.signal
23286
23897
  );
23287
23898
  } catch (error61) {
@@ -23300,7 +23911,7 @@ async function discoverSpecification(specification, options) {
23300
23911
  ...options.environment,
23301
23912
  [specification.adapterEnvironmentVariable]: agent.path
23302
23913
  },
23303
- options.approvedRoot,
23914
+ options.defaultWorkspace,
23304
23915
  options.signal
23305
23916
  );
23306
23917
  } catch (error61) {
@@ -23325,7 +23936,7 @@ async function discoverSpecification(specification, options) {
23325
23936
  await probeAcp(
23326
23937
  definition,
23327
23938
  options.environment,
23328
- options.approvedRoot,
23939
+ options.defaultWorkspace,
23329
23940
  options.signal
23330
23941
  );
23331
23942
  return new AvailableAgent(specification, definition);
@@ -23373,7 +23984,7 @@ var TOKEN_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
23373
23984
  var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
23374
23985
  var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken"];
23375
23986
  var SAVED_CONNECTION_KEYS = [
23376
- "approvedRoot",
23987
+ "defaultWorkspace",
23377
23988
  "channelId",
23378
23989
  "daemonToken",
23379
23990
  "relayOrigin"
@@ -23420,7 +24031,7 @@ function readSingleOption(arguments_, option) {
23420
24031
  function assertKnownArguments(arguments_) {
23421
24032
  for (let index = 0; index < arguments_.length; index += 2) {
23422
24033
  const option = arguments_[index];
23423
- if (option !== "--url" && option !== "--code" && option !== "--root") {
24034
+ if (option !== "--url" && option !== "--code" && option !== "--workspace") {
23424
24035
  throw new PairingClientError(
23425
24036
  "invalid_arguments",
23426
24037
  `Unknown pairing option: ${option ?? "missing option"}`
@@ -23477,7 +24088,7 @@ function parsePairCommand(arguments_) {
23477
24088
  return {
23478
24089
  code: parsePairingCode(readSingleOption(arguments_, "--code")),
23479
24090
  relayOrigin: parseRelayOrigin(readSingleOption(arguments_, "--url")),
23480
- root: readSingleOption(arguments_, "--root")
24091
+ workspace: arguments_.includes("--workspace") ? readSingleOption(arguments_, "--workspace") : loadDefaultWorkspace()
23481
24092
  };
23482
24093
  }
23483
24094
  function parseChannelArgument(arguments_) {
@@ -23496,25 +24107,26 @@ function parseChannelArgument(arguments_) {
23496
24107
  }
23497
24108
  return channelId;
23498
24109
  }
23499
- async function resolveApprovedRoot(path) {
23500
- const requestedRoot = resolve4(path);
24110
+ async function resolveDefaultWorkspace(path2) {
24111
+ const requestedWorkspace = resolve3(path2);
23501
24112
  try {
23502
- const approvedRoot = await realpath5(requestedRoot);
23503
- const metadata = await stat4(approvedRoot);
24113
+ await mkdir2(requestedWorkspace, { recursive: true, mode: 448 });
24114
+ const defaultWorkspace = await realpath3(requestedWorkspace);
24115
+ const metadata = await stat3(defaultWorkspace);
23504
24116
  if (!metadata.isDirectory()) {
23505
24117
  throw new PairingClientError(
23506
24118
  "invalid_workspace",
23507
- "The approved workspace root is not a directory"
24119
+ "The default workspace is not a directory"
23508
24120
  );
23509
24121
  }
23510
- return approvedRoot;
24122
+ return defaultWorkspace;
23511
24123
  } catch (error61) {
23512
24124
  if (error61 instanceof PairingClientError) {
23513
24125
  throw error61;
23514
24126
  }
23515
24127
  throw new PairingClientError(
23516
24128
  "invalid_workspace",
23517
- "The approved workspace root cannot be resolved",
24129
+ "The default workspace cannot be resolved",
23518
24130
  { cause: error61 }
23519
24131
  );
23520
24132
  }
@@ -23570,7 +24182,7 @@ function decodeClaimResponse(value) {
23570
24182
  }
23571
24183
  return { channelId, daemonToken };
23572
24184
  }
23573
- async function claimPairing(options, approvedRoot, localAgents, installableAgents, signal) {
24185
+ async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
23574
24186
  const agents = localAgents.map((agent) => ({
23575
24187
  id: agent.id,
23576
24188
  label: agent.label
@@ -23588,7 +24200,7 @@ async function claimPairing(options, approvedRoot, localAgents, installableAgent
23588
24200
  })),
23589
24201
  machineName: hostname3(),
23590
24202
  pairingCode: options.code,
23591
- workspaceName: basename(approvedRoot) || "Local workspace"
24203
+ workspaceName: basename(defaultWorkspace) || "Local workspace"
23592
24204
  }),
23593
24205
  dispatcher: environmentProxyDispatcher,
23594
24206
  headers: { "content-type": "application/json" },
@@ -23611,11 +24223,11 @@ async function claimPairing(options, approvedRoot, localAgents, installableAgent
23611
24223
  }
23612
24224
  return decodeClaimResponse(value);
23613
24225
  }
23614
- async function persistConnection(channelId, relayOrigin, daemonToken, approvedRoot) {
23615
- const connectionsDirectory = join6(readStateDirectory(), "connections");
24226
+ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
24227
+ const connectionsDirectory = join7(readStateDirectory(), "connections");
23616
24228
  await mkdir2(connectionsDirectory, { mode: 448, recursive: true });
23617
- const connectionPath = join6(connectionsDirectory, `${channelId}.json`);
23618
- const temporaryPath = join6(
24229
+ const connectionPath = join7(connectionsDirectory, `${channelId}.json`);
24230
+ const temporaryPath = join7(
23619
24231
  connectionsDirectory,
23620
24232
  `.${channelId}.${randomUUID()}.tmp`
23621
24233
  );
@@ -23623,7 +24235,7 @@ async function persistConnection(channelId, relayOrigin, daemonToken, approvedRo
23623
24235
  temporaryPath,
23624
24236
  `${JSON.stringify(
23625
24237
  {
23626
- approvedRoot,
24238
+ defaultWorkspace,
23627
24239
  channelId,
23628
24240
  daemonToken,
23629
24241
  relayOrigin: relayOrigin.toString()
@@ -23644,25 +24256,25 @@ function decodeSavedConnection(value, expectedChannelId) {
23644
24256
  "The saved connection is invalid"
23645
24257
  );
23646
24258
  }
23647
- const approvedRoot = value["approvedRoot"];
24259
+ const defaultWorkspace = value["defaultWorkspace"];
23648
24260
  const channelId = value["channelId"];
23649
24261
  const daemonToken = value["daemonToken"];
23650
24262
  const relayOrigin = value["relayOrigin"];
23651
- if (typeof approvedRoot !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN3.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof relayOrigin !== "string") {
24263
+ if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN3.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof relayOrigin !== "string") {
23652
24264
  throw new PairingClientError(
23653
24265
  "invalid_connection",
23654
24266
  "The saved connection is invalid"
23655
24267
  );
23656
24268
  }
23657
24269
  return {
23658
- approvedRoot,
24270
+ defaultWorkspace,
23659
24271
  channelId,
23660
24272
  daemonToken,
23661
24273
  relayOrigin: parseRelayOrigin(relayOrigin)
23662
24274
  };
23663
24275
  }
23664
24276
  async function readSavedConnection(channelId) {
23665
- const connectionPath = join6(
24277
+ const connectionPath = join7(
23666
24278
  readStateDirectory(),
23667
24279
  "connections",
23668
24280
  `${channelId}.json`
@@ -23693,7 +24305,9 @@ async function readSavedConnection(channelId) {
23693
24305
  }
23694
24306
  const connection = decodeSavedConnection(value, channelId);
23695
24307
  return {
23696
- approvedRoot: await resolveApprovedRoot(connection.approvedRoot),
24308
+ defaultWorkspace: await resolveDefaultWorkspace(
24309
+ connection.defaultWorkspace
24310
+ ),
23697
24311
  channelId: connection.channelId,
23698
24312
  daemonToken: connection.daemonToken,
23699
24313
  relayOrigin: connection.relayOrigin
@@ -23715,7 +24329,7 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
23715
24329
  );
23716
24330
  relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
23717
24331
  relayUrl.searchParams.set("token", connection.daemonToken);
23718
- const auditDatabasePath = join6(
24332
+ const auditDatabasePath = join7(
23719
24333
  readStateDirectory(),
23720
24334
  "audit",
23721
24335
  `${connection.channelId}.sqlite`
@@ -23727,7 +24341,7 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
23727
24341
  ).toString(),
23728
24342
  config: createDaemonConfig(
23729
24343
  {
23730
- approvedRoot: connection.approvedRoot,
24344
+ defaultWorkspace: connection.defaultWorkspace,
23731
24345
  auditDatabasePath,
23732
24346
  channelId: connection.channelId,
23733
24347
  relayUrl
@@ -23740,9 +24354,9 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
23740
24354
  }
23741
24355
  async function pairLocalMachine(arguments_, signal = new AbortController().signal) {
23742
24356
  const options = parsePairCommand(arguments_);
23743
- const approvedRoot = await resolveApprovedRoot(options.root);
24357
+ const defaultWorkspace = await resolveDefaultWorkspace(options.workspace);
23744
24358
  const inventory = await discoverLocalAgentInventory({
23745
- approvedRoot,
24359
+ defaultWorkspace,
23746
24360
  environment: process.env,
23747
24361
  signal
23748
24362
  });
@@ -23750,7 +24364,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
23750
24364
  const agents = inventory.readyAgents();
23751
24365
  const claim2 = await claimPairing(
23752
24366
  options,
23753
- approvedRoot,
24367
+ defaultWorkspace,
23754
24368
  agents,
23755
24369
  inventory.installable,
23756
24370
  signal
@@ -23759,11 +24373,11 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
23759
24373
  claim2.channelId,
23760
24374
  options.relayOrigin,
23761
24375
  claim2.daemonToken,
23762
- approvedRoot
24376
+ defaultWorkspace
23763
24377
  );
23764
24378
  return buildPairedDaemon(
23765
24379
  {
23766
- approvedRoot,
24380
+ defaultWorkspace,
23767
24381
  channelId: claim2.channelId,
23768
24382
  daemonToken: claim2.daemonToken,
23769
24383
  relayOrigin: options.relayOrigin
@@ -23774,14 +24388,14 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
23774
24388
  }
23775
24389
  async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
23776
24390
  const channelId = parseChannelArgument(arguments_);
23777
- const connectionPath = join6(
24391
+ const connectionPath = join7(
23778
24392
  readStateDirectory(),
23779
24393
  "connections",
23780
24394
  `${channelId}.json`
23781
24395
  );
23782
24396
  const connection = await readSavedConnection(channelId);
23783
24397
  const inventory = await discoverLocalAgentInventory({
23784
- approvedRoot: connection.approvedRoot,
24398
+ defaultWorkspace: connection.defaultWorkspace,
23785
24399
  environment: process.env,
23786
24400
  signal
23787
24401
  });
@@ -23789,7 +24403,7 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
23789
24403
  }
23790
24404
 
23791
24405
  // src/run-daemon.ts
23792
- import { randomUUID as randomUUID4 } from "node:crypto";
24406
+ import { randomUUID as randomUUID5 } from "node:crypto";
23793
24407
  import { basename as basename3 } from "node:path";
23794
24408
  import { WebSocket as WebSocket2 } from "undici";
23795
24409
 
@@ -24238,7 +24852,7 @@ function stableFailureCode(error61) {
24238
24852
  function discoveryOptions(options, environment, signal, specifications) {
24239
24853
  return {
24240
24854
  ...options.architecture === void 0 ? {} : { architecture: options.architecture },
24241
- approvedRoot: options.approvedRoot,
24855
+ defaultWorkspace: options.defaultWorkspace,
24242
24856
  environment,
24243
24857
  ...options.platform === void 0 ? {} : { platform: options.platform },
24244
24858
  signal,
@@ -24394,11 +25008,11 @@ var AutomaticAdapterProvisioner = class {
24394
25008
 
24395
25009
  // src/agent-installation/fixed-installation-executor.ts
24396
25010
  import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
24397
- import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve5 } from "node:path";
25011
+ import { resolve as resolve4 } from "node:path";
24398
25012
 
24399
25013
  // src/agent-installation/fixed-agent-install-recipes.ts
24400
25014
  import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
24401
- import { join as join7 } from "node:path";
25015
+ import { join as join8 } from "node:path";
24402
25016
 
24403
25017
  // src/agent-installation/verified-download.ts
24404
25018
  import { createHash } from "node:crypto";
@@ -24605,8 +25219,8 @@ var FixedAgentInstallRecipe = class {
24605
25219
  );
24606
25220
  }
24607
25221
  };
24608
- requireInstalledExecutable = async (path) => {
24609
- const executable = await resolveExecutablePath(path);
25222
+ requireInstalledExecutable = async (path2) => {
25223
+ const executable = await resolveExecutablePath(path2);
24610
25224
  if (executable === null) {
24611
25225
  throw new InstallationManagerError(
24612
25226
  "agent_verification_failed",
@@ -24622,18 +25236,18 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
24622
25236
  releaseChannel = "latest";
24623
25237
  install = async (options) => {
24624
25238
  this.assertSupportedPlatform();
24625
- const root = join7(options.stateDirectory, "agents", this.id);
24626
- const temporaryRoot = join7(options.stateDirectory, "temporary");
25239
+ const root = join8(options.stateDirectory, "agents", this.id);
25240
+ const temporaryRoot = join8(options.stateDirectory, "temporary");
24627
25241
  await Promise.all([
24628
25242
  mkdir3(root, { mode: 448, recursive: true }),
24629
25243
  mkdir3(temporaryRoot, { mode: 448, recursive: true })
24630
25244
  ]);
24631
25245
  const temporaryDirectory = await mkdtemp2(
24632
- join7(temporaryRoot, ".codex-install-")
25246
+ join8(temporaryRoot, ".codex-install-")
24633
25247
  );
24634
- const installerPath = join7(temporaryDirectory, "install.sh");
24635
- const installDirectory = join7(root, "bin");
24636
- const codexHome = join7(root, "home");
25248
+ const installerPath = join8(temporaryDirectory, "install.sh");
25249
+ const installDirectory = join8(root, "bin");
25250
+ const codexHome = join8(root, "home");
24637
25251
  try {
24638
25252
  await Promise.all([
24639
25253
  mkdir3(installDirectory, { mode: 448, recursive: true }),
@@ -24677,7 +25291,7 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
24677
25291
  timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
24678
25292
  });
24679
25293
  return await this.requireInstalledExecutable(
24680
- join7(installDirectory, "codex")
25294
+ join8(installDirectory, "codex")
24681
25295
  );
24682
25296
  } catch (error61) {
24683
25297
  if (options.signal.aborted) {
@@ -24701,17 +25315,17 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
24701
25315
  releaseChannel = "stable";
24702
25316
  install = async (options) => {
24703
25317
  this.assertSupportedPlatform();
24704
- const root = join7(options.stateDirectory, "agents", this.id);
24705
- const managedHome = join7(root, "home");
24706
- const temporaryRoot = join7(options.stateDirectory, "temporary");
25318
+ const root = join8(options.stateDirectory, "agents", this.id);
25319
+ const managedHome = join8(root, "home");
25320
+ const temporaryRoot = join8(options.stateDirectory, "temporary");
24707
25321
  await Promise.all([
24708
25322
  mkdir3(managedHome, { mode: 448, recursive: true }),
24709
25323
  mkdir3(temporaryRoot, { mode: 448, recursive: true })
24710
25324
  ]);
24711
25325
  const temporaryDirectory = await mkdtemp2(
24712
- join7(temporaryRoot, ".claude-install-")
25326
+ join8(temporaryRoot, ".claude-install-")
24713
25327
  );
24714
- const installerPath = join7(temporaryDirectory, "install.sh");
25328
+ const installerPath = join8(temporaryDirectory, "install.sh");
24715
25329
  try {
24716
25330
  await options.report("downloading");
24717
25331
  const download = await downloadVerifiedFile({
@@ -24748,7 +25362,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
24748
25362
  timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
24749
25363
  });
24750
25364
  return await this.requireInstalledExecutable(
24751
- join7(managedHome, ".local", "bin", "claude")
25365
+ join8(managedHome, ".local", "bin", "claude")
24752
25366
  );
24753
25367
  } catch (error61) {
24754
25368
  if (options.signal.aborted) {
@@ -24796,28 +25410,24 @@ function findRecipe(recipes, agentId) {
24796
25410
  "The requested Agent does not have an approved installation recipe"
24797
25411
  );
24798
25412
  }
24799
- function isInside2(root, candidate) {
24800
- const difference = relative4(resolve5(root), resolve5(candidate));
24801
- return difference.length === 0 || !difference.startsWith("..") && !isAbsolute3(difference);
24802
- }
24803
- function resolveApprovedRoot2(path) {
25413
+ function resolveDefaultWorkspace2(path2) {
24804
25414
  try {
24805
- const directory = realpathSync2(resolve5(path));
25415
+ const directory = realpathSync2(resolve4(path2));
24806
25416
  if (!statSync2(directory).isDirectory()) {
24807
- throw new Error("Approved root is not a directory");
25417
+ throw new Error("Default workspace is not a directory");
24808
25418
  }
24809
25419
  return directory;
24810
25420
  } catch (error61) {
24811
25421
  throw new InstallationManagerError(
24812
25422
  "unsafe_installation_root",
24813
- "The approved workspace is unavailable or unsafe",
25423
+ "The default workspace is unavailable or unsafe",
24814
25424
  { cause: error61 }
24815
25425
  );
24816
25426
  }
24817
25427
  }
24818
- function resolveUserInstallationDirectory(path) {
25428
+ function resolveUserInstallationDirectory(path2) {
24819
25429
  try {
24820
- const directory = realpathSync2(resolve5(path));
25430
+ const directory = realpathSync2(resolve4(path2));
24821
25431
  const metadata = statSync2(directory);
24822
25432
  if (!metadata.isDirectory() || typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
24823
25433
  throw new Error("Installation directory is not user-owned");
@@ -24854,7 +25464,7 @@ function requiresAdapterReplacement(code) {
24854
25464
  }
24855
25465
  var FixedInstallationExecutor = class {
24856
25466
  #adapterInstaller;
24857
- #approvedRoot;
25467
+ #defaultWorkspace;
24858
25468
  #audit;
24859
25469
  #catalog;
24860
25470
  #environment;
@@ -24863,17 +25473,11 @@ var FixedInstallationExecutor = class {
24863
25473
  #specifications;
24864
25474
  #stateDirectory;
24865
25475
  constructor(options, specifications = supportedLocalAgentSpecifications(), recipes = fixedAgentInstallRecipes(), adapterInstaller) {
24866
- const approvedRoot = resolveApprovedRoot2(options.approvedRoot);
25476
+ const defaultWorkspace = resolveDefaultWorkspace2(options.defaultWorkspace);
24867
25477
  const stateDirectory = resolveUserInstallationDirectory(
24868
25478
  options.stateDirectory
24869
25479
  );
24870
- if (isInside2(approvedRoot, stateDirectory)) {
24871
- throw new InstallationManagerError(
24872
- "unsafe_installation_root",
24873
- "The Mobius state directory cannot be inside the approved workspace"
24874
- );
24875
- }
24876
- this.#approvedRoot = approvedRoot;
25480
+ this.#defaultWorkspace = defaultWorkspace;
24877
25481
  this.#audit = options.audit;
24878
25482
  this.#catalog = options.catalog;
24879
25483
  this.#environment = Object.freeze({ ...options.environment });
@@ -24882,7 +25486,6 @@ var FixedInstallationExecutor = class {
24882
25486
  this.#specifications = Object.freeze([...specifications]);
24883
25487
  this.#stateDirectory = stateDirectory;
24884
25488
  this.#adapterInstaller = adapterInstaller ?? new ManagedAdapterInstaller({
24885
- approvedRoot,
24886
25489
  environment: this.#environment,
24887
25490
  stateDirectory
24888
25491
  });
@@ -24901,7 +25504,7 @@ var FixedInstallationExecutor = class {
24901
25504
  }
24902
25505
  );
24903
25506
  const discoveryOptions2 = {
24904
- approvedRoot: this.#approvedRoot,
25507
+ defaultWorkspace: this.#defaultWorkspace,
24905
25508
  environment: this.#environment,
24906
25509
  signal
24907
25510
  };
@@ -24936,7 +25539,7 @@ var FixedInstallationExecutor = class {
24936
25539
  environment[specification.agentOverrideVariable] = agent.path;
24937
25540
  environment[specification.adapterOverrideVariable] = adapter.path;
24938
25541
  const inventory = await discoverLocalAgentInventory({
24939
- approvedRoot: this.#approvedRoot,
25542
+ defaultWorkspace: this.#defaultWorkspace,
24940
25543
  environment,
24941
25544
  signal,
24942
25545
  specifications: this.#specifications
@@ -25049,18 +25652,16 @@ Mobius Web requested installation of ${label} (${requestId}). Allow this fixed u
25049
25652
  };
25050
25653
 
25051
25654
  // src/authorization/workspace-directory.ts
25052
- import { readdir, realpath as realpath6, stat as stat5 } from "node:fs/promises";
25655
+ import { readdir, realpath as realpath4, stat as stat4 } from "node:fs/promises";
25656
+ import { homedir as homedir2 } from "node:os";
25053
25657
  import {
25054
25658
  basename as basename2,
25055
25659
  dirname as dirname4,
25056
- isAbsolute as isAbsolute4,
25057
- join as join8,
25660
+ isAbsolute as isAbsolute2,
25661
+ join as join9,
25058
25662
  normalize,
25059
- relative as relative5
25663
+ relative as relative2
25060
25664
  } from "node:path";
25061
- var ROOT_DIRECTORY_ID = "root";
25062
- var DIRECTORY_ID_PREFIX = "dir-";
25063
- var DIRECTORY_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
25064
25665
  var WorkspaceDirectoryListing = class {
25065
25666
  directoryId;
25066
25667
  directoryLabel;
@@ -25073,151 +25674,691 @@ var WorkspaceDirectoryListing = class {
25073
25674
  this.parentDirectoryId = parentDirectoryId;
25074
25675
  }
25075
25676
  };
25076
- function directoryId(relativePath) {
25077
- if (relativePath.length === 0) {
25078
- return ROOT_DIRECTORY_ID;
25677
+ function encodePath(path2) {
25678
+ const encoded = Buffer.from(path2, "utf8").toString("base64url");
25679
+ if (encoded.length === 0 || encoded.length > 2e3) {
25680
+ throw new LocalAuthorizationError(
25681
+ "The local directory path is too long to select"
25682
+ );
25079
25683
  }
25080
- return `${DIRECTORY_ID_PREFIX}${Buffer.from(relativePath, "utf8").toString("base64url")}`;
25684
+ return `path-${encoded}`;
25081
25685
  }
25082
- function decodeDirectoryId(value) {
25083
- if (value === ROOT_DIRECTORY_ID) {
25084
- return "";
25085
- }
25086
- if (!value.startsWith(DIRECTORY_ID_PREFIX)) {
25087
- throw new LocalAuthorizationError("The workspace directory is invalid");
25088
- }
25089
- const encoded = value.slice(DIRECTORY_ID_PREFIX.length);
25090
- if (encoded.length === 0 || encoded.length > 2e3 || !DIRECTORY_ID_PATTERN.test(encoded)) {
25091
- throw new LocalAuthorizationError("The workspace directory is invalid");
25092
- }
25686
+ function decodePath(value, prefix) {
25687
+ const encoded = value.slice(prefix.length);
25688
+ if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded))
25689
+ throw new LocalAuthorizationError("The directory identifier is invalid");
25093
25690
  const decoded = Buffer.from(encoded, "base64url").toString("utf8");
25094
- if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded) {
25095
- throw new LocalAuthorizationError("The workspace directory is invalid");
25096
- }
25097
- const normalized = normalize(decoded);
25098
- if (decoded.includes("\0") || isAbsolute4(decoded) || normalized === ".." || normalized.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || normalized !== decoded) {
25099
- throw new LocalAuthorizationError("The workspace directory is invalid");
25100
- }
25101
- return normalized;
25102
- }
25103
- function isContained(root, target) {
25104
- const remainder = relative5(root, target);
25105
- return remainder.length === 0 || !isAbsolute4(remainder) && remainder !== ".." && !remainder.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
25691
+ if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize(decoded) !== decoded)
25692
+ throw new LocalAuthorizationError("The directory identifier is invalid");
25693
+ return decoded;
25106
25694
  }
25107
25695
  var WorkspaceDirectoryService = class {
25108
- #approvedBindingId;
25109
- #approvedRoot;
25110
- constructor(approvedBindingId, approvedRoot) {
25111
- this.#approvedBindingId = approvedBindingId;
25112
- this.#approvedRoot = approvedRoot;
25113
- }
25114
- resolve = async (requestedBindingId, requestedDirectoryId) => {
25115
- if (requestedBindingId !== this.#approvedBindingId) {
25696
+ #bindingId;
25697
+ #defaultWorkspace;
25698
+ constructor(bindingId, defaultWorkspace) {
25699
+ this.#bindingId = bindingId;
25700
+ this.#defaultWorkspace = defaultWorkspace;
25701
+ }
25702
+ authorizeMachine = (bindingId) => {
25703
+ if (bindingId !== this.#bindingId)
25116
25704
  throw new LocalAuthorizationError(
25117
25705
  "The runtime binding is not authorized"
25118
25706
  );
25707
+ };
25708
+ requestedPath = (id) => {
25709
+ if (id === "default") return this.#defaultWorkspace;
25710
+ if (id === "home") return homedir2();
25711
+ if (id.startsWith("path-")) {
25712
+ const path2 = decodePath(id, "path-");
25713
+ if (isAbsolute2(path2)) return path2;
25119
25714
  }
25120
- const root = await this.resolveRoot();
25121
- const relativePath = decodeDirectoryId(requestedDirectoryId);
25715
+ throw new LocalAuthorizationError("The directory identifier is invalid");
25716
+ };
25717
+ resolvePath = async (requested, signal) => {
25718
+ signal.throwIfAborted();
25719
+ if (!isAbsolute2(requested) || requested.includes("\0") || normalize(requested) !== requested)
25720
+ throw new LocalAuthorizationError("The local directory path is invalid");
25122
25721
  try {
25123
- const target = await realpath6(join8(root, relativePath));
25124
- const metadata = await stat5(target);
25125
- if (!metadata.isDirectory() || !isContained(root, target)) {
25722
+ const target = await realpath4(requested);
25723
+ signal.throwIfAborted();
25724
+ const metadata = await stat4(target);
25725
+ signal.throwIfAborted();
25726
+ if (!isAbsolute2(target) || normalize(target) !== target || !metadata.isDirectory())
25126
25727
  throw new LocalAuthorizationError(
25127
- "The workspace directory is not authorized"
25728
+ "The selected location is not a directory"
25128
25729
  );
25129
- }
25130
25730
  return target;
25131
- } catch (error61) {
25132
- if (error61 instanceof LocalAuthorizationError) {
25133
- throw error61;
25134
- }
25731
+ } catch (cause) {
25732
+ signal.throwIfAborted();
25733
+ if (cause instanceof LocalAuthorizationError) throw cause;
25135
25734
  throw new LocalAuthorizationError(
25136
- "The workspace directory cannot be resolved",
25137
- { cause: error61 }
25735
+ "This directory is missing or unavailable to your user account",
25736
+ { cause }
25138
25737
  );
25139
25738
  }
25140
25739
  };
25141
- list = async (requestedBindingId, requestedDirectoryId) => {
25142
- const root = await this.resolveRoot();
25143
- const logicalRelativePath = decodeDirectoryId(requestedDirectoryId);
25144
- const target = await this.resolve(requestedBindingId, requestedDirectoryId);
25740
+ label = (path2) => {
25741
+ const suffix = relative2(homedir2(), path2);
25742
+ return suffix === "" ? "~" : !isAbsolute2(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
25743
+ };
25744
+ identify = async (bindingId, requestedPath, signal) => {
25745
+ this.authorizeMachine(bindingId);
25746
+ const path2 = await this.resolvePath(requestedPath, signal);
25747
+ return {
25748
+ path: path2,
25749
+ directoryId: encodePath(path2),
25750
+ name: basename2(path2) || path2,
25751
+ label: this.label(path2)
25752
+ };
25753
+ };
25754
+ resolve = async (bindingId, id, signal) => {
25755
+ this.authorizeMachine(bindingId);
25756
+ return await this.resolvePath(this.requestedPath(id), signal);
25757
+ };
25758
+ list = async (bindingId, id, signal) => {
25759
+ const target = await this.resolve(bindingId, id, signal);
25145
25760
  try {
25146
- const entries = [];
25147
25761
  const children = await readdir(target, { withFileTypes: true });
25762
+ signal.throwIfAborted();
25763
+ const entries = [];
25148
25764
  for (const child of children) {
25149
- if (entries.length === 500) {
25150
- break;
25765
+ if (entries.length === 500) break;
25766
+ if (child.isFile() || child.isBlockDevice() || child.isCharacterDevice() || child.isFIFO() || child.isSocket()) {
25767
+ continue;
25151
25768
  }
25152
- const logicalChild = logicalRelativePath.length === 0 ? child.name : join8(logicalRelativePath, child.name);
25153
25769
  try {
25154
- const resolvedChild = await realpath6(join8(target, child.name));
25155
- const metadata = await stat5(resolvedChild);
25156
- if (metadata.isDirectory() && isContained(root, resolvedChild)) {
25157
- entries.push({
25158
- directoryId: directoryId(logicalChild),
25159
- name: child.name
25160
- });
25161
- }
25162
- } catch {
25770
+ const path2 = await this.resolvePath(join9(target, child.name), signal);
25771
+ entries.push({ directoryId: encodePath(path2), name: child.name });
25772
+ } catch (cause) {
25773
+ signal.throwIfAborted();
25774
+ if (!(cause instanceof LocalAuthorizationError)) throw cause;
25163
25775
  }
25164
25776
  }
25165
- entries.sort((left, right) => left.name.localeCompare(right.name));
25166
- const labelSuffix = logicalRelativePath.replaceAll("\\", "/");
25167
- const parentRelative = logicalRelativePath.length === 0 || dirname4(logicalRelativePath) === "." ? "" : dirname4(logicalRelativePath);
25777
+ entries.sort((a, b) => a.name.localeCompare(b.name));
25778
+ const parent = dirname4(target);
25168
25779
  return new WorkspaceDirectoryListing(
25169
- requestedDirectoryId,
25170
- labelSuffix.length === 0 ? basename2(root) : `${basename2(root)}/${labelSuffix}`,
25780
+ id,
25781
+ this.label(target),
25171
25782
  entries,
25172
- requestedDirectoryId === ROOT_DIRECTORY_ID ? "" : directoryId(parentRelative)
25783
+ parent === target ? "" : encodePath(parent)
25173
25784
  );
25174
- } catch (error61) {
25175
- if (error61 instanceof LocalAuthorizationError) {
25176
- throw error61;
25177
- }
25785
+ } catch (cause) {
25786
+ signal.throwIfAborted();
25787
+ if (cause instanceof LocalAuthorizationError) throw cause;
25178
25788
  throw new LocalAuthorizationError(
25179
- "The workspace directory cannot be listed",
25180
- { cause: error61 }
25789
+ "This directory cannot be browsed by your user account",
25790
+ { cause }
25181
25791
  );
25182
25792
  }
25183
25793
  };
25184
- resolveMany = async (requestedBindingId, directoryIds) => {
25185
- const resolved = [];
25186
- const unique = /* @__PURE__ */ new Set();
25187
- for (const requestedDirectoryId of directoryIds) {
25188
- const directory = await this.resolve(
25189
- requestedBindingId,
25190
- requestedDirectoryId
25794
+ resolveMany = async (bindingId, ids, signal) => {
25795
+ const paths = /* @__PURE__ */ new Set();
25796
+ for (const id of ids) paths.add(await this.resolve(bindingId, id, signal));
25797
+ return [...paths];
25798
+ };
25799
+ };
25800
+
25801
+ // src/native-sessions/service.ts
25802
+ import { randomUUID as randomUUID3 } from "node:crypto";
25803
+
25804
+ // src/native-sessions/codex-history.ts
25805
+ import { spawn as spawn4 } from "node:child_process";
25806
+ var responseSchema = external_exports.union([
25807
+ external_exports.object({
25808
+ id: external_exports.number(),
25809
+ error: external_exports.object({ code: external_exports.number(), message: external_exports.string() })
25810
+ }),
25811
+ external_exports.object({ id: external_exports.number(), result: external_exports.unknown() }),
25812
+ external_exports.object({ method: external_exports.string() })
25813
+ ]);
25814
+ var threadSchema = external_exports.object({
25815
+ thread: external_exports.object({
25816
+ id: nativeSessionIdSchema,
25817
+ cwd: external_exports.string().min(1).max(2048).refine((path2) => !path2.includes("\0"))
25818
+ })
25819
+ });
25820
+ var turnsSchema = external_exports.object({
25821
+ data: external_exports.array(external_exports.object({ items: external_exports.array(external_exports.unknown()).max(1e5) })).max(SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT),
25822
+ nextCursor: external_exports.string().nullish()
25823
+ });
25824
+ var itemTypeSchema = external_exports.object({ type: external_exports.string().min(1).max(80) });
25825
+ var userMessageSchema = external_exports.object({
25826
+ content: external_exports.array(external_exports.unknown()).max(1e4)
25827
+ });
25828
+ var textSchema = external_exports.object({ text: external_exports.string() });
25829
+ var imageSchema = external_exports.object({ url: external_exports.string() });
25830
+ var agentMessageSchema = textSchema.extend({ phase: external_exports.string().nullish() });
25831
+ function decodeHistory(thread, value) {
25832
+ const page = turnsSchema.parse(value);
25833
+ const messages = [];
25834
+ let characters = 0;
25835
+ let imageCharacters = 0;
25836
+ let truncated = page.nextCursor != null;
25837
+ for (const turn of page.data.toReversed()) {
25838
+ for (const item of turn.items) {
25839
+ const { type } = itemTypeSchema.parse(item);
25840
+ let message;
25841
+ if (type === "userMessage") {
25842
+ const { content } = userMessageSchema.parse(item);
25843
+ const parsed = parseNativeHistoryText(
25844
+ content.map((block) => {
25845
+ const { type: type2 } = itemTypeSchema.parse(block);
25846
+ if (type2 === "text") return textSchema.parse(block).text;
25847
+ if (type2 === "image")
25848
+ return `[@image](${imageSchema.parse(block).url})`;
25849
+ return "[Attachment]";
25850
+ }).join("")
25851
+ );
25852
+ message = {
25853
+ role: "user",
25854
+ text: parsed.text,
25855
+ ...parsed.images.length > 0 ? { images: parsed.images } : {}
25856
+ };
25857
+ } else if (type === "agentMessage") {
25858
+ const agent = agentMessageSchema.parse(item);
25859
+ if (agent.phase === "commentary") continue;
25860
+ message = { role: "assistant", text: agent.text };
25861
+ } else {
25862
+ continue;
25863
+ }
25864
+ const text = message.text.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
25865
+ if (text.length === 0 && (message.images?.length ?? 0) === 0) continue;
25866
+ truncated ||= text.length < message.text.length;
25867
+ messages.push({ ...message, text });
25868
+ characters += text.length;
25869
+ imageCharacters += (message.images ?? []).reduce(
25870
+ (size, image) => size + image.data.length,
25871
+ 0
25191
25872
  );
25192
- if (!unique.has(directory)) {
25193
- unique.add(directory);
25194
- resolved.push(directory);
25873
+ while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT || imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
25874
+ const removed = messages.shift();
25875
+ if (removed !== void 0) {
25876
+ characters -= removed.text.length;
25877
+ imageCharacters -= (removed.images ?? []).reduce(
25878
+ (size, image) => size + image.data.length,
25879
+ 0
25880
+ );
25881
+ }
25882
+ truncated = true;
25195
25883
  }
25196
25884
  }
25197
- return resolved;
25885
+ }
25886
+ return {
25887
+ nativeSessionId: thread.id,
25888
+ cwd: thread.cwd,
25889
+ history: {
25890
+ status: "available",
25891
+ messages,
25892
+ truncated,
25893
+ coveredCommandIds: []
25894
+ }
25895
+ };
25896
+ }
25897
+ async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
25898
+ signal.throwIfAborted();
25899
+ nativeSessionIdSchema.parse(nativeSessionId);
25900
+ if (agent.id !== "codex" || !await revalidateExecutable(agent.agentIdentity))
25901
+ throw new AcpExecutionError(
25902
+ "The local Codex executable changed. Restart Mobius to discover it again.",
25903
+ {},
25904
+ "agent_executable_changed"
25905
+ );
25906
+ signal.throwIfAborted();
25907
+ const child = spawn4(agent.agentIdentity.realPath, ["app-server"], {
25908
+ cwd,
25909
+ env: { ...process.env, ...agent.environment },
25910
+ detached: process.platform !== "win32",
25911
+ shell: false,
25912
+ stdio: ["pipe", "pipe", "ignore"]
25913
+ });
25914
+ const response = Promise.withResolvers();
25915
+ let state = { kind: "initializing", requestId: 1 };
25916
+ let pending = "";
25917
+ let receivedBytes = 0;
25918
+ const fail = (cause) => response.reject(
25919
+ cause instanceof AcpExecutionError ? cause : new AcpExecutionError(
25920
+ "Saved Codex history could not be read.",
25921
+ { cause },
25922
+ "native_history_unavailable"
25923
+ )
25924
+ );
25925
+ const send2 = (message) => {
25926
+ child.stdin.write(`${JSON.stringify(message)}
25927
+ `);
25198
25928
  };
25199
- resolveRoot = async () => {
25929
+ const onData = (chunk) => {
25200
25930
  try {
25201
- const root = await realpath6(this.#approvedRoot);
25202
- const metadata = await stat5(root);
25203
- if (!metadata.isDirectory()) {
25204
- throw new LocalAuthorizationError(
25205
- "The approved root is not a directory"
25931
+ receivedBytes += Buffer.byteLength(chunk);
25932
+ if (receivedBytes > 32 * 1024 * 1024)
25933
+ throw new AcpExecutionError(
25934
+ "This saved conversation is too large to preview.",
25935
+ {},
25936
+ "native_history_too_large"
25206
25937
  );
25938
+ pending += chunk;
25939
+ let newline = pending.indexOf("\n");
25940
+ while (newline >= 0) {
25941
+ const line = pending.slice(0, newline);
25942
+ pending = pending.slice(newline + 1);
25943
+ newline = pending.indexOf("\n");
25944
+ if (line.trim().length === 0) continue;
25945
+ const value = JSON.parse(line);
25946
+ const message = responseSchema.parse(value);
25947
+ if (!("id" in message)) continue;
25948
+ if (message.id !== state.requestId)
25949
+ throw new AcpExecutionError(
25950
+ "Codex returned an invalid history response.",
25951
+ {},
25952
+ "invalid_native_session_response"
25953
+ );
25954
+ if ("error" in message) {
25955
+ fail(
25956
+ new AcpExecutionError(
25957
+ "Saved Codex history could not be read.",
25958
+ { cause: message.error },
25959
+ "native_history_unavailable"
25960
+ )
25961
+ );
25962
+ return;
25963
+ }
25964
+ switch (state.kind) {
25965
+ case "initializing":
25966
+ state = { kind: "metadata", requestId: 2 };
25967
+ send2({ method: "initialized", params: {} });
25968
+ send2({
25969
+ id: state.requestId,
25970
+ method: "thread/read",
25971
+ params: { threadId: nativeSessionId, includeTurns: false }
25972
+ });
25973
+ break;
25974
+ case "metadata": {
25975
+ const { thread } = threadSchema.parse(message.result);
25976
+ state = { kind: "turns", requestId: 3, thread };
25977
+ send2({
25978
+ id: state.requestId,
25979
+ method: "thread/turns/list",
25980
+ params: {
25981
+ threadId: nativeSessionId,
25982
+ limit: SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT,
25983
+ sortDirection: "desc",
25984
+ itemsView: "summary"
25985
+ }
25986
+ });
25987
+ break;
25988
+ }
25989
+ case "turns":
25990
+ response.resolve(decodeHistory(state.thread, message.result));
25991
+ return;
25992
+ default: {
25993
+ const unhandled = state;
25994
+ throw new Error(`Unknown history read state: ${String(unhandled)}`);
25995
+ }
25996
+ }
25207
25997
  }
25208
- return root;
25209
- } catch (error61) {
25210
- if (error61 instanceof LocalAuthorizationError) {
25211
- throw error61;
25998
+ } catch (cause) {
25999
+ fail(cause);
26000
+ }
26001
+ };
26002
+ const abort = () => response.reject(signal.reason);
26003
+ const onExit = () => fail(
26004
+ new AcpExecutionError(
26005
+ "Codex stopped before its saved history was available.",
26006
+ {},
26007
+ "native_history_unavailable"
26008
+ )
26009
+ );
26010
+ const timeout = setTimeout(
26011
+ () => fail(
26012
+ new AcpExecutionError(
26013
+ "Reading saved Codex history timed out.",
26014
+ {},
26015
+ "native_history_timeout"
26016
+ )
26017
+ ),
26018
+ 15e3
26019
+ );
26020
+ child.stdout.setEncoding("utf8");
26021
+ child.stdout.on("data", onData);
26022
+ child.stdin.on("error", fail);
26023
+ child.on("error", fail);
26024
+ child.on("exit", onExit);
26025
+ signal.addEventListener("abort", abort, { once: true });
26026
+ try {
26027
+ if (signal.aborted) abort();
26028
+ else
26029
+ send2({
26030
+ id: 1,
26031
+ method: "initialize",
26032
+ params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
26033
+ });
26034
+ return await response.promise;
26035
+ } finally {
26036
+ clearTimeout(timeout);
26037
+ signal.removeEventListener("abort", abort);
26038
+ child.stdout.removeListener("data", onData);
26039
+ if (child.pid !== void 0) await stopProcessTree(child);
26040
+ child.stdin.removeListener("error", fail);
26041
+ child.removeListener("error", fail);
26042
+ child.removeListener("exit", onExit);
26043
+ }
26044
+ }
26045
+
26046
+ // src/native-sessions/service.ts
26047
+ var NativeSessionService = class {
26048
+ #entries = /* @__PURE__ */ new Map();
26049
+ #cursors = /* @__PURE__ */ new Map();
26050
+ #config;
26051
+ #directories;
26052
+ #sessions;
26053
+ #audit;
26054
+ constructor(config2, directories, sessions, audit) {
26055
+ this.#config = config2;
26056
+ this.#directories = directories;
26057
+ this.#sessions = sessions;
26058
+ this.#audit = audit;
26059
+ }
26060
+ execute = async (command, signal) => {
26061
+ signal.throwIfAborted();
26062
+ const cwd = await this.#directories.resolve(
26063
+ command.bindingId,
26064
+ command.directoryId,
26065
+ signal
26066
+ );
26067
+ const additionalDirectories = await this.#directories.resolveMany(
26068
+ command.bindingId,
26069
+ command.additionalDirectoryIds,
26070
+ signal
26071
+ );
26072
+ signal.throwIfAborted();
26073
+ const options = {
26074
+ additionalDirectories,
26075
+ agent: this.#config.catalog.find(command.agentId),
26076
+ cwd,
26077
+ sessionId: command.sessionId,
26078
+ signal
26079
+ };
26080
+ const prepared = await this.#sessions.prepareSession(options);
26081
+ if (!prepared.capabilities.listSessions)
26082
+ throw new AcpExecutionError(
26083
+ "This Agent does not support native session listing",
26084
+ {},
26085
+ "native_session_unsupported"
26086
+ );
26087
+ const scope = JSON.stringify([
26088
+ command.agentId,
26089
+ command.bindingId,
26090
+ command.sessionId,
26091
+ cwd
26092
+ ]);
26093
+ const envelope2 = {
26094
+ kind: "native.session.result",
26095
+ protocolVersion: 1,
26096
+ requestId: command.requestId,
26097
+ sessionId: command.sessionId
26098
+ };
26099
+ if (command.action === "list") {
26100
+ let cursor = null;
26101
+ if (command.cursor !== null) {
26102
+ const known = this.#cursors.get(command.cursor);
26103
+ if (known?.scope !== scope)
26104
+ throw new AcpExecutionError(
26105
+ "Refresh the native session list before continuing",
26106
+ {},
26107
+ "native_session_cursor_expired"
26108
+ );
26109
+ cursor = known.cursor;
25212
26110
  }
25213
- throw new LocalAuthorizationError(
25214
- "The approved root cannot be resolved",
25215
- {
25216
- cause: error61
25217
- }
26111
+ const page = await this.#sessions.listNativeSessions(options, cursor);
26112
+ const entries = [];
26113
+ for (const info of page.sessions) {
26114
+ const authorized = await this.authorizeEntry(command, options, info);
26115
+ if (authorized === null) continue;
26116
+ const entryId = randomUUID3();
26117
+ if (this.#entries.size >= 5e3) this.#entries.clear();
26118
+ this.#entries.set(entryId, {
26119
+ scope,
26120
+ nativeSessionId: info.sessionId,
26121
+ cwd: authorized.cwd,
26122
+ additionalDirectories: authorized.additionalDirectories
26123
+ });
26124
+ entries.push({
26125
+ entryId,
26126
+ title: info.title ?? "Untitled session",
26127
+ directoryId: authorized.directoryId,
26128
+ directoryLabel: authorized.directoryLabel,
26129
+ updatedAt: info.updatedAt ?? null,
26130
+ additionalDirectories: authorized.additionalEntries
26131
+ });
26132
+ }
26133
+ let nextCursor = null;
26134
+ if (page.nextCursor != null) {
26135
+ if (page.nextCursor === cursor)
26136
+ throw new AcpExecutionError(
26137
+ "The Agent returned a repeated session cursor",
26138
+ {},
26139
+ "invalid_native_session_response"
26140
+ );
26141
+ nextCursor = randomUUID3();
26142
+ if (this.#cursors.size >= 500) this.#cursors.clear();
26143
+ this.#cursors.set(nextCursor, { scope, cursor: page.nextCursor });
26144
+ }
26145
+ this.record(command, "native_sessions_listed");
26146
+ return {
26147
+ ...envelope2,
26148
+ action: "list",
26149
+ capabilities: prepared.capabilities,
26150
+ entries,
26151
+ nextCursor
26152
+ };
26153
+ }
26154
+ const selected = this.#entries.get(command.entryId);
26155
+ if (selected?.scope !== scope)
26156
+ throw new AcpExecutionError(
26157
+ "Select a session from a fresh native session list",
26158
+ {},
26159
+ "native_session_not_found"
26160
+ );
26161
+ const target = await this.resolveTarget(command, options, selected);
26162
+ if (command.action === "delete") {
26163
+ if (!prepared.capabilities.deleteSession)
26164
+ throw new AcpExecutionError(
26165
+ "This Agent does not support native session deletion",
26166
+ {},
26167
+ "native_session_unsupported"
26168
+ );
26169
+ signal.throwIfAborted();
26170
+ this.record(command, "native_session_delete_authorized");
26171
+ const deletedSessionIds = await this.#sessions.deleteNativeSession(
26172
+ options,
26173
+ target.info.sessionId
25218
26174
  );
26175
+ this.record(command, "native_session_deleted");
26176
+ return {
26177
+ ...envelope2,
26178
+ action: "delete",
26179
+ entryId: command.entryId,
26180
+ deletedSessionIds
26181
+ };
26182
+ }
26183
+ if (command.action === "import" && !prepared.capabilities.loadSession && !prepared.capabilities.resumeSession)
26184
+ throw new AcpExecutionError(
26185
+ "This Agent cannot import native sessions",
26186
+ {},
26187
+ "native_session_unsupported"
26188
+ );
26189
+ if (command.action === "fork" && !prepared.capabilities.unstableForkSession)
26190
+ throw new AcpExecutionError(
26191
+ "This Agent does not support session forking",
26192
+ {},
26193
+ "native_session_unsupported"
26194
+ );
26195
+ if (target.additionalDirectories.length > 0 && !prepared.capabilities.additionalDirectories)
26196
+ throw new AcpExecutionError(
26197
+ "This Agent cannot restore additional working directories",
26198
+ {},
26199
+ "native_session_unsupported"
26200
+ );
26201
+ const opening = this.#sessions.openNativeSession(
26202
+ {
26203
+ ...options,
26204
+ cwd: target.cwd,
26205
+ sessionId: command.targetSessionId,
26206
+ additionalDirectories: target.additionalDirectories
26207
+ },
26208
+ { kind: command.action, nativeSessionId: target.info.sessionId }
26209
+ );
26210
+ const opened = await opening.catch(async (cause) => {
26211
+ signal.throwIfAborted();
26212
+ if (command.action !== "import" || options.agent.id !== "codex" || !(cause instanceof AcpExecutionError) || cause.code !== "acp_execution_failed")
26213
+ throw cause;
26214
+ const snapshot = await readCodexHistory(
26215
+ options.agent,
26216
+ target.cwd,
26217
+ target.info.sessionId,
26218
+ signal
26219
+ );
26220
+ const resolved = await this.#directories.identify(
26221
+ command.bindingId,
26222
+ snapshot.cwd,
26223
+ signal
26224
+ );
26225
+ if (snapshot.nativeSessionId !== target.info.sessionId || resolved.path !== target.cwd)
26226
+ throw new AcpExecutionError(
26227
+ "Codex returned history for a different session or workspace.",
26228
+ { cause },
26229
+ "invalid_native_session_response"
26230
+ );
26231
+ signal.throwIfAborted();
26232
+ this.record(command, "native_session_previewed");
26233
+ return { kind: "preview", history: snapshot.history };
26234
+ });
26235
+ if ("kind" in opened)
26236
+ return {
26237
+ ...envelope2,
26238
+ action: "preview",
26239
+ entryId: command.entryId,
26240
+ reason: "continuation_unavailable",
26241
+ title: target.info.title ?? "Untitled session",
26242
+ history: opened.history
26243
+ };
26244
+ signal.throwIfAborted();
26245
+ const ready = {
26246
+ additionalDirectories: target.additionalEntries,
26247
+ agentId: command.agentId,
26248
+ agentName: opened.prepared.agentName,
26249
+ agentVersion: opened.prepared.agentVersion,
26250
+ capabilities: opened.prepared.capabilities,
26251
+ commands: opened.prepared.commands,
26252
+ configOptions: opened.prepared.configOptions,
26253
+ directoryId: target.directoryId,
26254
+ directoryLabel: target.directoryLabel,
26255
+ kind: "session.ready",
26256
+ protocolVersion: 1,
26257
+ requestId: command.requestId,
26258
+ restored: true,
26259
+ sessionId: opened.sessionId
26260
+ };
26261
+ this.record(
26262
+ command,
26263
+ command.action === "fork" ? "native_session_forked" : "native_session_imported"
26264
+ );
26265
+ return {
26266
+ ...envelope2,
26267
+ action: command.action,
26268
+ ready,
26269
+ title: target.info.title ?? "Untitled session",
26270
+ history: opened.history
26271
+ };
26272
+ };
26273
+ authorizeEntry = async (command, options, info) => {
26274
+ try {
26275
+ const primary = await this.#directories.identify(
26276
+ command.bindingId,
26277
+ info.cwd,
26278
+ options.signal
26279
+ );
26280
+ const additionalDirectories = [];
26281
+ const additionalEntries = [];
26282
+ const paths = /* @__PURE__ */ new Set([primary.path]);
26283
+ for (const path2 of info.additionalDirectories) {
26284
+ const directory = await this.#directories.identify(
26285
+ command.bindingId,
26286
+ path2,
26287
+ options.signal
26288
+ );
26289
+ if (paths.has(directory.path))
26290
+ throw new LocalAuthorizationError(
26291
+ "Native session roots must be distinct"
26292
+ );
26293
+ paths.add(directory.path);
26294
+ additionalDirectories.push(directory.path);
26295
+ additionalEntries.push({
26296
+ directoryId: directory.directoryId,
26297
+ name: directory.name
26298
+ });
26299
+ }
26300
+ return {
26301
+ info,
26302
+ cwd: primary.path,
26303
+ directoryId: primary.directoryId,
26304
+ directoryLabel: primary.label,
26305
+ additionalDirectories,
26306
+ additionalEntries
26307
+ };
26308
+ } catch (error61) {
26309
+ options.signal.throwIfAborted();
26310
+ if (error61 instanceof LocalAuthorizationError) return null;
26311
+ throw error61;
25219
26312
  }
25220
26313
  };
26314
+ resolveTarget = async (command, options, selected) => {
26315
+ let cursor = null;
26316
+ const visited = /* @__PURE__ */ new Set();
26317
+ for (let index = 0; index < 100; index += 1) {
26318
+ const page = await this.#sessions.listNativeSessions(options, cursor);
26319
+ const info = page.sessions.find(
26320
+ (entry) => entry.sessionId === selected.nativeSessionId
26321
+ );
26322
+ if (info !== void 0) {
26323
+ const target = await this.authorizeEntry(command, options, info);
26324
+ if (target === null)
26325
+ throw new LocalAuthorizationError(
26326
+ "The selected native session is not authorized"
26327
+ );
26328
+ if (target.cwd !== selected.cwd || target.additionalDirectories.length !== selected.additionalDirectories.length || target.additionalDirectories.some(
26329
+ (path2, index2) => path2 !== selected.additionalDirectories[index2]
26330
+ ))
26331
+ throw new AcpExecutionError(
26332
+ "This session's directory changed. Refresh the list before continuing.",
26333
+ {},
26334
+ "native_session_target_changed"
26335
+ );
26336
+ return target;
26337
+ }
26338
+ cursor = page.nextCursor ?? null;
26339
+ if (cursor === null) break;
26340
+ if (visited.has(cursor))
26341
+ throw new AcpExecutionError(
26342
+ "The Agent returned a repeated session cursor",
26343
+ {},
26344
+ "invalid_native_session_response"
26345
+ );
26346
+ visited.add(cursor);
26347
+ }
26348
+ throw new AcpExecutionError(
26349
+ "The selected native session no longer exists. Refresh the list.",
26350
+ {},
26351
+ "native_session_not_found"
26352
+ );
26353
+ };
26354
+ record = (command, event) => {
26355
+ this.#audit.record({
26356
+ commandId: command.requestId,
26357
+ sessionId: command.sessionId,
26358
+ event,
26359
+ details: { agentId: command.agentId }
26360
+ });
26361
+ };
25221
26362
  };
25222
26363
 
25223
26364
  // src/relay-connection/connect.ts
@@ -25233,7 +26374,7 @@ var RelayConnectionError = class extends Error {
25233
26374
  };
25234
26375
  function connectRelay(url2, signal) {
25235
26376
  signal.throwIfAborted();
25236
- return new Promise((resolve6, reject) => {
26377
+ return new Promise((resolve5, reject) => {
25237
26378
  const socket = new WebSocket(url2, {
25238
26379
  dispatcher: environmentProxyDispatcher
25239
26380
  });
@@ -25286,7 +26427,7 @@ function connectRelay(url2, signal) {
25286
26427
  }
25287
26428
  finished = true;
25288
26429
  cleanup();
25289
- resolve6(socket);
26430
+ resolve5(socket);
25290
26431
  };
25291
26432
  function onTimeout() {
25292
26433
  fail(
@@ -25307,7 +26448,7 @@ function connectRelay(url2, signal) {
25307
26448
  }
25308
26449
 
25309
26450
  // src/relay-connection/liveness.ts
25310
- import { randomUUID as randomUUID3 } from "node:crypto";
26451
+ import { randomUUID as randomUUID4 } from "node:crypto";
25311
26452
  var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
25312
26453
  var HEARTBEAT_INTERVAL_MILLISECONDS = 2e4;
25313
26454
  var RelayLivenessState = class {
@@ -25398,7 +26539,7 @@ var RelayConnectionLiveness = class {
25398
26539
  }
25399
26540
  throw new Error("Heartbeat was scheduled in an invalid state");
25400
26541
  }
25401
- const heartbeatId = randomUUID3();
26542
+ const heartbeatId = randomUUID4();
25402
26543
  this.#state = new AwaitingHeartbeatAckState(
25403
26544
  heartbeatId,
25404
26545
  this.#timer.schedule(
@@ -25725,15 +26866,16 @@ function reportOperationFailure(socket, requestId, sessionId, error61) {
25725
26866
  })
25726
26867
  );
25727
26868
  }
25728
- async function resolveSessionDirectories(directories, bindingId, directoryId2, additionalDirectoryIds) {
25729
- const cwd = await directories.resolve(bindingId, directoryId2);
26869
+ async function resolveSessionDirectories(directories, bindingId, directoryId2, additionalDirectoryIds, signal) {
26870
+ const cwd = await directories.resolve(bindingId, directoryId2, signal);
25730
26871
  const additionalDirectories = [];
25731
26872
  const additionalDirectoryEntries = [];
25732
26873
  const unique = /* @__PURE__ */ new Set([cwd]);
25733
26874
  for (const additionalDirectoryId of additionalDirectoryIds) {
25734
26875
  const directory = await directories.resolve(
25735
26876
  bindingId,
25736
- additionalDirectoryId
26877
+ additionalDirectoryId,
26878
+ signal
25737
26879
  );
25738
26880
  if (unique.has(directory)) {
25739
26881
  throw new LocalAuthorizationError(
@@ -25753,11 +26895,12 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
25753
26895
  additionalDirectoryEntries
25754
26896
  );
25755
26897
  }
25756
- async function executeWorkspaceList(socket, command, directories, audit) {
26898
+ async function executeWorkspaceList(socket, command, directories, audit, signal) {
25757
26899
  try {
25758
26900
  const listing = await directories.list(
25759
26901
  command.bindingId,
25760
- command.directoryId
26902
+ command.directoryId,
26903
+ signal
25761
26904
  );
25762
26905
  audit.record({
25763
26906
  commandId: command.requestId,
@@ -25787,7 +26930,8 @@ async function executeSessionPrepare(socket, command, config2, directories, audi
25787
26930
  directories,
25788
26931
  command.bindingId,
25789
26932
  command.directoryId,
25790
- command.additionalDirectoryIds
26933
+ command.additionalDirectoryIds,
26934
+ signal
25791
26935
  );
25792
26936
  const agent = config2.catalog.find(command.agentId);
25793
26937
  const prepared = await sessions.prepareSession({
@@ -25799,7 +26943,8 @@ async function executeSessionPrepare(socket, command, config2, directories, audi
25799
26943
  });
25800
26944
  const listing = await directories.list(
25801
26945
  command.bindingId,
25802
- command.directoryId
26946
+ command.directoryId,
26947
+ signal
25803
26948
  );
25804
26949
  audit.record({
25805
26950
  commandId: command.requestId,
@@ -25835,7 +26980,8 @@ async function executeSessionConfigure(socket, command, config2, directories, au
25835
26980
  directories,
25836
26981
  command.bindingId,
25837
26982
  command.directoryId,
25838
- command.additionalDirectoryIds
26983
+ command.additionalDirectoryIds,
26984
+ signal
25839
26985
  );
25840
26986
  const configOptions = await sessions.configureSession({
25841
26987
  additionalDirectories: resolved.additionalDirectories,
@@ -25874,10 +27020,11 @@ async function executePrompt(socket, command, config2, directories, audit, sessi
25874
27020
  directories,
25875
27021
  command.bindingId,
25876
27022
  command.directoryId,
25877
- command.additionalDirectoryIds
27023
+ command.additionalDirectoryIds,
27024
+ signal
25878
27025
  );
25879
27026
  const agent = config2.catalog.find(command.agentId);
25880
- const processAttemptId = randomUUID4();
27027
+ const processAttemptId = randomUUID5();
25881
27028
  audit.record({
25882
27029
  commandId: command.commandId,
25883
27030
  event: "session_authorized",
@@ -25975,262 +27122,383 @@ function waitForRelayRetry(signal, timer) {
25975
27122
  if (signal.aborted) {
25976
27123
  return Promise.resolve();
25977
27124
  }
25978
- return new Promise((resolve6) => {
27125
+ return new Promise((resolve5) => {
25979
27126
  const retry = timer.schedule(finish, RELAY_RECONNECT_DELAY_MILLISECONDS);
25980
27127
  function finish() {
25981
27128
  retry.cancel();
25982
27129
  signal.removeEventListener("abort", finish);
25983
- resolve6();
27130
+ resolve5();
25984
27131
  }
25985
27132
  signal.addEventListener("abort", finish, { once: true });
25986
27133
  });
25987
27134
  }
25988
- async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, signal, timer) {
27135
+ async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, signal, timer) {
25989
27136
  const relayUrl = new URL(config2.relayUrl);
25990
27137
  relayUrl.searchParams.set("liveness", "1");
25991
27138
  const socket = await connectRelay(relayUrl, signal);
25992
27139
  const activeTurns = /* @__PURE__ */ new Map();
25993
27140
  const connectionController = new AbortController();
27141
+ const nativeRequests = /* @__PURE__ */ new Map();
25994
27142
  sessions.setObserver(new DaemonAcpObserver(socket));
25995
27143
  installationObserver.connect(socket);
25996
- await new Promise((resolve6, reject) => {
25997
- let finished = false;
25998
- const cleanup = () => {
25999
- connectionRefresh.close();
26000
- connectionLiveness.close();
26001
- signal.removeEventListener("abort", stop);
26002
- socket.removeEventListener("close", handleClose);
26003
- socket.removeEventListener("error", handleError);
26004
- socket.removeEventListener("message", handleMessage);
26005
- installationObserver.disconnect(socket);
26006
- connectionController.abort();
26007
- for (const turn of activeTurns.values()) {
26008
- turn.abortConnection();
26009
- }
26010
- activeTurns.clear();
26011
- };
26012
- const resolveConnection = () => {
26013
- if (finished) {
26014
- return;
26015
- }
26016
- finished = true;
26017
- cleanup();
26018
- resolve6();
26019
- };
26020
- const rejectConnection = () => {
26021
- if (finished) {
26022
- return;
26023
- }
26024
- finished = true;
26025
- cleanup();
26026
- reject(new Error("Relay WebSocket failed"));
26027
- };
26028
- const stop = () => {
26029
- socket.close(1e3, "Daemon stopped");
26030
- resolveConnection();
26031
- };
26032
- const refreshConnection = () => {
26033
- socket.close(1e3, "Refreshing idle relay connection");
26034
- resolveConnection();
26035
- };
26036
- const connectionLiveness = new RelayConnectionLiveness(timer, {
26037
- send: (message) => send(socket, message),
26038
- unresponsive: () => {
26039
- socket.close(4001, "Relay liveness check timed out");
27144
+ try {
27145
+ await new Promise((resolve5, reject) => {
27146
+ let finished = false;
27147
+ const cleanup = () => {
27148
+ connectionRefresh.close();
27149
+ connectionLiveness.close();
27150
+ signal.removeEventListener("abort", stop);
27151
+ socket.removeEventListener("close", handleClose);
27152
+ socket.removeEventListener("error", handleError);
27153
+ socket.removeEventListener("message", handleMessage);
27154
+ installationObserver.disconnect(socket);
27155
+ connectionController.abort();
27156
+ for (const turn of activeTurns.values()) {
27157
+ turn.abortConnection();
27158
+ }
27159
+ activeTurns.clear();
27160
+ };
27161
+ const resolveConnection = () => {
27162
+ if (finished) {
27163
+ return;
27164
+ }
27165
+ finished = true;
27166
+ cleanup();
27167
+ resolve5();
27168
+ };
27169
+ const rejectConnection = () => {
27170
+ if (finished) {
27171
+ return;
27172
+ }
27173
+ finished = true;
27174
+ cleanup();
27175
+ reject(new Error("Relay WebSocket failed"));
27176
+ };
27177
+ const stop = () => {
27178
+ socket.close(1e3, "Daemon stopped");
26040
27179
  resolveConnection();
26041
- }
26042
- });
26043
- const connectionRefresh = new RelayConnectionRefresh(
26044
- timer,
26045
- () => activeTurns.size === 0,
26046
- refreshConnection
26047
- );
26048
- signal.addEventListener("abort", stop, { once: true });
26049
- const handleClose = () => {
26050
- resolveConnection();
26051
- };
26052
- const handleError = () => {
26053
- if (signal.aborted) {
27180
+ };
27181
+ const refreshConnection = () => {
27182
+ socket.close(1e3, "Refreshing idle relay connection");
26054
27183
  resolveConnection();
26055
- return;
26056
- }
26057
- rejectConnection();
26058
- };
26059
- const handleMessage = (event) => {
26060
- const encoded = event.data;
26061
- if (typeof encoded !== "string") {
26062
- socket.close(4003, "Text message required");
26063
- rejectConnection();
26064
- return;
26065
- }
26066
- try {
26067
- const kind = decodeMessageKind(encoded);
26068
- if (kind === RUNTIME_LIVENESS_READY_KIND) {
26069
- decodeRuntimeLivenessReadyEvent(encoded);
26070
- connectionLiveness.start();
27184
+ };
27185
+ const connectionLiveness = new RelayConnectionLiveness(timer, {
27186
+ send: (message) => send(socket, message),
27187
+ unresponsive: () => {
27188
+ socket.close(4001, "Relay liveness check timed out");
27189
+ resolveConnection();
27190
+ }
27191
+ });
27192
+ const connectionRefresh = new RelayConnectionRefresh(
27193
+ timer,
27194
+ () => activeTurns.size === 0,
27195
+ refreshConnection
27196
+ );
27197
+ signal.addEventListener("abort", stop, { once: true });
27198
+ const handleClose = () => {
27199
+ resolveConnection();
27200
+ };
27201
+ const handleError = () => {
27202
+ if (signal.aborted) {
27203
+ resolveConnection();
26071
27204
  return;
26072
27205
  }
26073
- if (kind === RUNTIME_HEARTBEAT_ACK_KIND) {
26074
- connectionLiveness.acknowledge(
26075
- decodeRuntimeHeartbeatAckEvent(encoded)
26076
- );
27206
+ rejectConnection();
27207
+ };
27208
+ const handleMessage = (event) => {
27209
+ const encoded = event.data;
27210
+ if (typeof encoded !== "string") {
27211
+ socket.close(4003, "Text message required");
27212
+ rejectConnection();
26077
27213
  return;
26078
27214
  }
26079
- if (kind === SESSION_CANCEL_KIND) {
26080
- const cancellation = decodeSessionCancelCommand(encoded);
26081
- const turn2 = activeTurns.get(cancellation.commandId);
26082
- if (turn2 === void 0 || !turn2.matches(cancellation)) {
26083
- console.warn(
26084
- "Mobius daemon ignored cancellation for an inactive turn"
27215
+ try {
27216
+ const kind = decodeMessageKind(encoded);
27217
+ if (kind === NATIVE_SESSION_CANCEL_KIND) {
27218
+ const command2 = decodeNativeSessionCancel(encoded);
27219
+ const pending = nativeRequests.get(command2.requestId);
27220
+ if (pending?.sessionId === command2.sessionId)
27221
+ pending.controller.abort(
27222
+ new AcpExecutionError(
27223
+ "Native session operation cancelled",
27224
+ {},
27225
+ "native_session_cancelled"
27226
+ )
27227
+ );
27228
+ return;
27229
+ }
27230
+ if (kind === NATIVE_SESSION_REQUEST_KIND) {
27231
+ const command2 = decodeNativeSessionCommand(encoded);
27232
+ const previous = [...nativeRequests.values()].filter(
27233
+ (request) => request.agentId === command2.agentId
26085
27234
  );
27235
+ if (nativeRequests.has(command2.requestId) || nativeRequests.size >= 4 || previous.some((request) => !request.controller.signal.aborted)) {
27236
+ reportOperationFailure(
27237
+ socket,
27238
+ command2.requestId,
27239
+ command2.sessionId,
27240
+ new AcpExecutionError(
27241
+ "Another native session operation is running",
27242
+ {},
27243
+ "native_session_busy"
27244
+ )
27245
+ );
27246
+ return;
27247
+ }
27248
+ const controller = new AbortController();
27249
+ const operationSignal = AbortSignal.any([
27250
+ connectionController.signal,
27251
+ controller.signal
27252
+ ]);
27253
+ const timeout = timer.schedule(
27254
+ () => controller.abort(
27255
+ new AcpExecutionError(
27256
+ "Native session operation timed out",
27257
+ {},
27258
+ "native_session_timeout"
27259
+ )
27260
+ ),
27261
+ 9e4
27262
+ );
27263
+ const completion = (async () => {
27264
+ try {
27265
+ operationSignal.throwIfAborted();
27266
+ if (previous.length > 0) {
27267
+ await new Promise((resolve6, reject2) => {
27268
+ const cancel = () => reject2(operationSignal.reason);
27269
+ operationSignal.addEventListener("abort", cancel, {
27270
+ once: true
27271
+ });
27272
+ void Promise.all(
27273
+ previous.map((request) => request.completion)
27274
+ ).then(
27275
+ () => {
27276
+ operationSignal.removeEventListener("abort", cancel);
27277
+ resolve6();
27278
+ },
27279
+ (error61) => {
27280
+ operationSignal.removeEventListener("abort", cancel);
27281
+ reject2(error61);
27282
+ }
27283
+ );
27284
+ });
27285
+ }
27286
+ operationSignal.throwIfAborted();
27287
+ const result = await nativeSessions.execute(
27288
+ command2,
27289
+ operationSignal
27290
+ );
27291
+ if (socket.readyState === WebSocket2.OPEN)
27292
+ send(socket, encodeNativeSessionResult(result));
27293
+ } catch (error61) {
27294
+ const failure = operationSignal.aborted ? controller.signal.reason ?? new AcpExecutionError(
27295
+ "Native session operation cancelled",
27296
+ {},
27297
+ "native_session_cancelled"
27298
+ ) : error61;
27299
+ audit.record({
27300
+ commandId: command2.requestId,
27301
+ sessionId: command2.sessionId,
27302
+ event: "native_session_operation_failed",
27303
+ details: { code: operationErrorCode(failure) }
27304
+ });
27305
+ reportOperationFailure(
27306
+ socket,
27307
+ command2.requestId,
27308
+ command2.sessionId,
27309
+ failure
27310
+ );
27311
+ } finally {
27312
+ timeout.cancel();
27313
+ nativeRequests.delete(command2.requestId);
27314
+ }
27315
+ })();
27316
+ nativeRequests.set(command2.requestId, {
27317
+ agentId: command2.agentId,
27318
+ sessionId: command2.sessionId,
27319
+ controller,
27320
+ completion
27321
+ });
26086
27322
  return;
26087
27323
  }
26088
- if (!turn2.requestCancellation()) {
27324
+ if (kind === RUNTIME_LIVENESS_READY_KIND) {
27325
+ decodeRuntimeLivenessReadyEvent(encoded);
27326
+ connectionLiveness.start();
26089
27327
  return;
26090
27328
  }
26091
- audit.record({
26092
- commandId: cancellation.commandId,
26093
- event: "session_cancellation_requested",
26094
- sessionId: cancellation.sessionId
26095
- });
26096
- void sessions.cancelPrompt(cancellation.sessionId).catch((error61) => {
26097
- console.error(
26098
- "Mobius daemon could not cancel the agent turn",
26099
- error61
27329
+ if (kind === RUNTIME_HEARTBEAT_ACK_KIND) {
27330
+ connectionLiveness.acknowledge(
27331
+ decodeRuntimeHeartbeatAckEvent(encoded)
26100
27332
  );
26101
- });
26102
- return;
26103
- }
26104
- if (kind === WORKSPACE_LIST_KIND) {
26105
- const command2 = decodeWorkspaceListCommand(encoded);
26106
- void executeWorkspaceList(socket, command2, directories, audit);
26107
- return;
26108
- }
26109
- if (kind === SESSION_PREPARE_KIND) {
26110
- const command2 = decodeSessionPrepareCommand(encoded);
26111
- void executeSessionPrepare(
26112
- socket,
26113
- command2,
26114
- config2,
26115
- directories,
26116
- audit,
26117
- sessions,
26118
- connectionController.signal
26119
- );
26120
- return;
26121
- }
26122
- if (kind === SESSION_CONFIGURE_KIND) {
26123
- const command2 = decodeSessionConfigureCommand(encoded);
26124
- void executeSessionConfigure(
26125
- socket,
26126
- command2,
26127
- config2,
26128
- directories,
26129
- audit,
26130
- sessions,
26131
- connectionController.signal
26132
- );
26133
- return;
26134
- }
26135
- if (kind === SESSION_PERMISSION_RESPOND_KIND) {
26136
- const command2 = decodeSessionPermissionRespondCommand(encoded);
26137
- void sessions.respondPermission(command2).then(() => {
27333
+ return;
27334
+ }
27335
+ if (kind === SESSION_CANCEL_KIND) {
27336
+ const cancellation = decodeSessionCancelCommand(encoded);
27337
+ const turn2 = activeTurns.get(cancellation.commandId);
27338
+ if (turn2 === void 0 || !turn2.matches(cancellation)) {
27339
+ console.warn(
27340
+ "Mobius daemon ignored cancellation for an inactive turn"
27341
+ );
27342
+ return;
27343
+ }
27344
+ if (!turn2.requestCancellation()) {
27345
+ return;
27346
+ }
26138
27347
  audit.record({
26139
- commandId: command2.interactionId,
26140
- event: "session_permission_resolved",
26141
- sessionId: command2.sessionId
27348
+ commandId: cancellation.commandId,
27349
+ event: "session_cancellation_requested",
27350
+ sessionId: cancellation.sessionId
27351
+ });
27352
+ void sessions.cancelPrompt(cancellation.sessionId).catch((error61) => {
27353
+ console.error(
27354
+ "Mobius daemon could not cancel the agent turn",
27355
+ error61
27356
+ );
26142
27357
  });
26143
- }).catch((error61) => {
26144
- reportOperationFailure(
27358
+ return;
27359
+ }
27360
+ if (kind === WORKSPACE_LIST_KIND) {
27361
+ const command2 = decodeWorkspaceListCommand(encoded);
27362
+ void executeWorkspaceList(
26145
27363
  socket,
26146
- command2.interactionId,
26147
- command2.sessionId,
26148
- error61
27364
+ command2,
27365
+ directories,
27366
+ audit,
27367
+ connectionController.signal
26149
27368
  );
26150
- });
26151
- return;
26152
- }
26153
- if (kind === SESSION_ELICITATION_RESPOND_KIND) {
26154
- const command2 = decodeSessionElicitationRespondCommand(encoded);
26155
- void sessions.respondElicitation(command2).then(() => {
26156
- audit.record({
26157
- commandId: command2.interactionId,
26158
- event: "session_elicitation_resolved",
26159
- sessionId: command2.sessionId
27369
+ return;
27370
+ }
27371
+ if (kind === SESSION_PREPARE_KIND) {
27372
+ const command2 = decodeSessionPrepareCommand(encoded);
27373
+ void executeSessionPrepare(
27374
+ socket,
27375
+ command2,
27376
+ config2,
27377
+ directories,
27378
+ audit,
27379
+ sessions,
27380
+ connectionController.signal
27381
+ );
27382
+ return;
27383
+ }
27384
+ if (kind === SESSION_CONFIGURE_KIND) {
27385
+ const command2 = decodeSessionConfigureCommand(encoded);
27386
+ void executeSessionConfigure(
27387
+ socket,
27388
+ command2,
27389
+ config2,
27390
+ directories,
27391
+ audit,
27392
+ sessions,
27393
+ connectionController.signal
27394
+ );
27395
+ return;
27396
+ }
27397
+ if (kind === SESSION_PERMISSION_RESPOND_KIND) {
27398
+ const command2 = decodeSessionPermissionRespondCommand(encoded);
27399
+ void sessions.respondPermission(command2).then(() => {
27400
+ audit.record({
27401
+ commandId: command2.interactionId,
27402
+ event: "session_permission_resolved",
27403
+ sessionId: command2.sessionId
27404
+ });
27405
+ }).catch((error61) => {
27406
+ reportOperationFailure(
27407
+ socket,
27408
+ command2.interactionId,
27409
+ command2.sessionId,
27410
+ error61
27411
+ );
27412
+ });
27413
+ return;
27414
+ }
27415
+ if (kind === SESSION_ELICITATION_RESPOND_KIND) {
27416
+ const command2 = decodeSessionElicitationRespondCommand(encoded);
27417
+ void sessions.respondElicitation(command2).then(() => {
27418
+ audit.record({
27419
+ commandId: command2.interactionId,
27420
+ event: "session_elicitation_resolved",
27421
+ sessionId: command2.sessionId
27422
+ });
27423
+ }).catch((error61) => {
27424
+ reportOperationFailure(
27425
+ socket,
27426
+ command2.interactionId,
27427
+ command2.sessionId,
27428
+ error61
27429
+ );
26160
27430
  });
26161
- }).catch((error61) => {
26162
- reportOperationFailure(
27431
+ return;
27432
+ }
27433
+ if (kind === AGENT_INSTALL_REQUEST_KIND) {
27434
+ const command2 = decodeAgentInstallRequestCommand(encoded);
27435
+ void installations.request(command2, signal).catch((error61) => {
27436
+ console.error("Mobius Agent installation failed", error61);
27437
+ });
27438
+ return;
27439
+ }
27440
+ if (kind === AGENT_INSTALL_CANCEL_KIND) {
27441
+ const command2 = decodeAgentInstallCancelCommand(encoded);
27442
+ void installations.cancel(command2.requestId).catch((error61) => {
27443
+ reportOperationFailure(socket, command2.requestId, "", error61);
27444
+ });
27445
+ return;
27446
+ }
27447
+ if (kind !== SESSION_PROMPT_KIND) {
27448
+ throw new Error("Unsupported protocol message");
27449
+ }
27450
+ const command = decodeSessionPromptCommand(encoded);
27451
+ if (activeTurns.has(command.commandId)) {
27452
+ reportFailure(
26163
27453
  socket,
26164
- command2.interactionId,
26165
- command2.sessionId,
26166
- error61
27454
+ command,
27455
+ "duplicate_command",
27456
+ "The command is already running"
26167
27457
  );
26168
- });
26169
- return;
26170
- }
26171
- if (kind === AGENT_INSTALL_REQUEST_KIND) {
26172
- const command2 = decodeAgentInstallRequestCommand(encoded);
26173
- void installations.request(command2, signal).catch((error61) => {
26174
- console.error("Mobius Agent installation failed", error61);
26175
- });
26176
- return;
26177
- }
26178
- if (kind === AGENT_INSTALL_CANCEL_KIND) {
26179
- const command2 = decodeAgentInstallCancelCommand(encoded);
26180
- void installations.cancel(command2.requestId).catch((error61) => {
26181
- reportOperationFailure(socket, command2.requestId, "", error61);
26182
- });
26183
- return;
26184
- }
26185
- if (kind !== SESSION_PROMPT_KIND) {
26186
- throw new Error("Unsupported protocol message");
26187
- }
26188
- const command = decodeSessionPromptCommand(encoded);
26189
- if (activeTurns.has(command.commandId)) {
26190
- reportFailure(
27458
+ return;
27459
+ }
27460
+ const turn = new ActiveDaemonTurn(command, new AbortController());
27461
+ activeTurns.set(command.commandId, turn);
27462
+ void executePrompt(
26191
27463
  socket,
26192
27464
  command,
26193
- "duplicate_command",
26194
- "The command is already running"
26195
- );
26196
- return;
27465
+ config2,
27466
+ directories,
27467
+ audit,
27468
+ sessions,
27469
+ turn.signal
27470
+ ).catch((error61) => {
27471
+ console.error("Mobius daemon turn failed", error61);
27472
+ }).finally(() => {
27473
+ activeTurns.delete(command.commandId);
27474
+ connectionRefresh.afterTurnFinished();
27475
+ });
27476
+ } catch (error61) {
27477
+ console.error("Mobius daemon rejected a message", error61);
27478
+ socket.close(4008, "Invalid protocol message");
27479
+ rejectConnection();
26197
27480
  }
26198
- const turn = new ActiveDaemonTurn(command, new AbortController());
26199
- activeTurns.set(command.commandId, turn);
26200
- void executePrompt(
26201
- socket,
26202
- command,
26203
- config2,
26204
- directories,
26205
- audit,
26206
- sessions,
26207
- turn.signal
26208
- ).catch((error61) => {
26209
- console.error("Mobius daemon turn failed", error61);
26210
- }).finally(() => {
26211
- activeTurns.delete(command.commandId);
26212
- connectionRefresh.afterTurnFinished();
26213
- });
26214
- } catch (error61) {
26215
- console.error("Mobius daemon rejected a message", error61);
26216
- socket.close(4008, "Invalid protocol message");
26217
- rejectConnection();
27481
+ };
27482
+ socket.addEventListener("close", handleClose);
27483
+ socket.addEventListener("error", handleError);
27484
+ socket.addEventListener("message", handleMessage);
27485
+ if (signal.aborted) {
27486
+ stop();
26218
27487
  }
26219
- };
26220
- socket.addEventListener("close", handleClose);
26221
- socket.addEventListener("error", handleError);
26222
- socket.addEventListener("message", handleMessage);
26223
- if (signal.aborted) {
26224
- stop();
26225
- }
26226
- });
27488
+ });
27489
+ } finally {
27490
+ connectionController.abort();
27491
+ await Promise.all(
27492
+ [...nativeRequests.values()].map((request) => request.completion)
27493
+ );
27494
+ }
26227
27495
  }
26228
27496
  async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
26229
27497
  const installationAudit = new AuditInstallationEvents(audit);
26230
27498
  const stateDirectory = readStateDirectory();
26231
27499
  const specifications = supportedLocalAgentSpecifications();
26232
27500
  const installationExecutor = new FixedInstallationExecutor({
26233
- approvedRoot: config2.approvedRoot,
27501
+ defaultWorkspace: config2.defaultWorkspace,
26234
27502
  audit: installationAudit,
26235
27503
  catalog: config2.catalog,
26236
27504
  environment: process.env,
@@ -26239,13 +27507,12 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
26239
27507
  });
26240
27508
  await new AutomaticAdapterProvisioner(
26241
27509
  {
26242
- approvedRoot: config2.approvedRoot,
27510
+ defaultWorkspace: config2.defaultWorkspace,
26243
27511
  audit: installationAudit,
26244
27512
  catalog: config2.catalog,
26245
27513
  environment: process.env
26246
27514
  },
26247
27515
  new ManagedAdapterInstaller({
26248
- approvedRoot: config2.approvedRoot,
26249
27516
  environment: process.env,
26250
27517
  stateDirectory
26251
27518
  }),
@@ -26258,9 +27525,15 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
26258
27525
  );
26259
27526
  const directories = new WorkspaceDirectoryService(
26260
27527
  config2.bindingId,
26261
- config2.approvedRoot
27528
+ config2.defaultWorkspace
26262
27529
  );
26263
27530
  const installationObserver = new DaemonInstallationObserver();
27531
+ const nativeSessions = new NativeSessionService(
27532
+ config2,
27533
+ directories,
27534
+ sessions,
27535
+ audit
27536
+ );
26264
27537
  const installations = new AgentInstallationManager(
26265
27538
  specifications,
26266
27539
  new ConsoleInstallationAuthorizer(stateDirectory),
@@ -26280,6 +27553,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
26280
27553
  sessions,
26281
27554
  installations,
26282
27555
  installationObserver,
27556
+ nativeSessions,
26283
27557
  signal,
26284
27558
  timer
26285
27559
  );
@@ -26312,7 +27586,6 @@ export {
26312
27586
  AuditStore,
26313
27587
  LocalAuthorizationError,
26314
27588
  PairingClientError,
26315
- authorizeBinding,
26316
27589
  createAcpClient,
26317
27590
  loadDaemonConfig,
26318
27591
  pairLocalMachine,