@moxt-ai/mobius 0.0.361 → 0.0.363

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 (39) hide show
  1. package/dist/{chunk-HXDMU5LX.js → chunk-DPKJ73U5.js} +2 -2
  2. package/dist/{chunk-HXDMU5LX.js.map → chunk-DPKJ73U5.js.map} +1 -1
  3. package/dist/{chunk-WQKXKY2U.js → chunk-DXA4UBI6.js} +296 -39
  4. package/dist/{chunk-WQKXKY2U.js.map → chunk-DXA4UBI6.js.map} +4 -4
  5. package/dist/{chunk-KSR6DYGI.js → chunk-ZW36FH6L.js} +2 -2
  6. package/dist/{cli-T5HY4JMT.js → cli-VFDSSFNB.js} +4 -4
  7. package/dist/cli.js +3 -3
  8. package/dist/engine/acp/adapter/claude/adapter.d.ts +1 -0
  9. package/dist/engine/acp/adapter/claude/adapter.d.ts.map +1 -1
  10. package/dist/engine/acp/adapter/claude/adapter.js +1 -0
  11. package/dist/engine/acp/adapter/claude/adapter.js.map +1 -1
  12. package/dist/engine/acp/adapter/codex/adapter.d.ts +1 -0
  13. package/dist/engine/acp/adapter/codex/adapter.d.ts.map +1 -1
  14. package/dist/engine/acp/adapter/codex/adapter.js +5 -0
  15. package/dist/engine/acp/adapter/codex/adapter.js.map +1 -1
  16. package/dist/engine/acp/adapter/execution-connections.d.ts +2 -0
  17. package/dist/engine/acp/adapter/execution-connections.d.ts.map +1 -1
  18. package/dist/engine/acp/adapter/execution-connections.js +25 -1
  19. package/dist/engine/acp/adapter/execution-connections.js.map +1 -1
  20. package/dist/engine/acp/adapter/pi/adapter.d.ts +1 -0
  21. package/dist/engine/acp/adapter/pi/adapter.d.ts.map +1 -1
  22. package/dist/engine/acp/adapter/pi/adapter.js +1 -0
  23. package/dist/engine/acp/adapter/pi/adapter.js.map +1 -1
  24. package/dist/engine/acp/harness/pi/endpoint.d.ts.map +1 -1
  25. package/dist/engine/acp/harness/pi/endpoint.js +1 -0
  26. package/dist/engine/acp/harness/pi/endpoint.js.map +1 -1
  27. package/dist/engine/acp/native-history/preview-contract.d.ts +13 -0
  28. package/dist/engine/acp/native-history/preview-contract.d.ts.map +1 -1
  29. package/dist/engine/session/live/agent-session.d.ts +6 -0
  30. package/dist/engine/session/live/agent-session.d.ts.map +1 -1
  31. package/dist/engine/session/live/agent-session.js +99 -6
  32. package/dist/engine/session/live/agent-session.js.map +1 -1
  33. package/dist/engine/session/manager/session-manager.d.ts.map +1 -1
  34. package/dist/engine/session/manager/session-manager.js +42 -10
  35. package/dist/engine/session/manager/session-manager.js.map +1 -1
  36. package/dist/engine.js +2 -2
  37. package/package.json +1 -1
  38. /package/dist/{chunk-KSR6DYGI.js.map → chunk-ZW36FH6L.js.map} +0 -0
  39. /package/dist/{cli-T5HY4JMT.js.map → cli-VFDSSFNB.js.map} +0 -0
@@ -3,7 +3,7 @@ import {
3
3
  __export,
4
4
  __using,
5
5
  package_default
6
- } from "./chunk-HXDMU5LX.js";
6
+ } from "./chunk-DPKJ73U5.js";
7
7
 
8
8
  // src/engine/runtime/relay/runtime-revocation.ts
9
9
  var runtimeRevocationCloseCode = 1008;
@@ -59921,6 +59921,15 @@ async function readFullHistory(transcript, sessionId, signal) {
59921
59921
  return await append(await project([...transcript])) ? result : null;
59922
59922
  }
59923
59923
 
59924
+ // src/engine/acp/harness/claude/upstream/dist/environment-session-revision.js
59925
+ var SESSION_REVISION_TIMEOUT_MILLISECONDS = 3e4;
59926
+ function getEnvironmentSessionRevision(environment, sessionId, cwd, ownMessageIds, signal) {
59927
+ return withEnvironment(environment, () => withDeadline(signal, SESSION_REVISION_TIMEOUT_MILLISECONDS, async () => {
59928
+ const messages = await FZt(sessionId, { dir: cwd });
59929
+ return messages.findLast((message) => !ownMessageIds.has(message.uuid))?.uuid ?? "";
59930
+ }));
59931
+ }
59932
+
59924
59933
  // src/engine/acp/harness/claude/upstream/dist/session-config-ids.js
59925
59934
  var DEFAULT_MODEL_ID = "default";
59926
59935
  var DEFAULT_AGENT_ID = "default";
@@ -62603,6 +62612,17 @@ function parseRenameRequest(params) {
62603
62612
  }
62604
62613
  return { sessionId, title: title2 };
62605
62614
  }
62615
+ var REVISION_METHOD = "_session/revision";
62616
+ function parseRevisionRequest(params) {
62617
+ if (!params || typeof params !== "object") {
62618
+ throw RequestError5.invalidParams(void 0, "revision params must be an object");
62619
+ }
62620
+ const { sessionId } = params;
62621
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
62622
+ throw RequestError5.invalidParams(void 0, "revision params require a non-empty sessionId");
62623
+ }
62624
+ return { sessionId };
62625
+ }
62606
62626
  var AUTONOMOUS_RESULT_ORIGINS = /* @__PURE__ */ new Set([
62607
62627
  "task-notification",
62608
62628
  "peer",
@@ -63222,6 +63242,10 @@ var ClaudeAcpAgent = class {
63222
63242
  return result;
63223
63243
  }
63224
63244
  async listSessions(params, signal) {
63245
+ const offset = params.cursor == null ? 0 : Number(params.cursor);
63246
+ if (!Number.isSafeInteger(offset) || offset < 0) {
63247
+ throw RequestError5.invalidParams("Invalid native session cursor");
63248
+ }
63225
63249
  const sdk_sessions = await listEnvironmentSessions(this.environment, params.cwd ?? void 0, signal);
63226
63250
  const sessions = [];
63227
63251
  for (const session of sdk_sessions) {
@@ -63235,8 +63259,12 @@ var ClaudeAcpAgent = class {
63235
63259
  updatedAt: new Date(session.lastModified).toISOString()
63236
63260
  });
63237
63261
  }
63262
+ sessions.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt) || left.sessionId.localeCompare(right.sessionId));
63263
+ const pageSize = 500;
63264
+ const end = offset + pageSize;
63238
63265
  return {
63239
- sessions
63266
+ sessions: sessions.slice(offset, end),
63267
+ ...end < sessions.length ? { nextCursor: String(end) } : {}
63240
63268
  };
63241
63269
  }
63242
63270
  async authenticate(_params) {
@@ -63421,6 +63449,7 @@ var ClaudeAcpAgent = class {
63421
63449
  });
63422
63450
  session.turnQueue ??= [];
63423
63451
  session.turnQueue.push(turn);
63452
+ session.streamedMessageIds.add(promptUuid);
63424
63453
  session.input.push(userMessage);
63425
63454
  this.ensureConsumer(session, params.sessionId);
63426
63455
  onSubmitted();
@@ -63557,6 +63586,7 @@ var ClaudeAcpAgent = class {
63557
63586
  turnInFlight.steeredSettle = turnInFlight.deferredSettle;
63558
63587
  turnInFlight.deferredSettle = void 0;
63559
63588
  }
63589
+ session.streamedMessageIds.add(steeredUuid);
63560
63590
  session.input.push(userMessage);
63561
63591
  const firstText = params.prompt[0]?.type === "text" ? params.prompt[0].text : "";
63562
63592
  for (const content of params.prompt) {
@@ -63871,6 +63901,9 @@ var ClaudeAcpAgent = class {
63871
63901
  this.closeQueryStream(session);
63872
63902
  return;
63873
63903
  }
63904
+ if ("uuid" in message && typeof message.uuid === "string") {
63905
+ session.streamedMessageIds.add(message.uuid);
63906
+ }
63874
63907
  if (session.emitRawSDKMessages && shouldEmitRawMessage(session.emitRawSDKMessages, message)) {
63875
63908
  await this.client.extNotification("_claude/sdkMessage", {
63876
63909
  sessionId: params.sessionId,
@@ -64992,6 +65025,15 @@ ${message.api_refusal_explanation}` : "";
64992
65025
  await jZt(params.sessionId, sanitizeTitle(params.title), { dir: session.cwd });
64993
65026
  return {};
64994
65027
  }
65028
+ async readSessionRevision(params, signal) {
65029
+ const session = this.sessions[params.sessionId];
65030
+ if (!session) {
65031
+ throw new Error("Session not found");
65032
+ }
65033
+ return {
65034
+ latestEntryId: await getEnvironmentSessionRevision(this.environment, params.sessionId, session.cwd, session.streamedMessageIds, signal)
65035
+ };
65036
+ }
64995
65037
  async setSessionMode(params) {
64996
65038
  return this.sessionModes.setSessionMode(params);
64997
65039
  }
@@ -65903,6 +65945,7 @@ ${message.api_refusal_explanation}` : "";
65903
65945
  query: q2,
65904
65946
  input: input2,
65905
65947
  cancelled: false,
65948
+ streamedMessageIds: /* @__PURE__ */ new Set(),
65906
65949
  cwd: params.cwd,
65907
65950
  sessionFingerprint: computeSessionFingerprint(params),
65908
65951
  creationParams: params,
@@ -67168,7 +67211,7 @@ function createClaudeAcpApp(options = {}) {
67168
67211
  const app = acpAgent({ name: "claude-code-acp" }).onConnect((connection) => {
67169
67212
  agent = new ClaudeAcpAgent(new ClientConnection(connection.client, options.onSessionUpdate), options.logger, options.environment, options.spawnClaudeCodeProcess, options.onBackgroundActivity);
67170
67213
  options.onConnect?.(connection);
67171
- }).onRequest(methods2.agent.initialize, (ctx) => requiredAgent(agent).initialize(ctx.params)).onRequest(methods2.agent.session.new, (ctx) => requiredAgent(agent).newSession(ctx.params)).onRequest(methods2.agent.session.load, (ctx) => requiredAgent(agent).loadSession(ctx.params, ctx.signal)).onRequest(methods2.agent.session.fork, (ctx) => requiredAgent(agent).unstable_forkSession(ctx.params, ctx.signal)).onRequest(methods2.agent.session.list, (ctx) => requiredAgent(agent).listSessions(ctx.params, ctx.signal)).onRequest(methods2.agent.session.delete, (ctx) => requiredAgent(agent).deleteSession(ctx.params)).onRequest(methods2.agent.session.resume, (ctx) => requiredAgent(agent).resumeSession(ctx.params)).onRequest(methods2.agent.session.close, (ctx) => requiredAgent(agent).closeSession(ctx.params)).onRequest(methods2.agent.session.setMode, (ctx) => requiredAgent(agent).setSessionMode(ctx.params)).onRequest(methods2.agent.session.setConfigOption, (ctx) => requiredAgent(agent).setSessionConfigOption(ctx.params)).onRequest(methods2.agent.authenticate, (ctx) => requiredAgent(agent).authenticate(ctx.params)).onRequest(methods2.agent.providers.list, (ctx) => requiredAgent(agent).unstable_listProviders(ctx.params)).onRequest(methods2.agent.providers.set, (ctx) => requiredAgent(agent).unstable_setProvider(ctx.params)).onRequest(methods2.agent.providers.disable, (ctx) => requiredAgent(agent).unstable_disableProvider(ctx.params)).onRequest(methods2.agent.logout, (ctx) => requiredAgent(agent).logout(ctx.params)).onRequest(methods2.agent.session.prompt, (ctx) => runPromptWithCancellation(requiredAgent(agent), ctx.params, ctx.signal)).onNotification(methods2.agent.session.cancel, (ctx) => requiredAgent(agent).cancel(ctx.params)).onRequest(STEER_METHOD, { parse: parseSteerRequest }, (ctx) => requiredAgent(agent).steer(ctx.params)).onRequest(RENAME_METHOD, { parse: parseRenameRequest }, (ctx) => requiredAgent(agent).renameSession(ctx.params)).onRequest(GOAL_CONTROL_METHOD, { parse: parseGoalRequest }, (ctx) => requiredAgent(agent).goal(ctx.params));
67214
+ }).onRequest(methods2.agent.initialize, (ctx) => requiredAgent(agent).initialize(ctx.params)).onRequest(methods2.agent.session.new, (ctx) => requiredAgent(agent).newSession(ctx.params)).onRequest(methods2.agent.session.load, (ctx) => requiredAgent(agent).loadSession(ctx.params, ctx.signal)).onRequest(methods2.agent.session.fork, (ctx) => requiredAgent(agent).unstable_forkSession(ctx.params, ctx.signal)).onRequest(methods2.agent.session.list, (ctx) => requiredAgent(agent).listSessions(ctx.params, ctx.signal)).onRequest(methods2.agent.session.delete, (ctx) => requiredAgent(agent).deleteSession(ctx.params)).onRequest(methods2.agent.session.resume, (ctx) => requiredAgent(agent).resumeSession(ctx.params)).onRequest(methods2.agent.session.close, (ctx) => requiredAgent(agent).closeSession(ctx.params)).onRequest(methods2.agent.session.setMode, (ctx) => requiredAgent(agent).setSessionMode(ctx.params)).onRequest(methods2.agent.session.setConfigOption, (ctx) => requiredAgent(agent).setSessionConfigOption(ctx.params)).onRequest(methods2.agent.authenticate, (ctx) => requiredAgent(agent).authenticate(ctx.params)).onRequest(methods2.agent.providers.list, (ctx) => requiredAgent(agent).unstable_listProviders(ctx.params)).onRequest(methods2.agent.providers.set, (ctx) => requiredAgent(agent).unstable_setProvider(ctx.params)).onRequest(methods2.agent.providers.disable, (ctx) => requiredAgent(agent).unstable_disableProvider(ctx.params)).onRequest(methods2.agent.logout, (ctx) => requiredAgent(agent).logout(ctx.params)).onRequest(methods2.agent.session.prompt, (ctx) => runPromptWithCancellation(requiredAgent(agent), ctx.params, ctx.signal)).onNotification(methods2.agent.session.cancel, (ctx) => requiredAgent(agent).cancel(ctx.params)).onRequest(STEER_METHOD, { parse: parseSteerRequest }, (ctx) => requiredAgent(agent).steer(ctx.params)).onRequest(RENAME_METHOD, { parse: parseRenameRequest }, (ctx) => requiredAgent(agent).renameSession(ctx.params)).onRequest(REVISION_METHOD, { parse: parseRevisionRequest }, (ctx) => requiredAgent(agent).readSessionRevision(ctx.params, ctx.signal)).onRequest(GOAL_CONTROL_METHOD, { parse: parseGoalRequest }, (ctx) => requiredAgent(agent).goal(ctx.params));
67172
67215
  return { agent: () => agent, app };
67173
67216
  }
67174
67217
  function requiredAgent(agent) {
@@ -71062,7 +71105,7 @@ import {
71062
71105
  // src/engine/acp/harness/pi/upstream/dist/acp/agent.js
71063
71106
  import { spawnSync } from "node:child_process";
71064
71107
  import { randomUUID as randomUUID11 } from "node:crypto";
71065
- import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync9, realpathSync as realpathSync3, statSync as statSync3, unlinkSync as unlinkSync2 } from "node:fs";
71108
+ import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync9, realpathSync as realpathSync3, statSync as statSync3, unlinkSync as unlinkSync2 } from "node:fs";
71066
71109
  import { basename as basename5, dirname as dirname8, isAbsolute as isAbsolute12, join as join20 } from "node:path";
71067
71110
  import { RequestError as RequestError11 } from "@agentclientprotocol/sdk";
71068
71111
 
@@ -71578,7 +71621,8 @@ function toAvailableCommandsFromPiGetCommands(data, opts) {
71578
71621
  }
71579
71622
 
71580
71623
  // src/engine/acp/harness/pi/upstream/dist/acp/pi-history.js
71581
- import { readFileSync as readFileSync3 } from "node:fs";
71624
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
71625
+ import { readFile as readFile6 } from "node:fs/promises";
71582
71626
  import { RequestError as RequestError8 } from "@agentclientprotocol/sdk";
71583
71627
  var entrySchema = external_exports.object({
71584
71628
  type: external_exports.string(),
@@ -71630,9 +71674,32 @@ function readPiHistory(sessionFile) {
71630
71674
  throw error62;
71631
71675
  }
71632
71676
  }
71677
+ async function readPiLatestEntryId(sessionFile) {
71678
+ if (!existsSync4(sessionFile)) {
71679
+ return "";
71680
+ }
71681
+ try {
71682
+ let latest = "";
71683
+ for (const line of (await readFile6(sessionFile, "utf8")).split(/\r?\n/u)) {
71684
+ if (!line.trim()) {
71685
+ continue;
71686
+ }
71687
+ const value = JSON.parse(line);
71688
+ if (external_exports.object({ type: external_exports.literal("session") }).safeParse(value).success) {
71689
+ continue;
71690
+ }
71691
+ latest = entrySchema.parse(value).id;
71692
+ }
71693
+ return latest;
71694
+ } catch (cause) {
71695
+ const error62 = RequestError8.internalError({ code: "PI_HISTORY_READ_FAILED" }, "Unable to read Pi history");
71696
+ error62.cause = cause;
71697
+ throw error62;
71698
+ }
71699
+ }
71633
71700
 
71634
71701
  // src/engine/acp/harness/pi/upstream/dist/acp/pi-sessions.js
71635
- 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";
71702
+ import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readdirSync as readdirSync4, readFileSync as readFileSync4, readSync as readSync2, statSync as statSync2 } from "node:fs";
71636
71703
  import { isAbsolute as isAbsolute10, join as join17, resolve as resolve10 } from "node:path";
71637
71704
  var DEFAULT_TAIL_BYTES = 256 * 1024;
71638
71705
  var DEFAULT_HEAD_BYTES = 64 * 1024;
@@ -71643,7 +71710,7 @@ function getPiAgentDir(environment) {
71643
71710
  function readSessionDirFromSettings(agentDir) {
71644
71711
  const settingsPath = join17(agentDir, "settings.json");
71645
71712
  try {
71646
- if (!existsSync4(settingsPath)) {
71713
+ if (!existsSync5(settingsPath)) {
71647
71714
  return null;
71648
71715
  }
71649
71716
  const raw = readFileSync4(settingsPath, "utf8");
@@ -71958,7 +72025,7 @@ function findPiSession(sessionId, environment = process.env) {
71958
72025
  }
71959
72026
 
71960
72027
  // src/engine/acp/harness/pi/upstream/dist/acp/pi-settings.js
71961
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
72028
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
71962
72029
  import { join as join18, resolve as resolve11 } from "node:path";
71963
72030
  function isObject2(x) {
71964
72031
  return Boolean(x) && typeof x === "object" && !Array.isArray(x);
@@ -71977,7 +72044,7 @@ function deepMerge(a, b2) {
71977
72044
  }
71978
72045
  function readJsonFile2(path7) {
71979
72046
  try {
71980
- if (!existsSync5(path7)) {
72047
+ if (!existsSync6(path7)) {
71981
72048
  return {};
71982
72049
  }
71983
72050
  const raw = readFileSync5(path7, "utf-8");
@@ -72251,7 +72318,7 @@ var SessionStore = class {
72251
72318
  };
72252
72319
 
72253
72320
  // src/engine/acp/harness/pi/upstream/dist/acp/slash-commands.js
72254
- import { existsSync as existsSync6, readdirSync as readdirSync5, readFileSync as readFileSync7 } from "node:fs";
72321
+ import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync7 } from "node:fs";
72255
72322
  import { join as join19, resolve as resolve12 } from "node:path";
72256
72323
  function parseFrontmatter(content) {
72257
72324
  const frontmatter = {};
@@ -72274,7 +72341,7 @@ function parseFrontmatter(content) {
72274
72341
  }
72275
72342
  function loadCommandsFromDir(dir, source, subdir = "") {
72276
72343
  const commands = [];
72277
- if (!existsSync6(dir)) {
72344
+ if (!existsSync7(dir)) {
72278
72345
  return commands;
72279
72346
  }
72280
72347
  try {
@@ -73410,6 +73477,7 @@ var contentBlockSchema2 = external_exports.discriminatedUnion("type", [
73410
73477
  ])
73411
73478
  })
73412
73479
  ]);
73480
+ var revisionRequestSchema = external_exports.object({ sessionId: external_exports.string().min(1) });
73413
73481
  var steerRequestSchema = external_exports.object({
73414
73482
  _meta: external_exports.object({
73415
73483
  steering: external_exports.object({ idleBehavior: external_exports.literal("promptRequired").optional() }).optional()
@@ -73497,7 +73565,7 @@ var PiAcpAgent = class {
73497
73565
  const sessionFile = typeof state?.sessionFile === "string" && state.sessionFile.trim() ? state.sessionFile : this.store.get(sessionId)?.sessionFile;
73498
73566
  if (typeof sessionFile === "string" && sessionFile.trim()) {
73499
73567
  try {
73500
- if (existsSync7(sessionFile)) {
73568
+ if (existsSync8(sessionFile)) {
73501
73569
  unlinkSync2(sessionFile);
73502
73570
  }
73503
73571
  } catch {
@@ -73989,7 +74057,7 @@ ${JSON.stringify(stats, null, 2)}`;
73989
74057
  const resolved = realpathSync3(piPath);
73990
74058
  const pkgRoot = dirname8(dirname8(resolved));
73991
74059
  const p = join20(pkgRoot, "CHANGELOG.md");
73992
- if (existsSync7(p)) {
74060
+ if (existsSync8(p)) {
73993
74061
  return p;
73994
74062
  }
73995
74063
  }
@@ -74000,7 +74068,7 @@ ${JSON.stringify(stats, null, 2)}`;
74000
74068
  const root = String(npmRoot.stdout ?? "").trim();
74001
74069
  if (root) {
74002
74070
  const p = join20(root, "@earendil-works", "pi-coding-agent", "CHANGELOG.md");
74003
- if (existsSync7(p)) {
74071
+ if (existsSync8(p)) {
74004
74072
  return p;
74005
74073
  }
74006
74074
  }
@@ -74051,7 +74119,7 @@ ${JSON.stringify(stats, null, 2)}`;
74051
74119
  const state = await session.proc.getState();
74052
74120
  const sessionFile = typeof state?.sessionFile === "string" ? state.sessionFile : null;
74053
74121
  const messageCount = typeof state?.messageCount === "number" ? state.messageCount : 0;
74054
- if (!sessionFile || messageCount === 0 || !existsSync7(sessionFile)) {
74122
+ if (!sessionFile || messageCount === 0 || !existsSync8(sessionFile)) {
74055
74123
  await this.conn.sessionUpdate({
74056
74124
  sessionId: session.sessionId,
74057
74125
  update: {
@@ -74184,6 +74252,17 @@ ${JSON.stringify(stats, null, 2)}`;
74184
74252
  const stopReason = result === "error" ? session.wasCancelRequested() ? "cancelled" : "end_turn" : result;
74185
74253
  return { stopReason };
74186
74254
  }
74255
+ async readSessionRevision(params) {
74256
+ const parsed = revisionRequestSchema.safeParse(params);
74257
+ if (!parsed.success) {
74258
+ throw RequestError11.invalidParams("Invalid revision request");
74259
+ }
74260
+ const stored = this.findStoredSession(parsed.data.sessionId);
74261
+ if (!stored) {
74262
+ throw RequestError11.invalidParams(`Unknown sessionId: ${parsed.data.sessionId}`);
74263
+ }
74264
+ return { latestEntryId: await readPiLatestEntryId(stored.sessionFile) };
74265
+ }
74187
74266
  async steer(params, signal) {
74188
74267
  signal.throwIfAborted();
74189
74268
  const parsed = steerRequestSchema.safeParse(params);
@@ -74552,7 +74631,7 @@ ${JSON.stringify(stats, null, 2)}`;
74552
74631
  const sessionFile = stored?.sessionFile ?? piSession?.sessionFile;
74553
74632
  if (sessionFile) {
74554
74633
  try {
74555
- if (existsSync7(sessionFile)) {
74634
+ if (existsSync8(sessionFile)) {
74556
74635
  unlinkSync2(sessionFile);
74557
74636
  }
74558
74637
  } catch {
@@ -74820,7 +74899,7 @@ function buildStartupInfo(opts) {
74820
74899
  };
74821
74900
  const contextItems = [];
74822
74901
  const contextPath = join20(opts.cwd, "AGENTS.md");
74823
- if (existsSync7(contextPath)) {
74902
+ if (existsSync8(contextPath)) {
74824
74903
  contextItems.push(contextPath);
74825
74904
  }
74826
74905
  addSection("Context", contextItems);
@@ -75005,6 +75084,10 @@ var PiAcpEndpoint = class {
75005
75084
  context.signal.removeEventListener("abort", cancel);
75006
75085
  }
75007
75086
  }).onRequest(
75087
+ "_session/revision",
75088
+ (params) => params,
75089
+ async (context) => await piAgentOrThrow(piAgent).readSessionRevision(context.params)
75090
+ ).onRequest(
75008
75091
  "_session/steering",
75009
75092
  (params) => params,
75010
75093
  async (context) => await piAgentOrThrow(piAgent).steer(context.params, context.signal)
@@ -75875,7 +75958,7 @@ var nativeSessionPageSchema = external_exports.object({
75875
75958
 
75876
75959
  // src/engine/acp/adapter/execution-connections.ts
75877
75960
  import { isAbsolute as isAbsolute14, resolve as resolve13 } from "node:path";
75878
- import { methods as methods11 } from "@agentclientprotocol/sdk";
75961
+ import { methods as methods11, RequestError as RequestError12 } from "@agentclientprotocol/sdk";
75879
75962
 
75880
75963
  // src/engine/acp/client/prompt-content.ts
75881
75964
  function validatePromptContent(options, capabilities) {
@@ -76605,6 +76688,8 @@ var AcpSessionConnector = class {
76605
76688
 
76606
76689
  // src/engine/acp/adapter/execution-connections.ts
76607
76690
  var absolutePathSchema = external_exports.string().min(1).refine(isAbsolute14);
76691
+ var nativeHistoryRevisionSchema = external_exports.object({ latestEntryId: external_exports.string().max(256) });
76692
+ var isMethodNotFound = (cause) => cause instanceof RequestError12 && cause.code === -32601;
76608
76693
  var targetSchema = external_exports.object({
76609
76694
  nativeSessionId: nativeSessionIdSchema,
76610
76695
  cwd: absolutePathSchema,
@@ -76868,6 +76953,38 @@ var AcpExecutionConnections = class {
76868
76953
  }
76869
76954
  return { nativeRenameApplied: true };
76870
76955
  };
76956
+ /** Asks the harness that owns the native history for its latest conversation entry. */
76957
+ readNativeHistoryRevision = async ({ signal, ...target }) => {
76958
+ signal.throwIfAborted();
76959
+ const { connection } = this.#resolve(target);
76960
+ let response;
76961
+ try {
76962
+ response = await connection.race(
76963
+ connection.connection.agent.request(
76964
+ "_session/revision",
76965
+ { sessionId: target.nativeSessionId },
76966
+ { cancellationSignal: AbortSignal.any([signal, AbortSignal.timeout(3e4)]) }
76967
+ ),
76968
+ "ACP agent exited while reading native history",
76969
+ signal
76970
+ );
76971
+ } catch (error62) {
76972
+ signal.throwIfAborted();
76973
+ if (error62 instanceof AcpExecutionError && isMethodNotFound(error62.cause)) {
76974
+ return { kind: "untracked" };
76975
+ }
76976
+ throw error62;
76977
+ }
76978
+ const decoded = nativeHistoryRevisionSchema.safeParse(response);
76979
+ if (!decoded.success) {
76980
+ throw new AcpExecutionError(
76981
+ "ACP agent returned an invalid native history revision",
76982
+ { cause: decoded.error },
76983
+ "invalid_native_session_response"
76984
+ );
76985
+ }
76986
+ return { kind: "tracked", latestEntryId: decoded.data.latestEntryId };
76987
+ };
76871
76988
  configureSession = async ({
76872
76989
  selection,
76873
76990
  signal,
@@ -77990,6 +78107,7 @@ var ClaudeAdapter = class {
77990
78107
  cancel = (...args) => this.#executionConnections.cancel(...args);
77991
78108
  closeSession = (...args) => this.#executionConnections.closeSession(...args);
77992
78109
  releaseSession = (params) => this.#executionConnections.releaseSession(params);
78110
+ readNativeHistoryRevision = (params) => this.#executionConnections.readNativeHistoryRevision(params);
77993
78111
  prompt = (...args) => this.#executionConnections.prompt(...args);
77994
78112
  steer = (...args) => this.#executionConnections.steer(...args);
77995
78113
  renameSession = (...args) => this.#executionConnections.renameSession(...args);
@@ -83407,6 +83525,11 @@ var CodexAdapter = class {
83407
83525
  };
83408
83526
  closeSession = (...args) => this.#executionConnections.closeSession(...args);
83409
83527
  releaseSession = (params) => this.#executionConnections.releaseSession(params);
83528
+ // Codex admits one active writer per thread; another client borrows the thread instead.
83529
+ readNativeHistoryRevision = async ({ signal }) => {
83530
+ signal.throwIfAborted();
83531
+ return { kind: "untracked" };
83532
+ };
83410
83533
  prompt = (...args) => this.#executionConnections.prompt(...args);
83411
83534
  steer = (...args) => this.#executionConnections.steer(...args);
83412
83535
  renameSession = (...args) => this.#executionConnections.renameSession(...args);
@@ -83574,6 +83697,7 @@ var PiAdapter = class {
83574
83697
  cancel = (...args) => this.#executionConnections.cancel(...args);
83575
83698
  closeSession = (...args) => this.#executionConnections.closeSession(...args);
83576
83699
  releaseSession = (params) => this.#executionConnections.releaseSession(params);
83700
+ readNativeHistoryRevision = (params) => this.#executionConnections.readNativeHistoryRevision(params);
83577
83701
  prompt = (...args) => this.#executionConnections.prompt(...args);
83578
83702
  steer = (...args) => this.#executionConnections.steer(...args);
83579
83703
  renameSession = (...args) => this.#executionConnections.renameSession(...args);
@@ -86028,6 +86152,8 @@ var AgentSession = class _AgentSession {
86028
86152
  #configOptions = [];
86029
86153
  #sessionConfigurations = new SessionConfigurations();
86030
86154
  #nativeHistoryOwnership = { kind: "unbound" };
86155
+ #nativeHistoryBaseline = { kind: "unavailable" };
86156
+ #nativeHistoryWrites = 0;
86031
86157
  #prompted = false;
86032
86158
  #sessionLoad = { kind: "not-requested" };
86033
86159
  #restored = false;
@@ -86070,8 +86196,12 @@ var AgentSession = class _AgentSession {
86070
86196
  await this.#processEvent(event);
86071
86197
  },
86072
86198
  onBackgroundActivity: (activity) => {
86199
+ const previous = this.#backgroundActivity;
86073
86200
  this.#backgroundActivity = activity;
86074
86201
  this.#getObserver().onBackgroundActivity?.(this, activity);
86202
+ if (previous !== "none" && activity === "none") {
86203
+ void this.#recordNativeHistoryRevision();
86204
+ }
86075
86205
  },
86076
86206
  interactions: {
86077
86207
  onPermission: this.#interactions.onPermission,
@@ -86164,7 +86294,9 @@ var AgentSession = class _AgentSession {
86164
86294
  }
86165
86295
  const nativeSessionId = this.#nativeSessionId;
86166
86296
  if (nativeSessionId.length > 0) {
86167
- await this.#adapter.renameSession({ ...this.#target(), title: normalized, signal });
86297
+ await this.#writeNativeHistory(
86298
+ async () => await this.#adapter.renameSession({ ...this.#target(), title: normalized, signal })
86299
+ );
86168
86300
  }
86169
86301
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
86170
86302
  await this.#processEvent({
@@ -86291,10 +86423,12 @@ var AgentSession = class _AgentSession {
86291
86423
  const history = new HistoryReplayCapture(this.#store.events, this.#mobiusSessionId);
86292
86424
  const completion = Promise.resolve().then(async () => {
86293
86425
  try {
86294
- const opened = await this.#adapter.openSessionWithReplay({
86295
- ...this.#sessionParams(signal),
86296
- nativeSessionId: this.nativeSessionId()
86297
- });
86426
+ const opened = await this.#writeNativeHistory(
86427
+ async () => await this.#adapter.openSessionWithReplay({
86428
+ ...this.#sessionParams(signal),
86429
+ nativeSessionId: this.nativeSessionId()
86430
+ })
86431
+ );
86298
86432
  signal.throwIfAborted();
86299
86433
  this.#capabilities = opened.capabilities;
86300
86434
  const loaded = { history, kind: "loaded", opened };
@@ -86308,7 +86442,82 @@ var AgentSession = class _AgentSession {
86308
86442
  this.#sessionLoad = { completion, history, kind: "capturing" };
86309
86443
  return await completion;
86310
86444
  }
86311
- initialize = async (signal, recovery, origin) => await restoreSession(this, signal, recovery, origin);
86445
+ initialize = async (signal, recovery, origin) => await this.#writeNativeHistory(async () => await restoreSession(this, signal, recovery, origin));
86446
+ /**
86447
+ * Native clients, such as the Agent's own terminal, can continue the conversation
86448
+ * while this process is idle. The Agent would then answer from, and append to, the
86449
+ * copy it loaded earlier, so the caller must reopen the conversation from native history.
86450
+ */
86451
+ nativeHistoryChanged = async (signal) => {
86452
+ const baseline = this.#nativeHistoryBaseline;
86453
+ if (this.#writingNativeHistory()) {
86454
+ return false;
86455
+ }
86456
+ switch (baseline.kind) {
86457
+ case "unavailable":
86458
+ return false;
86459
+ case "recording":
86460
+ await waitForSharedOperation(baseline.completion, signal);
86461
+ return await this.nativeHistoryChanged(signal);
86462
+ case "recorded": {
86463
+ let current;
86464
+ try {
86465
+ current = await this.#readNativeHistoryRevision(signal);
86466
+ } catch (error62) {
86467
+ signal.throwIfAborted();
86468
+ console.warn(`[${this.#agentId}-acp] Native history revision could not be read`, error62);
86469
+ return false;
86470
+ }
86471
+ return !this.#writingNativeHistory() && this.#nativeHistoryBaseline === baseline && current.kind === "tracked" && current.latestEntryId !== baseline.latestEntryId;
86472
+ }
86473
+ default: {
86474
+ const unreachable3 = baseline;
86475
+ throw new AcpExecutionError("Unexpected native history baseline", { cause: unreachable3 });
86476
+ }
86477
+ }
86478
+ };
86479
+ #writingNativeHistory = () => this.#nativeHistoryWrites > 0 || this.#backgroundActivity !== "none";
86480
+ /**
86481
+ * Runs an operation that may append to native history, then records what it left there.
86482
+ * The recording starts synchronously; a later comparison waits for it instead of the operation.
86483
+ */
86484
+ #writeNativeHistory = async (operation) => {
86485
+ this.#nativeHistoryWrites += 1;
86486
+ try {
86487
+ return await operation();
86488
+ } finally {
86489
+ this.#nativeHistoryWrites -= 1;
86490
+ void this.#recordNativeHistoryRevision();
86491
+ }
86492
+ };
86493
+ #readNativeHistoryRevision = async (signal) => this.#nativeIdentity.kind === "bound" ? await this.#adapter.readNativeHistoryRevision({
86494
+ ...this.#target(),
86495
+ signal: AbortSignal.any([signal, AbortSignal.timeout(3e4)])
86496
+ }) : { kind: "untracked" };
86497
+ #recordNativeHistoryRevision = async () => {
86498
+ if (this.#writingNativeHistory()) {
86499
+ return;
86500
+ }
86501
+ const recorded = Promise.withResolvers();
86502
+ const recording = { kind: "recording", completion: recorded.promise };
86503
+ this.#nativeHistoryBaseline = recording;
86504
+ let baseline = { kind: "unavailable" };
86505
+ try {
86506
+ const revision = await this.#readNativeHistoryRevision(AbortSignal.timeout(3e4));
86507
+ if (revision.kind === "tracked") {
86508
+ baseline = { kind: "recorded", latestEntryId: revision.latestEntryId };
86509
+ }
86510
+ } catch (error62) {
86511
+ if (!(error62 instanceof AcpExecutionError && error62.code === "invalid_agent_session")) {
86512
+ console.warn(`[${this.#agentId}-acp] Native history revision could not be recorded`, error62);
86513
+ }
86514
+ } finally {
86515
+ if (this.#nativeHistoryBaseline === recording) {
86516
+ this.#nativeHistoryBaseline = baseline;
86517
+ }
86518
+ recorded.resolve();
86519
+ }
86520
+ };
86312
86521
  nativeSessionId = () => this.#nativeSessionId;
86313
86522
  adoptNativeSessionId = (sessionId) => {
86314
86523
  if (this.#prompted || this.#nativeSessionId !== sessionId) {
@@ -86333,7 +86542,9 @@ var AgentSession = class _AgentSession {
86333
86542
  };
86334
86543
  #applyConfiguration = async (selection, signal) => {
86335
86544
  const configRevision = this.#configRevision;
86336
- const configured = await this.#adapter.configureSession({ ...this.#target(), selection, signal });
86545
+ const configured = await this.#writeNativeHistory(
86546
+ async () => await this.#adapter.configureSession({ ...this.#target(), selection, signal })
86547
+ );
86337
86548
  if (this.#configRevision === configRevision) {
86338
86549
  this.#configOptions = configured;
86339
86550
  this.#configRevision = crypto.randomUUID();
@@ -86437,7 +86648,9 @@ var AgentSession = class _AgentSession {
86437
86648
  });
86438
86649
  }
86439
86650
  try {
86440
- const result = await this.#adapter.prompt({ ...this.#target(), content: options, signal: options.signal });
86651
+ const result = await this.#writeNativeHistory(
86652
+ async () => await this.#adapter.prompt({ ...this.#target(), content: options, signal: options.signal })
86653
+ );
86441
86654
  this.writeStoredSession((/* @__PURE__ */ new Date()).toISOString());
86442
86655
  if (lifecycle !== void 0) {
86443
86656
  await this.recordLifecycleEvent({
@@ -87017,6 +87230,40 @@ var SessionManager2 = class {
87017
87230
  return runtime;
87018
87231
  });
87019
87232
  }
87233
+ /**
87234
+ * Reuses an idle process only while it still continues the latest native conversation.
87235
+ * Otherwise its Agent would answer from, and append to, an earlier copy, so the process is
87236
+ * released and the Session reopens from native history as after idle reclamation.
87237
+ */
87238
+ async #currentSessionProcess(existing, options, recovery) {
87239
+ const changed = !this.#isNativeSessionOperationActive(options.sessionId) && await existing.nativeHistoryChanged(options.signal);
87240
+ const pending = this.#executionProcesses.pending(options.sessionId);
87241
+ if (pending !== void 0) {
87242
+ return await waitForSharedOperation(pending, options.signal);
87243
+ }
87244
+ const current = this.#executionProcesses.get(options.sessionId);
87245
+ if (current !== void 0 && current !== existing) {
87246
+ return current;
87247
+ }
87248
+ if (!changed) {
87249
+ return existing;
87250
+ }
87251
+ return await this.#executionProcesses.prepare(options.sessionId, async () => {
87252
+ await this.#stopSessionProcess(options.sessionId, existing);
87253
+ return await this.#startRetainedSessionProcess(
87254
+ options,
87255
+ async (capabilities) => await AgentSession.start(
87256
+ options,
87257
+ recovery,
87258
+ () => this.#observer,
87259
+ this.#store,
87260
+ unmeasuredOperationMetrics,
87261
+ options.adapter,
87262
+ capabilities
87263
+ )
87264
+ );
87265
+ });
87266
+ }
87020
87267
  async #prepareSession(options, recovery, closed, metrics = unmeasuredOperationMetrics) {
87021
87268
  return await this.#executionProcesses.use(
87022
87269
  options.sessionId,
@@ -87055,14 +87302,15 @@ var SessionManager2 = class {
87055
87302
  const existing = this.#executionProcesses.get(options2.sessionId);
87056
87303
  if (existing !== void 0) {
87057
87304
  if (existing.belongsTo(options2.agent.id, options2.cwd, options2.additionalDirectories)) {
87058
- this.#executionProcesses.touch(options2.sessionId, existing);
87305
+ const runtime3 = await this.#currentSessionProcess(existing, options2, recovery);
87306
+ this.#executionProcesses.touch(options2.sessionId, runtime3);
87059
87307
  if (recovery.kind === "history-required") {
87060
87308
  await metrics.measure(
87061
87309
  "session-load",
87062
- async () => await existing.ensureHistoryLoaded(options2.signal)
87310
+ async () => await runtime3.ensureHistoryLoaded(options2.signal)
87063
87311
  );
87064
87312
  }
87065
- return existing.prepared();
87313
+ return runtime3.prepared();
87066
87314
  }
87067
87315
  if (!existing.canRebind()) {
87068
87316
  throw new AcpExecutionError(
@@ -87172,11 +87420,12 @@ var SessionManager2 = class {
87172
87420
  );
87173
87421
  }
87174
87422
  if (existing.usesEnvironment(options2.agent.environment)) {
87423
+ const runtime = await this.#currentSessionProcess(existing, options2, recovery);
87175
87424
  if (recovery.kind === "execution-only") {
87176
- existing.startExecutionOnlyCapture();
87425
+ runtime.startExecutionOnlyCapture();
87177
87426
  }
87178
- this.#executionProcesses.touch(options2.sessionId, existing);
87179
- return existing.prepared();
87427
+ this.#executionProcesses.touch(options2.sessionId, runtime);
87428
+ return runtime.prepared();
87180
87429
  }
87181
87430
  if (existing.hasRunningTurn()) {
87182
87431
  throw new AcpExecutionError(
@@ -87197,8 +87446,11 @@ var SessionManager2 = class {
87197
87446
  options.sessionId,
87198
87447
  async () => this.#operations.run(options, async (options2) => {
87199
87448
  this.#assertOpen(options2.sessionId);
87200
- if (this.#executionProcesses.get(options2.sessionId) === void 0) {
87449
+ const existing = this.#executionProcesses.get(options2.sessionId);
87450
+ if (existing === void 0) {
87201
87451
  await this.#prepareSession(options2, { kind: "interactive-only" }, "keep-closed");
87452
+ } else {
87453
+ await this.#currentSessionProcess(existing, options2, { kind: "interactive-only" });
87202
87454
  }
87203
87455
  const runtime = this.#executionProcesses.get(options2.sessionId);
87204
87456
  if (runtime === void 0) {
@@ -87462,11 +87714,16 @@ var SessionManager2 = class {
87462
87714
  "session_identity_mismatch"
87463
87715
  );
87464
87716
  }
87717
+ const runtime = await this.#currentSessionProcess(
87718
+ existing,
87719
+ options2,
87720
+ options2.recovery ?? { kind: "interactive-only" }
87721
+ );
87465
87722
  if (options2.recovery?.kind === "execution-only") {
87466
- existing.startExecutionOnlyCapture();
87723
+ runtime.startExecutionOnlyCapture();
87467
87724
  }
87468
- this.#executionProcesses.touch(options2.sessionId, existing);
87469
- return existing;
87725
+ this.#executionProcesses.touch(options2.sessionId, runtime);
87726
+ return runtime;
87470
87727
  }
87471
87728
  await this.#prepareSession(options2, options2.recovery ?? { kind: "interactive-only" }, "reopen");
87472
87729
  const started = this.#executionProcesses.get(options2.sessionId);
@@ -89122,7 +89379,7 @@ import { pathToFileURL as pathToFileURL3 } from "node:url";
89122
89379
 
89123
89380
  // src/engine/storage/files/scratch-directory.ts
89124
89381
  import { randomUUID as randomUUID17 } from "node:crypto";
89125
- import { lstat as lstat4, mkdir as mkdir5, readdir as readdir6, readFile as readFile6, realpath as realpath8, rename as rename4, rm as rm3, stat as stat7, utimes, writeFile as writeFile2 } from "node:fs/promises";
89382
+ import { lstat as lstat4, mkdir as mkdir5, readdir as readdir6, readFile as readFile7, realpath as realpath8, rename as rename4, rm as rm3, stat as stat7, utimes, writeFile as writeFile2 } from "node:fs/promises";
89126
89383
  import { dirname as dirname11, join as join28 } from "node:path";
89127
89384
  async function atomicWrite(path7, bytes, signal) {
89128
89385
  const temporary = `${path7}.${randomUUID17()}.tmp`;
@@ -89190,7 +89447,7 @@ var ScratchDirectory = class {
89190
89447
  read = async (path7, signal) => {
89191
89448
  const resolved = await this.resolveFile(path7);
89192
89449
  signal.throwIfAborted();
89193
- return resolved === null ? null : new Uint8Array(await readFile6(resolved, { signal }));
89450
+ return resolved === null ? null : new Uint8Array(await readFile7(resolved, { signal }));
89194
89451
  };
89195
89452
  removeAll = async () => {
89196
89453
  await rm3(this.#root, { force: true, recursive: true });
@@ -93132,4 +93389,4 @@ export {
93132
93389
  * MIT Licensed
93133
93390
  *)
93134
93391
  */
93135
- //# sourceMappingURL=chunk-WQKXKY2U.js.map
93392
+ //# sourceMappingURL=chunk-DXA4UBI6.js.map