@moxt-ai/mobius 0.0.182 → 0.0.184

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 (34) hide show
  1. package/dist/acp/agent-connection.d.ts.map +1 -1
  2. package/dist/acp/agent-connection.js +14 -2
  3. package/dist/acp/agent-connection.js.map +1 -1
  4. package/dist/acp/agent-runtime-manager.d.ts +2 -1
  5. package/dist/acp/agent-runtime-manager.d.ts.map +1 -1
  6. package/dist/acp/agent-runtime-manager.js +46 -36
  7. package/dist/acp/agent-runtime-manager.js.map +1 -1
  8. package/dist/acp/agent-session.d.ts +4 -3
  9. package/dist/acp/agent-session.d.ts.map +1 -1
  10. package/dist/acp/agent-session.js +15 -3
  11. package/dist/acp/agent-session.js.map +1 -1
  12. package/dist/acp/codex/app-server-protocol.d.ts +4 -0
  13. package/dist/acp/codex/app-server-protocol.d.ts.map +1 -1
  14. package/dist/acp/codex/app-server-protocol.js +2 -0
  15. package/dist/acp/codex/app-server-protocol.js.map +1 -1
  16. package/dist/acp/codex/items.d.ts.map +1 -1
  17. package/dist/acp/codex/items.js +35 -11
  18. package/dist/acp/codex/items.js.map +1 -1
  19. package/dist/acp/session-contracts.d.ts +5 -0
  20. package/dist/acp/session-contracts.d.ts.map +1 -1
  21. package/dist/acp/session-contracts.js.map +1 -1
  22. package/dist/cli.js +177 -83
  23. package/dist/cli.js.map +4 -4
  24. package/dist/daemon-session-commands.d.ts.map +1 -1
  25. package/dist/daemon-session-commands.js +6 -4
  26. package/dist/daemon-session-commands.js.map +1 -1
  27. package/dist/external-content/acp-content-externalizer.d.ts.map +1 -1
  28. package/dist/external-content/acp-content-externalizer.js +13 -0
  29. package/dist/external-content/acp-content-externalizer.js.map +1 -1
  30. package/dist/index.js +171 -79
  31. package/dist/index.js.map +3 -3
  32. package/dist/runtime.js +174 -82
  33. package/dist/runtime.js.map +3 -3
  34. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3381,7 +3381,7 @@ var program = new Command();
3381
3381
  // package.json
3382
3382
  var package_default = {
3383
3383
  name: "@moxt-ai/mobius",
3384
- version: "0.0.182",
3384
+ version: "0.0.184",
3385
3385
  description: "Mobius CLI for pairing and running local AI agent services.",
3386
3386
  type: "module",
3387
3387
  bin: {
@@ -4975,6 +4975,9 @@ function sessionFailureMeta(failure2) {
4975
4975
  // src/acp/codex/app-server-client.ts
4976
4976
  import { spawn as spawn2 } from "node:child_process";
4977
4977
 
4978
+ // src/acp/codex/app-server-protocol.ts
4979
+ import { isAbsolute as isAbsolute2 } from "node:path";
4980
+
4978
4981
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/external.js
4979
4982
  var external_exports = {};
4980
4983
  __export(external_exports, {
@@ -24714,6 +24717,7 @@ var imageGenerationItemSchema = external_exports.object({
24714
24717
  });
24715
24718
  var threadItemSchema = external_exports.discriminatedUnion("type", [
24716
24719
  imageGenerationItemSchema,
24720
+ external_exports.object({ type: external_exports.literal("imageView"), id: boundedText(256), path: boundedText(32768).refine(isAbsolute2) }),
24717
24721
  external_exports.object({
24718
24722
  id: boundedText(256),
24719
24723
  text: boundedText(1e6),
@@ -25138,6 +25142,7 @@ var CodexAppServerClient = class {
25138
25142
  };
25139
25143
 
25140
25144
  // src/acp/codex/items.ts
25145
+ import { pathToFileURL } from "node:url";
25141
25146
  var TOOL_OUTPUT_CHARACTER_LIMIT = 32768;
25142
25147
  var TITLE_CHARACTER_LIMIT = 500;
25143
25148
  function truncate2(value, limit) {
@@ -25159,6 +25164,14 @@ function textContent(text2) {
25159
25164
  const block = { text: truncate2(text2, TOOL_OUTPUT_CHARACTER_LIMIT), type: "text" };
25160
25165
  return { content: block, type: "content" };
25161
25166
  }
25167
+ function structuredToolText(value) {
25168
+ const result = external_exports.object({ content: external_exports.array(external_exports.unknown()) }).safeParse(value);
25169
+ const items = Array.isArray(value) ? value : result.success ? result.data.content : [];
25170
+ return items.flatMap((item) => {
25171
+ const text2 = external_exports.object({ type: external_exports.enum(["text", "inputText"]), text: external_exports.string() }).safeParse(item);
25172
+ return text2.success ? [textContent(text2.data.text)] : [];
25173
+ });
25174
+ }
25162
25175
  function firstLine(value) {
25163
25176
  const line = value.split("\n", 1)[0] ?? "";
25164
25177
  return line.trim().length > 0 ? line.trim() : value.trim();
@@ -25179,6 +25192,22 @@ function mcpStatus(status) {
25179
25192
  return status === "inProgress" ? "in_progress" : status === "completed" ? "completed" : "failed";
25180
25193
  }
25181
25194
  function presentToolItem(item) {
25195
+ if (item.type === "imageView") {
25196
+ return {
25197
+ content: [
25198
+ {
25199
+ type: "content",
25200
+ content: { type: "image", data: "", mimeType: "", uri: pathToFileURL(item.path).href }
25201
+ }
25202
+ ],
25203
+ kind: "read",
25204
+ locations: [{ path: item.path }],
25205
+ rawInput: { path: item.path },
25206
+ rawOutput: null,
25207
+ status: "completed",
25208
+ title: "View image"
25209
+ };
25210
+ }
25182
25211
  if (item.type === "imageGeneration") {
25183
25212
  const failed = item.failure != null || item.status === "failed";
25184
25213
  const content = [];
@@ -25243,13 +25272,7 @@ function presentToolItem(item) {
25243
25272
  }
25244
25273
  if (item.type === "mcpToolCall") {
25245
25274
  const label = `${item.server}/${item.tool}`;
25246
- const content = [];
25247
- if (item.result != null) {
25248
- content.push(textContent(JSON.stringify(item.result)));
25249
- }
25250
- if (item.error != null) {
25251
- content.push(textContent(JSON.stringify(item.error)));
25252
- }
25275
+ const content = structuredToolText(item.error ?? item.result);
25253
25276
  return {
25254
25277
  content,
25255
25278
  kind: "other",
@@ -25262,13 +25285,13 @@ function presentToolItem(item) {
25262
25285
  }
25263
25286
  if (item.type === "dynamicToolCall") {
25264
25287
  const label = item.namespace == null ? item.tool : `${item.namespace}/${item.tool}`;
25265
- const content = (item.contentItems ?? []).map((entry) => textContent(JSON.stringify(entry)));
25288
+ const content = structuredToolText(item.contentItems);
25266
25289
  return {
25267
25290
  content,
25268
25291
  kind: "other",
25269
25292
  locations: [],
25270
25293
  rawInput: item.arguments ?? null,
25271
- rawOutput: item.success === true ? null : item.contentItems ?? null,
25294
+ rawOutput: item.contentItems ?? null,
25272
25295
  status: mcpStatus(item.status),
25273
25296
  title: truncate2(label, TITLE_CHARACTER_LIMIT)
25274
25297
  };
@@ -25281,12 +25304,12 @@ function toolCallUpdate(item, lifecycle) {
25281
25304
  return null;
25282
25305
  }
25283
25306
  return {
25284
- content: [...presentation.content],
25307
+ content: item.type === "imageView" && lifecycle === "started" ? [] : [...presentation.content],
25285
25308
  kind: presentation.kind,
25286
25309
  locations: [...presentation.locations],
25287
25310
  rawInput: presentation.rawInput,
25288
25311
  rawOutput: presentation.rawOutput,
25289
- status: lifecycle === "completed" && presentation.status === "in_progress" ? "completed" : presentation.status,
25312
+ status: item.type === "imageView" && lifecycle === "started" ? "in_progress" : lifecycle === "completed" && presentation.status === "in_progress" ? "completed" : presentation.status,
25290
25313
  title: presentation.title,
25291
25314
  toolCallId: item.id
25292
25315
  };
@@ -26510,12 +26533,12 @@ var AgentProbeError = class extends Error {
26510
26533
  };
26511
26534
 
26512
26535
  // src/agent-catalog/agents/resolve-user-local-executable.ts
26513
- import { isAbsolute as isAbsolute2, join as join4 } from "node:path";
26536
+ import { isAbsolute as isAbsolute3, join as join4 } from "node:path";
26514
26537
  async function resolveUserLocalExecutable(executableName, context) {
26515
26538
  context.signal.throwIfAborted();
26516
26539
  const platform = context.platform ?? process.platform;
26517
26540
  const homeDirectory = context.environment["HOME"];
26518
- if (platform === "win32" || homeDirectory === void 0 || !isAbsolute2(homeDirectory)) {
26541
+ if (platform === "win32" || homeDirectory === void 0 || !isAbsolute3(homeDirectory)) {
26519
26542
  return [];
26520
26543
  }
26521
26544
  const executable = await resolveExecutablePath(join4(homeDirectory, ".local", "bin", executableName), platform);
@@ -26608,7 +26631,7 @@ var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
26608
26631
 
26609
26632
  // src/agent-catalog/agents/deepseek-harness-agent.ts
26610
26633
  import { mkdir as mkdir2, realpath as realpath3, stat as stat3, writeFile } from "node:fs/promises";
26611
- import { isAbsolute as isAbsolute3, join as join6, normalize } from "node:path";
26634
+ import { isAbsolute as isAbsolute4, join as join6, normalize } from "node:path";
26612
26635
 
26613
26636
  // src/agent-installation/deepseek-managed-package.ts
26614
26637
  var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
@@ -26643,7 +26666,7 @@ var DEEPSEEK_HARNESS_IMAGE_PROMPT_PATCH = `# Managed by Mobius: pin the ACP brid
26643
26666
  model: deepseek-v4-flash-vision-exp
26644
26667
  `;
26645
26668
  async function prepareAgentHome(path3, imagePrompts) {
26646
- if (!isAbsolute3(path3) || normalize(path3) !== path3) {
26669
+ if (!isAbsolute4(path3) || normalize(path3) !== path3) {
26647
26670
  throw new AgentProbeError("agent_environment_invalid", "The configured Agent home is invalid");
26648
26671
  }
26649
26672
  try {
@@ -26775,7 +26798,7 @@ var GeminiCliAgentSpecification = class extends DirectAcpAgentDefinition {
26775
26798
 
26776
26799
  // src/agent-catalog/agents/grok-build-agent.ts
26777
26800
  import { realpath as realpath4 } from "node:fs/promises";
26778
- import { isAbsolute as isAbsolute4, join as join7, relative as relative2, sep as sep2 } from "node:path";
26801
+ import { isAbsolute as isAbsolute5, join as join7, relative as relative2, sep as sep2 } from "node:path";
26779
26802
  import {
26780
26803
  RequestError
26781
26804
  } from "@agentclientprotocol/sdk";
@@ -26841,7 +26864,7 @@ function grokBuildManagedPackage(platform, architecture) {
26841
26864
  // src/agent-catalog/agents/grok-build-agent.ts
26842
26865
  function isContainedPath2(root, candidate) {
26843
26866
  const difference = relative2(root, candidate);
26844
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute4(difference);
26867
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute5(difference);
26845
26868
  }
26846
26869
  var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
26847
26870
  adapterVersion = GROK_BUILD_MANAGED_VERSION;
@@ -26990,7 +27013,7 @@ import { join as join9 } from "node:path";
26990
27013
  import { createHash } from "node:crypto";
26991
27014
  import { createReadStream } from "node:fs";
26992
27015
  import { chmod, copyFile, mkdir as mkdir3, mkdtemp as mkdtemp2, open as open3, realpath as realpath5, rename as rename2, rm as rm2, stat as stat4, writeFile as writeFile2 } from "node:fs/promises";
26993
- import { delimiter as delimiter2, dirname as dirname2, isAbsolute as isAbsolute5, join as join8, relative as relative3, sep as sep3 } from "node:path";
27016
+ import { delimiter as delimiter2, dirname as dirname2, isAbsolute as isAbsolute6, join as join8, relative as relative3, sep as sep3 } from "node:path";
26994
27017
 
26995
27018
  // src/agent-installation/verified-download.ts
26996
27019
  import { fetch } from "undici";
@@ -27096,7 +27119,7 @@ function isRecord4(value) {
27096
27119
  }
27097
27120
  function isContainedPath3(root, candidate) {
27098
27121
  const difference = relative3(root, candidate);
27099
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute5(difference);
27122
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute6(difference);
27100
27123
  }
27101
27124
  async function hashFile(path3, signal) {
27102
27125
  signal.throwIfAborted();
@@ -27486,7 +27509,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
27486
27509
  };
27487
27510
 
27488
27511
  // src/agent-catalog/agents/workbuddy-agent.ts
27489
- import { isAbsolute as isAbsolute6, join as join11 } from "node:path";
27512
+ import { isAbsolute as isAbsolute7, join as join11 } from "node:path";
27490
27513
 
27491
27514
  // src/agent-installation/workbuddy-managed-package.ts
27492
27515
  var WORKBUDDY_MANAGED_VERSION = "2.146.0";
@@ -27554,7 +27577,7 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
27554
27577
  }
27555
27578
  const requestedPaths = [join11("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
27556
27579
  const homeDirectory = context.environment["HOME"];
27557
- if (homeDirectory !== void 0 && isAbsolute6(homeDirectory)) {
27580
+ if (homeDirectory !== void 0 && isAbsolute7(homeDirectory)) {
27558
27581
  requestedPaths.unshift(join11(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
27559
27582
  }
27560
27583
  const executables = [];
@@ -27919,7 +27942,7 @@ function isAgentVersionSupported(reportedVersion, minimumSupportedVersion) {
27919
27942
  }
27920
27943
 
27921
27944
  // src/agent-catalog/executable-discovery.ts
27922
- import { isAbsolute as isAbsolute7, join as join13 } from "node:path";
27945
+ import { isAbsolute as isAbsolute8, join as join13 } from "node:path";
27923
27946
 
27924
27947
  // src/agent-installation/managed-adapter-installer.ts
27925
27948
  import { join as join12 } from "node:path";
@@ -28024,7 +28047,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
28024
28047
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveInstalled, resolveManaged, context) {
28025
28048
  const override = context.environment[overrideVariable];
28026
28049
  if (override !== void 0) {
28027
- if (override.length === 0 || !isAbsolute7(override)) {
28050
+ if (override.length === 0 || !isAbsolute8(override)) {
28028
28051
  return [];
28029
28052
  }
28030
28053
  const executable = await resolveExecutablePath(override, context.platform);
@@ -31314,7 +31337,7 @@ import {
31314
31337
 
31315
31338
  // src/authorization/local-raster.ts
31316
31339
  import { open as open5, readFile as readFile2, realpath as realpath7, stat as stat6 } from "node:fs/promises";
31317
- import { basename as basename2, isAbsolute as isAbsolute8, normalize as normalize2 } from "node:path";
31340
+ import { basename as basename2, isAbsolute as isAbsolute9, normalize as normalize2 } from "node:path";
31318
31341
  import { fileURLToPath } from "node:url";
31319
31342
  var MAX_LOCAL_RASTER_BYTES = 128 * 1024 * 1024;
31320
31343
  var MAX_INLINE_RASTER_BYTES = 3e6;
@@ -31380,13 +31403,13 @@ function readInlineRaster(data, name2 = "Image") {
31380
31403
  }
31381
31404
  async function resolveCanonicalPath(requested, signal) {
31382
31405
  signal.throwIfAborted();
31383
- if (!isAbsolute8(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
31406
+ if (!isAbsolute9(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
31384
31407
  return null;
31385
31408
  }
31386
31409
  try {
31387
31410
  const target = await realpath7(requested);
31388
31411
  signal.throwIfAborted();
31389
- if (!isAbsolute8(target) || normalize2(target) !== target) {
31412
+ if (!isAbsolute9(target) || normalize2(target) !== target) {
31390
31413
  return null;
31391
31414
  }
31392
31415
  return target;
@@ -31894,6 +31917,18 @@ function isProgressMessage(content) {
31894
31917
  // src/acp/agent-connection.ts
31895
31918
  import { spawn as spawn4 } from "node:child_process";
31896
31919
  import { ndJsonStream as ndJsonStream2, RequestError as RequestError3 } from "@agentclientprotocol/sdk";
31920
+ function requestErrorMessage(error62) {
31921
+ const fallback = truncate(error62.message, 500);
31922
+ if (error62.message !== "Internal error" || !isRecord3(error62.data)) {
31923
+ return fallback;
31924
+ }
31925
+ const agentError = error62.data["error"];
31926
+ if (!isRecord3(agentError) || agentError["code"] !== "invalid_prompt") {
31927
+ return fallback;
31928
+ }
31929
+ const message = agentError["message"];
31930
+ return typeof message === "string" && message.length > 0 ? truncate(message, 500) : fallback;
31931
+ }
31897
31932
  function readableWebStream(input2) {
31898
31933
  let streamOpen = true;
31899
31934
  return new ReadableStream({
@@ -32065,7 +32100,7 @@ var AgentConnection = class {
32065
32100
  );
32066
32101
  }
32067
32102
  if (error62 instanceof RequestError3) {
32068
- throw new AcpExecutionError(truncate(error62.message, 500), { cause: error62 }, "acp_agent_error");
32103
+ throw new AcpExecutionError(requestErrorMessage(error62), { cause: error62 }, "acp_agent_error");
32069
32104
  }
32070
32105
  throw error62;
32071
32106
  }
@@ -38873,11 +38908,11 @@ var AgentSession = class _AgentSession {
38873
38908
  }
38874
38909
  throw new AcpExecutionError("ACP agent initialization failed");
38875
38910
  }
38876
- static start = async (options, getObserver, store, metrics, contentExternalizer) => await _AgentSession.#start(
38911
+ static start = async (options, recovery, getObserver, store, metrics, contentExternalizer) => await _AgentSession.#start(
38877
38912
  options,
38878
38913
  getObserver,
38879
38914
  store,
38880
- async (runtime) => await runtime.initialize(options.signal, options.origin),
38915
+ async (runtime) => await runtime.initialize(options.signal, recovery, options.origin),
38881
38916
  metrics,
38882
38917
  contentExternalizer
38883
38918
  );
@@ -38915,6 +38950,16 @@ var AgentSession = class _AgentSession {
38915
38950
  const history = await this.#completedHistory(signal, "ACP agent exited while loading history");
38916
38951
  return await embedLocalHistoryImages(await history.snapshot(), signal);
38917
38952
  };
38953
+ ensureHistoryLoaded = async (signal) => {
38954
+ if (!this.#capabilities.loadSession) {
38955
+ throw new AcpExecutionError(
38956
+ "This Agent restores context but does not provide message history.",
38957
+ {},
38958
+ "native_history_unsupported"
38959
+ );
38960
+ }
38961
+ await this.#completedHistory(signal, "ACP agent exited while loading history");
38962
+ };
38918
38963
  loadHistoryEventsV2 = async (eventLimit, cursor, signal) => {
38919
38964
  if (!this.#capabilities.loadSession) {
38920
38965
  throw new AcpExecutionError(
@@ -39087,7 +39132,7 @@ var AgentSession = class _AgentSession {
39087
39132
  128
39088
39133
  );
39089
39134
  }
39090
- initialize = async (signal, origin) => {
39135
+ initialize = async (signal, recovery, origin) => {
39091
39136
  await this.#initializeAgent(signal);
39092
39137
  let stored = this.#metrics.measureSync(
39093
39138
  "session-state-read",
@@ -39156,7 +39201,19 @@ var AgentSession = class _AgentSession {
39156
39201
  this.#prompted = stored.session.prompted;
39157
39202
  this.#sessionTitle = stored.session.title;
39158
39203
  this.#restored = true;
39159
- if (this.#capabilities.resumeSession) {
39204
+ if (recovery.kind === "history-required") {
39205
+ if (!this.#capabilities.loadSession) {
39206
+ throw new AcpExecutionError(
39207
+ "This Agent restores context but does not provide message history.",
39208
+ {},
39209
+ "native_history_unsupported"
39210
+ );
39211
+ }
39212
+ lifecycleResponse = await this.#metrics.measure(
39213
+ "session-load",
39214
+ async () => (await this.#loadSession(signal, "ACP agent exited while loading a session")).response
39215
+ );
39216
+ } else if (this.#capabilities.resumeSession) {
39160
39217
  lifecycleResponse = await this.#metrics.measure(
39161
39218
  "session-resume",
39162
39219
  async () => await this.race(
@@ -40114,8 +40171,15 @@ var embeddedImageSchema = external_exports.looseObject({
40114
40171
  data: external_exports.string(),
40115
40172
  mimeType: external_exports.string()
40116
40173
  });
40174
+ var inlineImageUrlSchema = external_exports.string().regex(/^data:image\/(?:png|jpeg|gif|webp);base64,/u).transform((url2) => ({
40175
+ type: "image",
40176
+ data: url2.slice(url2.indexOf(",") + 1),
40177
+ mimeType: url2.slice(5, url2.indexOf(";"))
40178
+ }));
40117
40179
  var toolImageSchema = external_exports.union([
40118
40180
  embeddedImageSchema,
40181
+ external_exports.object({ type: external_exports.literal("file"), mime: external_exports.string(), url: inlineImageUrlSchema }).refine(({ mime, url: url2 }) => mime === url2.mimeType).transform(({ url: url2 }) => url2),
40182
+ external_exports.object({ type: external_exports.literal("inputImage"), imageUrl: inlineImageUrlSchema }).transform(({ imageUrl }) => imageUrl),
40119
40183
  external_exports.object({
40120
40184
  type: external_exports.literal("image"),
40121
40185
  source: external_exports.object({ type: external_exports.literal("base64"), data: external_exports.string(), media_type: external_exports.string() })
@@ -40767,12 +40831,13 @@ var AgentRuntimeManager = class {
40767
40831
  this.#executionProcesses.retain(options.sessionId, runtime);
40768
40832
  return runtime;
40769
40833
  }
40770
- async #startPreparation(options, metrics = unmeasuredOperationMetrics) {
40834
+ async #startPreparation(options, recovery, metrics = unmeasuredOperationMetrics) {
40771
40835
  return await this.#executionProcesses.prepare(options.sessionId, async () => {
40772
40836
  return await this.#startRetainedSessionProcess(
40773
40837
  options,
40774
40838
  async () => await AgentSession.start(
40775
40839
  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,
40840
+ recovery,
40776
40841
  () => this.#observer,
40777
40842
  this.#store,
40778
40843
  metrics,
@@ -40781,7 +40846,7 @@ var AgentRuntimeManager = class {
40781
40846
  );
40782
40847
  });
40783
40848
  }
40784
- async #replacePreparation(existing, options, metrics) {
40849
+ async #replacePreparation(existing, options, recovery, metrics) {
40785
40850
  return await this.#executionProcesses.prepare(options.sessionId, async () => {
40786
40851
  await this.#retireSessionProcess(
40787
40852
  options.sessionId,
@@ -40793,6 +40858,7 @@ var AgentRuntimeManager = class {
40793
40858
  options,
40794
40859
  async () => await AgentSession.start(
40795
40860
  options,
40861
+ recovery,
40796
40862
  () => this.#observer,
40797
40863
  this.#store,
40798
40864
  metrics,
@@ -40809,6 +40875,7 @@ var AgentRuntimeManager = class {
40809
40875
  options,
40810
40876
  async () => await AgentSession.start(
40811
40877
  options,
40878
+ { kind: "interactive-only" },
40812
40879
  () => this.#observer,
40813
40880
  this.#store,
40814
40881
  unmeasuredOperationMetrics,
@@ -40852,42 +40919,58 @@ var AgentRuntimeManager = class {
40852
40919
  return runtime;
40853
40920
  });
40854
40921
  }
40855
- prepareSession = async (options, metrics = unmeasuredOperationMetrics) => this.#operations.run(options, async (options2) => {
40856
- const stored = metrics.measureSync("session-state-read", () => this.#store.read(options2.sessionId));
40857
- if (stored instanceof FoundAcpStoredSession && this.#nativeOperations.has(`${stored.session.agentId}:${stored.session.nativeSessionId}`)) {
40858
- throw new AcpExecutionError("The native session is being managed", {}, "session_busy");
40859
- }
40860
- const pending = this.#executionProcesses.pending(options2.sessionId);
40861
- if (pending !== void 0) {
40862
- const runtime2 = await metrics.measure(
40863
- "session-preparation-wait",
40864
- async () => await waitForSharedOperation(pending, options2.signal)
40865
- );
40866
- if (runtime2.belongsTo(options2.agent.id, options2.cwd, options2.additionalDirectories)) {
40867
- this.#executionProcesses.touch(options2.sessionId, runtime2);
40868
- return runtime2.prepared();
40869
- }
40870
- return await this.prepareSession(options2, metrics);
40871
- }
40872
- const existing = this.#executionProcesses.get(options2.sessionId);
40873
- if (existing !== void 0) {
40874
- if (existing.belongsTo(options2.agent.id, options2.cwd, options2.additionalDirectories)) {
40875
- this.#executionProcesses.touch(options2.sessionId, existing);
40876
- return existing.prepared();
40922
+ async #prepareSession(options, recovery, metrics = unmeasuredOperationMetrics) {
40923
+ return await this.#operations.run(options, async (options2) => {
40924
+ const stored = metrics.measureSync("session-state-read", () => this.#store.read(options2.sessionId));
40925
+ if (stored instanceof FoundAcpStoredSession && this.#nativeOperations.has(`${stored.session.agentId}:${stored.session.nativeSessionId}`)) {
40926
+ throw new AcpExecutionError("The native session is being managed", {}, "session_busy");
40877
40927
  }
40878
- if (!existing.canRebind()) {
40879
- throw new AcpExecutionError(
40880
- "The agent or workspace cannot change after a conversation has started",
40881
- {},
40882
- "session_identity_mismatch"
40928
+ const pending = this.#executionProcesses.pending(options2.sessionId);
40929
+ if (pending !== void 0) {
40930
+ const runtime2 = await metrics.measure(
40931
+ "session-preparation-wait",
40932
+ async () => await waitForSharedOperation(pending, options2.signal)
40883
40933
  );
40934
+ if (runtime2.belongsTo(options2.agent.id, options2.cwd, options2.additionalDirectories)) {
40935
+ this.#executionProcesses.touch(options2.sessionId, runtime2);
40936
+ if (recovery.kind === "history-required") {
40937
+ await metrics.measure(
40938
+ "session-load",
40939
+ async () => await runtime2.ensureHistoryLoaded(options2.signal)
40940
+ );
40941
+ }
40942
+ return runtime2.prepared();
40943
+ }
40944
+ return await this.#prepareSession(options2, recovery, metrics);
40945
+ }
40946
+ const existing = this.#executionProcesses.get(options2.sessionId);
40947
+ if (existing !== void 0) {
40948
+ if (existing.belongsTo(options2.agent.id, options2.cwd, options2.additionalDirectories)) {
40949
+ this.#executionProcesses.touch(options2.sessionId, existing);
40950
+ if (recovery.kind === "history-required") {
40951
+ await metrics.measure(
40952
+ "session-load",
40953
+ async () => await existing.ensureHistoryLoaded(options2.signal)
40954
+ );
40955
+ }
40956
+ return existing.prepared();
40957
+ }
40958
+ if (!existing.canRebind()) {
40959
+ throw new AcpExecutionError(
40960
+ "The agent or workspace cannot change after a conversation has started",
40961
+ {},
40962
+ "session_identity_mismatch"
40963
+ );
40964
+ }
40965
+ const runtime2 = await this.#replacePreparation(existing, options2, recovery, metrics);
40966
+ return runtime2.prepared();
40884
40967
  }
40885
- const runtime2 = await this.#replacePreparation(existing, options2, metrics);
40886
- return runtime2.prepared();
40887
- }
40888
- const runtime = await this.#startPreparation(options2, metrics);
40889
- return runtime.prepared();
40890
- });
40968
+ const runtime = await this.#startPreparation(options2, recovery, metrics);
40969
+ return runtime.prepared();
40970
+ });
40971
+ }
40972
+ prepareSession = async (options, metrics = unmeasuredOperationMetrics) => await this.#prepareSession(options, { kind: "interactive-only" }, metrics);
40973
+ restoreSession = async (options, metrics = unmeasuredOperationMetrics) => await this.#prepareSession(options, { kind: "history-required" }, metrics);
40891
40974
  /**
40892
40975
  * Opens a short-lived native ACP session only to read the local Agent's
40893
40976
  * authoritative settings. Its identity and store are private to this
@@ -40901,6 +40984,7 @@ var AgentRuntimeManager = class {
40901
40984
  ...options2,
40902
40985
  sessionId: `agent-settings-${crypto.randomUUID()}`
40903
40986
  },
40987
+ { kind: "interactive-only" },
40904
40988
  () => this.#agentSettingsObserver,
40905
40989
  new MemoryAcpSessionStore(),
40906
40990
  unmeasuredOperationMetrics,
@@ -40938,7 +41022,7 @@ var AgentRuntimeManager = class {
40938
41022
  );
40939
41023
  }
40940
41024
  return await this.#executionProcesses.use(options2.sessionId, async () => {
40941
- const runtime = await this.#startPreparation(options2, metrics);
41025
+ const runtime = await this.#startPreparation(options2, { kind: "interactive-only" }, metrics);
40942
41026
  try {
40943
41027
  return runtime.prepared();
40944
41028
  } finally {
@@ -40958,7 +41042,7 @@ var AgentRuntimeManager = class {
40958
41042
  }
40959
41043
  const existing = this.#executionProcesses.get(options2.sessionId);
40960
41044
  if (existing === void 0) {
40961
- return (await this.#startPreparation(options2)).prepared();
41045
+ return (await this.#startPreparation(options2, { kind: "interactive-only" })).prepared();
40962
41046
  }
40963
41047
  if (!existing.belongsTo(options2.agent.id, options2.cwd, options2.additionalDirectories)) {
40964
41048
  throw new AcpExecutionError(
@@ -41143,7 +41227,7 @@ var AgentRuntimeManager = class {
41143
41227
  const temporaryOptions = { ...options2, sessionId: temporarySessionId };
41144
41228
  return await this.#executionProcesses.use(temporarySessionId, async () => {
41145
41229
  try {
41146
- const runtime = await this.#startPreparation(temporaryOptions);
41230
+ const runtime = await this.#startPreparation(temporaryOptions, { kind: "interactive-only" });
41147
41231
  let adopted = false;
41148
41232
  try {
41149
41233
  const nativeSessionId = runtime.nativeSessionId();
@@ -41309,7 +41393,7 @@ var AgentRuntimeManager = class {
41309
41393
  return await this.#executionProcesses.use(options2.sessionId, async () => {
41310
41394
  this.#nativeOperations.add(key);
41311
41395
  try {
41312
- const runtime = await this.#startPreparation({ ...options2, origin });
41396
+ const runtime = await this.#startPreparation({ ...options2, origin }, { kind: "interactive-only" });
41313
41397
  const openedKey = `${options2.agent.id}:${runtime.nativeSessionId()}`;
41314
41398
  this.#nativeOperations.add(openedKey);
41315
41399
  try {
@@ -41922,7 +42006,7 @@ var FixedInstallationExecutor = class {
41922
42006
  // src/authorization/workspace-directory.ts
41923
42007
  import { readdir as readdir4, realpath as realpath9, stat as stat8 } from "node:fs/promises";
41924
42008
  import { homedir as homedir2 } from "node:os";
41925
- import { basename as basename4, dirname as dirname5, isAbsolute as isAbsolute9, join as join17, normalize as normalize3, relative as relative4 } from "node:path";
42009
+ import { basename as basename4, dirname as dirname5, isAbsolute as isAbsolute10, join as join17, normalize as normalize3, relative as relative4 } from "node:path";
41926
42010
 
41927
42011
  // src/authorization/local-authorization-error.ts
41928
42012
  var LocalAuthorizationError = class extends Error {
@@ -41989,7 +42073,7 @@ var WorkspaceDirectoryService = class {
41989
42073
  }
41990
42074
  if (id.startsWith("path-")) {
41991
42075
  const path3 = expandCurrentUserHome(decodePath(id, "path-"));
41992
- if (isAbsolute9(path3)) {
42076
+ if (isAbsolute10(path3)) {
41993
42077
  return path3;
41994
42078
  }
41995
42079
  }
@@ -41997,7 +42081,7 @@ var WorkspaceDirectoryService = class {
41997
42081
  };
41998
42082
  resolvePath = async (requested, signal) => {
41999
42083
  signal.throwIfAborted();
42000
- if (!isAbsolute9(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
42084
+ if (!isAbsolute10(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
42001
42085
  throw new LocalAuthorizationError("The local directory path is invalid");
42002
42086
  }
42003
42087
  try {
@@ -42005,7 +42089,7 @@ var WorkspaceDirectoryService = class {
42005
42089
  signal.throwIfAborted();
42006
42090
  const metadata = await stat8(target);
42007
42091
  signal.throwIfAborted();
42008
- if (!isAbsolute9(target) || normalize3(target) !== target || !metadata.isDirectory()) {
42092
+ if (!isAbsolute10(target) || normalize3(target) !== target || !metadata.isDirectory()) {
42009
42093
  throw new LocalAuthorizationError("The selected location is not a directory");
42010
42094
  }
42011
42095
  return target;
@@ -42021,7 +42105,7 @@ var WorkspaceDirectoryService = class {
42021
42105
  };
42022
42106
  label = (path3) => {
42023
42107
  const suffix = relative4(homedir2(), path3);
42024
- return suffix === "" ? "~" : !isAbsolute9(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path3;
42108
+ return suffix === "" ? "~" : !isAbsolute10(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path3;
42025
42109
  };
42026
42110
  identify = async (bindingId, requestedPath2, signal) => {
42027
42111
  this.authorizeMachine(bindingId);
@@ -45099,7 +45183,7 @@ function createAgentSettingsDiscoveryHandler(dependencies) {
45099
45183
  // src/artifacts/local-file-streamer.ts
45100
45184
  import { createReadStream as createReadStream2 } from "node:fs";
45101
45185
  import { realpath as realpath10, stat as stat9 } from "node:fs/promises";
45102
- import { basename as basename5, isAbsolute as isAbsolute10, normalize as normalize4, resolve as resolve7 } from "node:path";
45186
+ import { basename as basename5, isAbsolute as isAbsolute11, normalize as normalize4, resolve as resolve7 } from "node:path";
45103
45187
  import { fileURLToPath as fileURLToPath2 } from "node:url";
45104
45188
  var CHUNK_BYTES = 192 * 1024;
45105
45189
  function requestedPath(value) {
@@ -45118,17 +45202,17 @@ function requestedPath(value) {
45118
45202
  }
45119
45203
  async function resolveFile(value, workingDirectory, signal) {
45120
45204
  const path3 = requestedPath(value);
45121
- if (path3 === null || !isAbsolute10(path3) && workingDirectory === null) {
45205
+ if (path3 === null || !isAbsolute11(path3) && workingDirectory === null) {
45122
45206
  return null;
45123
45207
  }
45124
45208
  const requested = workingDirectory === null ? path3 : resolve7(workingDirectory, path3);
45125
- if (!isAbsolute10(requested) || isAbsolute10(path3) && normalize4(path3) !== path3) {
45209
+ if (!isAbsolute11(requested) || isAbsolute11(path3) && normalize4(path3) !== path3) {
45126
45210
  return null;
45127
45211
  }
45128
45212
  try {
45129
45213
  const target = await realpath10(requested);
45130
45214
  signal.throwIfAborted();
45131
- return isAbsolute10(target) && normalize4(target) === target ? target : null;
45215
+ return isAbsolute11(target) && normalize4(target) === target ? target : null;
45132
45216
  } catch {
45133
45217
  signal.throwIfAborted();
45134
45218
  return null;
@@ -45657,7 +45741,7 @@ async function executePrompt({
45657
45741
  }
45658
45742
 
45659
45743
  // src/daemon-session-commands.ts
45660
- async function prepareSession(command, config2, directories, audit, sessions, metrics, signal) {
45744
+ async function prepareSession(command, recovery, config2, directories, audit, sessions, metrics, signal) {
45661
45745
  return await metrics.measure("prepare-total", async () => {
45662
45746
  const resolved = await metrics.measure(
45663
45747
  "workspace-resolve",
@@ -45677,7 +45761,7 @@ async function prepareSession(command, config2, directories, audit, sessions, me
45677
45761
  sessionId: command.sessionId,
45678
45762
  signal
45679
45763
  };
45680
- const prepared = command.transient === true ? await sessions.inspectSession(preparation, metrics) : await sessions.prepareSession(preparation, metrics);
45764
+ const prepared = command.transient === true ? await sessions.inspectSession(preparation, metrics) : recovery.kind === "history-required" ? await sessions.restoreSession(preparation, metrics) : await sessions.prepareSession(preparation, metrics);
45681
45765
  const configuration = command.configuration;
45682
45766
  const configOptions = configuration === void 0 ? prepared.configOptions : await metrics.measure(
45683
45767
  "configuration",
@@ -45747,7 +45831,16 @@ async function executeWorkspaceList(socket, command, directories, audit, signal)
45747
45831
  async function executeSessionPrepare(socket, command, config2, directories, audit, sessions, diagnostics, signal) {
45748
45832
  const metrics = new AccumulatingOperationMetrics();
45749
45833
  try {
45750
- const readyEvent = await prepareSession(command, config2, directories, audit, sessions, metrics, signal);
45834
+ const readyEvent = await prepareSession(
45835
+ command,
45836
+ { kind: "interactive-only" },
45837
+ config2,
45838
+ directories,
45839
+ audit,
45840
+ sessions,
45841
+ metrics,
45842
+ signal
45843
+ );
45751
45844
  send(socket, {
45752
45845
  ...readyEvent,
45753
45846
  runtimeTimings: metrics.snapshot()
@@ -45796,6 +45889,7 @@ async function executeSessionRestore(socket, command, config2, directories, audi
45796
45889
  sessionId: command.sessionId,
45797
45890
  sessionState: "provisioned"
45798
45891
  },
45892
+ { kind: "history-required" },
45799
45893
  config2,
45800
45894
  directories,
45801
45895
  audit,