@moxt-ai/mobius 0.0.354 → 0.0.356

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 (59) hide show
  1. package/dist/cli.js +613 -490
  2. package/dist/cli.js.map +4 -4
  3. package/dist/engine/agent/discovery/agent-discovery-context.d.ts +10 -0
  4. package/dist/engine/agent/discovery/agent-discovery-context.d.ts.map +1 -1
  5. package/dist/engine/agent/discovery/discover-agent.d.ts.map +1 -1
  6. package/dist/engine/agent/discovery/discover-agent.js +27 -6
  7. package/dist/engine/agent/discovery/discover-agent.js.map +1 -1
  8. package/dist/engine/agent/discovery/executable-discovery.d.ts.map +1 -1
  9. package/dist/engine/agent/discovery/executable-discovery.js +8 -1
  10. package/dist/engine/agent/discovery/executable-discovery.js.map +1 -1
  11. package/dist/engine/runtime/catalog/discover-agent-catalog.d.ts +4 -0
  12. package/dist/engine/runtime/catalog/discover-agent-catalog.d.ts.map +1 -0
  13. package/dist/engine/runtime/catalog/discover-agent-catalog.js +54 -0
  14. package/dist/engine/runtime/catalog/discover-agent-catalog.js.map +1 -0
  15. package/dist/engine/runtime/command/registry/interactions.d.ts.map +1 -1
  16. package/dist/engine/runtime/command/registry/interactions.js +7 -1
  17. package/dist/engine/runtime/command/registry/interactions.js.map +1 -1
  18. package/dist/engine/runtime/observability/diagnostic-log.d.ts.map +1 -1
  19. package/dist/engine/runtime/observability/diagnostic-log.js +6 -0
  20. package/dist/engine/runtime/observability/diagnostic-log.js.map +1 -1
  21. package/dist/engine/runtime/pairing.d.ts.map +1 -1
  22. package/dist/engine/runtime/pairing.js +6 -5
  23. package/dist/engine/runtime/pairing.js.map +1 -1
  24. package/dist/engine/runtime/runtime-loop.d.ts.map +1 -1
  25. package/dist/engine/runtime/runtime-loop.js +4 -3
  26. package/dist/engine/runtime/runtime-loop.js.map +1 -1
  27. package/dist/engine/session/live/agent-session-restore.d.ts +1 -1
  28. package/dist/engine/session/live/agent-session-restore.d.ts.map +1 -1
  29. package/dist/engine/session/live/agent-session.d.ts +1 -1
  30. package/dist/engine/session/live/agent-session.d.ts.map +1 -1
  31. package/dist/engine/session/live/agent-session.js +23 -2
  32. package/dist/engine/session/live/agent-session.js.map +1 -1
  33. package/dist/engine/session/live/session-configurations.d.ts +1 -1
  34. package/dist/engine/session/live/session-configurations.d.ts.map +1 -1
  35. package/dist/engine/session/live/session-configurations.js +1 -1
  36. package/dist/engine/session/live/session-configurations.js.map +1 -1
  37. package/dist/engine/session/live/session-restore.d.ts.map +1 -1
  38. package/dist/engine/session/live/session-restore.js +7 -1
  39. package/dist/engine/session/live/session-restore.js.map +1 -1
  40. package/dist/engine/session/native/native-session-browser.d.ts.map +1 -1
  41. package/dist/engine/session/native/native-session-browser.js +1 -0
  42. package/dist/engine/session/native/native-session-browser.js.map +1 -1
  43. package/dist/engine/session/prompt/execute-prompt.d.ts.map +1 -1
  44. package/dist/engine/session/prompt/execute-prompt.js +1 -0
  45. package/dist/engine/session/prompt/execute-prompt.js.map +1 -1
  46. package/dist/engine/session/turn/execution-receipts.d.ts +2 -0
  47. package/dist/engine/session/turn/execution-receipts.d.ts.map +1 -1
  48. package/dist/engine/session/turn/execution-receipts.js +7 -0
  49. package/dist/engine/session/turn/execution-receipts.js.map +1 -1
  50. package/dist/engine/util/process/executable.d.ts.map +1 -1
  51. package/dist/engine/util/process/executable.js +26 -8
  52. package/dist/engine/util/process/executable.js.map +1 -1
  53. package/dist/engine/util/process/process-error.d.ts +6 -1
  54. package/dist/engine/util/process/process-error.d.ts.map +1 -1
  55. package/dist/engine/util/process/process-error.js +2 -0
  56. package/dist/engine/util/process/process-error.js.map +1 -1
  57. package/dist/engine.js +572 -470
  58. package/dist/engine.js.map +4 -4
  59. package/package.json +2 -2
package/dist/engine.js CHANGED
@@ -20794,38 +20794,6 @@ function isRecord2(value) {
20794
20794
  }
20795
20795
  var sessionEventBatchSchema = external_exports.array(sessionEventSchema).min(1).max(SESSION_EVENT_BATCH_MAX_SIZE).readonly();
20796
20796
  var sessionLiveEventBatchSchema = external_exports.array(sessionLiveEventSchema).min(1).max(SESSION_EVENT_BATCH_MAX_SIZE).readonly();
20797
- var sessionExportSchema = external_exports.object({
20798
- binding: external_exports.object({
20799
- bindingId: identifierStringSchema,
20800
- runtimeId: identifierStringSchema
20801
- }).readonly(),
20802
- events: external_exports.array(sessionEventSchema).max(MAX_EVENT_COUNT).readonly(),
20803
- sessionId: identifierStringSchema,
20804
- truncated: external_exports.boolean()
20805
- }).readonly().superRefine((session, context) => {
20806
- const eventIds = /* @__PURE__ */ new Set();
20807
- for (const [index2, event] of session.events.entries()) {
20808
- if (event.sessionId !== session.sessionId) {
20809
- context.addIssue({
20810
- code: "custom",
20811
- message: "Exported event belongs to a different Session",
20812
- path: ["events", index2, "sessionId"]
20813
- });
20814
- }
20815
- if (eventIds.has(event.eventId)) {
20816
- context.addIssue({
20817
- code: "custom",
20818
- message: "Exported event identities are not unique",
20819
- path: ["events", index2, "eventId"]
20820
- });
20821
- }
20822
- eventIds.add(event.eventId);
20823
- }
20824
- });
20825
- var mobiusSessionExportSchema = external_exports.object({
20826
- formatVersion: external_exports.literal("2"),
20827
- session: sessionExportSchema
20828
- }).readonly();
20829
20797
  var sessionEventEnvelopeSchema = external_exports.object({ events: sessionLiveEventBatchSchema, kind: external_exports.literal(SESSION_EVENT_KIND) }).readonly();
20830
20798
  var sessionEventLogPageSchema = external_exports.object({
20831
20799
  events: external_exports.array(sessionEventSchema).max(MAX_EVENT_COUNT).readonly(),
@@ -20838,12 +20806,9 @@ var sessionEventLogPageSchema = external_exports.object({
20838
20806
  truncated: external_exports.boolean(),
20839
20807
  version: external_exports.literal(2)
20840
20808
  }).readonly();
20841
- var sessionEventOmissionSchema = external_exports.literal("agent-reasoning");
20842
20809
  var nativeEventPageRequestSchema = external_exports.object({
20843
20810
  cursor: external_exports.string().min(1).max(512).nullable(),
20844
- eventLimit: external_exports.number().int().min(1).max(1e4),
20845
- // Legacy callers may still send this option; readers must ignore it.
20846
- omit: external_exports.array(sessionEventOmissionSchema).max(1).readonly().optional()
20811
+ eventLimit: external_exports.number().int().min(1).max(1e4)
20847
20812
  }).readonly();
20848
20813
  var queuedPromptRequestEventLogSchema = external_exports.object({
20849
20814
  commandId: identifierStringSchema,
@@ -21476,7 +21441,9 @@ var nativeSessionResultSchema = external_exports.discriminatedUnion("action", [
21476
21441
  // unrecognized delivery from a newer peer reads as absent instead of failing the snapshot.
21477
21442
  command: commandDeliverySchema.optional().catch(void 0),
21478
21443
  // Absent from older Runtimes and while the last started command is still running.
21479
- lastTurn: lastTurnOutcomeSchema.optional().catch(void 0)
21444
+ lastTurn: lastTurnOutcomeSchema.optional().catch(void 0),
21445
+ // Runtime-owned support; older Relays strip this field before exposing the snapshot.
21446
+ queuedCancellation: external_exports.literal("before-start").optional().catch(void 0)
21480
21447
  }).readonly(),
21481
21448
  external_exports.object({
21482
21449
  ...resultEnvelope,
@@ -21522,8 +21489,6 @@ var SESSION_PREVIEW_HISTORY_PAGE_LOADED_KIND = "session.preview-history.page.loa
21522
21489
  var pageRequestFields = {
21523
21490
  cursor: external_exports.string().min(1).max(512).nullable(),
21524
21491
  eventLimit: external_exports.number().int().min(1).max(1e4),
21525
- // Decode old clients without rejecting their request; omission has no effect.
21526
- omit: external_exports.array(sessionEventOmissionSchema).max(1).readonly().optional(),
21527
21492
  requestId: identifierStringSchema,
21528
21493
  sessionId: identifierStringSchema
21529
21494
  };
@@ -59518,7 +59483,6 @@ function backgroundTaskId(result) {
59518
59483
  }
59519
59484
 
59520
59485
  // src/engine/acp/harness/claude/upstream/dist/context-resources.js
59521
- import { extname } from "node:path";
59522
59486
  function formatUriAsLink(uri) {
59523
59487
  if (uri.startsWith("file://")) {
59524
59488
  const path7 = uri.slice(7);
@@ -59533,91 +59497,6 @@ var formatContextBlock = (uri, text2) => `
59533
59497
  <context ref="${uri}">
59534
59498
  ${text2}
59535
59499
  </context>`;
59536
- function parseContextBlock(block) {
59537
- if (block.type !== "text" || typeof block.text !== "string") {
59538
- return null;
59539
- }
59540
- const match = /^\n<context ref="([^"\r\n]+)">\n([\s\S]*)\n<\/context>$/u.exec(block.text);
59541
- const uri = match?.[1];
59542
- const text2 = match?.[2];
59543
- if (uri === void 0 || text2 === void 0 || formatContextBlock(uri, text2) !== block.text) {
59544
- return null;
59545
- }
59546
- return { uri, text: text2 };
59547
- }
59548
- function contextMimeType(uri) {
59549
- let pathname = uri;
59550
- try {
59551
- pathname = new URL(uri).pathname;
59552
- } catch {
59553
- }
59554
- switch (extname(pathname).toLowerCase()) {
59555
- case ".html":
59556
- case ".htm":
59557
- return "text/html";
59558
- case ".js":
59559
- case ".mjs":
59560
- case ".cjs":
59561
- return "text/javascript";
59562
- case ".css":
59563
- return "text/css";
59564
- case ".json":
59565
- return "application/json";
59566
- case ".md":
59567
- case ".markdown":
59568
- return "text/markdown";
59569
- case ".xml":
59570
- return "application/xml";
59571
- case ".svg":
59572
- return "image/svg+xml";
59573
- case ".csv":
59574
- return "text/csv";
59575
- default:
59576
- return "text/plain";
59577
- }
59578
- }
59579
- function replayContextResources(content) {
59580
- const contexts = [];
59581
- let contextStart = content.length;
59582
- for (let index2 = content.length - 1; index2 >= 0; index2 -= 1) {
59583
- const block = content[index2];
59584
- const parsed = block === void 0 ? null : parseContextBlock(block);
59585
- if (parsed === null) {
59586
- break;
59587
- }
59588
- contexts.push(parsed);
59589
- contextStart = index2;
59590
- }
59591
- if (contexts.length === 0) {
59592
- return null;
59593
- }
59594
- contexts.reverse();
59595
- const links = new Set(contexts.map(({ uri }) => formatUriAsLink(uri)));
59596
- const resources = /* @__PURE__ */ new Map();
59597
- let nextContext = 0;
59598
- for (let index2 = 0; index2 < contextStart; index2 += 1) {
59599
- const block = content[index2];
59600
- if (block?.type !== "text" || typeof block.text !== "string") {
59601
- continue;
59602
- }
59603
- if (block.text.startsWith('\n<context ref="')) {
59604
- return null;
59605
- }
59606
- if (!links.has(block.text)) {
59607
- continue;
59608
- }
59609
- const context = contexts[nextContext];
59610
- if (context === void 0 || block.text !== formatUriAsLink(context.uri)) {
59611
- return null;
59612
- }
59613
- resources.set(index2, {
59614
- type: "resource",
59615
- resource: { ...context, mimeType: contextMimeType(context.uri) }
59616
- });
59617
- nextContext += 1;
59618
- }
59619
- return nextContext === contexts.length ? { contextStart, resources } : null;
59620
- }
59621
59500
 
59622
59501
  // src/engine/acp/harness/claude/upstream/dist/elicitation.js
59623
59502
  import { randomUUID as randomUUID4 } from "node:crypto";
@@ -66932,13 +66811,8 @@ function toAcpNotifications(content, role, sessionId, toolUseCache, client2, log
66932
66811
  const toolUseResult = options?.toolUseResult !== void 0 && content.filter((c) => typeof c === "object" && c !== null && c.type === "tool_result").length === 1 ? options.toolUseResult : void 0;
66933
66812
  const toolResultMeta = parseToolResultMeta(options?.toolResultMeta);
66934
66813
  const output2 = [];
66935
- const replayedResources = role === "user" && options.historical === true ? replayContextResources(content) : null;
66936
- for (const [index2, chunk] of content.entries()) {
66937
- if (replayedResources !== null && index2 >= replayedResources.contextStart) {
66938
- break;
66939
- }
66814
+ for (const chunk of content) {
66940
66815
  let update = null;
66941
- const resource = replayedResources?.resources.get(index2);
66942
66816
  switch (chunk.type) {
66943
66817
  case "text":
66944
66818
  case "text_delta": {
@@ -66947,7 +66821,7 @@ function toAcpNotifications(content, role, sessionId, toolUseCache, client2, log
66947
66821
  update = {
66948
66822
  sessionUpdate: role === "assistant" ? "agent_message_chunk" : "user_message_chunk",
66949
66823
  messageId,
66950
- content: resource ?? {
66824
+ content: {
66951
66825
  type: "text",
66952
66826
  text: chunk.text
66953
66827
  }
@@ -67717,14 +67591,16 @@ var macosProcessPlatform = {
67717
67591
  // src/engine/util/process/platform/windows.ts
67718
67592
  import { execFile as execFile4 } from "node:child_process";
67719
67593
  import { readFile as readFile5, realpath as realpath6 } from "node:fs/promises";
67720
- import { dirname as dirname6, extname as extname2, join as join14, resolve as resolve8 } from "node:path";
67594
+ import { dirname as dirname6, extname, join as join14, resolve as resolve8 } from "node:path";
67721
67595
 
67722
67596
  // src/engine/util/process/process-error.ts
67723
67597
  var ProcessExecutionError = class extends Error {
67724
67598
  code;
67599
+ diagnosticDetails;
67725
67600
  constructor(code, message, options = {}) {
67726
67601
  super(message, options);
67727
67602
  this.code = code;
67603
+ this.diagnosticDetails = options.diagnosticDetails ?? {};
67728
67604
  this.name = "ProcessExecutionError";
67729
67605
  }
67730
67606
  };
@@ -67744,14 +67620,14 @@ function executableExtensions(executableName, environment) {
67744
67620
  async function resolveExecutableTarget(path7) {
67745
67621
  let resolvedPath;
67746
67622
  try {
67747
- resolvedPath = await realpath6(extname2(path7) === "" ? `${path7}.cmd` : path7);
67623
+ resolvedPath = await realpath6(extname(path7) === "" ? `${path7}.cmd` : path7);
67748
67624
  } catch (cause) {
67749
- if (extname2(path7) !== "" || !(cause instanceof Error) || !("code" in cause) || cause.code !== "ENOENT") {
67625
+ if (extname(path7) !== "" || !(cause instanceof Error) || !("code" in cause) || cause.code !== "ENOENT") {
67750
67626
  throw cause;
67751
67627
  }
67752
67628
  resolvedPath = await realpath6(path7);
67753
67629
  }
67754
- if (extname2(resolvedPath).toLowerCase() === ".cmd") {
67630
+ if (extname(resolvedPath).toLowerCase() === ".cmd") {
67755
67631
  const shim = await readFile5(resolvedPath, "utf8");
67756
67632
  if (shim.includes('SET "NPM_CLI_JS=%~dp0\\node_modules\\npm\\bin\\npm-cli.js"') && shim.includes('"%NODE_EXE%" "%NPM_CLI_JS%" %*')) {
67757
67633
  return await realpath6(resolve8(dirname6(resolvedPath), "node_modules/npm/bin/npm-cli.js"));
@@ -68135,11 +68011,16 @@ async function runBoundedProcess(options) {
68135
68011
  abort();
68136
68012
  }
68137
68013
  try {
68138
- const exit = new Promise((resolveExit, rejectExit) => {
68139
- child.once("error", rejectExit);
68140
- child.once("exit", (code) => resolveExit(code ?? 1));
68014
+ const completion = new Promise((resolveCompletion, rejectCompletion) => {
68015
+ child.once("error", rejectCompletion);
68016
+ child.once("exit", (code) => {
68017
+ if (code !== 0) {
68018
+ resolveCompletion(code ?? 1);
68019
+ }
68020
+ });
68021
+ child.once("close", (code) => resolveCompletion(code ?? 1));
68141
68022
  });
68142
- const exitCode = await Promise.race([exit, interrupted.promise.then(() => -1)]);
68023
+ const exitCode = await Promise.race([completion, interrupted.promise.then(() => -1)]);
68143
68024
  if (interruptionCleanupFailure !== null) {
68144
68025
  throw interruptionCleanupFailure;
68145
68026
  }
@@ -68151,12 +68032,19 @@ async function runBoundedProcess(options) {
68151
68032
  }
68152
68033
  return new ProcessResult(Buffer.concat(stdout).toString("utf8"), Buffer.concat(stderr).toString("utf8"));
68153
68034
  } catch (error62) {
68154
- if (error62 instanceof ProcessExecutionError) {
68155
- throw error62;
68156
- }
68157
- throw new ProcessExecutionError("process_spawn_failed", "The executable could not be started", {
68035
+ const failure2 = error62 instanceof ProcessExecutionError ? error62 : new ProcessExecutionError("process_spawn_failed", "The executable could not be started", {
68158
68036
  cause: error62
68159
68037
  });
68038
+ throw new ProcessExecutionError(failure2.code, failure2.message, {
68039
+ cause: error62,
68040
+ diagnosticDetails: {
68041
+ stdoutBytes: stdoutBytes.toString(),
68042
+ stderrBytes: stderrBytes.toString(),
68043
+ outputLimitBytes: outputLimitBytes.toString(),
68044
+ ...child.exitCode === null ? {} : { exitCode: child.exitCode.toString() },
68045
+ ...child.signalCode === null ? {} : { signal: child.signalCode }
68046
+ }
68047
+ });
68160
68048
  } finally {
68161
68049
  clearTimeout(timeout);
68162
68050
  options.signal.removeEventListener("abort", abort);
@@ -71184,9 +71072,9 @@ import {
71184
71072
  // src/engine/acp/harness/pi/upstream/dist/acp/agent.js
71185
71073
  import { spawnSync } from "node:child_process";
71186
71074
  import { randomUUID as randomUUID11 } from "node:crypto";
71187
- import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, statSync as statSync3, unlinkSync as unlinkSync2 } from "node:fs";
71075
+ import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync9, realpathSync as realpathSync3, statSync as statSync3, unlinkSync as unlinkSync2 } from "node:fs";
71188
71076
  import { basename as basename5, dirname as dirname8, isAbsolute as isAbsolute12, join as join20 } from "node:path";
71189
- import { RequestError as RequestError10 } from "@agentclientprotocol/sdk";
71077
+ import { RequestError as RequestError11 } from "@agentclientprotocol/sdk";
71190
71078
 
71191
71079
  // src/engine/acp/harness/pi/upstream/dist/pi-rpc/process.js
71192
71080
  import { spawn as spawn5 } from "node:child_process";
@@ -71699,8 +71587,62 @@ function toAvailableCommandsFromPiGetCommands(data, opts) {
71699
71587
  return { commands: out2, raw: commandsRaw };
71700
71588
  }
71701
71589
 
71590
+ // src/engine/acp/harness/pi/upstream/dist/acp/pi-history.js
71591
+ import { readFileSync as readFileSync3 } from "node:fs";
71592
+ import { RequestError as RequestError8 } from "@agentclientprotocol/sdk";
71593
+ var entrySchema = external_exports.object({
71594
+ type: external_exports.string(),
71595
+ id: external_exports.string(),
71596
+ parentId: external_exports.string().nullable()
71597
+ }).passthrough();
71598
+ var messageSchema = external_exports.object({
71599
+ role: external_exports.enum(["user", "assistant", "toolResult"]),
71600
+ content: external_exports.unknown()
71601
+ }).passthrough();
71602
+ function readPiHistory(sessionFile) {
71603
+ try {
71604
+ const entries = /* @__PURE__ */ new Map();
71605
+ let leaf = null;
71606
+ for (const line of readFileSync3(sessionFile, "utf8").split(/\r?\n/u)) {
71607
+ if (!line.trim()) {
71608
+ continue;
71609
+ }
71610
+ const value = JSON.parse(line);
71611
+ if (external_exports.object({ type: external_exports.literal("session") }).safeParse(value).success) {
71612
+ continue;
71613
+ }
71614
+ const entry = entrySchema.parse(value);
71615
+ entries.set(entry.id, entry);
71616
+ leaf = entry.id;
71617
+ }
71618
+ const history = [];
71619
+ const visited = /* @__PURE__ */ new Set();
71620
+ while (leaf !== null) {
71621
+ const entry = entries.get(leaf);
71622
+ if (entry === void 0 || visited.has(leaf)) {
71623
+ throw new Error("Invalid Pi history branch");
71624
+ }
71625
+ visited.add(leaf);
71626
+ if (entry.type === "message") {
71627
+ const { role } = external_exports.object({ role: external_exports.string() }).parse(entry.message);
71628
+ if (role === "user" || role === "assistant" || role === "toolResult") {
71629
+ history.push({ type: "message", message: messageSchema.parse(entry.message) });
71630
+ }
71631
+ } else if (entry.type === "compaction") {
71632
+ history.push({ type: "compaction", id: entry.id, summary: external_exports.string().parse(entry.summary) });
71633
+ }
71634
+ leaf = entry.parentId;
71635
+ }
71636
+ return history.reverse();
71637
+ } catch (cause) {
71638
+ const error62 = RequestError8.internalError({ code: "PI_HISTORY_READ_FAILED" }, "Unable to read Pi history");
71639
+ error62.cause = cause;
71640
+ throw error62;
71641
+ }
71642
+ }
71643
+
71702
71644
  // src/engine/acp/harness/pi/upstream/dist/acp/pi-sessions.js
71703
- import { closeSync as closeSync2, existsSync as existsSync4, openSync as openSync2, readdirSync as readdirSync4, readFileSync as readFileSync3, readSync as readSync2, statSync as statSync2 } from "node:fs";
71645
+ import { closeSync as closeSync2, existsSync as existsSync4, openSync as openSync2, readdirSync as readdirSync4, readFileSync as readFileSync4, readSync as readSync2, statSync as statSync2 } from "node:fs";
71704
71646
  import { isAbsolute as isAbsolute10, join as join17, resolve as resolve10 } from "node:path";
71705
71647
  var DEFAULT_TAIL_BYTES = 256 * 1024;
71706
71648
  var DEFAULT_HEAD_BYTES = 64 * 1024;
@@ -71714,7 +71656,7 @@ function readSessionDirFromSettings(agentDir) {
71714
71656
  if (!existsSync4(settingsPath)) {
71715
71657
  return null;
71716
71658
  }
71717
- const raw = readFileSync3(settingsPath, "utf8");
71659
+ const raw = readFileSync4(settingsPath, "utf8");
71718
71660
  const data = JSON.parse(raw);
71719
71661
  if (!data || typeof data !== "object" || Array.isArray(data)) {
71720
71662
  return null;
@@ -71930,7 +71872,7 @@ function pickUpdatedAtFromTail(tail) {
71930
71872
  }
71931
71873
  function pickFallbackTitleFromHead(path7) {
71932
71874
  try {
71933
- const raw = readFileSync3(path7, { encoding: "utf8" });
71875
+ const raw = readFileSync4(path7, { encoding: "utf8" });
71934
71876
  const lines = raw.split(/\r?\n/);
71935
71877
  for (const line0 of lines) {
71936
71878
  const line = line0.trim();
@@ -72026,7 +71968,7 @@ function findPiSession(sessionId, environment = process.env) {
72026
71968
  }
72027
71969
 
72028
71970
  // src/engine/acp/harness/pi/upstream/dist/acp/pi-settings.js
72029
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
71971
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
72030
71972
  import { join as join18, resolve as resolve11 } from "node:path";
72031
71973
  function isObject2(x) {
72032
71974
  return Boolean(x) && typeof x === "object" && !Array.isArray(x);
@@ -72048,7 +71990,7 @@ function readJsonFile2(path7) {
72048
71990
  if (!existsSync5(path7)) {
72049
71991
  return {};
72050
71992
  }
72051
- const raw = readFileSync4(path7, "utf-8");
71993
+ const raw = readFileSync5(path7, "utf-8");
72052
71994
  const data = JSON.parse(raw);
72053
71995
  return isObject2(data) ? data : {};
72054
71996
  } catch {
@@ -72093,12 +72035,12 @@ function getQuietStartup(cwd, environment = process.env) {
72093
72035
 
72094
72036
  // src/engine/acp/harness/pi/upstream/dist/acp/session.js
72095
72037
  import { randomUUID as randomUUID10 } from "node:crypto";
72096
- import { readFileSync as readFileSync7 } from "node:fs";
72038
+ import { readFileSync as readFileSync8 } from "node:fs";
72097
72039
  import { isAbsolute as isAbsolute11, resolve as resolvePath } from "node:path";
72098
- import { RequestError as RequestError9 } from "@agentclientprotocol/sdk";
72040
+ import { RequestError as RequestError10 } from "@agentclientprotocol/sdk";
72099
72041
 
72100
72042
  // src/engine/acp/harness/pi/upstream/dist/acp/extension-questions.js
72101
- import { RequestError as RequestError8 } from "@agentclientprotocol/sdk";
72043
+ import { RequestError as RequestError9 } from "@agentclientprotocol/sdk";
72102
72044
  var questionBase = {
72103
72045
  id: external_exports.string().min(1).max(255),
72104
72046
  title: external_exports.string().max(255),
@@ -72115,7 +72057,7 @@ var questionSchema = external_exports.discriminatedUnion("method", [
72115
72057
  external_exports.object({ ...questionBase, method: external_exports.literal("editor"), prefill: external_exports.string().max(1e4).optional() })
72116
72058
  ]).readonly();
72117
72059
  var QUESTION_TIMEOUT_MS = 36e5;
72118
- var PiQuestionError = class extends RequestError8 {
72060
+ var PiQuestionError = class extends RequestError9 {
72119
72061
  constructor(kind, cause) {
72120
72062
  const messages = {
72121
72063
  request_failed: "Pi could not request an answer.",
@@ -72253,7 +72195,7 @@ var PiExtensionQuestions = class {
72253
72195
  throw new PiQuestionError("invalid_response");
72254
72196
  }
72255
72197
  } catch (cause) {
72256
- if (!signal.aborted && !(cause instanceof RequestError8 && cause.code === -32800)) {
72198
+ if (!signal.aborted && !(cause instanceof RequestError9 && cause.code === -32800)) {
72257
72199
  turn.controller.abort(cause instanceof PiQuestionError ? cause : new PiQuestionError("request_failed", cause));
72258
72200
  }
72259
72201
  } finally {
@@ -72267,14 +72209,14 @@ var PiExtensionQuestions = class {
72267
72209
  };
72268
72210
 
72269
72211
  // src/engine/acp/harness/pi/upstream/dist/acp/session-store.js
72270
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync } from "node:fs";
72212
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync } from "node:fs";
72271
72213
  import { dirname as dirname7 } from "node:path";
72272
72214
  function ensureParentDir(path7) {
72273
72215
  mkdirSync2(dirname7(path7), { recursive: true });
72274
72216
  }
72275
72217
  function loadFile(path7) {
72276
72218
  try {
72277
- const raw = readFileSync5(path7, "utf-8");
72219
+ const raw = readFileSync6(path7, "utf-8");
72278
72220
  const parsed = JSON.parse(raw);
72279
72221
  if (parsed?.version !== 1 || typeof parsed.sessions !== "object" || !parsed.sessions) {
72280
72222
  return { version: 1, sessions: {} };
@@ -72319,7 +72261,7 @@ var SessionStore = class {
72319
72261
  };
72320
72262
 
72321
72263
  // src/engine/acp/harness/pi/upstream/dist/acp/slash-commands.js
72322
- import { existsSync as existsSync6, readdirSync as readdirSync5, readFileSync as readFileSync6 } from "node:fs";
72264
+ import { existsSync as existsSync6, readdirSync as readdirSync5, readFileSync as readFileSync7 } from "node:fs";
72323
72265
  import { join as join19, resolve as resolve12 } from "node:path";
72324
72266
  function parseFrontmatter(content) {
72325
72267
  const frontmatter = {};
@@ -72358,7 +72300,7 @@ function loadCommandsFromDir(dir, source, subdir = "") {
72358
72300
  continue;
72359
72301
  }
72360
72302
  try {
72361
- const rawContent = readFileSync6(fullPath, "utf-8");
72303
+ const rawContent = readFileSync7(fullPath, "utf-8");
72362
72304
  const { frontmatter, content } = parseFrontmatter(rawContent);
72363
72305
  const name2 = entry.name.slice(0, -3);
72364
72306
  const sourceStr = source === "user" ? subdir ? `(user:${subdir})` : "(user)" : subdir ? `(project:${subdir})` : "(project)";
@@ -72533,6 +72475,16 @@ ${stderr}`);
72533
72475
  }
72534
72476
 
72535
72477
  // src/engine/acp/harness/pi/upstream/dist/acp/session.js
72478
+ var nativeUserMessageSchema = external_exports.object({
72479
+ role: external_exports.literal("user"),
72480
+ content: external_exports.union([
72481
+ external_exports.string().transform((text2) => [{ type: "text", text: text2 }]),
72482
+ external_exports.array(external_exports.discriminatedUnion("type", [
72483
+ external_exports.object({ type: external_exports.literal("text"), text: external_exports.string() }),
72484
+ external_exports.object({ type: external_exports.literal("image"), data: external_exports.string(), mimeType: external_exports.string() })
72485
+ ]))
72486
+ ])
72487
+ });
72536
72488
  function toUsageUpdate(stats) {
72537
72489
  const used = stats?.contextUsage?.tokens;
72538
72490
  const size = stats?.contextUsage?.contextWindow;
@@ -72678,7 +72630,7 @@ var SessionManager = class {
72678
72630
  });
72679
72631
  } catch (e) {
72680
72632
  if (e instanceof PiRpcSpawnError) {
72681
- throw RequestError9.internalError({ code: e.code }, e.message);
72633
+ throw RequestError10.internalError({ code: e.code }, e.message);
72682
72634
  }
72683
72635
  throw e;
72684
72636
  }
@@ -72707,7 +72659,7 @@ var SessionManager = class {
72707
72659
  get(sessionId) {
72708
72660
  const s = this.sessions.get(sessionId);
72709
72661
  if (!s) {
72710
- throw RequestError9.invalidParams(`Unknown sessionId: ${sessionId}`);
72662
+ throw RequestError10.invalidParams(`Unknown sessionId: ${sessionId}`);
72711
72663
  }
72712
72664
  return s;
72713
72665
  }
@@ -72807,8 +72759,8 @@ var PiAcpSession = class {
72807
72759
  if (cause instanceof PiRpcProcessError) {
72808
72760
  const pending = this.pendingTurn;
72809
72761
  const reason = pending?.questionSignal.reason;
72810
- const error62 = reason instanceof RequestError9 ? reason : RequestError9.internalError({ code: cause.code, details: cause.message });
72811
- if (!(reason instanceof RequestError9)) {
72762
+ const error62 = reason instanceof RequestError10 ? reason : RequestError10.internalError({ code: cause.code, details: cause.message });
72763
+ if (!(reason instanceof RequestError10)) {
72812
72764
  error62.cause = cause;
72813
72765
  }
72814
72766
  this.extensionQuestions.endTurn(error62);
@@ -72876,12 +72828,12 @@ var PiAcpSession = class {
72876
72828
  const signal = this.extensionQuestions.startTurn();
72877
72829
  try {
72878
72830
  const result = await this.proc.compact(customInstructions, { signal, timeoutMs });
72879
- if (signal.aborted && signal.reason instanceof RequestError9) {
72831
+ if (signal.aborted && signal.reason instanceof RequestError10) {
72880
72832
  throw signal.reason;
72881
72833
  }
72882
72834
  return result;
72883
72835
  } catch (cause) {
72884
- if (signal.aborted && signal.reason instanceof RequestError9) {
72836
+ if (signal.aborted && signal.reason instanceof RequestError10) {
72885
72837
  try {
72886
72838
  await this.proc.abort({ signal: this.proc.signal, timeoutMs });
72887
72839
  } catch (abortCause) {
@@ -72974,14 +72926,14 @@ var PiAcpSession = class {
72974
72926
  await this.publishContextUsage();
72975
72927
  const retryFailure = this.turnRetryFailure;
72976
72928
  this.turnRetryFailure = null;
72977
- if (questionSignal?.aborted && questionSignal.reason instanceof RequestError9 && !this.cancelRequested) {
72929
+ if (questionSignal?.aborted && questionSignal.reason instanceof RequestError10 && !this.cancelRequested) {
72978
72930
  this.pendingTurn?.reject(questionSignal.reason);
72979
72931
  } else if (retryFailure !== null && !this.cancelRequested) {
72980
72932
  this.pendingTurn?.reject(
72981
72933
  // The message rides in `data.details` so clients that unwrap the
72982
72934
  // JSON-RPC internal-error envelope (like Mobius) surface the real
72983
72935
  // model error; `code` keeps the failure machine-readable.
72984
- RequestError9.internalError({
72936
+ RequestError10.internalError({
72985
72937
  code: "pi_retries_exhausted",
72986
72938
  details: `Pi retries exhausted: ${retryFailure}`
72987
72939
  })
@@ -73065,6 +73017,17 @@ var PiAcpSession = class {
73065
73017
  handlePiEvent(ev2) {
73066
73018
  const type = String(ev2.type ?? "");
73067
73019
  switch (type) {
73020
+ case "message_start": {
73021
+ const message = nativeUserMessageSchema.safeParse(ev2.message);
73022
+ if (!message.success) {
73023
+ break;
73024
+ }
73025
+ this.lastEmit = this.lastEmit.then(() => this.conn.startUserMessage());
73026
+ for (const content of message.data.content) {
73027
+ this.emit({ sessionUpdate: "user_message_chunk", content });
73028
+ }
73029
+ break;
73030
+ }
73068
73031
  case "message_update": {
73069
73032
  const ame2 = ev2.assistantMessageEvent;
73070
73033
  if (this.turnRetryFailure !== null && (ame2?.type === "text_delta" || ame2?.type === "thinking_delta" || ame2?.type === "toolcall_start")) {
@@ -73171,7 +73134,7 @@ var PiAcpSession = class {
73171
73134
  if (p) {
73172
73135
  try {
73173
73136
  const abs = isAbsolute11(p) ? p : resolvePath(this.cwd, p);
73174
- snapshotOldText = readFileSync7(abs, "utf8");
73137
+ snapshotOldText = readFileSync8(abs, "utf8");
73175
73138
  this.fileSnapshots.set(toolCallId, { path: p, oldText: snapshotOldText });
73176
73139
  if (toolName === "edit") {
73177
73140
  for (const needle of getEditOldTexts(args)) {
@@ -73254,7 +73217,7 @@ var PiAcpSession = class {
73254
73217
  if (!isError && snapshot) {
73255
73218
  try {
73256
73219
  const abs = isAbsolute11(snapshot.path) ? snapshot.path : resolvePath(this.cwd, snapshot.path);
73257
- const newText = readFileSync7(abs, "utf8");
73220
+ const newText = readFileSync8(abs, "utf8");
73258
73221
  if (snapshot.oldText === null || newText !== snapshot.oldText) {
73259
73222
  hasStructuredDiff = true;
73260
73223
  content = [
@@ -73576,7 +73539,7 @@ var PiAcpAgent = class {
73576
73539
  const restorePromise = (async () => {
73577
73540
  const stored = this.findStoredSession(sessionId);
73578
73541
  if (!stored) {
73579
- throw RequestError10.invalidParams(`Unknown sessionId: ${sessionId}`);
73542
+ throw RequestError11.invalidParams(`Unknown sessionId: ${sessionId}`);
73580
73543
  }
73581
73544
  const cwd = opts?.cwd ?? stored.cwd;
73582
73545
  let proc;
@@ -73589,7 +73552,7 @@ var PiAcpAgent = class {
73589
73552
  });
73590
73553
  } catch (e) {
73591
73554
  if (e?.name === "PiRpcSpawnError") {
73592
- throw RequestError10.internalError({ code: e?.code }, String(e?.message ?? e));
73555
+ throw RequestError11.internalError({ code: e?.code }, String(e?.message ?? e));
73593
73556
  }
73594
73557
  throw e;
73595
73558
  }
@@ -73649,7 +73612,7 @@ var PiAcpAgent = class {
73649
73612
  }
73650
73613
  async newSession(params) {
73651
73614
  if (!isAbsolute12(params.cwd)) {
73652
- throw RequestError10.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
73615
+ throw RequestError11.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
73653
73616
  }
73654
73617
  this.lastSessionCwd = params.cwd;
73655
73618
  const fileCommands = loadSlashCommands(params.cwd, this.environment);
@@ -73688,16 +73651,16 @@ var PiAcpAgent = class {
73688
73651
  }
73689
73652
  if (availableModelsErr) {
73690
73653
  this.cleanupFailedNewSession(session.sessionId, state);
73691
- throw RequestError10.internalError({}, String(availableModelsErr?.message ?? availableModelsErr));
73654
+ throw RequestError11.internalError({}, String(availableModelsErr?.message ?? availableModelsErr));
73692
73655
  }
73693
73656
  const rawModelsCount = Array.isArray(availableModels?.models) ? availableModels.models.length : 0;
73694
73657
  if (rawModelsCount === 0) {
73695
73658
  this.cleanupFailedNewSession(session.sessionId, state);
73696
- throw RequestError10.authRequired({ authMethods: getAuthMethods() }, "Configure an API key or log in with an OAuth provider.");
73659
+ throw RequestError11.authRequired({ authMethods: getAuthMethods() }, "Configure an API key or log in with an OAuth provider.");
73697
73660
  }
73698
73661
  if (stateErr && maybeAuthRequiredError(stateErr)) {
73699
73662
  this.cleanupFailedNewSession(session.sessionId, state);
73700
- throw RequestError10.authRequired({ authMethods: getAuthMethods() }, "Configure an API key or log in with an OAuth provider.");
73663
+ throw RequestError11.authRequired({ authMethods: getAuthMethods() }, "Configure an API key or log in with an OAuth provider.");
73701
73664
  }
73702
73665
  let configuration;
73703
73666
  try {
@@ -73707,7 +73670,7 @@ var PiAcpAgent = class {
73707
73670
  configuration = await getSessionConfiguration(session.proc, { state, availableModels });
73708
73671
  } catch (err) {
73709
73672
  this.cleanupFailedNewSession(session.sessionId, state);
73710
- throw maybeAuthRequiredError(err) ?? RequestError10.internalError({}, String(err?.message ?? err));
73673
+ throw maybeAuthRequiredError(err) ?? RequestError11.internalError({}, String(err?.message ?? err));
73711
73674
  }
73712
73675
  const { configOptions, models, modes } = configuration;
73713
73676
  const quietStartup = getQuietStartup(params.cwd, this.environment);
@@ -73787,16 +73750,6 @@ var PiAcpAgent = class {
73787
73750
  }
73788
73751
  async promptSubmission(params, submission) {
73789
73752
  const session = await this.restoreSession(params.sessionId);
73790
- this.conn.startUserMessage();
73791
- for (const content of params.prompt) {
73792
- if (submission.aborted) {
73793
- return { stopReason: "cancelled" };
73794
- }
73795
- await this.conn.sessionUpdate({
73796
- sessionId: params.sessionId,
73797
- update: { sessionUpdate: "user_message_chunk", content }
73798
- });
73799
- }
73800
73753
  if (submission.aborted) {
73801
73754
  return { stopReason: "cancelled" };
73802
73755
  }
@@ -73807,6 +73760,9 @@ var PiAcpAgent = class {
73807
73760
  const cmd = space === -1 ? trimmed.slice(1) : trimmed.slice(1, space);
73808
73761
  const argsString = space === -1 ? "" : trimmed.slice(space + 1);
73809
73762
  const args = parseCommandArgs(argsString);
73763
+ if (builtinAvailableCommands().some((command) => command.name === cmd)) {
73764
+ this.conn.startUserMessage();
73765
+ }
73810
73766
  if (cmd === "compact") {
73811
73767
  const customInstructions = args.join(" ").trim() || void 0;
73812
73768
  const compactionId = randomUUID11();
@@ -74068,7 +74024,7 @@ ${JSON.stringify(stats, null, 2)}`;
74068
74024
  }
74069
74025
  let text2 = "";
74070
74026
  try {
74071
- text2 = readFileSync8(changelogPath, "utf-8");
74027
+ text2 = readFileSync9(changelogPath, "utf-8");
74072
74028
  } catch (e) {
74073
74029
  await this.conn.sessionUpdate({
74074
74030
  sessionId: session.sessionId,
@@ -74112,7 +74068,7 @@ ${JSON.stringify(stats, null, 2)}`;
74112
74068
  return { stopReason: "end_turn" };
74113
74069
  }
74114
74070
  try {
74115
- const raw = readFileSync8(sessionFile, "utf-8");
74071
+ const raw = readFileSync9(sessionFile, "utf-8");
74116
74072
  if (raw.trim().length === 0) {
74117
74073
  await this.conn.sessionUpdate({
74118
74074
  sessionId: session.sessionId,
@@ -74235,7 +74191,7 @@ ${JSON.stringify(stats, null, 2)}`;
74235
74191
  signal.throwIfAborted();
74236
74192
  const parsed = steerRequestSchema.safeParse(params);
74237
74193
  if (!parsed.success) {
74238
- throw RequestError10.invalidParams("Invalid steering request");
74194
+ throw RequestError11.invalidParams("Invalid steering request");
74239
74195
  }
74240
74196
  const session = this.sessions.maybeGet(parsed.data.sessionId);
74241
74197
  if (session === void 0) {
@@ -74247,14 +74203,6 @@ ${JSON.stringify(stats, null, 2)}`;
74247
74203
  case "idle":
74248
74204
  return { outcome: "promptRequired", reason: "noRunningTurn" };
74249
74205
  case "injected": {
74250
- this.conn.startUserMessage();
74251
- for (const content of parsed.data.prompt) {
74252
- signal.throwIfAborted();
74253
- await this.conn.sessionUpdate({
74254
- sessionId: parsed.data.sessionId,
74255
- update: { sessionUpdate: "user_message_chunk", content }
74256
- });
74257
- }
74258
74206
  return { outcome: "injected" };
74259
74207
  }
74260
74208
  }
@@ -74288,11 +74236,11 @@ ${JSON.stringify(stats, null, 2)}`;
74288
74236
  }
74289
74237
  async forkSession(params) {
74290
74238
  if (!isAbsolute12(params.cwd)) {
74291
- throw RequestError10.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
74239
+ throw RequestError11.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
74292
74240
  }
74293
74241
  const source = this.findStoredSession(params.sessionId);
74294
74242
  if (!source) {
74295
- throw RequestError10.invalidParams(`Unknown sessionId: ${params.sessionId}`);
74243
+ throw RequestError11.invalidParams(`Unknown sessionId: ${params.sessionId}`);
74296
74244
  }
74297
74245
  this.lastSessionCwd = params.cwd;
74298
74246
  const fileCommands = loadSlashCommands(params.cwd, this.environment);
@@ -74354,13 +74302,13 @@ ${JSON.stringify(stats, null, 2)}`;
74354
74302
  }
74355
74303
  async resumeSession(params) {
74356
74304
  if (!isAbsolute12(params.cwd)) {
74357
- throw RequestError10.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
74305
+ throw RequestError11.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
74358
74306
  }
74359
74307
  this.sessions.close(params.sessionId);
74360
74308
  this.lastSessionCwd = params.cwd;
74361
74309
  const stored = this.findStoredSession(params.sessionId);
74362
74310
  if (!stored) {
74363
- throw RequestError10.invalidParams(`Unknown sessionId: ${params.sessionId}`);
74311
+ throw RequestError11.invalidParams(`Unknown sessionId: ${params.sessionId}`);
74364
74312
  }
74365
74313
  const session = await this.restoreSession(params.sessionId, {
74366
74314
  cwd: params.cwd,
@@ -74425,13 +74373,13 @@ ${JSON.stringify(stats, null, 2)}`;
74425
74373
  }
74426
74374
  async loadSession(params) {
74427
74375
  if (!isAbsolute12(params.cwd)) {
74428
- throw RequestError10.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
74376
+ throw RequestError11.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
74429
74377
  }
74430
74378
  this.sessions.close(params.sessionId);
74431
74379
  this.lastSessionCwd = params.cwd;
74432
74380
  const stored = this.findStoredSession(params.sessionId);
74433
74381
  if (!stored) {
74434
- throw RequestError10.invalidParams(`Unknown sessionId: ${params.sessionId}`);
74382
+ throw RequestError11.invalidParams(`Unknown sessionId: ${params.sessionId}`);
74435
74383
  }
74436
74384
  const enableSkillCommands = getEnableSkillCommands(params.cwd, this.environment);
74437
74385
  const session = await this.restoreSession(params.sessionId, {
@@ -74454,9 +74402,29 @@ ${JSON.stringify(stats, null, 2)}`;
74454
74402
  cwd: params.cwd,
74455
74403
  sessionFile: stored.sessionFile
74456
74404
  });
74457
- const data = await proc.getMessages();
74458
- const messages = Array.isArray(data?.messages) ? data.messages : [];
74459
- for (const m of messages) {
74405
+ for (const entry of readPiHistory(stored.sessionFile)) {
74406
+ if (entry.type === "compaction") {
74407
+ await this.conn.sessionUpdate({
74408
+ sessionId: session.sessionId,
74409
+ update: {
74410
+ sessionUpdate: "compaction_update",
74411
+ compactionId: entry.id,
74412
+ status: "completed"
74413
+ }
74414
+ });
74415
+ if (entry.summary) {
74416
+ await this.conn.sessionUpdate({
74417
+ sessionId: session.sessionId,
74418
+ update: {
74419
+ sessionUpdate: "compaction_summary_chunk",
74420
+ compactionId: entry.id,
74421
+ content: { type: "text", text: entry.summary }
74422
+ }
74423
+ });
74424
+ }
74425
+ continue;
74426
+ }
74427
+ const m = entry.message;
74460
74428
  const role = String(m?.role ?? "");
74461
74429
  if (role === "user") {
74462
74430
  const text2 = normalizePiMessageText(m?.content);
@@ -74606,7 +74574,7 @@ ${JSON.stringify(stats, null, 2)}`;
74606
74574
  const session = await this.restoreSession(params.sessionId);
74607
74575
  const mode = params.modeId;
74608
74576
  if (typeof mode !== "string" || mode.length === 0) {
74609
- throw RequestError10.invalidParams("Expected nonempty string modeId");
74577
+ throw RequestError11.invalidParams("Expected nonempty string modeId");
74610
74578
  }
74611
74579
  await session.proc.setThinkingLevel(mode);
74612
74580
  await emitConfigOptionsUpdate(this.conn, session.sessionId, session.proc);
@@ -74617,18 +74585,18 @@ ${JSON.stringify(stats, null, 2)}`;
74617
74585
  const configId = String(params.configId);
74618
74586
  let modelChanged = false;
74619
74587
  if (typeof params.value !== "string") {
74620
- throw RequestError10.invalidParams(`Expected string value for config option: ${configId}`);
74588
+ throw RequestError11.invalidParams(`Expected string value for config option: ${configId}`);
74621
74589
  }
74622
74590
  if (configId === MODEL_CONFIG_ID2) {
74623
74591
  await setSessionModel(session.proc, params.value);
74624
74592
  modelChanged = true;
74625
74593
  } else if (configId === THOUGHT_LEVEL_CONFIG_ID) {
74626
74594
  if (params.value.length === 0) {
74627
- throw RequestError10.invalidParams("Expected nonempty thinking level");
74595
+ throw RequestError11.invalidParams("Expected nonempty thinking level");
74628
74596
  }
74629
74597
  await session.proc.setThinkingLevel(params.value);
74630
74598
  } else {
74631
- throw RequestError10.invalidParams(`Unknown config option: ${configId}`);
74599
+ throw RequestError11.invalidParams(`Unknown config option: ${configId}`);
74632
74600
  }
74633
74601
  const configOptions = await emitConfigOptionsUpdate(this.conn, session.sessionId, session.proc);
74634
74602
  if (modelChanged) {
@@ -74784,7 +74752,7 @@ async function setSessionModel(proc, requestedModelId) {
74784
74752
  }
74785
74753
  }
74786
74754
  if (!provider || !modelId) {
74787
- throw RequestError10.invalidParams(`Unknown modelId: ${requestedModelId}`);
74755
+ throw RequestError11.invalidParams(`Unknown modelId: ${requestedModelId}`);
74788
74756
  }
74789
74757
  await proc.setModel(provider, modelId);
74790
74758
  }
@@ -74938,7 +74906,7 @@ function buildStartupInfo(opts) {
74938
74906
  ];
74939
74907
  for (const settingsPath of settingsPaths) {
74940
74908
  try {
74941
- const settings = JSON.parse(readFileSync8(settingsPath, "utf-8"));
74909
+ const settings = JSON.parse(readFileSync9(settingsPath, "utf-8"));
74942
74910
  const pkgs = Array.isArray(settings?.packages) ? settings.packages : [];
74943
74911
  for (const pkg of pkgs) {
74944
74912
  const s = String(pkg);
@@ -75623,7 +75591,14 @@ async function probeVersion(executable, arguments_, environment, defaultWorkspac
75623
75591
  });
75624
75592
  const version2 = normalize4(result.stdout || result.stderr);
75625
75593
  if (version2.length === 0) {
75626
- throw new ProcessExecutionError("process_exit_failed", "The executable did not report a version");
75594
+ throw new ProcessExecutionError("process_exit_failed", "The executable did not report a version", {
75595
+ diagnosticDetails: {
75596
+ probeReason: "empty_version_output",
75597
+ exitCode: "0",
75598
+ stdoutBytes: Buffer.byteLength(result.stdout).toString(),
75599
+ stderrBytes: Buffer.byteLength(result.stderr).toString()
75600
+ }
75601
+ });
75627
75602
  }
75628
75603
  return version2;
75629
75604
  }
@@ -75645,9 +75620,27 @@ function isRetryableProbeFailure(error62) {
75645
75620
  }
75646
75621
  return error62 instanceof AgentProbeError && error62.code === "adapter_probe_timeout";
75647
75622
  }
75648
- async function probeWithRetry(signal, probe) {
75623
+ async function probeWithRetry(context, specification, source, probe) {
75624
+ const signal = context.signal;
75625
+ const run = async (attempt) => {
75626
+ const startedAt = performance.now();
75627
+ try {
75628
+ return await probe();
75629
+ } catch (failure2) {
75630
+ context.onProbeDiagnostic?.({
75631
+ agentId: specification.id,
75632
+ source,
75633
+ event: signal.aborted ? "agent_probe_cancelled" : "agent_probe_failed",
75634
+ attempt,
75635
+ elapsedMilliseconds: Math.round(performance.now() - startedAt),
75636
+ timeoutMilliseconds: source === "acp_readiness" ? specification.acpProbeTimeoutMilliseconds : specification.versionProbeTimeoutMilliseconds,
75637
+ failure: failure2
75638
+ });
75639
+ throw failure2;
75640
+ }
75641
+ };
75649
75642
  try {
75650
- return await probe();
75643
+ return await run(1);
75651
75644
  } catch (error62) {
75652
75645
  if (signal.aborted) {
75653
75646
  signal.throwIfAborted();
@@ -75655,7 +75648,7 @@ async function probeWithRetry(signal, probe) {
75655
75648
  if (!isRetryableProbeFailure(error62)) {
75656
75649
  throw error62;
75657
75650
  }
75658
- return await probe();
75651
+ return await run(2);
75659
75652
  }
75660
75653
  }
75661
75654
  function integrationProbeFailure(specification, error62) {
@@ -75685,7 +75678,9 @@ async function discoverAgent(specification, context) {
75685
75678
  let agentVersion = "";
75686
75679
  try {
75687
75680
  agentVersion = await probeWithRetry(
75688
- context.signal,
75681
+ context,
75682
+ specification,
75683
+ "agent_version",
75689
75684
  async () => await probeVersion(
75690
75685
  agent,
75691
75686
  specification.agentVersionArguments,
@@ -75733,7 +75728,9 @@ async function discoverAgent(specification, context) {
75733
75728
  launchEnvironment = await specification.createLaunchEnvironment(agent, context);
75734
75729
  if (specification.adapterVersionArguments.length > 0) {
75735
75730
  adapterVersion = await probeWithRetry(
75736
- context.signal,
75731
+ context,
75732
+ specification,
75733
+ "adapter_version",
75737
75734
  async () => await probeVersion(
75738
75735
  adapter,
75739
75736
  specification.adapterVersionArguments,
@@ -75768,7 +75765,9 @@ async function discoverAgent(specification, context) {
75768
75765
  );
75769
75766
  try {
75770
75767
  const readiness = await probeWithRetry(
75771
- context.signal,
75768
+ context,
75769
+ specification,
75770
+ "acp_readiness",
75772
75771
  async () => await probeAcpReadiness(
75773
75772
  specification,
75774
75773
  buildDefinition(adapterVersion, unsupportedSessionCapabilities()),
@@ -83471,6 +83470,266 @@ function describeEnvironmentProxyRoute(target) {
83471
83470
  };
83472
83471
  }
83473
83472
 
83473
+ // src/engine/runtime/observability/diagnostic-log.ts
83474
+ import { join as join26 } from "node:path";
83475
+
83476
+ // src/engine/storage/logs/bounded-log.ts
83477
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync10, renameSync as renameSync2, statSync as statSync5, writeFileSync as writeFileSync2 } from "node:fs";
83478
+ import { join as join24 } from "node:path";
83479
+ var BoundedLineLog = class {
83480
+ #path;
83481
+ #maximumBytes;
83482
+ #directory;
83483
+ #reportedFailure = false;
83484
+ #onWriteFailure;
83485
+ constructor(directory, filename, maximumBytes, onWriteFailure = () => void 0) {
83486
+ this.#directory = directory;
83487
+ this.#path = join24(directory, filename);
83488
+ this.#maximumBytes = maximumBytes;
83489
+ this.#onWriteFailure = onWriteFailure;
83490
+ }
83491
+ record = (line) => {
83492
+ try {
83493
+ mkdirSync4(this.#directory, { mode: 448, recursive: true });
83494
+ this.#append(line);
83495
+ } catch (cause) {
83496
+ if (!this.#reportedFailure) {
83497
+ this.#reportedFailure = true;
83498
+ this.#onWriteFailure(cause);
83499
+ }
83500
+ }
83501
+ };
83502
+ #append = (line) => {
83503
+ const encoded = `${line.replace(/[\r\n]+/gu, " ").trim()}
83504
+ `;
83505
+ const encodedBytes = Buffer.byteLength(encoded);
83506
+ let existingBytes = 0;
83507
+ try {
83508
+ existingBytes = statSync5(this.#path).size;
83509
+ } catch (cause) {
83510
+ if (!(cause instanceof Error && Reflect.get(cause, "code") === "ENOENT")) {
83511
+ throw cause;
83512
+ }
83513
+ }
83514
+ if (existingBytes + encodedBytes <= this.#maximumBytes) {
83515
+ appendFileSync2(this.#path, encoded, { encoding: "utf8", mode: 384 });
83516
+ return;
83517
+ }
83518
+ const lines = `${existingBytes === 0 ? "" : readFileSync10(this.#path, "utf8")}${encoded}`.split("\n").filter((candidate) => candidate.length > 0);
83519
+ let totalBytes = lines.reduce((total, candidate) => total + Buffer.byteLength(candidate) + 1, 0);
83520
+ while (totalBytes > this.#maximumBytes && lines.length > 0) {
83521
+ const oldest = lines.shift();
83522
+ if (oldest !== void 0) {
83523
+ totalBytes -= Buffer.byteLength(oldest) + 1;
83524
+ }
83525
+ }
83526
+ const temporaryPath = `${this.#path}.tmp`;
83527
+ writeFileSync2(temporaryPath, lines.length === 0 ? "" : `${lines.join("\n")}
83528
+ `, {
83529
+ encoding: "utf8",
83530
+ mode: 384
83531
+ });
83532
+ renameSync2(temporaryPath, this.#path);
83533
+ };
83534
+ };
83535
+
83536
+ // src/engine/storage/logs/log-files.ts
83537
+ import { readFileSync as readFileSync11 } from "node:fs";
83538
+ import { join as join25 } from "node:path";
83539
+ var DAEMON_LOG_FILENAME = "daemon.log";
83540
+ var WORKER_LIFECYCLE_LOG_FILENAME = "worker-lifecycle.log";
83541
+ function unhandledRejectionLogFilename(role) {
83542
+ return `unhandled-rejections-${role}.log`;
83543
+ }
83544
+ function logDirectory(dataDirectory) {
83545
+ return join25(dataDirectory, "logs");
83546
+ }
83547
+ function processLogPaths(dataDirectory) {
83548
+ return [
83549
+ WORKER_LIFECYCLE_LOG_FILENAME,
83550
+ unhandledRejectionLogFilename("manager"),
83551
+ unhandledRejectionLogFilename("worker")
83552
+ ].map((filename) => join25(logDirectory(dataDirectory), filename));
83553
+ }
83554
+ function readLogText(path7) {
83555
+ try {
83556
+ return readFileSync11(path7, "utf8");
83557
+ } catch {
83558
+ return null;
83559
+ }
83560
+ }
83561
+
83562
+ // src/engine/runtime/observability/diagnostic-log.ts
83563
+ var MAXIMUM_RUNTIME_LOG_BYTES = 1 * 1024 * 1024;
83564
+ var MAXIMUM_ENTRIES = 200;
83565
+ var MAXIMUM_REPORT_BYTES = 6e4;
83566
+ var REMOTE_DIAGNOSTIC_FIELDS = [
83567
+ "agentId",
83568
+ "operation",
83569
+ "runtimeId",
83570
+ "closeCode",
83571
+ "timeoutMilliseconds",
83572
+ "attempt",
83573
+ "elapsedMilliseconds",
83574
+ "stdoutBytes",
83575
+ "stderrBytes",
83576
+ "outputLimitBytes",
83577
+ "probeReason",
83578
+ "proxyRoute",
83579
+ "timestamp",
83580
+ "event",
83581
+ "channelId",
83582
+ "requestId",
83583
+ "commandId",
83584
+ "sessionId",
83585
+ "turnId",
83586
+ "connectionEpoch",
83587
+ "code",
83588
+ "source",
83589
+ "kind",
83590
+ "pid",
83591
+ "version",
83592
+ "exitCode",
83593
+ "signal",
83594
+ "failureName",
83595
+ "failureCode",
83596
+ "failureStatusCode",
83597
+ "cause1Name",
83598
+ "cause1Code",
83599
+ "cause2Name",
83600
+ "cause2Code"
83601
+ ];
83602
+ var FIELD_VALUE_PATTERN = /^[a-zA-Z0-9_.: -]{1,256}$/u;
83603
+ var RuntimeDiagnosticLog = class {
83604
+ #log;
83605
+ #maximumBytes;
83606
+ #sources;
83607
+ constructor(stateDirectory, options = {}) {
83608
+ const maximumBytes = options.maximumBytes ?? MAXIMUM_RUNTIME_LOG_BYTES;
83609
+ const directory = logDirectory(stateDirectory);
83610
+ this.#log = new BoundedLineLog(directory, DAEMON_LOG_FILENAME, maximumBytes);
83611
+ this.#maximumBytes = maximumBytes;
83612
+ const processLogsDirectory = options.processLogsDirectory;
83613
+ this.#sources = [
83614
+ { maximumBytes, path: join26(directory, DAEMON_LOG_FILENAME) },
83615
+ // The process logs a Runtime does not own, but must read to explain its own deaths.
83616
+ ...processLogsDirectory === void 0 ? [] : processLogPaths(processLogsDirectory).map((path7) => ({ maximumBytes: null, path: path7 }))
83617
+ ];
83618
+ }
83619
+ // Export only correlation and failure metadata. Local messages and paths stay local.
83620
+ snapshot = () => {
83621
+ const merged = [];
83622
+ let truncated = false;
83623
+ for (const source of this.#sources) {
83624
+ const collected = this.#read(source);
83625
+ merged.push(...collected.entries);
83626
+ truncated ||= collected.truncated;
83627
+ }
83628
+ merged.sort(compareTimestamp);
83629
+ const entries = merged.slice(-MAXIMUM_ENTRIES);
83630
+ truncated ||= entries.length < merged.length;
83631
+ while (JSON.stringify(entries).length > MAXIMUM_REPORT_BYTES && entries.length > 0) {
83632
+ entries.shift();
83633
+ truncated = true;
83634
+ }
83635
+ return { entries, truncated };
83636
+ };
83637
+ record = (diagnostic) => {
83638
+ this.#log.record(diagnostic);
83639
+ };
83640
+ #read = (source) => {
83641
+ const content = readLogText(source.path);
83642
+ if (content === null) {
83643
+ return { entries: [], truncated: false };
83644
+ }
83645
+ const lines = content.split("\n").filter((line) => line.length > 0);
83646
+ const entries = [];
83647
+ for (const line of lines.slice(-MAXIMUM_ENTRIES)) {
83648
+ const start = line.indexOf("{");
83649
+ if (start < 0) {
83650
+ continue;
83651
+ }
83652
+ let value;
83653
+ try {
83654
+ value = JSON.parse(line.slice(start));
83655
+ } catch {
83656
+ continue;
83657
+ }
83658
+ if (typeof value !== "object" || value === null) {
83659
+ continue;
83660
+ }
83661
+ entries.push(exportedFields(value));
83662
+ }
83663
+ const nearRotation = source.maximumBytes !== null && Buffer.byteLength(content) >= source.maximumBytes - 4096;
83664
+ return { entries, truncated: lines.length > MAXIMUM_ENTRIES || nearRotation };
83665
+ };
83666
+ };
83667
+ function exportedFields(value) {
83668
+ const entry = {};
83669
+ for (const field of REMOTE_DIAGNOSTIC_FIELDS) {
83670
+ const item = Reflect.get(value, field);
83671
+ if (typeof item === "string" && FIELD_VALUE_PATTERN.test(item)) {
83672
+ entry[field] = item;
83673
+ } else if (typeof item === "number" && Number.isFinite(item)) {
83674
+ entry[field] = String(item);
83675
+ }
83676
+ }
83677
+ return entry;
83678
+ }
83679
+ function compareTimestamp(left, right) {
83680
+ const leftAt = left["timestamp"] ?? "";
83681
+ const rightAt = right["timestamp"] ?? "";
83682
+ return leftAt < rightAt ? -1 : leftAt > rightAt ? 1 : 0;
83683
+ }
83684
+
83685
+ // src/engine/runtime/catalog/discover-agent-catalog.ts
83686
+ function failureDetails(failure2) {
83687
+ const fields = {};
83688
+ let current = failure2;
83689
+ for (let depth = 0; depth < 3 && current instanceof Error; depth += 1) {
83690
+ const prefix = depth === 0 ? "failure" : `cause${depth.toString()}`;
83691
+ if (current instanceof ProcessExecutionError || current instanceof AgentProbeError) {
83692
+ fields[`${prefix}Name`] = current instanceof ProcessExecutionError ? "ProcessExecutionError" : "AgentProbeError";
83693
+ fields[`${prefix}Code`] = current.code;
83694
+ } else {
83695
+ fields[`${prefix}Name`] = "Error";
83696
+ }
83697
+ if (depth === 0 && current instanceof ProcessExecutionError) {
83698
+ Object.assign(fields, current.diagnosticDetails);
83699
+ }
83700
+ current = current.cause;
83701
+ }
83702
+ return fields;
83703
+ }
83704
+ async function discoverRuntimeAgentInventory(options, channelId) {
83705
+ const log = new RuntimeDiagnosticLog(options.dataDirectory);
83706
+ const record2 = (details) => {
83707
+ log.record(
83708
+ `Mobius agent discovery diagnostic ${JSON.stringify({
83709
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
83710
+ channelId,
83711
+ ...details
83712
+ })}`
83713
+ );
83714
+ };
83715
+ const inventory = await discoverLocalAgentInventory({
83716
+ ...options,
83717
+ onProbeDiagnostic: ({ failure: failure2, ...diagnostic }) => {
83718
+ record2({ ...diagnostic, ...failureDetails(failure2) });
83719
+ }
83720
+ });
83721
+ for (const { discovery, detectionMilliseconds } of inventory.results) {
83722
+ record2({
83723
+ event: "agent_discovery_result",
83724
+ agentId: discovery.specification.id,
83725
+ code: discovery instanceof UnavailableAgent ? discovery.code : "ready",
83726
+ source: discovery.status,
83727
+ elapsedMilliseconds: detectionMilliseconds
83728
+ });
83729
+ }
83730
+ return inventory;
83731
+ }
83732
+
83474
83733
  // src/engine/runtime/catalog/publish-agent-catalog.ts
83475
83734
  import { fetch as fetch2 } from "undici";
83476
83735
 
@@ -83917,21 +84176,27 @@ function buildSavedRuntimeConfig(connection, defaultWorkspace, inventory, localC
83917
84176
  localContext,
83918
84177
  new OpaqueRuntimeReconnectTarget(connection.connectionId),
83919
84178
  createCatalogAgentResolver(
83920
- (refreshSignal) => discoverLocalAgentInventory({
84179
+ (refreshSignal) => discoverRuntimeAgentInventory(
84180
+ {
84181
+ defaultWorkspace,
84182
+ dataDirectory: localContext.stateDirectory,
84183
+ environment: localContext.agentLaunchEnvironment,
84184
+ signal: refreshSignal
84185
+ },
84186
+ connection.channelId
84187
+ ),
84188
+ () => config2,
84189
+ publishAgentCatalog
84190
+ ),
84191
+ (refreshSignal) => discoverRuntimeAgentInventory(
84192
+ {
83921
84193
  defaultWorkspace,
83922
84194
  dataDirectory: localContext.stateDirectory,
83923
84195
  environment: localContext.agentLaunchEnvironment,
83924
84196
  signal: refreshSignal
83925
- }),
83926
- () => config2,
83927
- publishAgentCatalog
83928
- ),
83929
- (refreshSignal) => discoverLocalAgentInventory({
83930
- defaultWorkspace,
83931
- dataDirectory: localContext.stateDirectory,
83932
- environment: localContext.agentLaunchEnvironment,
83933
- signal: refreshSignal
83934
- }).then((inventory2) => inventory2.readyAgents())
84197
+ },
84198
+ connection.channelId
84199
+ ).then((inventory2) => inventory2.readyAgents())
83935
84200
  );
83936
84201
  return config2;
83937
84202
  }
@@ -83975,12 +84240,15 @@ async function pairRuntimeConnection(installation, options, signal, environment)
83975
84240
  async function prepareRuntimeConnection(installation, connection, signal, environment, maxAcpProcesses) {
83976
84241
  const localContext = new RuntimeLocalContext(installation.stateDirectory, environment, maxAcpProcesses);
83977
84242
  const defaultWorkspace = await resolveDefaultWorkspace(connection.defaultWorkspace);
83978
- const inventory = await discoverLocalAgentInventory({
83979
- defaultWorkspace,
83980
- dataDirectory: localContext.stateDirectory,
83981
- environment: localContext.agentLaunchEnvironment,
83982
- signal
83983
- });
84243
+ const inventory = await discoverRuntimeAgentInventory(
84244
+ {
84245
+ defaultWorkspace,
84246
+ dataDirectory: localContext.stateDirectory,
84247
+ environment: localContext.agentLaunchEnvironment,
84248
+ signal
84249
+ },
84250
+ connection.channelId
84251
+ );
83984
84252
  return buildSavedRuntimeConfig(connection, defaultWorkspace, inventory, localContext);
83985
84253
  }
83986
84254
 
@@ -84926,7 +85194,7 @@ var SessionConfigurations = class {
84926
85194
  restore = async (stored, options, apply, signal) => {
84927
85195
  this.#selected = stored;
84928
85196
  for (const selection of this.#selected) {
84929
- const current = options.find(
85197
+ const current = options().find(
84930
85198
  (option) => option.id === selection.configId && option.type === selection.type
84931
85199
  );
84932
85200
  if (current === void 0) {
@@ -85118,6 +85386,7 @@ async function restoreSession(session, signal, recovery, origin) {
85118
85386
  session.store.remove(session.sessionId);
85119
85387
  stored = session.metrics.measureSync("session-state-read", () => session.store.read(session.sessionId));
85120
85388
  }
85389
+ const forkSource = origin?.kind === "fork" ? session.store.findNative(session.agentId, origin.nativeSessionId)[0] : void 0;
85121
85390
  let lifecycleResponse;
85122
85391
  if (origin?.kind === "fork") {
85123
85392
  if (!session.capabilities.unstableForkSession) {
@@ -85279,7 +85548,9 @@ async function restoreSession(session, signal, recovery, origin) {
85279
85548
  }
85280
85549
  session.restrictSessionCapabilities(lifecycleResponse);
85281
85550
  session.setConfigOptions(session.sessionConfigProtocol.normalizeLifecycle(lifecycleResponse));
85282
- if (stored instanceof FoundStoredSession && session.restored) {
85551
+ if (forkSource !== void 0) {
85552
+ await session.restoreStoredConfigurations(forkSource, signal, "fork");
85553
+ } else if (stored instanceof FoundStoredSession && session.restored) {
85283
85554
  await session.restoreStoredConfigurations(stored.session, signal);
85284
85555
  }
85285
85556
  await session.drained();
@@ -85491,13 +85762,31 @@ var AgentSession = class _AgentSession {
85491
85762
  this.writeStoredSession((/* @__PURE__ */ new Date()).toISOString());
85492
85763
  }
85493
85764
  };
85494
- restoreStoredConfigurations = async (session, signal) => {
85765
+ restoreStoredConfigurations = async (session, signal, intent = "restore") => {
85766
+ const configurations = intent === "fork" ? session.configurations.toSorted(
85767
+ (left, right) => Number(right.configId === "model") - Number(left.configId === "model")
85768
+ ) : session.configurations;
85495
85769
  await this.#sessionConfigurations.restore(
85496
- session.configurations,
85497
- this.#configOptions,
85770
+ configurations,
85771
+ () => this.#configOptions,
85498
85772
  this.#applyConfiguration,
85499
85773
  signal
85500
85774
  );
85775
+ if (intent === "fork") {
85776
+ for (const selection of session.configurations) {
85777
+ if (selection.configId !== "mode") {
85778
+ continue;
85779
+ }
85780
+ const current = this.#configOptions.find((option) => option.id === selection.configId);
85781
+ if (current?.type !== selection.type || (selection.type === "select" ? current.currentValue !== selection.value : current.booleanValue !== selection.booleanValue)) {
85782
+ throw new AcpExecutionError(
85783
+ "The Agent could not preserve the source Session mode for this Fork",
85784
+ {},
85785
+ "invalid_session_configuration"
85786
+ );
85787
+ }
85788
+ }
85789
+ }
85501
85790
  };
85502
85791
  restrictSessionCapabilities = (response) => {
85503
85792
  this.#capabilities = restrictAcpSessionCapabilities(this.#capabilities, response);
@@ -86938,7 +87227,8 @@ var NativeSessionService = class {
86938
87227
  requestId: command.requestId,
86939
87228
  sessionId: command.sessionId,
86940
87229
  targetSessionId: command.targetSessionId,
86941
- ...await this.#activeTurn(command, options)
87230
+ ...await this.#activeTurn(command, options),
87231
+ queuedCancellation: "before-start"
86942
87232
  };
86943
87233
  }
86944
87234
  const capabilities = await options.adapter.getCapabilities(options);
@@ -87548,6 +87838,11 @@ var ExecutionReceipts = class {
87548
87838
  return void 0;
87549
87839
  }
87550
87840
  };
87841
+ /** Started identities remain authoritative after their detailed receipt is evicted. */
87842
+ hasStarted = (commandId, sessionId) => {
87843
+ const receipt = this.#executions.get(commandId);
87844
+ return receipt === void 0 ? this.#table.identity(commandId)?.sessionId === sessionId : receipt.sessionId === sessionId && receipt.started;
87845
+ };
87551
87846
  /** Reserves an unseen command for cancellation before a delayed prompt can claim its identity. */
87552
87847
  recordCancellationBeforeAdmission = (commandId, sessionId) => {
87553
87848
  const existing = this.#executions.get(commandId);
@@ -88069,7 +88364,7 @@ var SessionTurns = class {
88069
88364
 
88070
88365
  // src/engine/session/workspace/workspace-directory.ts
88071
88366
  import { homedir as homedir3 } from "node:os";
88072
- import { basename as basename7, dirname as dirname10, isAbsolute as isAbsolute15, join as join24, normalize as normalize2, relative as relative2 } from "node:path";
88367
+ import { basename as basename7, dirname as dirname10, isAbsolute as isAbsolute15, join as join27, normalize as normalize2, relative as relative2 } from "node:path";
88073
88368
  var WorkspaceDirectoryListing = class {
88074
88369
  directoryId;
88075
88370
  directoryLabel;
@@ -88192,7 +88487,7 @@ var WorkspaceDirectoryService = class {
88192
88487
  continue;
88193
88488
  }
88194
88489
  try {
88195
- const path7 = await this.resolvePath(join24(target, child.name), signal);
88490
+ const path7 = await this.resolvePath(join27(target, child.name), signal);
88196
88491
  entries.push({ directoryId: encodePath(path7), name: child.name });
88197
88492
  } catch (cause) {
88198
88493
  signal.throwIfAborted();
@@ -88348,12 +88643,12 @@ function buildSessionLayer(options) {
88348
88643
 
88349
88644
  // src/engine/session/content/external-content-store.ts
88350
88645
  import { createHash as createHash8 } from "node:crypto";
88351
- import { extname as extname3, join as join26 } from "node:path";
88646
+ import { extname as extname2, join as join29 } from "node:path";
88352
88647
 
88353
88648
  // src/engine/storage/files/scratch-directory.ts
88354
88649
  import { randomUUID as randomUUID17 } from "node:crypto";
88355
88650
  import { lstat as lstat4, mkdir as mkdir5, readdir as readdir6, readFile as readFile6, realpath as realpath7, rename as rename4, rm as rm3, stat as stat6, utimes, writeFile as writeFile2 } from "node:fs/promises";
88356
- import { dirname as dirname11, join as join25 } from "node:path";
88651
+ import { dirname as dirname11, join as join28 } from "node:path";
88357
88652
  async function atomicWrite(path7, bytes, signal) {
88358
88653
  const temporary = `${path7}.${randomUUID17()}.tmp`;
88359
88654
  try {
@@ -88367,7 +88662,7 @@ async function atomicWrite(path7, bytes, signal) {
88367
88662
  var ScratchDirectory = class {
88368
88663
  #root;
88369
88664
  constructor(parent) {
88370
- this.#root = join25(parent, randomUUID17());
88665
+ this.#root = join28(parent, randomUUID17());
88371
88666
  }
88372
88667
  /** Refreshes this directory's lease and removes sibling directories whose lease is older than `leaseMilliseconds`. */
88373
88668
  refreshLease = async (leaseMilliseconds) => {
@@ -88378,7 +88673,7 @@ var ScratchDirectory = class {
88378
88673
  if (!directory.isDirectory() || !/^[a-f0-9-]{36}$/u.test(directory.name)) {
88379
88674
  continue;
88380
88675
  }
88381
- const path7 = join25(dirname11(this.#root), directory.name);
88676
+ const path7 = join28(dirname11(this.#root), directory.name);
88382
88677
  if (path7 === this.#root) {
88383
88678
  continue;
88384
88679
  }
@@ -88393,10 +88688,10 @@ var ScratchDirectory = class {
88393
88688
  };
88394
88689
  /** Writes `bytes` atomically to `<group>/<name>` with owner-only permissions and returns the path. */
88395
88690
  write = async (group, name2, bytes, signal) => {
88396
- const directory = join25(this.#root, group);
88691
+ const directory = join28(this.#root, group);
88397
88692
  await mkdir5(directory, { mode: 448, recursive: true });
88398
88693
  signal.throwIfAborted();
88399
- const path7 = join25(directory, name2);
88694
+ const path7 = join28(directory, name2);
88400
88695
  await atomicWrite(path7, bytes, signal);
88401
88696
  return path7;
88402
88697
  };
@@ -88436,7 +88731,7 @@ var metadataSchema = external_exports.strictObject({
88436
88731
  name: external_exports.string().min(1).max(500)
88437
88732
  });
88438
88733
  function contentFileName(key, name2) {
88439
- const extension = extname3(name2).toLowerCase();
88734
+ const extension = extname2(name2).toLowerCase();
88440
88735
  return /^\.[a-z0-9]{1,16}$/u.test(extension) ? `${key}${extension}` : key;
88441
88736
  }
88442
88737
  var LocalExternalContentStore = class {
@@ -88447,7 +88742,7 @@ var LocalExternalContentStore = class {
88447
88742
  #expirationTimer;
88448
88743
  #cleanup = Promise.resolve();
88449
88744
  constructor(stateDirectory) {
88450
- this.#scratch = new ScratchDirectory(join26(stateDirectory, "tmp", "session-content"));
88745
+ this.#scratch = new ScratchDirectory(join29(stateDirectory, "tmp", "session-content"));
88451
88746
  this.#expirationTimer = setInterval(() => {
88452
88747
  void this.#expire().catch(() => void 0);
88453
88748
  }, 6e4);
@@ -88821,212 +89116,6 @@ var AgentProcessPool = class {
88821
89116
  };
88822
89117
  };
88823
89118
 
88824
- // src/engine/runtime/observability/diagnostic-log.ts
88825
- import { join as join29 } from "node:path";
88826
-
88827
- // src/engine/storage/logs/bounded-log.ts
88828
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync9, renameSync as renameSync2, statSync as statSync5, writeFileSync as writeFileSync2 } from "node:fs";
88829
- import { join as join27 } from "node:path";
88830
- var BoundedLineLog = class {
88831
- #path;
88832
- #maximumBytes;
88833
- #directory;
88834
- #reportedFailure = false;
88835
- #onWriteFailure;
88836
- constructor(directory, filename, maximumBytes, onWriteFailure = () => void 0) {
88837
- this.#directory = directory;
88838
- this.#path = join27(directory, filename);
88839
- this.#maximumBytes = maximumBytes;
88840
- this.#onWriteFailure = onWriteFailure;
88841
- }
88842
- record = (line) => {
88843
- try {
88844
- mkdirSync4(this.#directory, { mode: 448, recursive: true });
88845
- this.#append(line);
88846
- } catch (cause) {
88847
- if (!this.#reportedFailure) {
88848
- this.#reportedFailure = true;
88849
- this.#onWriteFailure(cause);
88850
- }
88851
- }
88852
- };
88853
- #append = (line) => {
88854
- const encoded = `${line.replace(/[\r\n]+/gu, " ").trim()}
88855
- `;
88856
- const encodedBytes = Buffer.byteLength(encoded);
88857
- let existingBytes = 0;
88858
- try {
88859
- existingBytes = statSync5(this.#path).size;
88860
- } catch (cause) {
88861
- if (!(cause instanceof Error && Reflect.get(cause, "code") === "ENOENT")) {
88862
- throw cause;
88863
- }
88864
- }
88865
- if (existingBytes + encodedBytes <= this.#maximumBytes) {
88866
- appendFileSync2(this.#path, encoded, { encoding: "utf8", mode: 384 });
88867
- return;
88868
- }
88869
- const lines = `${existingBytes === 0 ? "" : readFileSync9(this.#path, "utf8")}${encoded}`.split("\n").filter((candidate) => candidate.length > 0);
88870
- let totalBytes = lines.reduce((total, candidate) => total + Buffer.byteLength(candidate) + 1, 0);
88871
- while (totalBytes > this.#maximumBytes && lines.length > 0) {
88872
- const oldest = lines.shift();
88873
- if (oldest !== void 0) {
88874
- totalBytes -= Buffer.byteLength(oldest) + 1;
88875
- }
88876
- }
88877
- const temporaryPath = `${this.#path}.tmp`;
88878
- writeFileSync2(temporaryPath, lines.length === 0 ? "" : `${lines.join("\n")}
88879
- `, {
88880
- encoding: "utf8",
88881
- mode: 384
88882
- });
88883
- renameSync2(temporaryPath, this.#path);
88884
- };
88885
- };
88886
-
88887
- // src/engine/storage/logs/log-files.ts
88888
- import { readFileSync as readFileSync10 } from "node:fs";
88889
- import { join as join28 } from "node:path";
88890
- var DAEMON_LOG_FILENAME = "daemon.log";
88891
- var WORKER_LIFECYCLE_LOG_FILENAME = "worker-lifecycle.log";
88892
- function unhandledRejectionLogFilename(role) {
88893
- return `unhandled-rejections-${role}.log`;
88894
- }
88895
- function logDirectory(dataDirectory) {
88896
- return join28(dataDirectory, "logs");
88897
- }
88898
- function processLogPaths(dataDirectory) {
88899
- return [
88900
- WORKER_LIFECYCLE_LOG_FILENAME,
88901
- unhandledRejectionLogFilename("manager"),
88902
- unhandledRejectionLogFilename("worker")
88903
- ].map((filename) => join28(logDirectory(dataDirectory), filename));
88904
- }
88905
- function readLogText(path7) {
88906
- try {
88907
- return readFileSync10(path7, "utf8");
88908
- } catch {
88909
- return null;
88910
- }
88911
- }
88912
-
88913
- // src/engine/runtime/observability/diagnostic-log.ts
88914
- var MAXIMUM_RUNTIME_LOG_BYTES = 1 * 1024 * 1024;
88915
- var MAXIMUM_ENTRIES = 200;
88916
- var MAXIMUM_REPORT_BYTES = 6e4;
88917
- var REMOTE_DIAGNOSTIC_FIELDS = [
88918
- "agentId",
88919
- "operation",
88920
- "runtimeId",
88921
- "closeCode",
88922
- "timeoutMilliseconds",
88923
- "proxyRoute",
88924
- "timestamp",
88925
- "event",
88926
- "channelId",
88927
- "requestId",
88928
- "commandId",
88929
- "sessionId",
88930
- "turnId",
88931
- "connectionEpoch",
88932
- "code",
88933
- "source",
88934
- "kind",
88935
- "pid",
88936
- "version",
88937
- "exitCode",
88938
- "signal",
88939
- "failureName",
88940
- "failureCode",
88941
- "failureStatusCode",
88942
- "cause1Name",
88943
- "cause1Code",
88944
- "cause2Name",
88945
- "cause2Code"
88946
- ];
88947
- var FIELD_VALUE_PATTERN = /^[a-zA-Z0-9_.: -]{1,256}$/u;
88948
- var RuntimeDiagnosticLog = class {
88949
- #log;
88950
- #maximumBytes;
88951
- #sources;
88952
- constructor(stateDirectory, options = {}) {
88953
- const maximumBytes = options.maximumBytes ?? MAXIMUM_RUNTIME_LOG_BYTES;
88954
- const directory = logDirectory(stateDirectory);
88955
- this.#log = new BoundedLineLog(directory, DAEMON_LOG_FILENAME, maximumBytes);
88956
- this.#maximumBytes = maximumBytes;
88957
- const processLogsDirectory = options.processLogsDirectory;
88958
- this.#sources = [
88959
- { maximumBytes, path: join29(directory, DAEMON_LOG_FILENAME) },
88960
- // The process logs a Runtime does not own, but must read to explain its own deaths.
88961
- ...processLogsDirectory === void 0 ? [] : processLogPaths(processLogsDirectory).map((path7) => ({ maximumBytes: null, path: path7 }))
88962
- ];
88963
- }
88964
- // Export only correlation and failure metadata. Local messages and paths stay local.
88965
- snapshot = () => {
88966
- const merged = [];
88967
- let truncated = false;
88968
- for (const source of this.#sources) {
88969
- const collected = this.#read(source);
88970
- merged.push(...collected.entries);
88971
- truncated ||= collected.truncated;
88972
- }
88973
- merged.sort(compareTimestamp);
88974
- const entries = merged.slice(-MAXIMUM_ENTRIES);
88975
- truncated ||= entries.length < merged.length;
88976
- while (JSON.stringify(entries).length > MAXIMUM_REPORT_BYTES && entries.length > 0) {
88977
- entries.shift();
88978
- truncated = true;
88979
- }
88980
- return { entries, truncated };
88981
- };
88982
- record = (diagnostic) => {
88983
- this.#log.record(diagnostic);
88984
- };
88985
- #read = (source) => {
88986
- const content = readLogText(source.path);
88987
- if (content === null) {
88988
- return { entries: [], truncated: false };
88989
- }
88990
- const lines = content.split("\n").filter((line) => line.length > 0);
88991
- const entries = [];
88992
- for (const line of lines.slice(-MAXIMUM_ENTRIES)) {
88993
- const start = line.indexOf("{");
88994
- if (start < 0) {
88995
- continue;
88996
- }
88997
- let value;
88998
- try {
88999
- value = JSON.parse(line.slice(start));
89000
- } catch {
89001
- continue;
89002
- }
89003
- if (typeof value !== "object" || value === null) {
89004
- continue;
89005
- }
89006
- entries.push(exportedFields(value));
89007
- }
89008
- const nearRotation = source.maximumBytes !== null && Buffer.byteLength(content) >= source.maximumBytes - 4096;
89009
- return { entries, truncated: lines.length > MAXIMUM_ENTRIES || nearRotation };
89010
- };
89011
- };
89012
- function exportedFields(value) {
89013
- const entry = {};
89014
- for (const field of REMOTE_DIAGNOSTIC_FIELDS) {
89015
- const item = Reflect.get(value, field);
89016
- if (typeof item === "string" && FIELD_VALUE_PATTERN.test(item)) {
89017
- entry[field] = item;
89018
- } else if (typeof item === "number" && Number.isFinite(item)) {
89019
- entry[field] = String(item);
89020
- }
89021
- }
89022
- return entry;
89023
- }
89024
- function compareTimestamp(left, right) {
89025
- const leftAt = left["timestamp"] ?? "";
89026
- const rightAt = right["timestamp"] ?? "";
89027
- return leftAt < rightAt ? -1 : leftAt > rightAt ? 1 : 0;
89028
- }
89029
-
89030
89119
  // src/engine/runtime/relay/diagnostics.ts
89031
89120
  var MAX_DIAGNOSTIC_TEXT_LENGTH = 256;
89032
89121
  function sanitizeDiagnosticText(value) {
@@ -89951,7 +90040,7 @@ function createContentWriteCommands(context) {
89951
90040
  import { WebSocket as WebSocket5 } from "undici";
89952
90041
 
89953
90042
  // src/engine/session/content/session-files.ts
89954
- import { basename as basename8, extname as extname4, isAbsolute as isAbsolute16, join as join30, normalize as normalize3, resolve as resolve16 } from "node:path";
90043
+ import { basename as basename8, extname as extname3, isAbsolute as isAbsolute16, join as join30, normalize as normalize3, resolve as resolve16 } from "node:path";
89955
90044
  import { fileURLToPath as fileURLToPath2 } from "node:url";
89956
90045
  function requestedPath(value) {
89957
90046
  if (value.includes("\0")) {
@@ -90007,7 +90096,7 @@ async function streamLocalFile(command, send2, sendChunk, signal, workingDirecto
90007
90096
  send2({
90008
90097
  byteLength: before.size,
90009
90098
  kind: FILE_BEGIN_KIND,
90010
- mediaType: external?.mediaType ?? raster?.mimeType ?? (extname4(target).toLowerCase() === ".svg" ? "image/svg+xml" : "application/octet-stream"),
90099
+ mediaType: external?.mediaType ?? raster?.mimeType ?? (extname3(target).toLowerCase() === ".svg" ? "image/svg+xml" : "application/octet-stream"),
90011
90100
  modifiedAt: before.modifiedAt.toISOString(),
90012
90101
  name: external?.name ?? (basename8(target) || "file"),
90013
90102
  requestId: command.requestId,
@@ -90312,10 +90401,19 @@ var sessionCancelBeforeStartCommand = {
90312
90401
  if (message.kind !== SESSION_CANCEL_BEFORE_START_KIND) {
90313
90402
  throw new Error("Command kind mismatch");
90314
90403
  }
90404
+ if (operations.hasStarted(message.commandId, message.sessionId)) {
90405
+ reportOperationFailure(
90406
+ socket,
90407
+ message.commandId,
90408
+ message.sessionId,
90409
+ new SessionError("turn_already_started", "The message already started and could not be withdrawn")
90410
+ );
90411
+ return;
90412
+ }
90315
90413
  const turn = sessionTurns.get(message.commandId, message.sessionId);
90316
90414
  if (turn === void 0) {
90317
90415
  const outcome = operations.recordCancellationBeforeAdmission(message.commandId, message.sessionId);
90318
- if (outcome !== void 0) {
90416
+ if (outcome?.type === "lifecycle-metadata" && outcome.payload.kind === "prompt.completed" && outcome.payload.stopReason === "cancelled") {
90319
90417
  void eventProjection.replayOutcome(message.sessionId, outcome).catch((error62) => {
90320
90418
  reportOperationFailure(socket, message.commandId, message.sessionId, error62);
90321
90419
  });
@@ -90787,6 +90885,7 @@ async function executePrompt({
90787
90885
  );
90788
90886
  prepared = await sessions.prepareExecutionSession(preparation);
90789
90887
  }
90888
+ signal.throwIfAborted();
90790
90889
  operations.markExecutionStarted(command.commandId);
90791
90890
  if (availability.disposition === SessionPromptDisposition.Steer) {
90792
90891
  if (!recordSteeringPrompt()) {
@@ -90969,7 +91068,7 @@ var sessionPromptCommand = {
90969
91068
  // package.json
90970
91069
  var package_default = {
90971
91070
  name: "@moxt-ai/mobius",
90972
- version: "0.0.354",
91071
+ version: "0.0.356",
90973
91072
  description: "Mobius CLI for pairing and running local AI agent services.",
90974
91073
  type: "module",
90975
91074
  bin: {
@@ -92426,13 +92525,16 @@ async function prepareProvidedRuntime({
92426
92525
  const defaultWorkspace = await resolveWorkspace(connection.defaultWorkspace);
92427
92526
  const specifications = supportedLocalAgentSpecifications();
92428
92527
  const discoveryEnvironment = localContext.agentLaunchEnvironment;
92429
- const discover = async (refreshSignal) => await discoverLocalAgentInventory({
92430
- defaultWorkspace,
92431
- dataDirectory: localContext.stateDirectory,
92432
- environment: discoveryEnvironment,
92433
- signal: refreshSignal,
92434
- specifications
92435
- });
92528
+ const discover = async (refreshSignal) => await discoverRuntimeAgentInventory(
92529
+ {
92530
+ defaultWorkspace,
92531
+ dataDirectory: localContext.stateDirectory,
92532
+ environment: discoveryEnvironment,
92533
+ signal: refreshSignal,
92534
+ specifications
92535
+ },
92536
+ connection.channelId
92537
+ );
92436
92538
  const inventory = await discover(signal);
92437
92539
  const config2 = createRuntimeConfig(
92438
92540
  {