@moxt-ai/mobius 0.0.307 → 0.0.308

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 (44) hide show
  1. package/dist/acp/adapter/codex/adapter.d.ts.map +1 -1
  2. package/dist/acp/adapter/codex/adapter.js +66 -9
  3. package/dist/acp/adapter/codex/adapter.js.map +1 -1
  4. package/dist/acp/adapter/codex/tool-event.d.ts +6 -0
  5. package/dist/acp/adapter/codex/tool-event.d.ts.map +1 -0
  6. package/dist/acp/adapter/codex/tool-event.js +66 -0
  7. package/dist/acp/adapter/codex/tool-event.js.map +1 -0
  8. package/dist/acp/adapter/session-events.d.ts +2 -2
  9. package/dist/acp/adapter/session-events.d.ts.map +1 -1
  10. package/dist/acp/adapter/session-events.js +81 -56
  11. package/dist/acp/adapter/session-events.js.map +1 -1
  12. package/dist/acp/content/content-externalizer.d.ts.map +1 -1
  13. package/dist/acp/content/content-externalizer.js +1 -31
  14. package/dist/acp/content/content-externalizer.js.map +1 -1
  15. package/dist/acp/harness/codex/agent.d.ts.map +1 -1
  16. package/dist/acp/harness/codex/agent.js +4 -75
  17. package/dist/acp/harness/codex/agent.js.map +1 -1
  18. package/dist/acp/harness/codex/app-server-protocol.d.ts +9 -0
  19. package/dist/acp/harness/codex/app-server-protocol.d.ts.map +1 -1
  20. package/dist/acp/harness/codex/app-server-protocol.js +1 -0
  21. package/dist/acp/harness/codex/app-server-protocol.js.map +1 -1
  22. package/dist/acp/harness/codex/history.d.ts +5 -0
  23. package/dist/acp/harness/codex/history.d.ts.map +1 -0
  24. package/dist/acp/harness/codex/history.js +116 -0
  25. package/dist/acp/harness/codex/history.js.map +1 -0
  26. package/dist/cli.js +723 -1346
  27. package/dist/cli.js.map +4 -4
  28. package/dist/runtime/command/registry/history.d.ts.map +1 -1
  29. package/dist/runtime/command/registry/history.js +5 -36
  30. package/dist/runtime/command/registry/history.js.map +1 -1
  31. package/dist/runtime.js +662 -1287
  32. package/dist/runtime.js.map +4 -4
  33. package/dist/session/history/session-event-history-projection.d.ts.map +1 -1
  34. package/dist/session/history/session-event-history-projection.js +23 -2
  35. package/dist/session/history/session-event-history-projection.js.map +1 -1
  36. package/package.json +2 -2
  37. package/dist/acp/native-history/codex/codex-history.d.ts +0 -17
  38. package/dist/acp/native-history/codex/codex-history.d.ts.map +0 -1
  39. package/dist/acp/native-history/codex/codex-history.js +0 -661
  40. package/dist/acp/native-history/codex/codex-history.js.map +0 -1
  41. package/dist/acp/native-history/codex/native-history-events.d.ts +0 -8
  42. package/dist/acp/native-history/codex/native-history-events.d.ts.map +0 -1
  43. package/dist/acp/native-history/codex/native-history-events.js +0 -92
  44. package/dist/acp/native-history/codex/native-history-events.js.map +0 -1
package/dist/runtime.js CHANGED
@@ -21783,8 +21783,6 @@ function encodeSessionPromptDispositionCommand(message) {
21783
21783
  var NATIVE_SESSION_REQUEST_KIND = "native.session.request";
21784
21784
  var NATIVE_SESSION_RESULT_KIND = "native.session.result";
21785
21785
  var NATIVE_SESSION_CANCEL_KIND = "native.session.cancel";
21786
- var SESSION_HISTORY_CHARACTER_LIMIT = 256e3;
21787
- var SESSION_HISTORY_MESSAGE_LIMIT = 1e3;
21788
21786
  var envelope = {
21789
21787
  requestId: identifierStringSchema,
21790
21788
  sessionId: identifierStringSchema
@@ -22247,6 +22245,7 @@ var sessionEventOmissionSchema = external_exports.literal("agent-reasoning");
22247
22245
  var nativeEventPageRequestSchema = external_exports.object({
22248
22246
  cursor: external_exports.string().min(1).max(512).nullable(),
22249
22247
  eventLimit: external_exports.number().int().min(1).max(1e4),
22248
+ // Legacy callers may still send this option; readers must ignore it.
22250
22249
  omit: external_exports.array(sessionEventOmissionSchema).max(1).readonly().optional()
22251
22250
  }).readonly();
22252
22251
  var queuedPromptRequestEventLogSchema = external_exports.object({
@@ -22294,6 +22293,7 @@ var SESSION_PREVIEW_HISTORY_PAGE_LOADED_KIND = "session.preview-history.page.loa
22294
22293
  var pageRequestFields = {
22295
22294
  cursor: external_exports.string().min(1).max(512).nullable(),
22296
22295
  eventLimit: external_exports.number().int().min(1).max(1e4),
22296
+ // Decode old clients without rejecting their request; omission has no effect.
22297
22297
  omit: external_exports.array(sessionEventOmissionSchema).max(1).readonly().optional(),
22298
22298
  requestId: identifierStringSchema,
22299
22299
  sessionId: identifierStringSchema
@@ -22691,7 +22691,7 @@ import { fetch as fetch3 } from "undici";
22691
22691
  // package.json
22692
22692
  var package_default = {
22693
22693
  name: "@moxt-ai/mobius",
22694
- version: "0.0.307",
22694
+ version: "0.0.308",
22695
22695
  description: "Mobius CLI for pairing and running local AI agent services.",
22696
22696
  type: "module",
22697
22697
  bin: {
@@ -62173,11 +62173,11 @@ var SessionModeManager = class {
62173
62173
  }
62174
62174
  return modes;
62175
62175
  }
62176
- async trySyncMode(query, mode, errorMessage2) {
62176
+ async trySyncMode(query, mode, errorMessage) {
62177
62177
  try {
62178
62178
  await query.setPermissionMode(mode);
62179
62179
  } catch (error62) {
62180
- this.options.logError(errorMessage2, error62);
62180
+ this.options.logError(errorMessage, error62);
62181
62181
  }
62182
62182
  }
62183
62183
  };
@@ -66838,6 +66838,9 @@ import {
66838
66838
  PROTOCOL_VERSION
66839
66839
  } from "@agentclientprotocol/sdk";
66840
66840
 
66841
+ // src/acp/harness/codex/app-server-client.ts
66842
+ import { spawn as spawn4 } from "node:child_process";
66843
+
66841
66844
  // src/infra/operation-error.ts
66842
66845
  var OperationError = class extends Error {
66843
66846
  code;
@@ -66875,9 +66878,6 @@ var AcpConfigurationValueUnavailableError = class extends AcpExecutionError {
66875
66878
  }
66876
66879
  };
66877
66880
 
66878
- // src/acp/harness/codex/app-server-client.ts
66879
- import { spawn as spawn4 } from "node:child_process";
66880
-
66881
66881
  // src/acp/agent/in-process-endpoint.ts
66882
66882
  function acpEndpointTerminationError(termination) {
66883
66883
  switch (termination.kind) {
@@ -67129,6 +67129,7 @@ var threadStartResponseSchema = external_exports.object({
67129
67129
  var threadTurnSchema = external_exports.object({
67130
67130
  id: boundedText(256).optional(),
67131
67131
  status: turnStatusSchema.optional(),
67132
+ error: external_exports.object({ message: external_exports.string().transform((message) => message.slice(0, 4096)) }).nullish(),
67132
67133
  items: external_exports.array(external_exports.unknown()).max(1e5)
67133
67134
  });
67134
67135
  var threadTurnsSchema = external_exports.array(threadTurnSchema).max(1e5);
@@ -67596,12 +67597,12 @@ function presentToolItem(item) {
67596
67597
  };
67597
67598
  }
67598
67599
  if (item.type === "collabAgentToolCall") {
67599
- const spawn9 = item.tool === "spawnAgent";
67600
+ const spawn8 = item.tool === "spawnAgent";
67600
67601
  return {
67601
67602
  content: [],
67602
67603
  kind: "other",
67603
67604
  locations: [],
67604
- rawInput: spawn9 ? {
67605
+ rawInput: spawn8 ? {
67605
67606
  model: item.model,
67606
67607
  prompt: item.prompt,
67607
67608
  reasoningEffort: item.reasoningEffort,
@@ -67609,10 +67610,10 @@ function presentToolItem(item) {
67609
67610
  } : { receiverThreadIds: item.receiverThreadIds, senderThreadId: item.senderThreadId },
67610
67611
  rawOutput: {
67611
67612
  agentsStates: item.agentsStates,
67612
- ...spawn9 ? { receiverThreadIds: item.receiverThreadIds } : {}
67613
+ ...spawn8 ? { receiverThreadIds: item.receiverThreadIds } : {}
67613
67614
  },
67614
67615
  status: collaborationStatus(item.status),
67615
- title: spawn9 ? "Dispatch subagent" : "Wait for subagent"
67616
+ title: spawn8 ? "Dispatch subagent" : "Wait for subagent"
67616
67617
  };
67617
67618
  }
67618
67619
  if (item.type === "subAgentActivity" && item.kind === "started") {
@@ -67922,6 +67923,277 @@ var CodexBorrowedAcpAgent = class {
67922
67923
  };
67923
67924
  };
67924
67925
 
67926
+ // src/acp/harness/codex/history.ts
67927
+ import { createHash } from "node:crypto";
67928
+
67929
+ // src/acp/content/raster.ts
67930
+ import { basename as basename4, isAbsolute as isAbsolute9, normalize } from "node:path";
67931
+ import { fileURLToPath } from "node:url";
67932
+
67933
+ // src/storage/files/local-files.ts
67934
+ import { createReadStream as createReadStream2 } from "node:fs";
67935
+ import { mkdir as mkdir3, open as open4, readdir as readdir4, readFile as readFile5, realpath as realpath6, stat as stat5 } from "node:fs/promises";
67936
+ function entryKind(entry) {
67937
+ if (entry.isDirectory()) {
67938
+ return "directory";
67939
+ }
67940
+ if (entry.isFile()) {
67941
+ return "file";
67942
+ }
67943
+ if (entry.isSymbolicLink()) {
67944
+ return "symbolic-link";
67945
+ }
67946
+ if (entry.isBlockDevice() || entry.isCharacterDevice()) {
67947
+ return "device";
67948
+ }
67949
+ if (entry.isFIFO()) {
67950
+ return "fifo";
67951
+ }
67952
+ return entry.isSocket() ? "socket" : "unknown";
67953
+ }
67954
+ async function canonicalPath(path7) {
67955
+ return await realpath6(path7);
67956
+ }
67957
+ async function readPathMetadata(path7) {
67958
+ const metadata = await stat5(path7);
67959
+ return {
67960
+ kind: metadata.isDirectory() ? "directory" : metadata.isFile() ? "file" : "other",
67961
+ modifiedAt: metadata.mtime,
67962
+ modifiedMilliseconds: metadata.mtimeMs,
67963
+ size: metadata.size
67964
+ };
67965
+ }
67966
+ async function listDirectory(path7) {
67967
+ const entries = await readdir4(path7, { withFileTypes: true });
67968
+ return entries.map((entry) => ({ kind: entryKind(entry), name: entry.name }));
67969
+ }
67970
+ async function ensurePrivateDirectory(path7) {
67971
+ await mkdir3(path7, { mode: 448, recursive: true });
67972
+ }
67973
+ async function ensureCanonicalDirectory(path7) {
67974
+ await ensurePrivateDirectory(path7);
67975
+ const resolved = await realpath6(path7);
67976
+ return (await stat5(resolved)).isDirectory() ? resolved : null;
67977
+ }
67978
+ async function readFileStart(path7, byteLength) {
67979
+ const bytes = new Uint8Array(byteLength);
67980
+ const handle = await open4(path7, "r");
67981
+ try {
67982
+ await handle.read(bytes, 0, byteLength, 0);
67983
+ } finally {
67984
+ await handle.close();
67985
+ }
67986
+ return bytes;
67987
+ }
67988
+ async function readFileBytes(path7) {
67989
+ return await readFile5(path7);
67990
+ }
67991
+ function readFileChunks(path7, chunkBytes, signal) {
67992
+ return createReadStream2(path7, { highWaterMark: chunkBytes, signal });
67993
+ }
67994
+
67995
+ // src/acp/content/raster.ts
67996
+ var MAX_LOCAL_RASTER_BYTES = 128 * 1024 * 1024;
67997
+ var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
67998
+ var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
67999
+ var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
68000
+ var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
68001
+ var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
68002
+ var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
68003
+ var LocalRasterImage = class {
68004
+ mimeType;
68005
+ name;
68006
+ sourceUri;
68007
+ constructor(name2, mimeType, sourceUri) {
68008
+ this.mimeType = mimeType;
68009
+ this.name = name2;
68010
+ this.sourceUri = sourceUri;
68011
+ }
68012
+ base64 = async () => Buffer.from(await readFileBytes(this.sourceUri)).toString("base64");
68013
+ };
68014
+ function startsWith(bytes, signature, offset = 0) {
68015
+ if (bytes.byteLength < offset + signature.byteLength) {
68016
+ return false;
68017
+ }
68018
+ return signature.every((value, index2) => bytes[offset + index2] === value);
68019
+ }
68020
+ function sniffRasterMime(bytes) {
68021
+ if (startsWith(bytes, PNG_SIGNATURE)) {
68022
+ return "image/png";
68023
+ }
68024
+ if (startsWith(bytes, JPEG_SIGNATURE)) {
68025
+ return "image/jpeg";
68026
+ }
68027
+ if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
68028
+ return "image/gif";
68029
+ }
68030
+ if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
68031
+ return "image/webp";
68032
+ }
68033
+ return null;
68034
+ }
68035
+ async function resolveCanonicalPath(requested, signal) {
68036
+ signal.throwIfAborted();
68037
+ if (!isAbsolute9(requested) || requested.includes("\0") || normalize(requested) !== requested) {
68038
+ return null;
68039
+ }
68040
+ try {
68041
+ const target = await canonicalPath(requested);
68042
+ signal.throwIfAborted();
68043
+ if (!isAbsolute9(target) || normalize(target) !== target) {
68044
+ return null;
68045
+ }
68046
+ return target;
68047
+ } catch (cause) {
68048
+ signal.throwIfAborted();
68049
+ if (cause instanceof Error && cause.name === "AbortError") {
68050
+ throw cause;
68051
+ }
68052
+ return null;
68053
+ }
68054
+ }
68055
+ function parseLocalImageUri(uri) {
68056
+ const trimmed = uri.trim();
68057
+ if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
68058
+ return null;
68059
+ }
68060
+ if (trimmed.startsWith("data:")) {
68061
+ return null;
68062
+ }
68063
+ if (trimmed.startsWith("file:")) {
68064
+ try {
68065
+ const url2 = new URL(trimmed);
68066
+ if (url2.protocol !== "file:" || url2.host.length > 0) {
68067
+ return null;
68068
+ }
68069
+ return fileURLToPath(url2);
68070
+ } catch {
68071
+ return null;
68072
+ }
68073
+ }
68074
+ if (!isAbsolute9(trimmed) && /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
68075
+ return null;
68076
+ }
68077
+ return trimmed;
68078
+ }
68079
+ async function readLocalRaster(uri, signal) {
68080
+ signal.throwIfAborted();
68081
+ const requested = parseLocalImageUri(uri);
68082
+ if (requested === null) {
68083
+ return null;
68084
+ }
68085
+ const target = await resolveCanonicalPath(requested, signal);
68086
+ if (target === null) {
68087
+ return null;
68088
+ }
68089
+ const targetMetadata = await readPathMetadata(target);
68090
+ signal.throwIfAborted();
68091
+ if (targetMetadata.kind !== "file" || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
68092
+ return null;
68093
+ }
68094
+ const header = await readFileStart(target, 12);
68095
+ signal.throwIfAborted();
68096
+ const mimeType = sniffRasterMime(header);
68097
+ if (mimeType === null) {
68098
+ return null;
68099
+ }
68100
+ return new LocalRasterImage(basename4(target) || "Image", mimeType, target);
68101
+ }
68102
+
68103
+ // src/acp/native-history/codex/history-images.ts
68104
+ var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
68105
+ var DATA_IMAGE_HEADER = /^data:(image\/[a-z+]+);base64,/;
68106
+ var BASE_64 = /^[A-Za-z0-9+/]*={0,2}$/;
68107
+ var SESSION_HISTORY_IMAGE_CHARACTER_LIMIT = 4e6;
68108
+ function isRasterMime(value) {
68109
+ return value === "image/png" || value === "image/jpeg" || value === "image/gif" || value === "image/webp";
68110
+ }
68111
+ function parseNativeHistoryImage(uri) {
68112
+ const header = DATA_IMAGE_HEADER.exec(uri);
68113
+ if (header === null) {
68114
+ return null;
68115
+ }
68116
+ const mimeType = header[1] ?? "";
68117
+ const data = uri.slice(header[0].length);
68118
+ if (!isRasterMime(mimeType) || data.length < 4 || data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
68119
+ return null;
68120
+ }
68121
+ if (data.length % 4 !== 0 || !BASE_64.test(data)) {
68122
+ return null;
68123
+ }
68124
+ return { data, mimeType, name: "" };
68125
+ }
68126
+ async function embedLocalHistoryImages(history, signal) {
68127
+ if (history.status !== "available") {
68128
+ return history;
68129
+ }
68130
+ const messages = [];
68131
+ let imageCharacters = 0;
68132
+ for (const message of history.messages) {
68133
+ signal.throwIfAborted();
68134
+ const resolved = await resolveMessageImages(message, imageCharacters, signal);
68135
+ imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
68136
+ messages.push(resolved);
68137
+ }
68138
+ return {
68139
+ ...history,
68140
+ messages
68141
+ };
68142
+ }
68143
+ async function resolveMessageImages(message, usedCharacters, signal) {
68144
+ const images = [...message.images ?? []];
68145
+ let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
68146
+ const text2 = await replaceImageMarkers(message.text, async (uri) => {
68147
+ if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
68148
+ return "[Image unavailable]";
68149
+ }
68150
+ const embedded = parseNativeHistoryImage(uri);
68151
+ if (embedded !== null) {
68152
+ if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
68153
+ return "[Image unavailable]";
68154
+ }
68155
+ images.push({ ...embedded, name: `Image ${(images.length + 1).toString()}` });
68156
+ imageCharacters += embedded.data.length;
68157
+ return "";
68158
+ }
68159
+ const local = await readLocalRaster(uri, signal);
68160
+ if (local === null) {
68161
+ return "[Image unavailable]";
68162
+ }
68163
+ const data = await local.base64();
68164
+ if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
68165
+ return "[Image unavailable]";
68166
+ }
68167
+ images.push({
68168
+ data,
68169
+ mimeType: local.mimeType,
68170
+ name: local.name
68171
+ });
68172
+ imageCharacters += data.length;
68173
+ return "";
68174
+ });
68175
+ return {
68176
+ ...message,
68177
+ text: text2,
68178
+ ...images.length > 0 ? { images } : {}
68179
+ };
68180
+ }
68181
+ async function replaceImageMarkers(text2, replace) {
68182
+ const matches = [...text2.matchAll(IMAGE_MARKER)];
68183
+ if (matches.length === 0) {
68184
+ return text2;
68185
+ }
68186
+ let cursor = 0;
68187
+ let rewritten = "";
68188
+ for (const match of matches) {
68189
+ const index2 = match.index ?? 0;
68190
+ rewritten += text2.slice(cursor, index2);
68191
+ rewritten += await replace(match[1] ?? "");
68192
+ cursor = index2 + match[0].length;
68193
+ }
68194
+ return `${rewritten}${text2.slice(cursor)}`;
68195
+ }
68196
+
67925
68197
  // src/acp/harness/codex/owned-agent.ts
67926
68198
  import { randomUUID as randomUUID5 } from "node:crypto";
67927
68199
  import { setTimeout as delay } from "node:timers/promises";
@@ -68574,6 +68846,115 @@ var CodexOwnedAcpAgent = class {
68574
68846
  };
68575
68847
  };
68576
68848
 
68849
+ // src/acp/harness/codex/history.ts
68850
+ async function replayCodexHistory(client2, threadId, emit, signal) {
68851
+ const deadline = AbortSignal.any([signal, AbortSignal.timeout(6e4)]);
68852
+ const seenCursors = /* @__PURE__ */ new Set();
68853
+ let cursor = null;
68854
+ let turnIndex = 0;
68855
+ for (; ; ) {
68856
+ deadline.throwIfAborted();
68857
+ const page = threadTurnsPageSchema.parse(
68858
+ await client2.request(
68859
+ "thread/turns/list",
68860
+ {
68861
+ threadId,
68862
+ limit: CODEX_HISTORY_TURN_PAGE_LIMIT,
68863
+ sortDirection: "asc",
68864
+ itemsView: "full",
68865
+ ...cursor === null ? {} : { cursor }
68866
+ },
68867
+ deadline
68868
+ )
68869
+ );
68870
+ for (const turn of page.data) {
68871
+ for (const rawItem of turn.items) {
68872
+ deadline.throwIfAborted();
68873
+ const item = decodeThreadItem(rawItem);
68874
+ if (item === null) {
68875
+ continue;
68876
+ }
68877
+ if (item.type === "userMessage") {
68878
+ const text2 = item.content.flatMap((content) => {
68879
+ if (typeof content !== "object" || content === null) {
68880
+ return [];
68881
+ }
68882
+ const type = Reflect.get(content, "type");
68883
+ const text3 = Reflect.get(content, "text");
68884
+ const url2 = Reflect.get(content, "url");
68885
+ if (type === "image" && typeof url2 === "string") {
68886
+ return [`[@image](${url2})`];
68887
+ }
68888
+ return type === "text" && typeof text3 === "string" ? [text3] : [];
68889
+ }).join("");
68890
+ const history = await embedLocalHistoryImages(
68891
+ { status: "available", truncated: false, messages: [{ role: "user", text: text2 }] },
68892
+ deadline
68893
+ );
68894
+ if (history.status !== "available") {
68895
+ continue;
68896
+ }
68897
+ const message = history.messages[0];
68898
+ for (const image of message?.images ?? []) {
68899
+ await emit({
68900
+ content: { type: "image", data: image.data, mimeType: image.mimeType },
68901
+ messageId: item.id,
68902
+ sessionUpdate: "user_message_chunk"
68903
+ });
68904
+ }
68905
+ const restoredText = message?.text ?? "";
68906
+ if (restoredText.length > 0) {
68907
+ await emit({
68908
+ content: { text: restoredText, type: "text" },
68909
+ messageId: item.id,
68910
+ sessionUpdate: "user_message_chunk"
68911
+ });
68912
+ }
68913
+ } else if (item.type === "agentMessage") {
68914
+ await emit(agentMessageUpdate(item.id, item.text));
68915
+ } else if (item.type === "reasoning") {
68916
+ const text2 = reasoningText(item);
68917
+ if (text2 !== null && text2.length > 0) {
68918
+ await emit({
68919
+ content: { text: text2, type: "text" },
68920
+ messageId: item.id,
68921
+ sessionUpdate: "agent_thought_chunk"
68922
+ });
68923
+ }
68924
+ } else if (item.type === "contextCompaction") {
68925
+ await emit({ compactionId: item.id, sessionUpdate: "compaction_update", status: "completed" });
68926
+ } else {
68927
+ const update = toolCallUpdate(item, "snapshot");
68928
+ if (update !== null) {
68929
+ await emit({ ...update, sessionUpdate: "tool_call" });
68930
+ }
68931
+ }
68932
+ }
68933
+ if (turn.error != null) {
68934
+ const identity2 = createHash("sha256").update(threadId).update("\0").update(turn.id ?? turnIndex.toString()).digest("hex");
68935
+ await emit({
68936
+ sessionUpdate: "tool_call",
68937
+ toolCallId: `agent-error-${identity2}`,
68938
+ title: "Agent error",
68939
+ kind: "other",
68940
+ status: "failed",
68941
+ rawOutput: { message: turn.error.message },
68942
+ content: [{ type: "content", content: { type: "text", text: turn.error.message } }]
68943
+ });
68944
+ }
68945
+ turnIndex += 1;
68946
+ }
68947
+ if (page.nextCursor == null) {
68948
+ return;
68949
+ }
68950
+ if (page.data.length === 0 || seenCursors.has(page.nextCursor)) {
68951
+ throw new AcpExecutionError("Codex repeated a history page cursor", {}, "invalid_native_session_response");
68952
+ }
68953
+ seenCursors.add(page.nextCursor);
68954
+ cursor = page.nextCursor;
68955
+ }
68956
+ }
68957
+
68577
68958
  // src/acp/harness/codex/settings.ts
68578
68959
  var APPROVAL_TIMEOUT_MILLISECONDS2 = 36e5;
68579
68960
  var MODEL_SETTING_ID = "model";
@@ -69240,83 +69621,7 @@ var CodexAcpAgent = class {
69240
69621
  // ACP load requires chronological replay. Resume only restores execution;
69241
69622
  // native pages supply history without a single full-transcript response.
69242
69623
  #replaySavedHistory = async (signal) => {
69243
- const deadline = AbortSignal.any([signal, AbortSignal.timeout(6e4)]);
69244
- const seenCursors = /* @__PURE__ */ new Set();
69245
- let cursor = null;
69246
- for (; ; ) {
69247
- deadline.throwIfAborted();
69248
- const page = threadTurnsPageSchema.parse(
69249
- await this.#appServer.request(
69250
- "thread/turns/list",
69251
- {
69252
- threadId: this.#nativeSessionId,
69253
- limit: CODEX_HISTORY_TURN_PAGE_LIMIT,
69254
- sortDirection: "asc",
69255
- itemsView: "full",
69256
- ...cursor === null ? {} : { cursor }
69257
- },
69258
- deadline
69259
- )
69260
- );
69261
- await this.#replayHistory(page.data, deadline);
69262
- if (page.nextCursor == null) {
69263
- return;
69264
- }
69265
- if (page.data.length === 0 || seenCursors.has(page.nextCursor)) {
69266
- throw new AcpExecutionError(
69267
- "Codex repeated a history page cursor",
69268
- {},
69269
- "invalid_native_session_response"
69270
- );
69271
- }
69272
- seenCursors.add(page.nextCursor);
69273
- cursor = page.nextCursor;
69274
- }
69275
- };
69276
- #replayHistory = async (turns, signal) => {
69277
- for (const turn of turns) {
69278
- for (const rawItem of turn.items) {
69279
- signal.throwIfAborted();
69280
- const item = decodeThreadItem(rawItem);
69281
- if (item === null) {
69282
- continue;
69283
- }
69284
- if (item.type === "userMessage") {
69285
- const text2 = item.content.flatMap((content) => {
69286
- if (typeof content !== "object" || content === null) {
69287
- return [];
69288
- }
69289
- const type = Reflect.get(content, "type");
69290
- const text3 = Reflect.get(content, "text");
69291
- return type === "text" && typeof text3 === "string" ? [text3] : [];
69292
- }).join("");
69293
- if (text2.length > 0) {
69294
- await this.#emit({
69295
- content: { text: text2, type: "text" },
69296
- messageId: item.id,
69297
- sessionUpdate: "user_message_chunk"
69298
- });
69299
- }
69300
- continue;
69301
- }
69302
- if (item.type === "agentMessage") {
69303
- await this.#emit(agentMessageUpdate(item.id, item.text));
69304
- continue;
69305
- }
69306
- if (item.type === "contextCompaction") {
69307
- await this.#emit({
69308
- compactionId: item.id,
69309
- sessionUpdate: "compaction_update",
69310
- status: "completed"
69311
- });
69312
- continue;
69313
- }
69314
- const update = toolCallUpdate(item, "snapshot");
69315
- if (update !== null) {
69316
- await this.#emit({ ...update, sessionUpdate: "tool_call" });
69317
- }
69318
- }
69319
- }
69624
+ await replayCodexHistory(this.#appServer, this.#nativeSessionId, this.#emit, signal);
69320
69625
  };
69321
69626
  /** Announces the manual compact command after every session entry point —
69322
69627
  * new, load, resume, and fork — so clients on restored sessions discover
@@ -69364,7 +69669,7 @@ var CodexAgentSpecification = class extends InProcessAcpAgentSpecification {
69364
69669
  };
69365
69670
 
69366
69671
  // src/agent/specification/vendors/pi-agent.ts
69367
- import { createHash } from "node:crypto";
69672
+ import { createHash as createHash2 } from "node:crypto";
69368
69673
  import { join as join19 } from "node:path";
69369
69674
  import {
69370
69675
  methods as methods6
@@ -69377,7 +69682,7 @@ import { agent as createAgentApp2, methods as methods5 } from "@agentclientproto
69377
69682
  import { spawnSync } from "node:child_process";
69378
69683
  import { randomUUID as randomUUID7 } from "node:crypto";
69379
69684
  import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync4, statSync as statSync4, unlinkSync as unlinkSync2 } from "node:fs";
69380
- import { basename as basename4, dirname as dirname7, isAbsolute as isAbsolute11, join as join17 } from "node:path";
69685
+ import { basename as basename5, dirname as dirname7, isAbsolute as isAbsolute12, join as join17 } from "node:path";
69381
69686
  import { RequestError as RequestError7 } from "@agentclientprotocol/sdk";
69382
69687
 
69383
69688
  // src/acp/harness/pi/upstream/dist/pi-rpc/process.js
@@ -69893,7 +70198,7 @@ function toAvailableCommandsFromPiGetCommands(data, opts) {
69893
70198
 
69894
70199
  // src/acp/harness/pi/upstream/dist/acp/pi-sessions.js
69895
70200
  import { closeSync as closeSync2, existsSync as existsSync4, openSync as openSync2, readdirSync as readdirSync4, readFileSync as readFileSync3, readSync as readSync2, statSync as statSync3 } from "node:fs";
69896
- import { isAbsolute as isAbsolute9, join as join14, resolve as resolve9 } from "node:path";
70201
+ import { isAbsolute as isAbsolute10, join as join14, resolve as resolve9 } from "node:path";
69897
70202
  var DEFAULT_TAIL_BYTES = 256 * 1024;
69898
70203
  var DEFAULT_HEAD_BYTES = 64 * 1024;
69899
70204
  function getPiAgentDir(environment) {
@@ -69915,7 +70220,7 @@ function readSessionDirFromSettings(agentDir) {
69915
70220
  if (typeof sessionDir !== "string" || !sessionDir.trim()) {
69916
70221
  return null;
69917
70222
  }
69918
- return isAbsolute9(sessionDir) ? sessionDir : resolve9(agentDir, sessionDir);
70223
+ return isAbsolute10(sessionDir) ? sessionDir : resolve9(agentDir, sessionDir);
69919
70224
  } catch {
69920
70225
  return null;
69921
70226
  }
@@ -70286,7 +70591,7 @@ function getQuietStartup(cwd, environment = process.env) {
70286
70591
  // src/acp/harness/pi/upstream/dist/acp/session.js
70287
70592
  import { randomUUID as randomUUID6 } from "node:crypto";
70288
70593
  import { readFileSync as readFileSync7 } from "node:fs";
70289
- import { isAbsolute as isAbsolute10, resolve as resolvePath } from "node:path";
70594
+ import { isAbsolute as isAbsolute11, resolve as resolvePath } from "node:path";
70290
70595
  import { RequestError as RequestError6 } from "@agentclientprotocol/sdk";
70291
70596
 
70292
70597
  // src/acp/harness/pi/upstream/dist/acp/extension-questions.js
@@ -70819,7 +71124,7 @@ function toToolCallLocations(args, cwd, line) {
70819
71124
  if (!path7) {
70820
71125
  return void 0;
70821
71126
  }
70822
- const resolvedPath = isAbsolute10(path7) ? path7 : resolvePath(cwd, path7);
71127
+ const resolvedPath = isAbsolute11(path7) ? path7 : resolvePath(cwd, path7);
70823
71128
  return [{ path: resolvedPath, ...typeof line === "number" ? { line } : {} }];
70824
71129
  }
70825
71130
  var SessionManager = class {
@@ -71359,7 +71664,7 @@ var PiAcpSession = class {
71359
71664
  const p = getToolPath(args);
71360
71665
  if (p) {
71361
71666
  try {
71362
- const abs = isAbsolute10(p) ? p : resolvePath(this.cwd, p);
71667
+ const abs = isAbsolute11(p) ? p : resolvePath(this.cwd, p);
71363
71668
  snapshotOldText = readFileSync7(abs, "utf8");
71364
71669
  this.fileSnapshots.set(toolCallId, { path: p, oldText: snapshotOldText });
71365
71670
  if (toolName === "edit") {
@@ -71442,7 +71747,7 @@ var PiAcpSession = class {
71442
71747
  let hasStructuredDiff = false;
71443
71748
  if (!isError && snapshot) {
71444
71749
  try {
71445
- const abs = isAbsolute10(snapshot.path) ? snapshot.path : resolvePath(this.cwd, snapshot.path);
71750
+ const abs = isAbsolute11(snapshot.path) ? snapshot.path : resolvePath(this.cwd, snapshot.path);
71446
71751
  const newText = readFileSync7(abs, "utf8");
71447
71752
  if (snapshot.oldText === null || newText !== snapshot.oldText) {
71448
71753
  hasStructuredDiff = true;
@@ -71836,7 +72141,7 @@ var PiAcpAgent = class {
71836
72141
  };
71837
72142
  }
71838
72143
  async newSession(params) {
71839
- if (!isAbsolute11(params.cwd)) {
72144
+ if (!isAbsolute12(params.cwd)) {
71840
72145
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
71841
72146
  }
71842
72147
  this.lastSessionCwd = params.cwd;
@@ -72433,7 +72738,7 @@ ${JSON.stringify(stats, null, 2)}`;
72433
72738
  return { sessions, nextCursor, _meta: {} };
72434
72739
  }
72435
72740
  async forkSession(params) {
72436
- if (!isAbsolute11(params.cwd)) {
72741
+ if (!isAbsolute12(params.cwd)) {
72437
72742
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
72438
72743
  }
72439
72744
  const source = this.findStoredSession(params.sessionId);
@@ -72499,7 +72804,7 @@ ${JSON.stringify(stats, null, 2)}`;
72499
72804
  return { sessionId: session.sessionId, configOptions, modes };
72500
72805
  }
72501
72806
  async resumeSession(params) {
72502
- if (!isAbsolute11(params.cwd)) {
72807
+ if (!isAbsolute12(params.cwd)) {
72503
72808
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
72504
72809
  }
72505
72810
  this.sessions.close(params.sessionId);
@@ -72570,7 +72875,7 @@ ${JSON.stringify(stats, null, 2)}`;
72570
72875
  return response;
72571
72876
  }
72572
72877
  async loadSession(params) {
72573
- if (!isAbsolute11(params.cwd)) {
72878
+ if (!isAbsolute12(params.cwd)) {
72574
72879
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
72575
72880
  }
72576
72881
  this.sessions.close(params.sessionId);
@@ -73064,7 +73369,7 @@ function buildStartupInfo(opts) {
73064
73369
  try {
73065
73370
  const prompts = readdirSync6(promptsDir).filter((f) => f.endsWith(".md"));
73066
73371
  for (const f of prompts) {
73067
- promptsItems.push(`/${basename4(f, ".md")}`);
73372
+ promptsItems.push(`/${basename5(f, ".md")}`);
73068
73373
  }
73069
73374
  } catch {
73070
73375
  }
@@ -73244,7 +73549,7 @@ var PiAgentSpecification = class extends InProcessAcpAgentSpecification {
73244
73549
  // The Pi ACP fork inlines embedded prompt resources into the turn message, so Mobius
73245
73550
  // keeps the adapter's opt-in capability flag enabled for every launch it owns.
73246
73551
  createLaunchEnvironment = async (_agent, context) => {
73247
- const workspaceHash = createHash("sha256").update(context.defaultWorkspace).digest("hex").slice(0, 24);
73552
+ const workspaceHash = createHash2("sha256").update(context.defaultWorkspace).digest("hex").slice(0, 24);
73248
73553
  const sessionDirectory = join19(
73249
73554
  readStateDirectory(context.environment),
73250
73555
  "agents",
@@ -73760,11 +74065,11 @@ function isAgentVersionSupported(reportedVersion, minimumSupportedVersion) {
73760
74065
  }
73761
74066
 
73762
74067
  // src/agent/discovery/executable-discovery.ts
73763
- import { isAbsolute as isAbsolute12 } from "node:path";
74068
+ import { isAbsolute as isAbsolute13 } from "node:path";
73764
74069
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveInstalled, context) {
73765
74070
  const override = context.environment[overrideVariable];
73766
74071
  if (override !== void 0) {
73767
- if (override.length === 0 || !isAbsolute12(override)) {
74072
+ if (override.length === 0 || !isAbsolute13(override)) {
73768
74073
  return [];
73769
74074
  }
73770
74075
  const executable = await resolveExecutablePath(override, context.platform);
@@ -74272,8 +74577,27 @@ var AdapterRegistry = class {
74272
74577
  import { randomUUID as randomUUID8 } from "node:crypto";
74273
74578
 
74274
74579
  // src/session/history/session-event-history-projection.ts
74580
+ var MAXIMUM_PROJECTED_REASONING_BYTES = 24 * 1024;
74581
+ function boundReasoning(payload) {
74582
+ if (payload.content.type !== "text" || Buffer.byteLength(payload.content.text, "utf8") <= MAXIMUM_PROJECTED_REASONING_BYTES) {
74583
+ return payload;
74584
+ }
74585
+ const bytes = Buffer.from(payload.content.text, "utf8");
74586
+ let start = bytes.length - MAXIMUM_PROJECTED_REASONING_BYTES;
74587
+ while (start < bytes.length && (bytes.readUInt8(start) & 192) === 128) {
74588
+ start += 1;
74589
+ }
74590
+ return {
74591
+ ...payload,
74592
+ content: { ...payload.content, text: bytes.toString("utf8", start) },
74593
+ meta: { ...payload.meta, truncated: true }
74594
+ };
74595
+ }
74275
74596
  function projectNewEvent(liveEvent2, eventId) {
74276
74597
  const { position: _position, eventId: _liveEventId, ...event } = liveEvent2;
74598
+ if (event.type === "acp" && event.payload.sessionUpdate === "agent_thought_chunk") {
74599
+ return { ...event, eventId, payload: boundReasoning(event.payload) };
74600
+ }
74277
74601
  return { ...event, eventId };
74278
74602
  }
74279
74603
  function replaceAcpPayload(event, payload) {
@@ -74324,11 +74648,11 @@ function mergeTextChunk(previous, incoming) {
74324
74648
  }
74325
74649
  const content = { text: `${previous.content.text}${incoming.content.text}`, type: "text" };
74326
74650
  if (previous.sessionUpdate === "agent_thought_chunk" && incoming.sessionUpdate === "agent_thought_chunk") {
74327
- return {
74651
+ return boundReasoning({
74328
74652
  ...previous,
74329
74653
  content,
74330
74654
  ...previous.meta?.truncated === true || incoming.meta?.truncated === true ? { meta: { ...previous.meta, ...incoming.meta, truncated: true } } : {}
74331
- };
74655
+ });
74332
74656
  }
74333
74657
  return { ...previous, content };
74334
74658
  }
@@ -75792,12 +76116,30 @@ function sessionConfigProtocolForAgent(_agentId) {
75792
76116
  }
75793
76117
 
75794
76118
  // src/acp/adapter/session-events.ts
76119
+ var MAXIMUM_REASONING_UPDATE_CHARACTERS = 1e6;
76120
+ function* reasoningWireUpdates(update) {
76121
+ if (update.sessionUpdate !== "agent_thought_chunk" || update.content.type !== "text" || update.content.text.length <= MAXIMUM_REASONING_UPDATE_CHARACTERS) {
76122
+ yield update;
76123
+ return;
76124
+ }
76125
+ const text2 = update.content.text;
76126
+ for (let start = 0; start < text2.length; ) {
76127
+ let end = Math.min(start + MAXIMUM_REASONING_UPDATE_CHARACTERS, text2.length);
76128
+ const last = text2.charCodeAt(end - 1);
76129
+ const next = text2.charCodeAt(end);
76130
+ if (last >= 55296 && last <= 56319 && next >= 56320 && next <= 57343) {
76131
+ end -= 1;
76132
+ }
76133
+ yield { ...update, content: { ...update.content, text: text2.slice(start, end) } };
76134
+ start = end;
76135
+ }
76136
+ }
75795
76137
  var AdapterSessionConnection = class {
75796
76138
  #connection;
75797
76139
  #updates;
75798
76140
  #lifetime = new AbortController();
75799
76141
  events;
75800
- constructor(options, externalizer) {
76142
+ constructor(options, externalizer, normalizeEvent) {
75801
76143
  const protocol = sessionConfigProtocolForAgent(options.agent.id);
75802
76144
  this.#updates = new AgentUpdateStream(async (notification) => {
75803
76145
  this.#lifetime.signal.throwIfAborted();
@@ -75805,58 +76147,60 @@ var AdapterSessionConnection = class {
75805
76147
  throw new AcpExecutionError("ACP agent referenced an unknown session", {}, "invalid_agent_session");
75806
76148
  }
75807
76149
  const signal = AbortSignal.any([this.#lifetime.signal, AbortSignal.timeout(3e4)]);
75808
- const externalized = await externalizer.update(options.sessionId(), notification.update, signal);
75809
- signal.throwIfAborted();
75810
- const update = externalized.agent;
75811
- const payload = decodeAcpSessionUpdate(JSON.stringify(externalized.event));
75812
- let event;
75813
- switch (update.sessionUpdate) {
75814
- case "available_commands_update":
75815
- event = {
75816
- kind: "commands",
75817
- payload,
75818
- commands: update.availableCommands.slice(0, 500).map((command) => ({
75819
- description: truncate(command.description, 500),
75820
- inputHint: truncate(command.input?.hint ?? "", 255),
75821
- name: truncate(command.name, 128)
75822
- })).filter((command) => command.name.length > 0)
75823
- };
75824
- break;
75825
- case "config_option_update":
75826
- event = {
75827
- kind: "configuration",
75828
- payload,
75829
- configOptions: protocol.normalizeUpdate(options.configOptions(), update.configOptions)
75830
- };
75831
- break;
75832
- case "current_mode_update":
75833
- event = { kind: "mode", payload, modeId: update.currentModeId };
75834
- break;
75835
- case "session_info_update": {
75836
- const changes = [];
75837
- if (Object.hasOwn(update, "title")) {
75838
- changes.push({ kind: "title", value: truncate(update.title ?? "", 500) });
75839
- }
75840
- if (Object.hasOwn(update, "updatedAt")) {
75841
- changes.push({ kind: "updated-at", value: truncate(update.updatedAt ?? "", 128) });
76150
+ for (const incoming of reasoningWireUpdates(notification.update)) {
76151
+ const externalized = await externalizer.update(options.sessionId(), incoming, signal);
76152
+ signal.throwIfAborted();
76153
+ const update = externalized.agent;
76154
+ const payload = decodeAcpSessionUpdate(JSON.stringify(normalizeEvent(externalized.event)));
76155
+ let event;
76156
+ switch (update.sessionUpdate) {
76157
+ case "available_commands_update":
76158
+ event = {
76159
+ kind: "commands",
76160
+ payload,
76161
+ commands: update.availableCommands.slice(0, 500).map((command) => ({
76162
+ description: truncate(command.description, 500),
76163
+ inputHint: truncate(command.input?.hint ?? "", 255),
76164
+ name: truncate(command.name, 128)
76165
+ })).filter((command) => command.name.length > 0)
76166
+ };
76167
+ break;
76168
+ case "config_option_update":
76169
+ event = {
76170
+ kind: "configuration",
76171
+ payload,
76172
+ configOptions: protocol.normalizeUpdate(options.configOptions(), update.configOptions)
76173
+ };
76174
+ break;
76175
+ case "current_mode_update":
76176
+ event = { kind: "mode", payload, modeId: update.currentModeId };
76177
+ break;
76178
+ case "session_info_update": {
76179
+ const changes = [];
76180
+ if (Object.hasOwn(update, "title")) {
76181
+ changes.push({ kind: "title", value: truncate(update.title ?? "", 500) });
76182
+ }
76183
+ if (Object.hasOwn(update, "updatedAt")) {
76184
+ changes.push({ kind: "updated-at", value: truncate(update.updatedAt ?? "", 128) });
76185
+ }
76186
+ event = { kind: "info", payload, changes };
76187
+ break;
75842
76188
  }
75843
- event = { kind: "info", payload, changes };
75844
- break;
76189
+ case "user_message_chunk":
76190
+ case "agent_message_chunk":
76191
+ case "agent_thought_chunk":
76192
+ case "tool_call":
76193
+ case "tool_call_update":
76194
+ case "plan":
76195
+ case "plan_update":
76196
+ case "plan_removed":
76197
+ event = { kind: "content", payload };
76198
+ break;
76199
+ default:
76200
+ event = { kind: "other", payload };
75845
76201
  }
75846
- case "user_message_chunk":
75847
- case "agent_message_chunk":
75848
- case "agent_thought_chunk":
75849
- case "tool_call":
75850
- case "tool_call_update":
75851
- case "plan":
75852
- case "plan_update":
75853
- case "plan_removed":
75854
- event = { kind: "content", payload };
75855
- break;
75856
- default:
75857
- event = { kind: "other", payload };
76202
+ await options.onEvent(event);
75858
76203
  }
75859
- await options.onEvent(event);
75860
76204
  });
75861
76205
  this.events = this.#updates;
75862
76206
  const client2 = {
@@ -75903,10 +76247,12 @@ var AdapterSessionConnection = class {
75903
76247
  };
75904
76248
  var AcpSessionConnector = class {
75905
76249
  #externalizer;
75906
- constructor(externalizer) {
76250
+ #normalizeEvent;
76251
+ constructor(externalizer, normalizeEvent = (event) => event) {
75907
76252
  this.#externalizer = externalizer;
76253
+ this.#normalizeEvent = normalizeEvent;
75908
76254
  }
75909
- connectSession = (options) => new AdapterSessionConnection(options, this.#externalizer);
76255
+ connectSession = (options) => new AdapterSessionConnection(options, this.#externalizer, this.#normalizeEvent);
75910
76256
  connectQuerySession = (options) => {
75911
76257
  const rejectInteraction = async () => {
75912
76258
  throw new AcpExecutionError(
@@ -75924,7 +76270,8 @@ var AcpSessionConnector = class {
75924
76270
  onElicitationComplete: rejectInteraction
75925
76271
  }
75926
76272
  },
75927
- this.#externalizer
76273
+ this.#externalizer,
76274
+ this.#normalizeEvent
75928
76275
  );
75929
76276
  };
75930
76277
  };
@@ -75944,1042 +76291,8 @@ var ClaudeAdapter = class {
75944
76291
  close = async () => await this.#queryProcesses.close();
75945
76292
  };
75946
76293
 
75947
- // src/acp/native-history/codex/codex-history.ts
75948
- import { spawn as spawn8 } from "node:child_process";
75949
-
75950
- // src/acp/content/raster.ts
75951
- import { basename as basename5, isAbsolute as isAbsolute13, normalize } from "node:path";
75952
- import { fileURLToPath } from "node:url";
75953
-
75954
- // src/storage/files/local-files.ts
75955
- import { createReadStream as createReadStream2 } from "node:fs";
75956
- import { mkdir as mkdir3, open as open4, readdir as readdir4, readFile as readFile5, realpath as realpath6, stat as stat5 } from "node:fs/promises";
75957
- function entryKind(entry) {
75958
- if (entry.isDirectory()) {
75959
- return "directory";
75960
- }
75961
- if (entry.isFile()) {
75962
- return "file";
75963
- }
75964
- if (entry.isSymbolicLink()) {
75965
- return "symbolic-link";
75966
- }
75967
- if (entry.isBlockDevice() || entry.isCharacterDevice()) {
75968
- return "device";
75969
- }
75970
- if (entry.isFIFO()) {
75971
- return "fifo";
75972
- }
75973
- return entry.isSocket() ? "socket" : "unknown";
75974
- }
75975
- async function canonicalPath(path7) {
75976
- return await realpath6(path7);
75977
- }
75978
- async function readPathMetadata(path7) {
75979
- const metadata = await stat5(path7);
75980
- return {
75981
- kind: metadata.isDirectory() ? "directory" : metadata.isFile() ? "file" : "other",
75982
- modifiedAt: metadata.mtime,
75983
- modifiedMilliseconds: metadata.mtimeMs,
75984
- size: metadata.size
75985
- };
75986
- }
75987
- async function listDirectory(path7) {
75988
- const entries = await readdir4(path7, { withFileTypes: true });
75989
- return entries.map((entry) => ({ kind: entryKind(entry), name: entry.name }));
75990
- }
75991
- async function ensurePrivateDirectory(path7) {
75992
- await mkdir3(path7, { mode: 448, recursive: true });
75993
- }
75994
- async function ensureCanonicalDirectory(path7) {
75995
- await ensurePrivateDirectory(path7);
75996
- const resolved = await realpath6(path7);
75997
- return (await stat5(resolved)).isDirectory() ? resolved : null;
75998
- }
75999
- async function readFileStart(path7, byteLength) {
76000
- const bytes = new Uint8Array(byteLength);
76001
- const handle = await open4(path7, "r");
76002
- try {
76003
- await handle.read(bytes, 0, byteLength, 0);
76004
- } finally {
76005
- await handle.close();
76006
- }
76007
- return bytes;
76008
- }
76009
- async function readFileBytes(path7) {
76010
- return await readFile5(path7);
76011
- }
76012
- function readFileChunks(path7, chunkBytes, signal) {
76013
- return createReadStream2(path7, { highWaterMark: chunkBytes, signal });
76014
- }
76015
-
76016
- // src/acp/content/raster.ts
76017
- var MAX_LOCAL_RASTER_BYTES = 128 * 1024 * 1024;
76018
- var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
76019
- var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
76020
- var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
76021
- var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
76022
- var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
76023
- var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
76024
- var LocalRasterImage = class {
76025
- mimeType;
76026
- name;
76027
- sourceUri;
76028
- constructor(name2, mimeType, sourceUri) {
76029
- this.mimeType = mimeType;
76030
- this.name = name2;
76031
- this.sourceUri = sourceUri;
76032
- }
76033
- base64 = async () => Buffer.from(await readFileBytes(this.sourceUri)).toString("base64");
76034
- };
76035
- function startsWith(bytes, signature, offset = 0) {
76036
- if (bytes.byteLength < offset + signature.byteLength) {
76037
- return false;
76038
- }
76039
- return signature.every((value, index2) => bytes[offset + index2] === value);
76040
- }
76041
- function sniffRasterMime(bytes) {
76042
- if (startsWith(bytes, PNG_SIGNATURE)) {
76043
- return "image/png";
76044
- }
76045
- if (startsWith(bytes, JPEG_SIGNATURE)) {
76046
- return "image/jpeg";
76047
- }
76048
- if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
76049
- return "image/gif";
76050
- }
76051
- if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
76052
- return "image/webp";
76053
- }
76054
- return null;
76055
- }
76056
- async function resolveCanonicalPath(requested, signal) {
76057
- signal.throwIfAborted();
76058
- if (!isAbsolute13(requested) || requested.includes("\0") || normalize(requested) !== requested) {
76059
- return null;
76060
- }
76061
- try {
76062
- const target = await canonicalPath(requested);
76063
- signal.throwIfAborted();
76064
- if (!isAbsolute13(target) || normalize(target) !== target) {
76065
- return null;
76066
- }
76067
- return target;
76068
- } catch (cause) {
76069
- signal.throwIfAborted();
76070
- if (cause instanceof Error && cause.name === "AbortError") {
76071
- throw cause;
76072
- }
76073
- return null;
76074
- }
76075
- }
76076
- function parseLocalImageUri(uri) {
76077
- const trimmed = uri.trim();
76078
- if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
76079
- return null;
76080
- }
76081
- if (trimmed.startsWith("data:")) {
76082
- return null;
76083
- }
76084
- if (trimmed.startsWith("file:")) {
76085
- try {
76086
- const url2 = new URL(trimmed);
76087
- if (url2.protocol !== "file:" || url2.host.length > 0) {
76088
- return null;
76089
- }
76090
- return fileURLToPath(url2);
76091
- } catch {
76092
- return null;
76093
- }
76094
- }
76095
- if (!isAbsolute13(trimmed) && /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
76096
- return null;
76097
- }
76098
- return trimmed;
76099
- }
76100
- async function readLocalRaster(uri, signal) {
76101
- signal.throwIfAborted();
76102
- const requested = parseLocalImageUri(uri);
76103
- if (requested === null) {
76104
- return null;
76105
- }
76106
- const target = await resolveCanonicalPath(requested, signal);
76107
- if (target === null) {
76108
- return null;
76109
- }
76110
- const targetMetadata = await readPathMetadata(target);
76111
- signal.throwIfAborted();
76112
- if (targetMetadata.kind !== "file" || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
76113
- return null;
76114
- }
76115
- const header = await readFileStart(target, 12);
76116
- signal.throwIfAborted();
76117
- const mimeType = sniffRasterMime(header);
76118
- if (mimeType === null) {
76119
- return null;
76120
- }
76121
- return new LocalRasterImage(basename5(target) || "Image", mimeType, target);
76122
- }
76123
-
76124
- // src/acp/native-history/codex/history-images.ts
76125
- var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
76126
- var DATA_IMAGE_HEADER = /^data:(image\/[a-z+]+);base64,/;
76127
- var BASE_64 = /^[A-Za-z0-9+/]*={0,2}$/;
76128
- var SESSION_HISTORY_IMAGE_CHARACTER_LIMIT = 4e6;
76129
- var SESSION_HISTORY_PREVIEW_TURN_LIMIT = 10;
76130
- function isRasterMime(value) {
76131
- return value === "image/png" || value === "image/jpeg" || value === "image/gif" || value === "image/webp";
76132
- }
76133
- function parseNativeHistoryImage(uri) {
76134
- const header = DATA_IMAGE_HEADER.exec(uri);
76135
- if (header === null) {
76136
- return null;
76137
- }
76138
- const mimeType = header[1] ?? "";
76139
- const data = uri.slice(header[0].length);
76140
- if (!isRasterMime(mimeType) || data.length < 4 || data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
76141
- return null;
76142
- }
76143
- if (data.length % 4 !== 0 || !BASE_64.test(data)) {
76144
- return null;
76145
- }
76146
- return { data, mimeType, name: "" };
76147
- }
76148
- async function embedLocalHistoryImages(history, signal) {
76149
- if (history.status !== "available") {
76150
- return history;
76151
- }
76152
- const messages = [];
76153
- let imageCharacters = 0;
76154
- for (const message of history.messages) {
76155
- signal.throwIfAborted();
76156
- const resolved = await resolveMessageImages(message, imageCharacters, signal);
76157
- imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
76158
- messages.push(resolved);
76159
- }
76160
- return {
76161
- ...history,
76162
- messages
76163
- };
76164
- }
76165
- async function resolveMessageImages(message, usedCharacters, signal) {
76166
- const images = [...message.images ?? []];
76167
- let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
76168
- const text2 = await replaceImageMarkers(message.text, async (uri) => {
76169
- if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
76170
- return "[Image unavailable]";
76171
- }
76172
- const embedded = parseNativeHistoryImage(uri);
76173
- if (embedded !== null) {
76174
- if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
76175
- return "[Image unavailable]";
76176
- }
76177
- images.push({ ...embedded, name: `Image ${(images.length + 1).toString()}` });
76178
- imageCharacters += embedded.data.length;
76179
- return "";
76180
- }
76181
- const local = await readLocalRaster(uri, signal);
76182
- if (local === null) {
76183
- return "[Image unavailable]";
76184
- }
76185
- const data = await local.base64();
76186
- if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
76187
- return "[Image unavailable]";
76188
- }
76189
- images.push({
76190
- data,
76191
- mimeType: local.mimeType,
76192
- name: local.name
76193
- });
76194
- imageCharacters += data.length;
76195
- return "";
76196
- });
76197
- return {
76198
- ...message,
76199
- text: text2,
76200
- ...images.length > 0 ? { images } : {}
76201
- };
76202
- }
76203
- async function replaceImageMarkers(text2, replace) {
76204
- const matches = [...text2.matchAll(IMAGE_MARKER)];
76205
- if (matches.length === 0) {
76206
- return text2;
76207
- }
76208
- let cursor = 0;
76209
- let rewritten = "";
76210
- for (const match of matches) {
76211
- const index2 = match.index ?? 0;
76212
- rewritten += text2.slice(cursor, index2);
76213
- rewritten += await replace(match[1] ?? "");
76214
- cursor = index2 + match[0].length;
76215
- }
76216
- return `${rewritten}${text2.slice(cursor)}`;
76217
- }
76218
-
76219
- // src/acp/native-history/codex/codex-history.ts
76220
- var responseSchema = external_exports.union([
76221
- external_exports.object({
76222
- id: external_exports.number(),
76223
- error: external_exports.object({ code: external_exports.number(), message: external_exports.string() })
76224
- }),
76225
- external_exports.object({ id: external_exports.number(), result: external_exports.unknown() }),
76226
- external_exports.object({ method: external_exports.string() })
76227
- ]);
76228
- var threadSchema = external_exports.object({
76229
- thread: external_exports.object({
76230
- id: nativeSessionIdSchema,
76231
- cwd: external_exports.string().min(1).max(2048).refine((path7) => !path7.includes("\0"))
76232
- })
76233
- });
76234
- var turnsSchema = external_exports.object({
76235
- data: external_exports.array(
76236
- external_exports.object({
76237
- id: external_exports.string().min(1),
76238
- status: external_exports.enum(["completed", "interrupted", "failed", "inProgress"]),
76239
- error: external_exports.unknown().nullish(),
76240
- items: external_exports.array(external_exports.unknown()).max(1e5)
76241
- })
76242
- ).max(SESSION_HISTORY_MESSAGE_LIMIT),
76243
- nextCursor: external_exports.string().nullish()
76244
- });
76245
- var itemTypeSchema = external_exports.object({ type: external_exports.string().min(1).max(80) });
76246
- var userMessageSchema = external_exports.object({
76247
- content: external_exports.array(external_exports.unknown()).max(1e4),
76248
- type: external_exports.literal("userMessage")
76249
- });
76250
- var textSchema = external_exports.object({ text: external_exports.string() });
76251
- var imageSchema = external_exports.object({ url: external_exports.string() });
76252
- var agentMessageSchema = textSchema.extend({
76253
- id: external_exports.string().optional(),
76254
- phase: external_exports.string().nullish(),
76255
- type: external_exports.literal("agentMessage")
76256
- });
76257
- var reasoningSchema = external_exports.object({
76258
- id: external_exports.string(),
76259
- summary: external_exports.array(external_exports.string()).max(1e4),
76260
- content: external_exports.array(external_exports.string()).max(1e4),
76261
- type: external_exports.literal("reasoning")
76262
- });
76263
- var commandExecutionSchema = external_exports.object({
76264
- id: external_exports.string(),
76265
- command: external_exports.string(),
76266
- cwd: external_exports.string(),
76267
- status: external_exports.string(),
76268
- commandActions: external_exports.array(external_exports.object({ type: external_exports.string() }).passthrough()).max(100),
76269
- aggregatedOutput: external_exports.string().nullish(),
76270
- exitCode: external_exports.number().int().nullish(),
76271
- type: external_exports.literal("commandExecution")
76272
- });
76273
- var fileChangeSchema = external_exports.object({
76274
- changes: external_exports.array(external_exports.object({ diff: external_exports.string(), path: external_exports.string() })).max(1e4),
76275
- id: external_exports.string(),
76276
- status: external_exports.string(),
76277
- type: external_exports.literal("fileChange")
76278
- });
76279
- var mcpToolCallSchema = external_exports.object({
76280
- arguments: external_exports.unknown().optional(),
76281
- error: external_exports.unknown().nullish(),
76282
- id: external_exports.string(),
76283
- result: external_exports.unknown().nullish(),
76284
- server: external_exports.string(),
76285
- status: external_exports.string(),
76286
- tool: external_exports.string(),
76287
- type: external_exports.literal("mcpToolCall")
76288
- });
76289
- var dynamicToolCallSchema = external_exports.object({
76290
- arguments: external_exports.unknown().optional(),
76291
- contentItems: external_exports.array(external_exports.unknown()).max(1e4).nullish(),
76292
- id: external_exports.string(),
76293
- namespace: external_exports.string().nullish(),
76294
- status: external_exports.string(),
76295
- tool: external_exports.string(),
76296
- type: external_exports.literal("dynamicToolCall")
76297
- });
76298
- var planSchema = external_exports.object({ id: external_exports.string(), text: external_exports.string(), type: external_exports.literal("plan") });
76299
- var historyItemSchema = external_exports.discriminatedUnion("type", [
76300
- userMessageSchema,
76301
- agentMessageSchema,
76302
- reasoningSchema,
76303
- commandExecutionSchema,
76304
- fileChangeSchema,
76305
- mcpToolCallSchema,
76306
- dynamicToolCallSchema,
76307
- planSchema
76308
- ]);
76309
- var CodexHistoryResponseError = class extends Error {
76310
- code;
76311
- constructor(response) {
76312
- super(response.message);
76313
- this.code = response.code;
76314
- this.name = "CodexHistoryResponseError";
76315
- }
76316
- };
76317
- function bounded(value, maximum) {
76318
- return value.slice(0, maximum);
76319
- }
76320
- function activity(activityId, activityType, sequence, fields) {
76321
- return {
76322
- activityId: bounded(activityId, 128) || `history-${sequence.toString()}`,
76323
- activityType,
76324
- content: [],
76325
- input: bounded(fields.input, 1e5),
76326
- locations: fields.locations.filter((location) => location.length > 0).map((location) => bounded(location, 2048)).slice(0, 100),
76327
- name: bounded(fields.name, 128),
76328
- output: bounded(fields.output, 1e5),
76329
- sequence,
76330
- status: bounded(fields.status, 64),
76331
- title: bounded(fields.title, 500),
76332
- toolKind: bounded(fields.toolKind, 64)
76333
- };
76334
- }
76335
- function errorMessage(value) {
76336
- if (typeof value === "string") {
76337
- return value;
76338
- }
76339
- if (typeof value === "object" && value !== null) {
76340
- const message = Reflect.get(value, "message");
76341
- if (typeof message === "string") {
76342
- return message;
76343
- }
76344
- }
76345
- return JSON.stringify(value) ?? "Codex stopped before completing this turn.";
76346
- }
76347
- function formatted(value) {
76348
- if (value === void 0) {
76349
- return "";
76350
- }
76351
- if (typeof value === "string") {
76352
- return value;
76353
- }
76354
- return JSON.stringify(value) ?? "";
76355
- }
76356
- function toolStatus(status) {
76357
- return status === "inProgress" ? "running" : status === "completed" ? "completed" : "failed";
76358
- }
76359
- function diffContent(path7, newText) {
76360
- return { newText, path: path7, type: "diff" };
76361
- }
76362
- function messageSize(message) {
76363
- return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
76364
- }
76365
- var SESSION_HISTORY_MESSAGE_CHARACTER_LIMIT = Math.floor(SESSION_HISTORY_CHARACTER_LIMIT / 2);
76366
- function fitActivity(activity2, maximumCharacters) {
76367
- const truncate4 = (limit) => ({
76368
- ...activity2,
76369
- input: bounded(activity2.input, limit),
76370
- locations: activity2.locations.map((location) => bounded(location, Math.max(1, limit))),
76371
- name: bounded(activity2.name, limit),
76372
- output: bounded(activity2.output, limit),
76373
- title: bounded(activity2.title, limit),
76374
- toolKind: bounded(activity2.toolKind, limit)
76375
- });
76376
- let minimum = 1;
76377
- let maximum = 1e5;
76378
- let fitted = truncate4(0);
76379
- while (minimum <= maximum) {
76380
- const limit = Math.floor((minimum + maximum) / 2);
76381
- const candidate = truncate4(limit);
76382
- if (JSON.stringify(candidate).length <= maximumCharacters) {
76383
- fitted = candidate;
76384
- minimum = limit + 1;
76385
- } else {
76386
- maximum = limit - 1;
76387
- }
76388
- }
76389
- return fitted;
76390
- }
76391
- function fitActivities(activities, maximumCharacters) {
76392
- if (activities.length === 0) {
76393
- return activities;
76394
- }
76395
- const arrayCharacters = 2 + activities.length - 1;
76396
- const maximumActivityCharacters = Math.floor(Math.max(0, maximumCharacters - arrayCharacters) / activities.length);
76397
- return activities.map((activity2) => fitActivity(activity2, maximumActivityCharacters));
76398
- }
76399
- function fitHistoryMessage(message, maximumCharacters = SESSION_HISTORY_MESSAGE_CHARACTER_LIMIT) {
76400
- const text2 = message.text.slice(-maximumCharacters);
76401
- if (message.role === "user") {
76402
- return {
76403
- message: { ...message, text: text2 },
76404
- truncated: text2.length < message.text.length
76405
- };
76406
- }
76407
- let activities = message.activities;
76408
- const content = message.content;
76409
- let fitted = { ...message, activities, content, text: text2 };
76410
- if (messageSize(fitted) > maximumCharacters && activities.length > 0) {
76411
- const maximumActivityCharacters = maximumCharacters - text2.length - JSON.stringify(content).length;
76412
- activities = fitActivities(activities, maximumActivityCharacters);
76413
- fitted = { ...fitted, activities };
76414
- }
76415
- const excess = Math.max(0, messageSize(fitted) - maximumCharacters);
76416
- if (excess > 0) {
76417
- const maximumTextLength = Math.max(0, fitted.text.length - excess);
76418
- fitted = {
76419
- ...fitted,
76420
- text: maximumTextLength === 0 ? "" : fitted.text.slice(-maximumTextLength)
76421
- };
76422
- }
76423
- return {
76424
- message: fitted,
76425
- truncated: fitted.text.length < message.text.length || JSON.stringify(activities).length < JSON.stringify(message.activities).length
76426
- };
76427
- }
76428
- function turnOutcome2(status) {
76429
- switch (status) {
76430
- case "completed":
76431
- return "succeeded";
76432
- case "interrupted":
76433
- return "cancelled";
76434
- case "failed":
76435
- return "failed";
76436
- case "inProgress":
76437
- return void 0;
76438
- default: {
76439
- const unhandled = status;
76440
- throw new Error(`Unknown Codex turn status: ${String(unhandled)}`);
76441
- }
76442
- }
76443
- }
76444
- function decodeHistory(thread, value, options) {
76445
- const page = turnsSchema.parse(value);
76446
- const nativeTurn = options.nativeTurn?.();
76447
- const coveredCommandIds = nativeTurn != null && page.data[0]?.id === nativeTurn.nativeTurnId ? [nativeTurn.commandId] : [];
76448
- const messages = [];
76449
- let characters = 0;
76450
- let truncated = page.nextCursor != null;
76451
- for (const turn of page.data.toReversed()) {
76452
- const outcome = turnOutcome2(turn.status);
76453
- const turnMessageCharacterLimit = Math.max(
76454
- 1,
76455
- Math.floor(SESSION_HISTORY_CHARACTER_LIMIT / Math.max(1, turn.items.length + (turn.error == null ? 0 : 1)))
76456
- );
76457
- let sequence = 0;
76458
- let assistantMessageIndex = null;
76459
- const append = (message) => {
76460
- const fitted = fitHistoryMessage(message, turnMessageCharacterLimit);
76461
- if (fitted.message.text.length === 0 && (fitted.message.images?.length ?? 0) === 0 && (fitted.message.role === "user" || fitted.message.activities.length === 0 && fitted.message.content.length === 0)) {
76462
- return;
76463
- }
76464
- truncated ||= fitted.truncated;
76465
- messages.push(fitted.message);
76466
- if (fitted.message.role === "assistant") {
76467
- assistantMessageIndex = messages.length - 1;
76468
- }
76469
- characters += messageSize(fitted.message);
76470
- };
76471
- for (const item of turn.items) {
76472
- const decoded = historyItemSchema.safeParse(item);
76473
- if (!decoded.success) {
76474
- continue;
76475
- }
76476
- const historyItem = decoded.data;
76477
- if (historyItem.type === "userMessage") {
76478
- const text2 = historyItem.content.map((block) => {
76479
- const { type } = itemTypeSchema.parse(block);
76480
- if (type === "text") {
76481
- return textSchema.parse(block).text;
76482
- }
76483
- if (type === "image") {
76484
- return `[@image](${imageSchema.parse(block).url})`;
76485
- }
76486
- return "[Attachment]";
76487
- }).join("");
76488
- append({
76489
- role: "user",
76490
- text: text2
76491
- });
76492
- } else if (historyItem.type === "agentMessage") {
76493
- append({ activities: [], content: [], role: "assistant", text: historyItem.text });
76494
- } else if (historyItem.type === "reasoning") {
76495
- const output2 = (historyItem.content.length > 0 ? historyItem.content : historyItem.summary).join(
76496
- "\n\n"
76497
- );
76498
- if (output2.length > 0) {
76499
- append({
76500
- activities: [
76501
- activity(historyItem.id, "reasoning", sequence, {
76502
- input: "",
76503
- locations: [],
76504
- name: "",
76505
- output: output2,
76506
- status: "completed",
76507
- title: "Reasoning",
76508
- toolKind: ""
76509
- })
76510
- ],
76511
- content: [],
76512
- role: "assistant",
76513
- text: ""
76514
- });
76515
- sequence += 1;
76516
- }
76517
- } else if (historyItem.type === "commandExecution") {
76518
- const action = historyItem.commandActions[0]?.type ?? "execute";
76519
- append({
76520
- activities: [
76521
- activity(historyItem.id, "tool", sequence, {
76522
- input: JSON.stringify({ command: historyItem.command, cwd: historyItem.cwd }),
76523
- locations: [historyItem.cwd],
76524
- name: "",
76525
- output: JSON.stringify({
76526
- formatted_output: historyItem.aggregatedOutput ?? "",
76527
- ...historyItem.exitCode == null ? {} : { exit_code: historyItem.exitCode }
76528
- }),
76529
- status: toolStatus(historyItem.status),
76530
- title: historyItem.command,
76531
- toolKind: action
76532
- })
76533
- ],
76534
- content: [],
76535
- role: "assistant",
76536
- text: ""
76537
- });
76538
- sequence += 1;
76539
- } else if (historyItem.type === "fileChange") {
76540
- const paths = historyItem.changes.map((change) => change.path);
76541
- const content = historyItem.changes.map(
76542
- (change) => diffContent(change.path, change.diff)
76543
- );
76544
- append({
76545
- activities: [
76546
- activity(historyItem.id, "tool", sequence, {
76547
- input: JSON.stringify({ changes: paths }),
76548
- locations: paths,
76549
- name: "",
76550
- output: "",
76551
- status: toolStatus(historyItem.status),
76552
- title: paths.join(", "),
76553
- toolKind: "edit"
76554
- })
76555
- ].map((entry) => ({ ...entry, content })),
76556
- content: [],
76557
- role: "assistant",
76558
- text: ""
76559
- });
76560
- sequence += 1;
76561
- } else if (historyItem.type === "mcpToolCall") {
76562
- append({
76563
- activities: [
76564
- activity(historyItem.id, "tool", sequence, {
76565
- input: formatted(historyItem.arguments),
76566
- locations: [],
76567
- name: historyItem.tool,
76568
- output: formatted(historyItem.error ?? historyItem.result),
76569
- status: toolStatus(historyItem.status),
76570
- title: `${historyItem.server}/${historyItem.tool}`,
76571
- toolKind: "other"
76572
- })
76573
- ],
76574
- content: [],
76575
- role: "assistant",
76576
- text: ""
76577
- });
76578
- sequence += 1;
76579
- } else if (historyItem.type === "dynamicToolCall") {
76580
- append({
76581
- activities: [
76582
- activity(historyItem.id, "tool", sequence, {
76583
- input: formatted(historyItem.arguments),
76584
- locations: [],
76585
- name: historyItem.tool,
76586
- output: formatted(historyItem.contentItems),
76587
- status: toolStatus(historyItem.status),
76588
- title: historyItem.namespace == null ? historyItem.tool : `${historyItem.namespace}/${historyItem.tool}`,
76589
- toolKind: "other"
76590
- })
76591
- ],
76592
- content: [],
76593
- role: "assistant",
76594
- text: ""
76595
- });
76596
- sequence += 1;
76597
- } else if (historyItem.type === "plan") {
76598
- append({
76599
- activities: [
76600
- activity(historyItem.id, "plan", sequence, {
76601
- input: "",
76602
- locations: [],
76603
- name: "",
76604
- output: historyItem.text,
76605
- status: "completed",
76606
- title: "Plan",
76607
- toolKind: ""
76608
- })
76609
- ],
76610
- content: [],
76611
- role: "assistant",
76612
- text: ""
76613
- });
76614
- sequence += 1;
76615
- }
76616
- }
76617
- if (turn.error != null) {
76618
- append({
76619
- activities: [
76620
- activity(`agent-error-${sequence.toString()}`, "tool", sequence, {
76621
- input: "",
76622
- locations: [],
76623
- name: "",
76624
- output: errorMessage(turn.error),
76625
- status: "failed",
76626
- title: "Agent error",
76627
- toolKind: "other"
76628
- })
76629
- ],
76630
- content: [],
76631
- role: "assistant",
76632
- text: ""
76633
- });
76634
- }
76635
- if (assistantMessageIndex !== null) {
76636
- const assistant = messages[assistantMessageIndex];
76637
- if (assistant?.role === "assistant") {
76638
- characters -= messageSize(assistant);
76639
- const updated = {
76640
- ...assistant,
76641
- ...outcome === void 0 ? {} : { outcome }
76642
- };
76643
- const fitted = fitHistoryMessage(updated, turnMessageCharacterLimit);
76644
- truncated ||= fitted.truncated;
76645
- messages[assistantMessageIndex] = fitted.message;
76646
- characters += messageSize(fitted.message);
76647
- }
76648
- } else if (outcome !== void 0) {
76649
- const message = {
76650
- activities: [],
76651
- content: [],
76652
- role: "assistant",
76653
- ...outcome === void 0 ? {} : { outcome },
76654
- text: ""
76655
- };
76656
- const fitted = fitHistoryMessage(message, turnMessageCharacterLimit);
76657
- truncated ||= fitted.truncated;
76658
- messages.push(fitted.message);
76659
- characters += messageSize(fitted.message);
76660
- }
76661
- while (messages.length > SESSION_HISTORY_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
76662
- const removed = messages.shift();
76663
- if (removed !== void 0) {
76664
- characters -= messageSize(removed);
76665
- }
76666
- truncated = true;
76667
- }
76668
- }
76669
- return {
76670
- nativeSessionId: thread.id,
76671
- cwd: thread.cwd,
76672
- history: {
76673
- status: "available",
76674
- messages,
76675
- truncated,
76676
- coveredCommandIds,
76677
- coveredMessageIds: []
76678
- }
76679
- };
76680
- }
76681
- async function readCodexHistoryWithOptions(agent, cwd, nativeSessionId, signal, options) {
76682
- signal.throwIfAborted();
76683
- nativeSessionIdSchema.parse(nativeSessionId);
76684
- if (agent.id !== "codex" || !await revalidateExecutable(agent.agentIdentity)) {
76685
- throw new AcpExecutionError(
76686
- "The local Codex executable changed. Restart Mobius to discover it again.",
76687
- {},
76688
- "agent_executable_changed"
76689
- );
76690
- }
76691
- signal.throwIfAborted();
76692
- const launch = executableLaunch2(agent.agentIdentity.realPath, ["app-server"]);
76693
- const child = spawn8(launch.command, [...launch.arguments], {
76694
- cwd,
76695
- env: { ...process.env, ...agent.environment },
76696
- ...platformSpawnOptions,
76697
- shell: false,
76698
- stdio: ["pipe", "pipe", "ignore"]
76699
- });
76700
- const response = Promise.withResolvers();
76701
- let state = { kind: "initializing", requestId: 1 };
76702
- const seenCursors = /* @__PURE__ */ new Set();
76703
- let pendingBytes = 0;
76704
- let pendingFragments = [];
76705
- const fail = (cause) => response.reject(
76706
- cause instanceof AcpExecutionError ? cause : new AcpExecutionError(
76707
- "Saved Codex history could not be read.",
76708
- { cause },
76709
- "native_history_unavailable"
76710
- )
76711
- );
76712
- const send2 = (message) => {
76713
- child.stdin.write(`${JSON.stringify(message)}
76714
- `);
76715
- };
76716
- const onData = (chunk) => {
76717
- try {
76718
- let cursor = 0;
76719
- let newline = chunk.indexOf("\n");
76720
- while (newline >= 0) {
76721
- const fragment = chunk.slice(cursor, newline);
76722
- const lineBytes = pendingBytes + Buffer.byteLength(fragment);
76723
- if (lineBytes > 32 * 1024 * 1024) {
76724
- throw new AcpExecutionError(
76725
- "This saved conversation is too large to preview.",
76726
- {},
76727
- "native_history_too_large"
76728
- );
76729
- }
76730
- const line = pendingFragments.length === 0 ? fragment : [...pendingFragments, fragment].join("");
76731
- pendingBytes = 0;
76732
- pendingFragments = [];
76733
- cursor = newline + 1;
76734
- newline = chunk.indexOf("\n", cursor);
76735
- if (line.trim().length === 0) {
76736
- continue;
76737
- }
76738
- const value = JSON.parse(line);
76739
- const message = responseSchema.parse(value);
76740
- if (!("id" in message)) {
76741
- continue;
76742
- }
76743
- if (message.id !== state.requestId) {
76744
- throw new AcpExecutionError(
76745
- "Codex returned an invalid history response.",
76746
- {},
76747
- "invalid_native_session_response"
76748
- );
76749
- }
76750
- if ("error" in message) {
76751
- fail(
76752
- new AcpExecutionError(
76753
- "Saved Codex history could not be read.",
76754
- { cause: new CodexHistoryResponseError(message.error) },
76755
- "native_history_unavailable"
76756
- )
76757
- );
76758
- return;
76759
- }
76760
- switch (state.kind) {
76761
- case "initializing":
76762
- state = { kind: "metadata", requestId: 2 };
76763
- send2({ method: "initialized", params: {} });
76764
- send2({
76765
- id: state.requestId,
76766
- method: "thread/read",
76767
- params: { threadId: nativeSessionId, includeTurns: false }
76768
- });
76769
- break;
76770
- case "metadata": {
76771
- const { thread } = threadSchema.parse(message.result);
76772
- state = { kind: "turns", requestId: 3, thread, pages: [] };
76773
- send2({
76774
- id: state.requestId,
76775
- method: "thread/turns/list",
76776
- params: {
76777
- threadId: nativeSessionId,
76778
- limit: SESSION_HISTORY_PREVIEW_TURN_LIMIT,
76779
- sortDirection: "desc",
76780
- itemsView: "full"
76781
- }
76782
- });
76783
- break;
76784
- }
76785
- case "turns": {
76786
- const page = turnsSchema.parse(message.result);
76787
- const pages = [...state.pages, ...page.data];
76788
- const maxTurns = SESSION_HISTORY_MESSAGE_LIMIT;
76789
- if (page.nextCursor == null || pages.length >= maxTurns) {
76790
- response.resolve(
76791
- decodeHistory(
76792
- state.thread,
76793
- {
76794
- data: pages.slice(0, maxTurns),
76795
- nextCursor: page.nextCursor
76796
- },
76797
- options
76798
- )
76799
- );
76800
- return;
76801
- }
76802
- if (page.data.length === 0 || seenCursors.has(page.nextCursor)) {
76803
- throw new AcpExecutionError(
76804
- "Codex repeated a history page cursor.",
76805
- {},
76806
- "invalid_native_session_response"
76807
- );
76808
- }
76809
- seenCursors.add(page.nextCursor);
76810
- state = { kind: "turns", requestId: state.requestId + 1, thread: state.thread, pages };
76811
- send2({
76812
- id: state.requestId,
76813
- method: "thread/turns/list",
76814
- params: {
76815
- threadId: nativeSessionId,
76816
- cursor: page.nextCursor,
76817
- limit: Math.min(SESSION_HISTORY_PREVIEW_TURN_LIMIT, maxTurns - pages.length),
76818
- sortDirection: "desc",
76819
- itemsView: "full"
76820
- }
76821
- });
76822
- break;
76823
- }
76824
- default: {
76825
- const unhandled = state;
76826
- throw new Error(`Unknown history read state: ${String(unhandled)}`);
76827
- }
76828
- }
76829
- }
76830
- const remainder = chunk.slice(cursor);
76831
- if (remainder.length > 0) {
76832
- pendingBytes += Buffer.byteLength(remainder);
76833
- if (pendingBytes > 32 * 1024 * 1024) {
76834
- throw new AcpExecutionError(
76835
- "This saved conversation is too large to preview.",
76836
- {},
76837
- "native_history_too_large"
76838
- );
76839
- }
76840
- pendingFragments.push(remainder);
76841
- }
76842
- } catch (cause) {
76843
- fail(cause);
76844
- }
76845
- };
76846
- const abort = () => response.reject(signal.reason);
76847
- const onExit = () => fail(
76848
- new AcpExecutionError(
76849
- "Codex stopped before its saved history was available.",
76850
- {},
76851
- "native_history_unavailable"
76852
- )
76853
- );
76854
- const timeout = setTimeout(
76855
- () => fail(new AcpExecutionError("Reading saved Codex history timed out.", {}, "native_history_timeout")),
76856
- 6e4
76857
- );
76858
- child.stdout.setEncoding("utf8");
76859
- child.stdout.on("data", onData);
76860
- child.stdin.on("error", fail);
76861
- child.on("error", fail);
76862
- child.on("exit", onExit);
76863
- signal.addEventListener("abort", abort, { once: true });
76864
- try {
76865
- if (signal.aborted) {
76866
- abort();
76867
- } else {
76868
- send2({
76869
- id: 1,
76870
- method: "initialize",
76871
- params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
76872
- });
76873
- }
76874
- const snapshot = await response.promise;
76875
- return {
76876
- ...snapshot,
76877
- history: await embedLocalHistoryImages(snapshot.history, signal)
76878
- };
76879
- } finally {
76880
- clearTimeout(timeout);
76881
- signal.removeEventListener("abort", abort);
76882
- child.stdout.removeListener("data", onData);
76883
- if (child.pid !== void 0) {
76884
- await stopProcessTree(child);
76885
- }
76886
- child.stdin.removeListener("error", fail);
76887
- child.removeListener("error", fail);
76888
- child.removeListener("exit", onExit);
76889
- }
76890
- }
76891
- var readCodexFullHistory = async (agent, cwd, nativeSessionId, signal, nativeTurn) => await readCodexHistoryWithOptions(agent, cwd, nativeSessionId, signal, {
76892
- ...nativeTurn === void 0 ? {} : { nativeTurn }
76893
- });
76894
-
76895
- // src/acp/native-history/codex/native-history-events.ts
76896
- import { createHash as createHash2 } from "node:crypto";
76897
- function toolKind(value) {
76898
- switch (value) {
76899
- case "read":
76900
- case "edit":
76901
- case "delete":
76902
- case "move":
76903
- case "search":
76904
- case "execute":
76905
- case "think":
76906
- case "fetch":
76907
- case "switch_mode":
76908
- case "other":
76909
- return value;
76910
- default:
76911
- return "other";
76912
- }
76913
- }
76914
- function toolStatus2(value) {
76915
- switch (value) {
76916
- case "pending":
76917
- return "pending";
76918
- case "running":
76919
- case "in_progress":
76920
- return "in_progress";
76921
- case "completed":
76922
- return "completed";
76923
- default:
76924
- return "failed";
76925
- }
76926
- }
76927
- function activityEvent(activity2) {
76928
- if (activity2.activityType === "reasoning") {
76929
- return {
76930
- payload: {
76931
- content: { text: activity2.output, type: "text" },
76932
- messageId: activity2.activityId,
76933
- sessionUpdate: "agent_thought_chunk"
76934
- },
76935
- type: "acp"
76936
- };
76937
- }
76938
- return {
76939
- payload: {
76940
- content: activity2.content,
76941
- kind: toolKind(activity2.toolKind),
76942
- locations: activity2.locations.map((path7) => ({ path: path7 })),
76943
- rawInput: activity2.input,
76944
- rawOutput: activity2.output,
76945
- sessionUpdate: "tool_call",
76946
- status: toolStatus2(activity2.status),
76947
- title: activity2.title,
76948
- toolCallId: activity2.activityId,
76949
- ...activity2.name.length === 0 ? {} : { name: activity2.name }
76950
- },
76951
- type: "acp"
76952
- };
76953
- }
76954
- function contentEvent(sessionUpdate, messageId, content) {
76955
- return { payload: { content, messageId, sessionUpdate }, type: "acp" };
76956
- }
76957
- function historyEvents(history) {
76958
- return history.messages.flatMap((message, index2) => {
76959
- const messageId = `native-history-${index2.toString()}`;
76960
- const sessionUpdate = message.role === "user" ? "user_message_chunk" : "agent_message_chunk";
76961
- const images = (message.images ?? []).map(
76962
- (image) => contentEvent(sessionUpdate, messageId, {
76963
- data: image.data,
76964
- mimeType: image.mimeType,
76965
- type: "image"
76966
- })
76967
- );
76968
- const text2 = message.text.length === 0 ? [] : [contentEvent(sessionUpdate, messageId, { text: message.text, type: "text" })];
76969
- if (message.role === "user") {
76970
- return [...images, ...text2];
76971
- }
76972
- const activities = message.activities.map(activityEvent);
76973
- const content = message.content.map((block) => contentEvent(sessionUpdate, messageId, block));
76974
- return [...activities, ...content, ...images, ...text2];
76975
- });
76976
- }
76977
- function nativeHistoryEvents(sessionId, nativeSessionId, history, eventLimit, cursor, eventStore) {
76978
- const events = historyEvents(history);
76979
- const generationId = createHash2("sha256").update(nativeSessionId).update("\0").update(JSON.stringify(events)).digest("hex");
76980
- eventStore.materialize(sessionId, generationId, events);
76981
- return eventStore.page(sessionId, eventLimit, cursor);
76982
- }
76294
+ // src/acp/adapter/codex/adapter.ts
76295
+ import { createHash as createHash4 } from "node:crypto";
76983
76296
 
76984
76297
  // src/storage/session/temporary-session-event-cache.ts
76985
76298
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
@@ -82189,13 +81502,85 @@ function openPreviewEventCache() {
82189
81502
  }
82190
81503
  }
82191
81504
 
81505
+ // src/acp/adapter/codex/tool-event.ts
81506
+ var toolEventSchema = external_exports.looseObject({
81507
+ sessionUpdate: external_exports.enum(["tool_call", "tool_call_update"]),
81508
+ rawInput: external_exports.unknown().optional(),
81509
+ rawOutput: external_exports.unknown().optional()
81510
+ });
81511
+ var TRUNCATED_TOOL_PAYLOAD_CHARACTER_LIMIT = 32768;
81512
+ var MAX_TOOL_PAYLOAD_DEPTH = 16;
81513
+ function payloadText(value) {
81514
+ let text2;
81515
+ try {
81516
+ text2 = JSON.stringify(value) ?? "";
81517
+ } catch {
81518
+ text2 = "Tool payload could not be represented as JSON.";
81519
+ }
81520
+ return text2.slice(0, TRUNCATED_TOOL_PAYLOAD_CHARACTER_LIMIT);
81521
+ }
81522
+ function fitNesting(value, depth = 0) {
81523
+ if (typeof value !== "object" || value === null) {
81524
+ return value;
81525
+ }
81526
+ if (depth === MAX_TOOL_PAYLOAD_DEPTH && Object.keys(value).length > 0) {
81527
+ return `[truncated: nesting depth] ${payloadText(value)}`;
81528
+ }
81529
+ if (Array.isArray(value)) {
81530
+ return value.map((child) => fitNesting(child, depth + 1));
81531
+ }
81532
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, fitNesting(child, depth + 1)]));
81533
+ }
81534
+ function prepareCodexToolUpdate(update) {
81535
+ if (update.sessionUpdate !== "tool_call" && update.sessionUpdate !== "tool_call_update") {
81536
+ return update;
81537
+ }
81538
+ return {
81539
+ ...update,
81540
+ ...update.rawOutput === void 0 ? {} : { rawOutput: fitNesting(update.rawOutput) },
81541
+ ...update._meta == null ? {} : {
81542
+ _meta: Object.fromEntries(
81543
+ Object.entries(update._meta).map(([key, child]) => [key, fitNesting(child, 1)])
81544
+ )
81545
+ }
81546
+ };
81547
+ }
81548
+ function fitPayload(value) {
81549
+ if (value === void 0 || boundedJsonSchema.safeParse(value).success) {
81550
+ return value;
81551
+ }
81552
+ return { truncated: true, text: payloadText(value) };
81553
+ }
81554
+ function fitCodexToolEvent(event) {
81555
+ const decoded = toolEventSchema.safeParse(event);
81556
+ if (!decoded.success) {
81557
+ return event;
81558
+ }
81559
+ return {
81560
+ ...decoded.data,
81561
+ rawInput: fitPayload(decoded.data.rawInput),
81562
+ rawOutput: fitPayload(decoded.data.rawOutput)
81563
+ };
81564
+ }
81565
+
82192
81566
  // src/acp/adapter/codex/adapter.ts
82193
81567
  var CodexAdapter = class {
82194
81568
  #queryProcesses;
82195
81569
  #connector;
81570
+ #dependencies;
81571
+ #contentExternalizer;
82196
81572
  #previewCache = null;
82197
81573
  constructor(dependencies) {
82198
- this.#connector = new AcpSessionConnector(dependencies.contentExternalizer);
81574
+ this.#dependencies = dependencies;
81575
+ this.#contentExternalizer = {
81576
+ update: async (sessionId, update, signal) => {
81577
+ signal.throwIfAborted();
81578
+ const prepared = prepareCodexToolUpdate(update);
81579
+ signal.throwIfAborted();
81580
+ return await dependencies.contentExternalizer.update(sessionId, prepared, signal);
81581
+ }
81582
+ };
81583
+ this.#connector = new AcpSessionConnector(this.#contentExternalizer, fitCodexToolEvent);
82199
81584
  this.#queryProcesses = new AgentQueryProcesses(dependencies.processes, this.#connector);
82200
81585
  }
82201
81586
  capabilities = async (query) => await this.#queryProcesses.capabilities(query);
@@ -82209,21 +81594,73 @@ var CodexAdapter = class {
82209
81594
  }
82210
81595
  };
82211
81596
  previewSessionEvents = async (query, request) => {
82212
- const { agent, cwd, signal } = query;
81597
+ const { agent, cwd } = query;
81598
+ const signal = AbortSignal.any([query.signal, AbortSignal.timeout(6e4)]);
82213
81599
  const { sessionId } = request;
82214
- this.#previewCache ??= openPreviewEventCache();
82215
- const snapshot = await readCodexFullHistory(agent, cwd, request.nativeSessionId, signal);
82216
- if (snapshot.history.status === "unavailable") {
82217
- throw new AcpExecutionError(snapshot.history.cause.message, {}, snapshot.history.cause.code);
81600
+ signal.throwIfAborted();
81601
+ nativeSessionIdSchema.parse(request.nativeSessionId);
81602
+ if (agent.id !== "codex") {
81603
+ throw new AcpExecutionError(
81604
+ "The Codex adapter cannot preview history for another agent.",
81605
+ {},
81606
+ "agent_adapter_mismatch"
81607
+ );
82218
81608
  }
82219
- return nativeHistoryEvents(
82220
- sessionId,
82221
- request.nativeSessionId,
82222
- snapshot.history,
82223
- request.eventLimit,
82224
- request.cursor,
82225
- this.#previewCache.events
81609
+ if (!await revalidateExecutable(agent.agentIdentity)) {
81610
+ throw new AcpExecutionError(
81611
+ "The local Codex executable changed. Restart Mobius to discover it again.",
81612
+ {},
81613
+ "agent_executable_changed"
81614
+ );
81615
+ }
81616
+ this.#previewCache ??= openPreviewEventCache();
81617
+ const events = [];
81618
+ await this.#dependencies.processes.runTransient(
81619
+ signal,
81620
+ async () => {
81621
+ const client2 = new CodexAppServerClient({
81622
+ command: agent.command,
81623
+ cwd,
81624
+ environment: agent.environment,
81625
+ handlers: {
81626
+ onNotification: async () => void 0,
81627
+ onServerRequest: async () => {
81628
+ throw new AcpExecutionError(
81629
+ "Unexpected request while reading saved history",
81630
+ {},
81631
+ "invalid_native_session_response"
81632
+ );
81633
+ }
81634
+ }
81635
+ });
81636
+ return {
81637
+ client: client2,
81638
+ closeProcess: async () => {
81639
+ client2.detach();
81640
+ await stopProcessTree(client2.child());
81641
+ }
81642
+ };
81643
+ },
81644
+ async ({ client: client2 }) => {
81645
+ await client2.initialize(signal);
81646
+ return await replayCodexHistory(
81647
+ client2,
81648
+ request.nativeSessionId,
81649
+ async (update) => {
81650
+ const externalized = await this.#contentExternalizer.update(sessionId, update, signal);
81651
+ events.push({
81652
+ type: "acp",
81653
+ payload: decodeAcpSessionUpdate(JSON.stringify(fitCodexToolEvent(externalized.event)))
81654
+ });
81655
+ },
81656
+ signal
81657
+ );
81658
+ },
81659
+ async (runtime) => await runtime.closeProcess()
82226
81660
  );
81661
+ const generationId = createHash4("sha256").update(request.nativeSessionId).update("\0").update(JSON.stringify(events)).digest("hex");
81662
+ this.#previewCache.events.materialize(sessionId, generationId, events);
81663
+ return this.#previewCache.events.page(sessionId, request.eventLimit, request.cursor);
82227
81664
  };
82228
81665
  };
82229
81666
 
@@ -82262,18 +81699,6 @@ var harnessAdapters = (agent, dependencies) => {
82262
81699
 
82263
81700
  // src/acp/content/content-externalizer.ts
82264
81701
  var MAXIMUM_ENCODED_CONTENT_CHARACTERS = 4e6;
82265
- var MAXIMUM_REASONING_CHUNK_BYTES = 24 * 1024;
82266
- function reasoningTail(text2) {
82267
- if (Buffer.byteLength(text2, "utf8") <= MAXIMUM_REASONING_CHUNK_BYTES) {
82268
- return text2;
82269
- }
82270
- const bytes = Buffer.from(text2, "utf8");
82271
- let start = bytes.length - MAXIMUM_REASONING_CHUNK_BYTES;
82272
- while (start < bytes.length && (bytes.readUInt8(start) & 192) === 128) {
82273
- start += 1;
82274
- }
82275
- return bytes.toString("utf8", start);
82276
- }
82277
81702
  function decodeBase64(data) {
82278
81703
  if (data.length > MAXIMUM_ENCODED_CONTENT_CHARACTERS || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/u.test(data)) {
82279
81704
  throw new Error("The ACP embedded content is not valid bounded base64");
@@ -82469,24 +81894,7 @@ var AcpContentExternalizer = class {
82469
81894
  }
82470
81895
  update = async (sessionId, update, signal) => {
82471
81896
  switch (update.sessionUpdate) {
82472
- case "agent_thought_chunk": {
82473
- if (update.content.type === "text") {
82474
- const text2 = reasoningTail(update.content.text);
82475
- const bounded2 = { ...update, content: { ...update.content, text: text2 } };
82476
- return {
82477
- agent: bounded2,
82478
- event: {
82479
- ...bounded2,
82480
- ...text2 === update.content.text ? {} : { meta: { truncated: true } }
82481
- }
82482
- };
82483
- }
82484
- const content = await this.#content(sessionId, update.content, signal);
82485
- return {
82486
- agent: { ...update, content: content.agent },
82487
- event: { ...update, content: content.event }
82488
- };
82489
- }
81897
+ case "agent_thought_chunk":
82490
81898
  case "user_message_chunk":
82491
81899
  case "agent_message_chunk":
82492
81900
  case "compaction_summary_chunk": {
@@ -82648,7 +82056,7 @@ import { randomUUID as randomUUID10 } from "node:crypto";
82648
82056
  import { resolve as resolve14 } from "node:path";
82649
82057
 
82650
82058
  // src/storage/installation/installation-files.ts
82651
- import { createHash as createHash4, randomUUID as randomUUID9 } from "node:crypto";
82059
+ import { createHash as createHash5, randomUUID as randomUUID9 } from "node:crypto";
82652
82060
  import { mkdir as mkdir4, open as open5, readdir as readdir5, rename as rename3, unlink as unlink3, writeFile } from "node:fs/promises";
82653
82061
  import { dirname as dirname9, join as join23 } from "node:path";
82654
82062
 
@@ -82675,7 +82083,7 @@ function connectionFilePath(connectionDirectory2, connectionId2) {
82675
82083
  return join23(connectionDirectory2, `${connectionId2}.json`);
82676
82084
  }
82677
82085
  function channelIndexFilePath(installationDirectory2, channelId) {
82678
- return join23(installationDirectory2, "channels", `mci_${createHash4("sha256").update(channelId).digest("hex")}.json`);
82086
+ return join23(installationDirectory2, "channels", `mci_${createHash5("sha256").update(channelId).digest("hex")}.json`);
82679
82087
  }
82680
82088
  async function readInstallationFile(path7) {
82681
82089
  let handle;
@@ -86984,7 +86392,7 @@ async function settleAbandonedTurn(projection, operations, cancellation) {
86984
86392
  }
86985
86393
 
86986
86394
  // src/session/turn/execution-receipts.ts
86987
- import { createHash as createHash5, randomUUID as randomUUID12 } from "node:crypto";
86395
+ import { createHash as createHash6, randomUUID as randomUUID12 } from "node:crypto";
86988
86396
  var MAX_TERMINAL_RECEIPTS = 1024;
86989
86397
  function isTerminal(state) {
86990
86398
  return state === "succeeded" || state === "failed" || state === "cancelled";
@@ -87100,7 +86508,7 @@ var ExecutionReceipts = class {
87100
86508
  ];
87101
86509
  });
87102
86510
  claimExecution = (commandId, sessionId, commandJson) => {
87103
- const commandHash = createHash5("sha256").update(commandJson).digest("hex");
86511
+ const commandHash = createHash6("sha256").update(commandJson).digest("hex");
87104
86512
  let existing = this.#executions.get(commandId);
87105
86513
  const previous = this.outcome(commandId);
87106
86514
  if (existing?.sessionId === sessionId && !existing.started && previous?.type === "lifecycle-metadata" && previous.payload.kind === "prompt.failed-before-start" && previous.payload.code === "runtime_restarted") {
@@ -87453,9 +86861,9 @@ var SessionTurns = class {
87453
86861
  #bySessionId = /* @__PURE__ */ new Map();
87454
86862
  #operations;
87455
86863
  #activity;
87456
- constructor(operations, activity2 = new RuntimeTurnActivity()) {
86864
+ constructor(operations, activity = new RuntimeTurnActivity()) {
87457
86865
  this.#operations = operations;
87458
- this.#activity = activity2;
86866
+ this.#activity = activity;
87459
86867
  }
87460
86868
  acceptsPrompts = () => this.#activity.acceptsPrompts();
87461
86869
  session = (sessionId) => {
@@ -87788,7 +87196,7 @@ function buildSessionLayer(options) {
87788
87196
  }
87789
87197
 
87790
87198
  // src/session/content/external-content-store.ts
87791
- import { createHash as createHash6 } from "node:crypto";
87199
+ import { createHash as createHash7 } from "node:crypto";
87792
87200
  import { join as join27 } from "node:path";
87793
87201
 
87794
87202
  // src/storage/files/scratch-directory.ts
@@ -87912,7 +87320,7 @@ var LocalExternalContentStore = class {
87912
87320
  const active = AbortSignal.any([signal, this.#lifetime.signal]);
87913
87321
  active.throwIfAborted();
87914
87322
  const metadata = metadataSchema.parse({ kind, mediaType, name: name2 });
87915
- const key = createHash6("sha256").update(bytes).digest("hex");
87323
+ const key = createHash7("sha256").update(bytes).digest("hex");
87916
87324
  const request = `mobius-content:${kind}:${key}`;
87917
87325
  const existing = this.#entries.get(request);
87918
87326
  if (existing !== void 0 && existing.expiresAt > Date.now()) {
@@ -88777,7 +88185,7 @@ var SessionError = class extends OperationError {
88777
88185
  };
88778
88186
 
88779
88187
  // src/session/settings/discover-agent-settings.ts
88780
- import { createHash as createHash7 } from "node:crypto";
88188
+ import { createHash as createHash8 } from "node:crypto";
88781
88189
 
88782
88190
  // src/agent/settings/agent-settings-base.ts
88783
88191
  var AgentSettingsLaunchSelectionResult = class {
@@ -89095,7 +88503,7 @@ function settingsRevision(agent, reportedAgentVersion, settings, modelEffort) {
89095
88503
  unsupportedModelIds: modelEffort.unsupportedModelIds,
89096
88504
  valuesByModel: {}
89097
88505
  };
89098
- return createHash7("sha256").update(
88506
+ return createHash8("sha256").update(
89099
88507
  JSON.stringify({
89100
88508
  adapterVersion: agent.kind === "acp-adapter-process" ? agent.adapterVersion : agent.agentVersion,
89101
88509
  agentId: agent.id,
@@ -89404,35 +88812,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId, ad
89404
88812
  }
89405
88813
 
89406
88814
  // src/runtime/command/registry/history.ts
89407
- function isAgentReasoning(event) {
89408
- return event?.type === "acp" && event.payload.sessionUpdate === "agent_thought_chunk";
89409
- }
89410
- function omitAgentReasoning(events) {
89411
- const retained = [];
89412
- let previousReasoningMessageId;
89413
- for (const positioned of events) {
89414
- const { event } = positioned;
89415
- if (event.type !== "acp" || event.payload.sessionUpdate !== "agent_thought_chunk") {
89416
- previousReasoningMessageId = void 0;
89417
- retained.push(positioned);
89418
- continue;
89419
- }
89420
- const messageId = event.payload.messageId ?? null;
89421
- if (previousReasoningMessageId === void 0 || previousReasoningMessageId !== messageId) {
89422
- retained.push({
89423
- ...positioned,
89424
- event: {
89425
- ...event,
89426
- mobiusMetadata: { omitted: true },
89427
- payload: { ...event.payload, content: { text: "", type: "text" } }
89428
- }
89429
- });
89430
- }
89431
- previousReasoningMessageId = messageId;
89432
- }
89433
- return retained;
89434
- }
89435
- async function loadHistoryPage(sessionId, eventLimit, initialCursor, omitReasoning, queuedPromptRequests, load) {
88815
+ async function loadHistoryPage(sessionId, eventLimit, initialCursor, queuedPromptRequests, load) {
89436
88816
  let cursor = initialCursor;
89437
88817
  let loaded = [];
89438
88818
  let sessionGenerationId = null;
@@ -89459,9 +88839,7 @@ async function loadHistoryPage(sessionId, eventLimit, initialCursor, omitReasoni
89459
88839
  });
89460
88840
  loaded = [...events, ...loaded];
89461
88841
  sourceNextCursor = replay.nextCursor;
89462
- const visible2 = omitReasoning ? omitAgentReasoning(loaded) : loaded;
89463
- const reasoningContinuesBeforePage = sourceNextCursor !== null && isAgentReasoning(loaded[0]?.event);
89464
- if (visible2.length >= eventLimit && !reasoningContinuesBeforePage) {
88842
+ if (loaded.length >= eventLimit) {
89465
88843
  break;
89466
88844
  }
89467
88845
  cursor = sourceNextCursor;
@@ -89469,8 +88847,7 @@ async function loadHistoryPage(sessionId, eventLimit, initialCursor, omitReasoni
89469
88847
  if (sessionGenerationId === null || throughPosition === null) {
89470
88848
  throw new SessionError("session_history_unavailable", "The Session history is unavailable");
89471
88849
  }
89472
- const visible = omitReasoning ? omitAgentReasoning(loaded) : loaded;
89473
- const orderedEvents = visible.slice(-eventLimit);
88850
+ const orderedEvents = loaded.slice(-eventLimit);
89474
88851
  const nextCursor = orderedEvents[0]?.cursor ?? null;
89475
88852
  return {
89476
88853
  events: {
@@ -89512,7 +88889,6 @@ async function executeSessionHistoryPageLoad(socket, command, config2, resolveAg
89512
88889
  command.sessionId,
89513
88890
  command.eventLimit,
89514
88891
  command.cursor,
89515
- command.omit?.includes("agent-reasoning") === true,
89516
88892
  recovery.queuedPromptRequests,
89517
88893
  async (eventLimit, cursor) => await sessions.loadSessionEvents(loadOptions, eventLimit, cursor)
89518
88894
  );
@@ -89559,7 +88935,6 @@ async function executeSessionPreviewHistoryPageLoad(socket, command, config2, re
89559
88935
  command.sessionId,
89560
88936
  command.eventLimit,
89561
88937
  command.cursor,
89562
- command.omit?.includes("agent-reasoning") === true,
89563
88938
  [],
89564
88939
  async (eventLimit, cursor) => await sessions.previewNativeSessionEvents(loadOptions, command.sessionId, eventLimit, cursor)
89565
88940
  );
@@ -90292,7 +89667,7 @@ async function executePrompt({
90292
89667
  }
90293
89668
 
90294
89669
  // src/runtime/relay/artifact-download.ts
90295
- import { createHash as createHash8 } from "node:crypto";
89670
+ import { createHash as createHash9 } from "node:crypto";
90296
89671
  import { fetch as fetch4 } from "undici";
90297
89672
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
90298
89673
  function downloadUrl(config2, artifact) {
@@ -90380,7 +89755,7 @@ async function downloadPromptArtifact(config2, artifact, signal) {
90380
89755
  );
90381
89756
  }
90382
89757
  const bytes = await responseBytes(response, artifact.byteLength, requestSignal);
90383
- if (createHash8("sha256").update(bytes).digest("hex") !== artifact.sha256) {
89758
+ if (createHash9("sha256").update(bytes).digest("hex") !== artifact.sha256) {
90384
89759
  throw new PromptArtifactError(
90385
89760
  "artifact_integrity_failed",
90386
89761
  "The prompt artifact failed integrity validation"