@moxt-ai/mobius 0.0.166 → 0.0.168

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 (52) hide show
  1. package/dist/acp/agent-query-processes.d.ts +2 -1
  2. package/dist/acp/agent-query-processes.d.ts.map +1 -1
  3. package/dist/acp/agent-query-processes.js +6 -4
  4. package/dist/acp/agent-query-processes.js.map +1 -1
  5. package/dist/acp/agent-runtime-manager.d.ts +2 -1
  6. package/dist/acp/agent-runtime-manager.d.ts.map +1 -1
  7. package/dist/acp/agent-runtime-manager.js +11 -6
  8. package/dist/acp/agent-runtime-manager.js.map +1 -1
  9. package/dist/acp/agent-session.d.ts +3 -2
  10. package/dist/acp/agent-session.d.ts.map +1 -1
  11. package/dist/acp/agent-session.js +10 -7
  12. package/dist/acp/agent-session.js.map +1 -1
  13. package/dist/artifacts/local-file-streamer.d.ts +2 -1
  14. package/dist/artifacts/local-file-streamer.d.ts.map +1 -1
  15. package/dist/artifacts/local-file-streamer.js +6 -5
  16. package/dist/artifacts/local-file-streamer.js.map +1 -1
  17. package/dist/authorization/local-raster.d.ts +1 -0
  18. package/dist/authorization/local-raster.d.ts.map +1 -1
  19. package/dist/authorization/local-raster.js +1 -1
  20. package/dist/authorization/local-raster.js.map +1 -1
  21. package/dist/cli.js +565 -99
  22. package/dist/cli.js.map +4 -4
  23. package/dist/config.d.ts +1 -1
  24. package/dist/config.d.ts.map +1 -1
  25. package/dist/config.js +1 -1
  26. package/dist/config.js.map +1 -1
  27. package/dist/daemon-command-handler.d.ts +3 -1
  28. package/dist/daemon-command-handler.d.ts.map +1 -1
  29. package/dist/daemon-command-handler.js +2 -2
  30. package/dist/daemon-command-handler.js.map +1 -1
  31. package/dist/external-content/acp-content-externalizer.d.ts +12 -0
  32. package/dist/external-content/acp-content-externalizer.d.ts.map +1 -0
  33. package/dist/external-content/acp-content-externalizer.js +233 -0
  34. package/dist/external-content/acp-content-externalizer.js.map +1 -0
  35. package/dist/external-content/local-external-content-store.d.ts +34 -0
  36. package/dist/external-content/local-external-content-store.d.ts.map +1 -0
  37. package/dist/external-content/local-external-content-store.js +174 -0
  38. package/dist/external-content/local-external-content-store.js.map +1 -0
  39. package/dist/index.js +639 -179
  40. package/dist/index.js.map +4 -4
  41. package/dist/relay-connection/run-relay-connection.d.ts +3 -1
  42. package/dist/relay-connection/run-relay-connection.d.ts.map +1 -1
  43. package/dist/relay-connection/run-relay-connection.js +2 -1
  44. package/dist/relay-connection/run-relay-connection.js.map +1 -1
  45. package/dist/run-daemon.d.ts.map +1 -1
  46. package/dist/run-daemon.js +208 -140
  47. package/dist/run-daemon.js.map +1 -1
  48. package/dist/runtime.d.ts +2 -1
  49. package/dist/runtime.d.ts.map +1 -1
  50. package/dist/runtime.js +572 -111
  51. package/dist/runtime.js.map +4 -4
  52. package/package.json +16 -10
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/cli.ts
9
9
  import { constants as constants2 } from "node:fs";
10
- import { mkdir as mkdir6, open as open6 } from "node:fs/promises";
10
+ import { mkdir as mkdir7, open as open6 } from "node:fs/promises";
11
11
  import { resolve as resolve8 } from "node:path";
12
12
 
13
13
  // ../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
@@ -3381,21 +3381,16 @@ var program = new Command();
3381
3381
  // package.json
3382
3382
  var package_default = {
3383
3383
  name: "@moxt-ai/mobius",
3384
- version: "0.0.166",
3384
+ version: "0.0.168",
3385
3385
  description: "Mobius CLI for pairing and running local AI agent services.",
3386
3386
  type: "module",
3387
3387
  bin: {
3388
3388
  mobius: "dist/cli.js"
3389
3389
  },
3390
+ types: "./src/index.ts",
3390
3391
  exports: {
3391
- ".": {
3392
- types: "./dist/index.d.ts",
3393
- import: "./dist/index.js"
3394
- },
3395
- "./runtime": {
3396
- types: "./dist/runtime.d.ts",
3397
- import: "./dist/runtime.js"
3398
- }
3392
+ ".": "./src/index.ts",
3393
+ "./runtime": "./src/runtime.ts"
3399
3394
  },
3400
3395
  files: [
3401
3396
  "dist"
@@ -3404,7 +3399,18 @@ var package_default = {
3404
3399
  node: ">=22.13.0"
3405
3400
  },
3406
3401
  publishConfig: {
3407
- access: "public"
3402
+ access: "public",
3403
+ types: "./dist/index.d.ts",
3404
+ exports: {
3405
+ ".": {
3406
+ types: "./dist/index.d.ts",
3407
+ import: "./dist/index.js"
3408
+ },
3409
+ "./runtime": {
3410
+ types: "./dist/runtime.d.ts",
3411
+ import: "./dist/runtime.js"
3412
+ }
3413
+ }
3408
3414
  },
3409
3415
  repository: {
3410
3416
  type: "git",
@@ -29799,6 +29805,7 @@ var MAX_JSON_KEYS = 1e3;
29799
29805
  var SESSION_EVENT_V2_KIND = "session.event.v2";
29800
29806
  var boundedString = external_exports.string().max(MAX_CONTENT_LENGTH);
29801
29807
  var shortString = external_exports.string().max(2048);
29808
+ var externalContentKeySchema = external_exports.string().regex(/^[a-f0-9]{64}$/u);
29802
29809
  function boundedJsonIssue(value, depth = 0) {
29803
29810
  if (depth > MAX_JSON_DEPTH) {
29804
29811
  return "JSON nesting exceeds the maximum depth";
@@ -29866,6 +29873,30 @@ var imageContentSchema = external_exports.object({
29866
29873
  uri: boundedString.nullable().optional()
29867
29874
  }).readonly();
29868
29875
  var audioContentSchema = external_exports.object({ ...contentFields, data: boundedString, mimeType: shortString, type: external_exports.literal("audio") }).readonly();
29876
+ var externalImageContentSchema = external_exports.strictObject({
29877
+ ...contentFields,
29878
+ byteLength: external_exports.number().int().positive().safe(),
29879
+ imageKey: externalContentKeySchema,
29880
+ mimeType: shortString,
29881
+ type: external_exports.literal("external_image"),
29882
+ uri: boundedString.nullable().optional()
29883
+ }).readonly();
29884
+ var externalAudioContentSchema = external_exports.strictObject({
29885
+ ...contentFields,
29886
+ audioKey: externalContentKeySchema,
29887
+ byteLength: external_exports.number().int().positive().safe(),
29888
+ mimeType: shortString,
29889
+ type: external_exports.literal("external_audio")
29890
+ }).readonly();
29891
+ var externalResourceContentSchema = external_exports.strictObject({
29892
+ ...contentFields,
29893
+ byteLength: external_exports.number().int().positive().safe(),
29894
+ encoding: external_exports.enum(["binary", "text"]),
29895
+ mimeType: shortString.nullable().optional(),
29896
+ resourceKey: externalContentKeySchema,
29897
+ type: external_exports.literal("external_resource"),
29898
+ uri: boundedString
29899
+ }).readonly();
29869
29900
  var resourceLinkSchema = external_exports.object({
29870
29901
  ...contentFields,
29871
29902
  description: boundedString.nullable().optional(),
@@ -29898,7 +29929,10 @@ var contentBlockV2Schema = external_exports.discriminatedUnion("type", [
29898
29929
  imageContentSchema,
29899
29930
  audioContentSchema,
29900
29931
  resourceLinkSchema,
29901
- embeddedResourceSchema
29932
+ embeddedResourceSchema,
29933
+ externalImageContentSchema,
29934
+ externalAudioContentSchema,
29935
+ externalResourceContentSchema
29902
29936
  ]);
29903
29937
  var toolCallContentSchema = external_exports.discriminatedUnion("type", [
29904
29938
  external_exports.object({ _meta: optionalMetadata, content: contentBlockV2Schema, type: external_exports.literal("content") }).readonly(),
@@ -30710,11 +30744,11 @@ function createDaemonConfig(connection, agents = [], installableAgents = [], loc
30710
30744
 
30711
30745
  // src/daemon-manager.ts
30712
30746
  import { spawn as spawn6 } from "node:child_process";
30713
- import { createHash as createHash8, randomBytes } from "node:crypto";
30714
- import { readFile as readFile3, unlink as unlink2, writeFile as writeFile4 } from "node:fs/promises";
30747
+ import { createHash as createHash9, randomBytes } from "node:crypto";
30748
+ import { readFile as readFile3, unlink as unlink2, writeFile as writeFile5 } from "node:fs/promises";
30715
30749
  import { createConnection, createServer } from "node:net";
30716
30750
  import { tmpdir } from "node:os";
30717
- import { join as join19 } from "node:path";
30751
+ import { join as join20 } from "node:path";
30718
30752
 
30719
30753
  // src/pairing/pair-local-machine.ts
30720
30754
  import { mkdir as mkdir5, realpath as realpath6, stat as stat5 } from "node:fs/promises";
@@ -31544,8 +31578,8 @@ var AuditStore = class {
31544
31578
  };
31545
31579
 
31546
31580
  // src/run-daemon.ts
31547
- import { createHash as createHash7, randomUUID as randomUUID7 } from "node:crypto";
31548
- import { join as join18 } from "node:path";
31581
+ import { createHash as createHash8, randomUUID as randomUUID8 } from "node:crypto";
31582
+ import { join as join19 } from "node:path";
31549
31583
  import { styleText } from "node:util";
31550
31584
 
31551
31585
  // src/acp/active-executions.ts
@@ -34917,7 +34951,7 @@ function sql(strings, ...params) {
34917
34951
  return new SQL([new StringChunk(str)]);
34918
34952
  }
34919
34953
  sql2.raw = raw;
34920
- function join20(chunks, separator) {
34954
+ function join21(chunks, separator) {
34921
34955
  const result = [];
34922
34956
  for (const [i, chunk] of chunks.entries()) {
34923
34957
  if (i > 0 && separator !== void 0) {
@@ -34927,7 +34961,7 @@ function sql(strings, ...params) {
34927
34961
  }
34928
34962
  return new SQL(result);
34929
34963
  }
34930
- sql2.join = join20;
34964
+ sql2.join = join21;
34931
34965
  function identifier(value) {
34932
34966
  return new Name(value);
34933
34967
  }
@@ -37471,7 +37505,7 @@ var SQLiteSelectQueryBuilderBase = class extends TypedQueryBuilder {
37471
37505
  const baseTableName = this.tableName;
37472
37506
  const tableName = getTableLikeName(table);
37473
37507
  for (const item of extractUsedTable(table)) this.usedTables.add(item);
37474
- if (typeof tableName === "string" && this.config.joins?.some((join20) => join20.alias === tableName)) {
37508
+ if (typeof tableName === "string" && this.config.joins?.some((join21) => join21.alias === tableName)) {
37475
37509
  throw new Error(`Alias "${tableName}" is already used in this query`);
37476
37510
  }
37477
37511
  if (!this.isPartialSelect) {
@@ -38330,7 +38364,7 @@ var SQLiteUpdateBase = class extends QueryPromise {
38330
38364
  createJoin(joinType) {
38331
38365
  return (table, on) => {
38332
38366
  const tableName = getTableLikeName(table);
38333
- if (typeof tableName === "string" && this.config.joins.some((join20) => join20.alias === tableName)) {
38367
+ if (typeof tableName === "string" && this.config.joins.some((join21) => join21.alias === tableName)) {
38334
38368
  throw new Error(`Alias "${tableName}" is already used in this query`);
38335
38369
  }
38336
38370
  if (typeof on === "function") {
@@ -39653,6 +39687,7 @@ function recordsEqual(left, right) {
39653
39687
  }
39654
39688
  var AgentSession = class _AgentSession {
39655
39689
  #connection;
39690
+ #contentExternalizer;
39656
39691
  #interactions;
39657
39692
  #additionalDirectories;
39658
39693
  #agentId;
@@ -39680,7 +39715,7 @@ var AgentSession = class _AgentSession {
39680
39715
  #sessionTitle = null;
39681
39716
  #sessionUpdatedAt = "";
39682
39717
  #turn = new IdleAcpTurn();
39683
- constructor(agent, cwd, additionalDirectories, mobiusSessionId, getObserver, store, metrics) {
39718
+ constructor(agent, cwd, additionalDirectories, mobiusSessionId, getObserver, store, metrics, contentExternalizer) {
39684
39719
  this.#updates = new AgentUpdateStream((notification) => this.#processUpdate(notification));
39685
39720
  this.#additionalDirectories = [...additionalDirectories];
39686
39721
  this.#agentId = agent.id;
@@ -39700,8 +39735,9 @@ var AgentSession = class _AgentSession {
39700
39735
  observer: getObserver
39701
39736
  });
39702
39737
  this.#connection = new AgentConnection(agent, cwd, this);
39738
+ this.#contentExternalizer = contentExternalizer;
39703
39739
  }
39704
- static async #start(options, getObserver, store, initialize, metrics) {
39740
+ static async #start(options, getObserver, store, initialize, metrics, contentExternalizer) {
39705
39741
  for (let attempt = 1; attempt <= 2; attempt += 1) {
39706
39742
  options.signal.throwIfAborted();
39707
39743
  const unchanged = await metrics.measure(
@@ -39729,7 +39765,8 @@ var AgentSession = class _AgentSession {
39729
39765
  options.sessionId,
39730
39766
  getObserver,
39731
39767
  store,
39732
- metrics
39768
+ metrics,
39769
+ contentExternalizer
39733
39770
  )
39734
39771
  );
39735
39772
  try {
@@ -39752,19 +39789,21 @@ var AgentSession = class _AgentSession {
39752
39789
  }
39753
39790
  throw new AcpExecutionError("ACP agent initialization failed");
39754
39791
  }
39755
- static start = async (options, getObserver, store, metrics = unmeasuredOperationMetrics) => await _AgentSession.#start(
39792
+ static start = async (options, getObserver, store, metrics, contentExternalizer) => await _AgentSession.#start(
39756
39793
  options,
39757
39794
  getObserver,
39758
39795
  store,
39759
39796
  async (runtime) => await runtime.initialize(options.signal, options.origin),
39760
- metrics
39797
+ metrics,
39798
+ contentExternalizer
39761
39799
  );
39762
- static startNativeSessionBrowser = async (options, getObserver, store) => await _AgentSession.#start(
39800
+ static startNativeSessionBrowser = async (options, getObserver, store, contentExternalizer) => await _AgentSession.#start(
39763
39801
  options,
39764
39802
  getObserver,
39765
39803
  store,
39766
39804
  async (runtime) => await runtime.#initializeAgent(options.signal),
39767
- unmeasuredOperationMetrics
39805
+ unmeasuredOperationMetrics,
39806
+ contentExternalizer
39768
39807
  );
39769
39808
  belongsTo = (agentId, cwd, additionalDirectories) => this.#agentId === agentId && this.#cwd === cwd && arraysEqual(this.#additionalDirectories, additionalDirectories);
39770
39809
  usesEnvironment = (environment) => recordsEqual(this.#environment, environment);
@@ -40468,8 +40507,13 @@ var AgentSession = class _AgentSession {
40468
40507
  };
40469
40508
  #processUpdate = async (notification) => {
40470
40509
  this.assertNativeSession(notification.sessionId);
40471
- const update = notification.update;
40472
- const rawUpdate = decodeAcpSessionUpdateV2(JSON.stringify(update));
40510
+ const externalized = await this.#contentExternalizer.update(
40511
+ this.#mobiusSessionId,
40512
+ notification.update,
40513
+ AbortSignal.timeout(3e4)
40514
+ );
40515
+ const update = externalized.agent;
40516
+ const rawUpdate = decodeAcpSessionUpdateV2(JSON.stringify(externalized.event));
40473
40517
  if (this.#sessionLoad.kind === "capturing") {
40474
40518
  await this.#sessionLoad.history.record(update, rawUpdate);
40475
40519
  } else {
@@ -40756,8 +40800,10 @@ var AgentQueryProcesses = class {
40756
40800
  #processes;
40757
40801
  #observer = new NullAcpSessionObserver();
40758
40802
  #store = new MemoryAcpSessionStore();
40759
- constructor(processes) {
40803
+ #contentExternalizer;
40804
+ constructor(processes, contentExternalizer) {
40760
40805
  this.#processes = processes;
40806
+ this.#contentExternalizer = contentExternalizer;
40761
40807
  this.#processesByQuery = new RetainedAgentProcesses({
40762
40808
  touch: processes.touch,
40763
40809
  changed: processes.notifyChanged
@@ -40773,7 +40819,12 @@ var AgentQueryProcesses = class {
40773
40819
  async #startRetained(options) {
40774
40820
  const runtime = await this.#processes.startRetained(
40775
40821
  options.signal,
40776
- () => AgentSession.startNativeSessionBrowser(options, () => this.#observer, this.#store),
40822
+ () => AgentSession.startNativeSessionBrowser(
40823
+ options,
40824
+ () => this.#observer,
40825
+ this.#store,
40826
+ this.#contentExternalizer
40827
+ ),
40777
40828
  {
40778
40829
  isBusy: () => this.#processesByQuery.isBusy(options.sessionId),
40779
40830
  retire: (runtime2) => this.retire(options.sessionId, runtime2)
@@ -40849,7 +40900,8 @@ var AgentQueryProcesses = class {
40849
40900
  async () => await AgentSession.startNativeSessionBrowser(
40850
40901
  options,
40851
40902
  () => this.#observer,
40852
- new MemoryAcpSessionStore()
40903
+ new MemoryAcpSessionStore(),
40904
+ this.#contentExternalizer
40853
40905
  ),
40854
40906
  async (runtime) => {
40855
40907
  runtime.selectNativeSession(nativeSessionId);
@@ -40864,7 +40916,8 @@ var AgentQueryProcesses = class {
40864
40916
  async () => await AgentSession.startNativeSessionBrowser(
40865
40917
  options,
40866
40918
  () => this.#observer,
40867
- new MemoryAcpSessionStore()
40919
+ new MemoryAcpSessionStore(),
40920
+ this.#contentExternalizer
40868
40921
  ),
40869
40922
  async (runtime) => {
40870
40923
  runtime.selectNativeSession(nativeSessionId);
@@ -40880,6 +40933,393 @@ var AgentQueryProcesses = class {
40880
40933
  };
40881
40934
  };
40882
40935
 
40936
+ // src/external-content/acp-content-externalizer.ts
40937
+ var MAXIMUM_ENCODED_CONTENT_CHARACTERS = 4e6;
40938
+ function decodeBase64(data) {
40939
+ if (data.length > MAXIMUM_ENCODED_CONTENT_CHARACTERS || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/u.test(data)) {
40940
+ throw new Error("The ACP embedded content is not valid bounded base64");
40941
+ }
40942
+ const bytes = Buffer.from(data, "base64");
40943
+ if (bytes.toString("base64") !== data) {
40944
+ throw new Error("The ACP embedded content is not canonical base64");
40945
+ }
40946
+ return bytes;
40947
+ }
40948
+ var embeddedImageSchema = external_exports.looseObject({
40949
+ type: external_exports.literal("image"),
40950
+ data: external_exports.string(),
40951
+ mimeType: external_exports.string()
40952
+ });
40953
+ function isRecord10(value) {
40954
+ return typeof value === "object" && value !== null && !Array.isArray(value);
40955
+ }
40956
+ var AcpContentExternalizer = class {
40957
+ #store;
40958
+ constructor(store) {
40959
+ this.#store = store;
40960
+ }
40961
+ async #content(sessionId, content, signal) {
40962
+ switch (content.type) {
40963
+ case "text":
40964
+ case "resource_link":
40965
+ return { agent: content, event: content };
40966
+ case "image": {
40967
+ if (content.data.length === 0) {
40968
+ return { agent: content, event: content };
40969
+ }
40970
+ try {
40971
+ const bytes = decodeBase64(content.data);
40972
+ if (sniffRasterMime(bytes) !== content.mimeType) {
40973
+ throw new Error("Embedded image bytes do not match a supported image MIME type");
40974
+ }
40975
+ const stored = await this.#store.put({
40976
+ bytes,
40977
+ kind: "image",
40978
+ mediaType: content.mimeType,
40979
+ name: "image",
40980
+ sessionId,
40981
+ signal
40982
+ });
40983
+ return {
40984
+ agent: { ...content, data: "", uri: `mobius-content:image:${stored.key}` },
40985
+ event: {
40986
+ _meta: content._meta,
40987
+ annotations: content.annotations,
40988
+ byteLength: stored.byteLength,
40989
+ imageKey: stored.key,
40990
+ mimeType: content.mimeType,
40991
+ type: "external_image",
40992
+ uri: content.uri
40993
+ }
40994
+ };
40995
+ } catch {
40996
+ signal.throwIfAborted();
40997
+ const unavailable = { type: "text", text: "[Image unavailable]" };
40998
+ return { agent: unavailable, event: unavailable };
40999
+ }
41000
+ }
41001
+ case "audio": {
41002
+ if (content.data.length === 0) {
41003
+ return { agent: content, event: content };
41004
+ }
41005
+ const stored = await this.#store.put({
41006
+ bytes: decodeBase64(content.data),
41007
+ kind: "audio",
41008
+ mediaType: content.mimeType,
41009
+ name: "audio",
41010
+ sessionId,
41011
+ signal
41012
+ });
41013
+ return {
41014
+ agent: content,
41015
+ event: {
41016
+ _meta: content._meta,
41017
+ annotations: content.annotations,
41018
+ audioKey: stored.key,
41019
+ byteLength: stored.byteLength,
41020
+ mimeType: content.mimeType,
41021
+ type: "external_audio"
41022
+ }
41023
+ };
41024
+ }
41025
+ case "resource": {
41026
+ const embedded = content.resource;
41027
+ const encoding = "text" in embedded ? "text" : "binary";
41028
+ const bytes = "text" in embedded ? Buffer.from(embedded.text, "utf8") : decodeBase64(embedded.blob);
41029
+ if (bytes.byteLength === 0) {
41030
+ return { agent: content, event: content };
41031
+ }
41032
+ const mediaType = embedded.mimeType ?? "application/octet-stream";
41033
+ const stored = await this.#store.put({
41034
+ bytes,
41035
+ kind: "resource",
41036
+ mediaType,
41037
+ name: "resource",
41038
+ sessionId,
41039
+ signal
41040
+ });
41041
+ return {
41042
+ agent: content,
41043
+ event: {
41044
+ _meta: content._meta,
41045
+ annotations: content.annotations,
41046
+ byteLength: stored.byteLength,
41047
+ encoding,
41048
+ mimeType: embedded.mimeType,
41049
+ resourceKey: stored.key,
41050
+ type: "external_resource",
41051
+ uri: embedded.uri
41052
+ }
41053
+ };
41054
+ }
41055
+ }
41056
+ }
41057
+ async #rawOutput(sessionId, value, images, signal, depth = 0) {
41058
+ signal.throwIfAborted();
41059
+ if (depth > 16) {
41060
+ throw new Error("ACP tool output exceeds the maximum nesting depth");
41061
+ }
41062
+ if (Array.isArray(value)) {
41063
+ const result2 = [];
41064
+ for (const item of value) {
41065
+ result2.push(await this.#rawOutput(sessionId, item, images, signal, depth + 1));
41066
+ }
41067
+ return result2;
41068
+ }
41069
+ if (!isRecord10(value)) {
41070
+ return value;
41071
+ }
41072
+ const image = embeddedImageSchema.safeParse(value);
41073
+ if (image.success && image.data.data.length > 0) {
41074
+ const prepared = await this.#content(sessionId, image.data, signal);
41075
+ if (isRecord10(prepared.event) && typeof prepared.event["imageKey"] === "string") {
41076
+ images.set(prepared.event["imageKey"], prepared);
41077
+ } else {
41078
+ images.set(`unavailable:${images.size}`, prepared);
41079
+ }
41080
+ return prepared.event;
41081
+ }
41082
+ const result = {};
41083
+ for (const [key, item] of Object.entries(value)) {
41084
+ result[key] = await this.#rawOutput(sessionId, item, images, signal, depth + 1);
41085
+ }
41086
+ return result;
41087
+ }
41088
+ async #toolUpdate(sessionId, update, signal) {
41089
+ const images = /* @__PURE__ */ new Map();
41090
+ const rawOutput = update.rawOutput === void 0 ? void 0 : await this.#rawOutput(sessionId, update.rawOutput, images, signal);
41091
+ const originalJson = images.size === 0 ? void 0 : JSON.stringify(update.rawOutput);
41092
+ const rewrittenJson = images.size === 0 ? void 0 : JSON.stringify(rawOutput);
41093
+ const agentContent = [];
41094
+ const eventContent = [];
41095
+ for (const item of update.content ?? []) {
41096
+ if (item.type !== "content") {
41097
+ agentContent.push(item);
41098
+ eventContent.push(item);
41099
+ continue;
41100
+ }
41101
+ const content = item.content.type === "text" && item.content.text === originalJson && rewrittenJson !== void 0 ? { ...item.content, text: rewrittenJson } : item.content;
41102
+ const prepared = await this.#content(sessionId, content, signal);
41103
+ agentContent.push({ ...item, content: prepared.agent });
41104
+ eventContent.push({ ...item, content: prepared.event });
41105
+ if (isRecord10(prepared.event) && typeof prepared.event["imageKey"] === "string") {
41106
+ images.delete(prepared.event["imageKey"]);
41107
+ }
41108
+ }
41109
+ for (const prepared of images.values()) {
41110
+ agentContent.push({ type: "content", content: prepared.agent });
41111
+ eventContent.push({ type: "content", content: prepared.event });
41112
+ }
41113
+ const output2 = update.rawOutput === void 0 ? {} : { rawOutput };
41114
+ const hasContent = update.content !== void 0 && update.content !== null || agentContent.length > 0;
41115
+ return {
41116
+ agent: { ...update, ...output2, ...hasContent ? { content: agentContent } : {} },
41117
+ event: { ...update, ...output2, ...hasContent ? { content: eventContent } : {} }
41118
+ };
41119
+ }
41120
+ update = async (sessionId, update, signal) => {
41121
+ switch (update.sessionUpdate) {
41122
+ case "user_message_chunk":
41123
+ case "agent_message_chunk":
41124
+ case "agent_thought_chunk":
41125
+ case "compaction_summary_chunk": {
41126
+ const content = await this.#content(sessionId, update.content, signal);
41127
+ return {
41128
+ agent: { ...update, content: content.agent },
41129
+ event: { ...update, content: content.event }
41130
+ };
41131
+ }
41132
+ case "tool_call":
41133
+ case "tool_call_update":
41134
+ return await this.#toolUpdate(sessionId, update, signal);
41135
+ case "compaction_update": {
41136
+ if (update.summary === void 0 || update.summary === null) {
41137
+ return { agent: update, event: update };
41138
+ }
41139
+ const content = await Promise.all(
41140
+ update.summary.map(async (item) => await this.#content(sessionId, item, signal))
41141
+ );
41142
+ return {
41143
+ agent: { ...update, summary: content.map((item) => item.agent) },
41144
+ event: { ...update, summary: content.map((item) => item.event) }
41145
+ };
41146
+ }
41147
+ case "plan":
41148
+ case "plan_update":
41149
+ case "plan_removed":
41150
+ case "available_commands_update":
41151
+ case "current_mode_update":
41152
+ case "config_option_update":
41153
+ case "session_info_update":
41154
+ case "usage_update":
41155
+ return { agent: update, event: update };
41156
+ }
41157
+ };
41158
+ };
41159
+
41160
+ // src/external-content/local-external-content-store.ts
41161
+ import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
41162
+ import { lstat, mkdir as mkdir6, readdir as readdir3, realpath as realpath8, rename as rename4, rm as rm3, stat as stat7, utimes, writeFile as writeFile4 } from "node:fs/promises";
41163
+ import { dirname as dirname5, join as join16 } from "node:path";
41164
+ var contentRequest = /^mobius-content:(image|audio|resource):([a-f0-9]{64})$/u;
41165
+ var CONTENT_LIFETIME_MILLISECONDS = 24 * 60 * 60 * 1e3;
41166
+ var metadataSchema2 = external_exports.strictObject({
41167
+ kind: external_exports.enum(["image", "audio", "resource"]),
41168
+ mediaType: external_exports.string().min(1).max(2048).regex(/^[\u0020-\u007e]+$/u),
41169
+ name: external_exports.string().min(1).max(500)
41170
+ });
41171
+ var UnretainedExternalContentStore = class {
41172
+ put = async ({ bytes, signal }) => {
41173
+ signal.throwIfAborted();
41174
+ return { byteLength: bytes.byteLength, key: createHash3("sha256").update(bytes).digest("hex") };
41175
+ };
41176
+ resolve = (_sessionId, _request, signal) => {
41177
+ signal.throwIfAborted();
41178
+ return Promise.resolve(null);
41179
+ };
41180
+ };
41181
+ async function atomicWrite(path3, bytes, signal) {
41182
+ const temporary = `${path3}.${randomUUID2()}.tmp`;
41183
+ try {
41184
+ await writeFile4(temporary, bytes, { mode: 384, signal });
41185
+ signal.throwIfAborted();
41186
+ await rename4(temporary, path3);
41187
+ } finally {
41188
+ await rm3(temporary, { force: true });
41189
+ }
41190
+ }
41191
+ var LocalExternalContentStore = class {
41192
+ #root;
41193
+ #entries = /* @__PURE__ */ new Map();
41194
+ #operations = /* @__PURE__ */ new Set();
41195
+ #lifetime = new AbortController();
41196
+ #expirationTimer;
41197
+ #cleanup = Promise.resolve();
41198
+ constructor(stateDirectory) {
41199
+ this.#root = join16(stateDirectory, "tmp", "session-content", randomUUID2());
41200
+ this.#expirationTimer = setInterval(() => {
41201
+ void this.#expire().catch(() => void 0);
41202
+ }, 6e4);
41203
+ this.#expirationTimer.unref();
41204
+ }
41205
+ #expire = () => {
41206
+ this.#cleanup = this.#cleanup.catch(() => void 0).then(async () => {
41207
+ await mkdir6(this.#root, { mode: 448, recursive: true });
41208
+ const now = /* @__PURE__ */ new Date();
41209
+ await utimes(this.#root, now, now);
41210
+ for (const directory of await readdir3(dirname5(this.#root), { withFileTypes: true })) {
41211
+ if (!directory.isDirectory() || !/^[a-f0-9-]{36}$/u.test(directory.name)) {
41212
+ continue;
41213
+ }
41214
+ const path3 = join16(dirname5(this.#root), directory.name);
41215
+ if (path3 === this.#root) {
41216
+ continue;
41217
+ }
41218
+ const modified = await stat7(path3).then(
41219
+ (entry) => entry.mtimeMs,
41220
+ () => Date.now()
41221
+ );
41222
+ if (modified + CONTENT_LIFETIME_MILLISECONDS <= Date.now()) {
41223
+ await rm3(path3, { force: true, recursive: true });
41224
+ }
41225
+ }
41226
+ for (const [request, entry] of this.#entries) {
41227
+ if (entry.expiresAt > Date.now()) {
41228
+ continue;
41229
+ }
41230
+ await rm3(entry.path, { force: true });
41231
+ this.#entries.delete(request);
41232
+ }
41233
+ });
41234
+ return this.#cleanup;
41235
+ };
41236
+ #track = async (operation) => {
41237
+ this.#lifetime.signal.throwIfAborted();
41238
+ const pending = operation();
41239
+ this.#operations.add(pending);
41240
+ try {
41241
+ return await pending;
41242
+ } finally {
41243
+ this.#operations.delete(pending);
41244
+ }
41245
+ };
41246
+ put = (input2) => this.#track(() => this.#put(input2));
41247
+ #put = async ({ bytes, kind, mediaType, name, sessionId, signal }) => {
41248
+ const active = AbortSignal.any([signal, this.#lifetime.signal]);
41249
+ active.throwIfAborted();
41250
+ const metadata = metadataSchema2.parse({ kind, mediaType, name });
41251
+ const key = createHash3("sha256").update(bytes).digest("hex");
41252
+ const request = `mobius-content:${kind}:${key}`;
41253
+ const existing = this.#entries.get(request);
41254
+ if (existing !== void 0 && existing.expiresAt > Date.now()) {
41255
+ this.#entries.set(request, {
41256
+ ...existing,
41257
+ expiresAt: Date.now() + CONTENT_LIFETIME_MILLISECONDS,
41258
+ sessions: /* @__PURE__ */ new Set([...existing.sessions, sessionId])
41259
+ });
41260
+ return { byteLength: existing.byteLength, key };
41261
+ }
41262
+ await this.#expire();
41263
+ active.throwIfAborted();
41264
+ const directory = join16(this.#root, kind);
41265
+ await mkdir6(directory, { mode: 448, recursive: true });
41266
+ active.throwIfAborted();
41267
+ const path3 = join16(directory, key);
41268
+ const write = atomicWrite(path3, bytes, active);
41269
+ await write;
41270
+ active.throwIfAborted();
41271
+ const retained = this.#entries.get(request);
41272
+ this.#entries.set(request, {
41273
+ byteLength: bytes.byteLength,
41274
+ expiresAt: Date.now() + CONTENT_LIFETIME_MILLISECONDS,
41275
+ mediaType: metadata.mediaType,
41276
+ name: metadata.name,
41277
+ path: path3,
41278
+ sessions: /* @__PURE__ */ new Set([...retained?.sessions ?? [], sessionId])
41279
+ });
41280
+ return { byteLength: bytes.byteLength, key };
41281
+ };
41282
+ resolve = (sessionId, request, signal) => this.#track(() => this.#resolve(sessionId, request, AbortSignal.any([signal, this.#lifetime.signal])));
41283
+ #resolve = async (sessionId, request, signal) => {
41284
+ signal.throwIfAborted();
41285
+ this.#lifetime.signal.throwIfAborted();
41286
+ if (!contentRequest.test(request)) {
41287
+ return null;
41288
+ }
41289
+ const entry = this.#entries.get(request);
41290
+ if (entry === void 0 || !entry.sessions.has(sessionId)) {
41291
+ return null;
41292
+ }
41293
+ if (entry.expiresAt <= Date.now()) {
41294
+ await this.#expire();
41295
+ signal.throwIfAborted();
41296
+ return null;
41297
+ }
41298
+ try {
41299
+ const [resolvedDirectory, resolvedPath, file2] = await Promise.all([
41300
+ realpath8(dirname5(entry.path)),
41301
+ realpath8(entry.path),
41302
+ lstat(entry.path)
41303
+ ]);
41304
+ signal.throwIfAborted();
41305
+ if (!file2.isFile() || file2.isSymbolicLink() || dirname5(resolvedPath) !== resolvedDirectory) {
41306
+ return null;
41307
+ }
41308
+ return { mediaType: entry.mediaType, name: entry.name, path: resolvedPath };
41309
+ } catch {
41310
+ signal.throwIfAborted();
41311
+ return null;
41312
+ }
41313
+ };
41314
+ [Symbol.asyncDispose] = async () => {
41315
+ clearInterval(this.#expirationTimer);
41316
+ this.#lifetime.abort();
41317
+ await Promise.allSettled([...this.#operations, this.#cleanup]);
41318
+ this.#entries.clear();
41319
+ await rm3(this.#root, { force: true, recursive: true });
41320
+ };
41321
+ };
41322
+
40883
41323
  // src/native-sessions/chat-agent.ts
40884
41324
  function supportsNativeChat(agentId) {
40885
41325
  return agentId === "codex" || agentId === "claude" || agentId === "opencode" || agentId === "pi";
@@ -41096,7 +41536,7 @@ var AgentRuntimeManager = class {
41096
41536
  touch: this.#processes.touch,
41097
41537
  changed: this.#processes.notifyChanged
41098
41538
  });
41099
- #queryProcesses = new AgentQueryProcesses(this.#processes);
41539
+ #queryProcesses;
41100
41540
  #executions = new ActiveExecutions();
41101
41541
  #agentSettingsObserver = new NullAcpSessionObserver();
41102
41542
  #nativeOperations = /* @__PURE__ */ new Set();
@@ -41104,13 +41544,16 @@ var AgentRuntimeManager = class {
41104
41544
  #nativeHistoryReader;
41105
41545
  #sessionIdentity;
41106
41546
  #onSessionStatusChanged;
41547
+ #contentExternalizer;
41107
41548
  #observer;
41108
- constructor(observer = new NullAcpSessionObserver(), store = new MemoryAcpSessionStore(), nativeHistoryReader = null, sessionIdentity = "assigned", onSessionStatusChanged = () => void 0) {
41549
+ constructor(observer = new NullAcpSessionObserver(), store = new MemoryAcpSessionStore(), nativeHistoryReader = null, sessionIdentity = "assigned", onSessionStatusChanged = () => void 0, contentExternalizer = new AcpContentExternalizer(new UnretainedExternalContentStore())) {
41109
41550
  this.#observer = observer;
41110
41551
  this.#store = store;
41111
41552
  this.#nativeHistoryReader = nativeHistoryReader;
41112
41553
  this.#sessionIdentity = sessionIdentity;
41113
41554
  this.#onSessionStatusChanged = onSessionStatusChanged;
41555
+ this.#contentExternalizer = contentExternalizer;
41556
+ this.#queryProcesses = new AgentQueryProcesses(this.#processes, contentExternalizer);
41114
41557
  }
41115
41558
  setObserver = (observer) => {
41116
41559
  this.#observer = observer;
@@ -41151,7 +41594,8 @@ var AgentRuntimeManager = class {
41151
41594
  options.origin === void 0 && this.#sessionIdentity === "native" && isNativeChatSessionId(options.agent.id, options.sessionId) && this.#store.read(options.sessionId) instanceof MissingAcpStoredSession ? { ...options, origin: { kind: "import", nativeSessionId: options.sessionId } } : options,
41152
41595
  () => this.#observer,
41153
41596
  this.#store,
41154
- metrics
41597
+ metrics,
41598
+ this.#contentExternalizer
41155
41599
  )
41156
41600
  );
41157
41601
  });
@@ -41166,7 +41610,13 @@ var AgentRuntimeManager = class {
41166
41610
  this.#store.remove(options.sessionId);
41167
41611
  return await this.#startRetainedSessionProcess(
41168
41612
  options,
41169
- async () => await AgentSession.start(options, () => this.#observer, this.#store, metrics)
41613
+ async () => await AgentSession.start(
41614
+ options,
41615
+ () => this.#observer,
41616
+ this.#store,
41617
+ metrics,
41618
+ this.#contentExternalizer
41619
+ )
41170
41620
  );
41171
41621
  });
41172
41622
  }
@@ -41176,7 +41626,13 @@ var AgentRuntimeManager = class {
41176
41626
  await this.#retireSessionProcess(options.sessionId, existing, async () => await existing.close());
41177
41627
  const runtime = await this.#startRetainedSessionProcess(
41178
41628
  options,
41179
- async () => await AgentSession.start(options, () => this.#observer, this.#store)
41629
+ async () => await AgentSession.start(
41630
+ options,
41631
+ () => this.#observer,
41632
+ this.#store,
41633
+ unmeasuredOperationMetrics,
41634
+ this.#contentExternalizer
41635
+ )
41180
41636
  );
41181
41637
  try {
41182
41638
  for (const desired of desiredConfigOptions) {
@@ -41272,7 +41728,9 @@ var AgentRuntimeManager = class {
41272
41728
  sessionId: `agent-settings-${crypto.randomUUID()}`
41273
41729
  },
41274
41730
  () => this.#agentSettingsObserver,
41275
- new MemoryAcpSessionStore()
41731
+ new MemoryAcpSessionStore(),
41732
+ unmeasuredOperationMetrics,
41733
+ this.#contentExternalizer
41276
41734
  ),
41277
41735
  async (runtime) => {
41278
41736
  const prepared = runtime.prepared();
@@ -41781,7 +42239,7 @@ var AgentCatalogPublishError = class extends Error {
41781
42239
  this.name = "AgentCatalogPublishError";
41782
42240
  }
41783
42241
  };
41784
- function isRecord10(value) {
42242
+ function isRecord11(value) {
41785
42243
  return typeof value === "object" && value !== null && !Array.isArray(value);
41786
42244
  }
41787
42245
  function isSafeRelayErrorMessage(value) {
@@ -41794,7 +42252,7 @@ async function rejectedCatalogError(response) {
41794
42252
  } catch {
41795
42253
  return new AgentCatalogPublishError("The Relay rejected the Agent catalog update");
41796
42254
  }
41797
- if (!isRecord10(value) || !isRecord10(value["error"])) {
42255
+ if (!isRecord11(value) || !isRecord11(value["error"])) {
41798
42256
  return new AgentCatalogPublishError("The Relay rejected the Agent catalog update");
41799
42257
  }
41800
42258
  const code = value["error"]["code"];
@@ -42325,9 +42783,9 @@ var FixedInstallationExecutor = class {
42325
42783
  };
42326
42784
 
42327
42785
  // src/authorization/workspace-directory.ts
42328
- import { readdir as readdir3, realpath as realpath8, stat as stat7 } from "node:fs/promises";
42786
+ import { readdir as readdir4, realpath as realpath9, stat as stat8 } from "node:fs/promises";
42329
42787
  import { homedir as homedir2 } from "node:os";
42330
- import { basename as basename4, dirname as dirname5, isAbsolute as isAbsolute9, join as join16, normalize as normalize3, relative as relative4 } from "node:path";
42788
+ import { basename as basename4, dirname as dirname6, isAbsolute as isAbsolute9, join as join17, normalize as normalize3, relative as relative4 } from "node:path";
42331
42789
 
42332
42790
  // src/authorization/local-authorization-error.ts
42333
42791
  var LocalAuthorizationError = class extends Error {
@@ -42406,9 +42864,9 @@ var WorkspaceDirectoryService = class {
42406
42864
  throw new LocalAuthorizationError("The local directory path is invalid");
42407
42865
  }
42408
42866
  try {
42409
- const target = await realpath8(requested);
42867
+ const target = await realpath9(requested);
42410
42868
  signal.throwIfAborted();
42411
- const metadata = await stat7(target);
42869
+ const metadata = await stat8(target);
42412
42870
  signal.throwIfAborted();
42413
42871
  if (!isAbsolute9(target) || normalize3(target) !== target || !metadata.isDirectory()) {
42414
42872
  throw new LocalAuthorizationError("The selected location is not a directory");
@@ -42445,7 +42903,7 @@ var WorkspaceDirectoryService = class {
42445
42903
  list = async (bindingId, id, signal) => {
42446
42904
  const target = await this.resolve(bindingId, id, signal);
42447
42905
  try {
42448
- const children = await readdir3(target, { withFileTypes: true });
42906
+ const children = await readdir4(target, { withFileTypes: true });
42449
42907
  signal.throwIfAborted();
42450
42908
  const entries = [];
42451
42909
  for (const child2 of children) {
@@ -42456,7 +42914,7 @@ var WorkspaceDirectoryService = class {
42456
42914
  continue;
42457
42915
  }
42458
42916
  try {
42459
- const path3 = await this.resolvePath(join16(target, child2.name), signal);
42917
+ const path3 = await this.resolvePath(join17(target, child2.name), signal);
42460
42918
  entries.push({ directoryId: encodePath(path3), name: child2.name });
42461
42919
  } catch (cause) {
42462
42920
  signal.throwIfAborted();
@@ -42466,7 +42924,7 @@ var WorkspaceDirectoryService = class {
42466
42924
  }
42467
42925
  }
42468
42926
  entries.sort((a, b) => a.name.localeCompare(b.name));
42469
- const parent = dirname5(target);
42927
+ const parent = dirname6(target);
42470
42928
  return new WorkspaceDirectoryListing(
42471
42929
  id,
42472
42930
  this.label(target),
@@ -42492,15 +42950,15 @@ var WorkspaceDirectoryService = class {
42492
42950
 
42493
42951
  // src/daemon-diagnostic-log.ts
42494
42952
  import { appendFileSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, statSync as statSync3, writeFileSync } from "node:fs";
42495
- import { join as join17 } from "node:path";
42953
+ import { join as join18 } from "node:path";
42496
42954
  var MAXIMUM_DAEMON_LOG_BYTES = 1 * 1024 * 1024;
42497
42955
  var DaemonDiagnosticLog = class {
42498
42956
  #directory;
42499
42957
  #path;
42500
42958
  #maximumBytes;
42501
42959
  constructor(stateDirectory, maximumBytes = MAXIMUM_DAEMON_LOG_BYTES) {
42502
- this.#directory = join17(stateDirectory, "logs");
42503
- this.#path = join17(this.#directory, "daemon.log");
42960
+ this.#directory = join18(stateDirectory, "logs");
42961
+ this.#path = join18(this.#directory, "daemon.log");
42504
42962
  this.#maximumBytes = maximumBytes;
42505
42963
  }
42506
42964
  record = (diagnostic) => {
@@ -42545,7 +43003,7 @@ import { WebSocket as WebSocket2 } from "undici";
42545
43003
  import { WebSocket } from "undici";
42546
43004
 
42547
43005
  // src/prompt-artifact-resolver.ts
42548
- import { createHash as createHash3 } from "node:crypto";
43006
+ import { createHash as createHash4 } from "node:crypto";
42549
43007
  import { fetch as fetch4 } from "undici";
42550
43008
  var ARTIFACT_SCHEME = "mobius-artifact:";
42551
43009
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
@@ -42683,7 +43141,7 @@ async function download(config2, command, reference, signal) {
42683
43141
  );
42684
43142
  }
42685
43143
  const bytes = await responseBytes(response, reference.byteLength, requestSignal);
42686
- if (createHash3("sha256").update(bytes).digest("hex") !== reference.sha256) {
43144
+ if (createHash4("sha256").update(bytes).digest("hex") !== reference.sha256) {
42687
43145
  throw new PromptArtifactError(
42688
43146
  "artifact_integrity_failed",
42689
43147
  "The prompt artifact failed integrity validation"
@@ -42988,7 +43446,7 @@ var DaemonInstallationObserver = class {
42988
43446
  };
42989
43447
 
42990
43448
  // src/daemon-active-turn.ts
42991
- import { randomUUID as randomUUID2 } from "node:crypto";
43449
+ import { randomUUID as randomUUID3 } from "node:crypto";
42992
43450
  function activeMessageCharacters(message) {
42993
43451
  return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
42994
43452
  }
@@ -43022,7 +43480,7 @@ var ActiveDaemonTurn = class {
43022
43480
  #timeline;
43023
43481
  #sequence = 0;
43024
43482
  #interaction = null;
43025
- #epoch = decodeIdentifier(randomUUID2());
43483
+ #epoch = decodeIdentifier(randomUUID3());
43026
43484
  constructor(command, attemptId) {
43027
43485
  this.attemptId = attemptId;
43028
43486
  this.command = command;
@@ -43084,7 +43542,7 @@ var ActiveDaemonTurn = class {
43084
43542
  if (!this.#activities.has(event.activityId)) {
43085
43543
  this.#timeline = [
43086
43544
  ...this.#timeline,
43087
- { activityId: event.activityId, id: decodeIdentifier(randomUUID2()), kind: "activity" }
43545
+ { activityId: event.activityId, id: decodeIdentifier(randomUUID3()), kind: "activity" }
43088
43546
  ];
43089
43547
  }
43090
43548
  this.#activities.set(event.activityId, {
@@ -43105,7 +43563,7 @@ var ActiveDaemonTurn = class {
43105
43563
  if (previous === void 0) {
43106
43564
  this.#timeline = [
43107
43565
  ...this.#timeline,
43108
- { activityId: event.activityId, id: decodeIdentifier(randomUUID2()), kind: "activity" }
43566
+ { activityId: event.activityId, id: decodeIdentifier(randomUUID3()), kind: "activity" }
43109
43567
  ];
43110
43568
  }
43111
43569
  this.#activities.set(event.activityId, {
@@ -43130,7 +43588,7 @@ var ActiveDaemonTurn = class {
43130
43588
  ...this.#timeline,
43131
43589
  {
43132
43590
  content: /* @__PURE__ */ new Map([[event.contentId, event.content]]),
43133
- id: decodeIdentifier(randomUUID2()),
43591
+ id: decodeIdentifier(randomUUID3()),
43134
43592
  kind: "message",
43135
43593
  sourceMessageId: event.messageId,
43136
43594
  text: ""
@@ -43170,7 +43628,7 @@ var ActiveDaemonTurn = class {
43170
43628
  ...this.#timeline,
43171
43629
  {
43172
43630
  content: /* @__PURE__ */ new Map(),
43173
- id: decodeIdentifier(randomUUID2()),
43631
+ id: decodeIdentifier(randomUUID3()),
43174
43632
  kind: "message",
43175
43633
  sourceMessageId: messageId,
43176
43634
  text: remaining.slice(0, ACTIVE_TURN_TEXT_CHUNK_LIMIT)
@@ -44146,7 +44604,7 @@ var readCodexFullHistory = async (agent, cwd, nativeSessionId, signal, nativeTur
44146
44604
  });
44147
44605
 
44148
44606
  // src/native-sessions/service.ts
44149
- import { randomUUID as randomUUID3 } from "node:crypto";
44607
+ import { randomUUID as randomUUID4 } from "node:crypto";
44150
44608
  import { basename as basename5 } from "node:path";
44151
44609
 
44152
44610
  // src/native-sessions/acp-history.ts
@@ -44361,7 +44819,7 @@ var NativeSessionService = class {
44361
44819
  if (authorized === null) {
44362
44820
  return null;
44363
44821
  }
44364
- const entryId = decodeIdentifier(randomUUID3());
44822
+ const entryId = decodeIdentifier(randomUUID4());
44365
44823
  if (this.#entries.size >= 5e3) {
44366
44824
  this.#entries.clear();
44367
44825
  }
@@ -44417,7 +44875,7 @@ var NativeSessionService = class {
44417
44875
  "invalid_native_session_response"
44418
44876
  );
44419
44877
  }
44420
- nextCursor = decodeIdentifier(randomUUID3());
44878
+ nextCursor = decodeIdentifier(randomUUID4());
44421
44879
  if (this.#cursors.size >= 500) {
44422
44880
  this.#cursors.clear();
44423
44881
  }
@@ -44699,7 +45157,7 @@ var NativeSessionService = class {
44699
45157
  };
44700
45158
 
44701
45159
  // src/relay-connection/daemon-operation-state.ts
44702
- import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
45160
+ import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
44703
45161
  var MAX_TERMINAL_RECEIPTS = 1024;
44704
45162
  function isTerminal(state) {
44705
45163
  return state === "succeeded" || state === "failed" || state === "cancelled";
@@ -44708,7 +45166,7 @@ var DaemonOperationState = class {
44708
45166
  #executions = /* @__PURE__ */ new Map();
44709
45167
  #terminalCount = 0;
44710
45168
  claimExecution = (commandId, sessionId, commandJson) => {
44711
- const commandHash = createHash4("sha256").update(commandJson).digest("hex");
45169
+ const commandHash = createHash5("sha256").update(commandJson).digest("hex");
44712
45170
  const existing = this.#executions.get(commandId);
44713
45171
  if (existing !== void 0) {
44714
45172
  if (existing.sessionId !== sessionId || existing.commandHash !== commandHash) {
@@ -44716,7 +45174,7 @@ var DaemonOperationState = class {
44716
45174
  }
44717
45175
  return { attemptId: existing.attemptId, commandId, kind: "duplicate", state: existing.state };
44718
45176
  }
44719
- const attemptId = randomUUID4();
45177
+ const attemptId = randomUUID5();
44720
45178
  this.#executions.set(commandId, { attemptId, commandHash, sessionId, state: "dispatching" });
44721
45179
  return { attemptId, commandId, kind: "accepted", state: "dispatching" };
44722
45180
  };
@@ -45052,7 +45510,7 @@ function createAgentCatalogRefreshHandler(dependencies) {
45052
45510
  import { WebSocket as WebSocket4 } from "undici";
45053
45511
 
45054
45512
  // src/agent-catalog/discover-agent-settings.ts
45055
- import { createHash as createHash5 } from "node:crypto";
45513
+ import { createHash as createHash6 } from "node:crypto";
45056
45514
 
45057
45515
  // src/agent-catalog/agent-settings-base.ts
45058
45516
  var AgentSettingsConfigurationError = class extends Error {
@@ -45516,7 +45974,7 @@ function settingsRevision(agent, reportedAgentVersion, settings, modelEffort) {
45516
45974
  unsupportedModelIds: modelEffort.unsupportedModelIds,
45517
45975
  valuesByModel: {}
45518
45976
  };
45519
- return createHash5("sha256").update(
45977
+ return createHash6("sha256").update(
45520
45978
  JSON.stringify({
45521
45979
  adapterVersion: agent.kind === "acp-adapter-process" ? agent.adapterVersion : agent.agentVersion,
45522
45980
  agentId: agent.id,
@@ -45667,7 +46125,7 @@ function createAgentSettingsDiscoveryHandler(dependencies) {
45667
46125
 
45668
46126
  // src/artifacts/local-file-streamer.ts
45669
46127
  import { createReadStream as createReadStream2 } from "node:fs";
45670
- import { realpath as realpath9, stat as stat8 } from "node:fs/promises";
46128
+ import { realpath as realpath10, stat as stat9 } from "node:fs/promises";
45671
46129
  import { basename as basename6, isAbsolute as isAbsolute10, normalize as normalize4, resolve as resolve7 } from "node:path";
45672
46130
  import { fileURLToPath as fileURLToPath2 } from "node:url";
45673
46131
  var CHUNK_BYTES = 192 * 1024;
@@ -45695,7 +46153,7 @@ async function resolveFile(value, workingDirectory, signal) {
45695
46153
  return null;
45696
46154
  }
45697
46155
  try {
45698
- const target = await realpath9(requested);
46156
+ const target = await realpath10(requested);
45699
46157
  signal.throwIfAborted();
45700
46158
  return isAbsolute10(target) && normalize4(target) === target ? target : null;
45701
46159
  } catch {
@@ -45703,23 +46161,24 @@ async function resolveFile(value, workingDirectory, signal) {
45703
46161
  return null;
45704
46162
  }
45705
46163
  }
45706
- async function streamLocalFile(command, send2, signal, workingDirectory) {
45707
- const target = await resolveFile(command.path, workingDirectory, signal);
46164
+ async function streamLocalFile(command, send2, signal, workingDirectory, externalContent) {
46165
+ const external = await externalContent.resolve(command.sessionId, command.path, signal);
46166
+ const target = external?.path ?? await resolveFile(command.path, workingDirectory, signal);
45708
46167
  if (target === null) {
45709
46168
  throw new Error("The local file is unavailable");
45710
46169
  }
45711
- const before = await stat8(target);
46170
+ const before = await stat9(target);
45712
46171
  signal.throwIfAborted();
45713
46172
  if (!before.isFile() || before.size < 1 || before.size > command.maxBytes) {
45714
46173
  throw new Error("The local file is too large to read");
45715
46174
  }
45716
- const raster = await readLocalRaster(target, signal);
46175
+ const raster = external === null ? await readLocalRaster(target, signal) : null;
45717
46176
  send2({
45718
46177
  byteLength: before.size,
45719
46178
  kind: FILE_BEGIN_KIND,
45720
- mediaType: raster?.mimeType ?? "application/octet-stream",
46179
+ mediaType: external?.mediaType ?? raster?.mimeType ?? "application/octet-stream",
45721
46180
  modifiedAt: before.mtime.toISOString(),
45722
- name: basename6(target) || "file",
46181
+ name: external?.name ?? (basename6(target) || "file"),
45723
46182
  requestId: command.requestId,
45724
46183
  sessionId: command.sessionId
45725
46184
  });
@@ -45736,7 +46195,7 @@ async function streamLocalFile(command, send2, signal, workingDirectory) {
45736
46195
  });
45737
46196
  sequence += 1;
45738
46197
  }
45739
- const after = await stat8(target);
46198
+ const after = await stat9(target);
45740
46199
  signal.throwIfAborted();
45741
46200
  if (after.size !== before.size || after.mtimeMs !== before.mtimeMs) {
45742
46201
  throw new Error("The local file changed during transfer");
@@ -45749,7 +46208,7 @@ async function streamLocalFile(command, send2, signal, workingDirectory) {
45749
46208
  }
45750
46209
 
45751
46210
  // src/daemon-history-commands.ts
45752
- import { createHash as createHash6 } from "node:crypto";
46211
+ import { createHash as createHash7 } from "node:crypto";
45753
46212
 
45754
46213
  // src/authorization/resolve-session-directories.ts
45755
46214
  import { basename as basename7 } from "node:path";
@@ -46143,7 +46602,7 @@ async function executeSessionLiveHistoryPageLoad(socket, command, config2, direc
46143
46602
  }
46144
46603
  function replayEvent(sessionId, position, update) {
46145
46604
  const encoded = JSON.stringify(update);
46146
- const eventId = `native-${createHash6("sha256").update(sessionId).update(":").update(position.toString()).update(":").update(encoded).digest("hex")}`;
46605
+ const eventId = `native-${createHash7("sha256").update(sessionId).update(":").update(position.toString()).update(":").update(encoded).digest("hex")}`;
46147
46606
  return {
46148
46607
  eventId,
46149
46608
  payload: update,
@@ -46226,7 +46685,7 @@ async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, dir
46226
46685
  }
46227
46686
 
46228
46687
  // src/acp/session-config/apply-session-configuration.ts
46229
- import { randomUUID as randomUUID5 } from "node:crypto";
46688
+ import { randomUUID as randomUUID6 } from "node:crypto";
46230
46689
  function invalidSessionConfiguration(message) {
46231
46690
  return new AcpExecutionError(message, {}, "invalid_session_configuration");
46232
46691
  }
@@ -46367,7 +46826,7 @@ async function applySessionConfigurationSelection(sessions, audit, options, sele
46367
46826
  booleanValue: selection.booleanValue,
46368
46827
  configId: selection.configId,
46369
46828
  cwd,
46370
- requestId: `cfg_${randomUUID5()}`,
46829
+ requestId: `cfg_${randomUUID6()}`,
46371
46830
  sessionId,
46372
46831
  signal,
46373
46832
  value: selection.value,
@@ -47041,6 +47500,7 @@ function createDaemonCommandHandler({
47041
47500
  operations,
47042
47501
  publisher,
47043
47502
  eventLogV2,
47503
+ externalContent,
47044
47504
  activeTurns,
47045
47505
  diagnostics,
47046
47506
  socket,
@@ -47149,7 +47609,8 @@ function createDaemonCommandHandler({
47149
47609
  command2,
47150
47610
  (message2) => send(socket, message2),
47151
47611
  signal,
47152
- sessions.findSessions([command2.sessionId])[0]?.cwd ?? null
47612
+ sessions.findSessions([command2.sessionId])[0]?.cwd ?? null,
47613
+ externalContent
47153
47614
  ).catch((error62) => {
47154
47615
  if (socket.readyState !== WebSocket6.OPEN || signal.aborted) {
47155
47616
  return;
@@ -47488,7 +47949,7 @@ function connectRelay(url2, signal) {
47488
47949
  }
47489
47950
 
47490
47951
  // src/relay-connection/liveness.ts
47491
- import { randomUUID as randomUUID6 } from "node:crypto";
47952
+ import { randomUUID as randomUUID7 } from "node:crypto";
47492
47953
  var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
47493
47954
  var HEARTBEAT_INTERVAL_MILLISECONDS = 2e4;
47494
47955
  var RelayLivenessState = class {
@@ -47577,7 +48038,7 @@ var RelayConnectionLiveness = class {
47577
48038
  }
47578
48039
  throw new Error("Heartbeat was scheduled in an invalid state");
47579
48040
  }
47580
- const heartbeatId = randomUUID6();
48041
+ const heartbeatId = randomUUID7();
47581
48042
  this.#state = new AwaitingHeartbeatAckState(
47582
48043
  heartbeatId,
47583
48044
  this.#timer.schedule(this.#handleTimeout, HEARTBEAT_ACK_TIMEOUT_MILLISECONDS)
@@ -47617,6 +48078,7 @@ async function runRelayConnection({
47617
48078
  operations,
47618
48079
  publisher,
47619
48080
  eventLogV2,
48081
+ externalContent,
47620
48082
  activeTurns,
47621
48083
  connectionEpoch,
47622
48084
  diagnostics,
@@ -47640,6 +48102,7 @@ async function runRelayConnection({
47640
48102
  operations,
47641
48103
  publisher,
47642
48104
  eventLogV2,
48105
+ externalContent,
47643
48106
  activeTurns,
47644
48107
  diagnostics,
47645
48108
  socket,
@@ -48118,7 +48581,7 @@ async function installDetectedAgentIntegrations(config2, installations, signal)
48118
48581
  {
48119
48582
  agentId: agent.id,
48120
48583
  kind: AGENT_INSTALL_REQUEST_KIND,
48121
- requestId: `automatic-integration-${randomUUID7()}`
48584
+ requestId: `automatic-integration-${randomUUID8()}`
48122
48585
  },
48123
48586
  signal
48124
48587
  );
@@ -48137,8 +48600,9 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer, opti
48137
48600
  stateDirectory
48138
48601
  });
48139
48602
  const sessionStore = new SqliteAcpSessionStore(
48140
- join18(stateDirectory, "sessions", `${createHash7("sha256").update(config2.channelId).digest("hex")}.sqlite`)
48603
+ join19(stateDirectory, "sessions", `${createHash8("sha256").update(config2.channelId).digest("hex")}.sqlite`)
48141
48604
  );
48605
+ await using externalContent = new LocalExternalContentStore(stateDirectory);
48142
48606
  const operations = new DaemonOperationState();
48143
48607
  const publisher = new DaemonSessionEventPublisher(sessionStore);
48144
48608
  const eventLogV2 = new DaemonSessionEventLogV2(publisher, sessionStore);
@@ -48159,7 +48623,8 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer, opti
48159
48623
  )).history : null
48160
48624
  },
48161
48625
  "native",
48162
- publisher.publishStatus
48626
+ publisher.publishStatus,
48627
+ new AcpContentExternalizer(externalContent)
48163
48628
  );
48164
48629
  const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
48165
48630
  const installationObserver = new DaemonInstallationObserver();
@@ -48273,6 +48738,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer, opti
48273
48738
  operations,
48274
48739
  publisher,
48275
48740
  eventLogV2,
48741
+ externalContent,
48276
48742
  activeTurns,
48277
48743
  connectionEpoch,
48278
48744
  diagnostics,
@@ -48394,10 +48860,10 @@ var START_TIMEOUT_MILLISECONDS = 12e4;
48394
48860
  var MAXIMUM_MESSAGE_BYTES = 64 * 1024;
48395
48861
  var CONNECTION_ID_PATTERN2 = /^mcn_[a-f0-9]{32}$/;
48396
48862
  async function acquireManagerLock(stateDirectory) {
48397
- const path3 = join19(stateDirectory, "manager.lock");
48863
+ const path3 = join20(stateDirectory, "manager.lock");
48398
48864
  for (let attempt = 0; attempt < 2; attempt += 1) {
48399
48865
  try {
48400
- await writeFile4(path3, `${process.pid.toString()}
48866
+ await writeFile5(path3, `${process.pid.toString()}
48401
48867
  `, { flag: "wx", mode: 384 });
48402
48868
  return async () => await unlink2(path3).catch(() => void 0);
48403
48869
  } catch (cause) {
@@ -48421,15 +48887,15 @@ async function acquireManagerLock(stateDirectory) {
48421
48887
  }
48422
48888
  return null;
48423
48889
  }
48424
- function isRecord11(value) {
48890
+ function isRecord12(value) {
48425
48891
  return typeof value === "object" && value !== null && !Array.isArray(value);
48426
48892
  }
48427
48893
  function controlSocketPath(stateDirectory) {
48428
- const installationHash = createHash8("sha256").update(stateDirectory).digest("hex").slice(0, 32);
48429
- return process.platform === "win32" ? `\\\\.\\pipe\\mobius-${installationHash}` : join19(tmpdir(), `mobius-${installationHash}.sock`);
48894
+ const installationHash = createHash9("sha256").update(stateDirectory).digest("hex").slice(0, 32);
48895
+ return process.platform === "win32" ? `\\\\.\\pipe\\mobius-${installationHash}` : join20(tmpdir(), `mobius-${installationHash}.sock`);
48430
48896
  }
48431
48897
  function controlTokenPath(stateDirectory) {
48432
- return join19(stateDirectory, "manager.token");
48898
+ return join20(stateDirectory, "manager.token");
48433
48899
  }
48434
48900
  async function readOrCreateControlToken(stateDirectory) {
48435
48901
  const path3 = controlTokenPath(stateDirectory);
@@ -48442,7 +48908,7 @@ async function readOrCreateControlToken(stateDirectory) {
48442
48908
  }
48443
48909
  const token = randomBytes(32).toString("base64url");
48444
48910
  try {
48445
- await writeFile4(path3, `${token}
48911
+ await writeFile5(path3, `${token}
48446
48912
  `, { flag: "wx", mode: 384 });
48447
48913
  return token;
48448
48914
  } catch (cause) {
@@ -48456,7 +48922,7 @@ function isNodeError2(error62, code) {
48456
48922
  return typeof error62 === "object" && error62 !== null && "code" in error62 && error62.code === code;
48457
48923
  }
48458
48924
  function decodeCommand(value, expectedToken) {
48459
- if (!isRecord11(value) || value["token"] !== expectedToken || typeof value["kind"] !== "string") {
48925
+ if (!isRecord12(value) || value["token"] !== expectedToken || typeof value["kind"] !== "string") {
48460
48926
  throw new Error("The manager request is invalid");
48461
48927
  }
48462
48928
  if (value["kind"] === "list" || value["kind"] === "stop") {
@@ -48475,7 +48941,7 @@ function decodeCommand(value, expectedToken) {
48475
48941
  throw new Error("The manager command is unsupported");
48476
48942
  }
48477
48943
  function decodeResponse(value) {
48478
- if (!isRecord11(value) || typeof value["kind"] !== "string") {
48944
+ if (!isRecord12(value) || typeof value["kind"] !== "string") {
48479
48945
  throw new Error("The Mobius manager returned an invalid response");
48480
48946
  }
48481
48947
  if (value["kind"] === "error" && typeof value["code"] === "string" && typeof value["message"] === "string") {
@@ -48502,7 +48968,7 @@ function decodeResponse(value) {
48502
48968
  throw new Error("The Mobius manager returned an invalid response");
48503
48969
  }
48504
48970
  function isManagedRuntimeSummary(value) {
48505
- return isRecord11(value) && typeof value["appId"] === "string" && typeof value["connectionId"] === "string" && typeof value["runtimeId"] === "string" && typeof value["workspace"] === "string" && ["starting", "online", "reconnecting", "failed", "stopped"].includes(String(value["status"]));
48971
+ return isRecord12(value) && typeof value["appId"] === "string" && typeof value["connectionId"] === "string" && typeof value["runtimeId"] === "string" && typeof value["workspace"] === "string" && ["starting", "online", "reconnecting", "failed", "stopped"].includes(String(value["status"]));
48506
48972
  }
48507
48973
  function summary(connection, status) {
48508
48974
  return {
@@ -48761,7 +49227,7 @@ async function waitForManagerExit(stateDirectory, signal) {
48761
49227
  const deadline = AbortSignal.any([signal, AbortSignal.timeout(1e4)]);
48762
49228
  while (!deadline.aborted) {
48763
49229
  try {
48764
- await readFile3(join19(stateDirectory, "manager.lock"), "utf8");
49230
+ await readFile3(join20(stateDirectory, "manager.lock"), "utf8");
48765
49231
  } catch (cause) {
48766
49232
  if (isNodeError2(cause, "ENOENT")) {
48767
49233
  return;
@@ -49039,7 +49505,7 @@ function createProgram() {
49039
49505
  const installation = await openMobiusCliInstallation(shutdown.signal, process.env);
49040
49506
  const localContext = new DaemonLocalContext(installation.stateDirectory, process.env);
49041
49507
  const defaultWorkspace = loadDefaultWorkspace(localContext.environment);
49042
- await mkdir6(defaultWorkspace, { recursive: true, mode: 448 });
49508
+ await mkdir7(defaultWorkspace, { recursive: true, mode: 448 });
49043
49509
  const inventory = await discoverLocalAgentInventory({
49044
49510
  defaultWorkspace,
49045
49511
  environment: localContext.environment,