@moxt-ai/mobius 0.0.307 → 0.0.309

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 (51) 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 +728 -1349
  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 +666 -1289
  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/dist/util/filesystem/private-path.js +4 -2
  37. package/dist/util/filesystem/private-path.js.map +2 -2
  38. package/dist/util/platform/windows.d.ts.map +1 -1
  39. package/dist/util/platform/windows.js +6 -2
  40. package/dist/util/platform/windows.js.map +1 -1
  41. package/dist/util/process/executable.js +4 -2
  42. package/dist/util/process/executable.js.map +2 -2
  43. package/package.json +2 -2
  44. package/dist/acp/native-history/codex/codex-history.d.ts +0 -17
  45. package/dist/acp/native-history/codex/codex-history.d.ts.map +0 -1
  46. package/dist/acp/native-history/codex/codex-history.js +0 -661
  47. package/dist/acp/native-history/codex/codex-history.js.map +0 -1
  48. package/dist/acp/native-history/codex/native-history-events.d.ts +0 -8
  49. package/dist/acp/native-history/codex/native-history-events.d.ts.map +0 -1
  50. package/dist/acp/native-history/codex/native-history-events.js +0 -92
  51. package/dist/acp/native-history/codex/native-history-events.js.map +0 -1
package/dist/runtime.js CHANGED
@@ -499,6 +499,7 @@ function terminateProcess2(child, signal) {
499
499
  }
500
500
  var windowsPermissions = `
501
501
  $ErrorActionPreference = 'Stop'
502
+ $ProgressPreference = 'SilentlyContinue'
502
503
  Import-Module (Join-Path $PSHOME 'Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1')
503
504
  $item = Get-Item -LiteralPath $env:MOBIUS_PERMISSION_PATH -Force
504
505
  if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'Unsafe path' }
@@ -520,6 +521,7 @@ if ($env:MOBIUS_PERMISSION_PRIVATE -eq '1') {
520
521
  Set-Acl -LiteralPath $item.FullName -AclObject $private
521
522
  }
522
523
  `;
524
+ var windowsPermissionsTimeoutMs = 3e4;
523
525
  async function validatePathPermissions(path7, _directory, privateAccess, signal) {
524
526
  signal.throwIfAborted();
525
527
  const systemRoot = environmentValue(process.env, "SystemRoot");
@@ -543,8 +545,8 @@ async function validatePathPermissions(path7, _directory, privateAccess, signal)
543
545
  MOBIUS_PERMISSION_PRIVATE: privateAccess ? "1" : "0"
544
546
  },
545
547
  windowsHide: true,
546
- signal: AbortSignal.any([signal, AbortSignal.timeout(1e4)]),
547
- timeout: 1e4,
548
+ signal: AbortSignal.any([signal, AbortSignal.timeout(windowsPermissionsTimeoutMs)]),
549
+ timeout: windowsPermissionsTimeoutMs,
548
550
  maxBuffer: 16384
549
551
  }
550
552
  );
@@ -21783,8 +21785,6 @@ function encodeSessionPromptDispositionCommand(message) {
21783
21785
  var NATIVE_SESSION_REQUEST_KIND = "native.session.request";
21784
21786
  var NATIVE_SESSION_RESULT_KIND = "native.session.result";
21785
21787
  var NATIVE_SESSION_CANCEL_KIND = "native.session.cancel";
21786
- var SESSION_HISTORY_CHARACTER_LIMIT = 256e3;
21787
- var SESSION_HISTORY_MESSAGE_LIMIT = 1e3;
21788
21788
  var envelope = {
21789
21789
  requestId: identifierStringSchema,
21790
21790
  sessionId: identifierStringSchema
@@ -22247,6 +22247,7 @@ var sessionEventOmissionSchema = external_exports.literal("agent-reasoning");
22247
22247
  var nativeEventPageRequestSchema = external_exports.object({
22248
22248
  cursor: external_exports.string().min(1).max(512).nullable(),
22249
22249
  eventLimit: external_exports.number().int().min(1).max(1e4),
22250
+ // Legacy callers may still send this option; readers must ignore it.
22250
22251
  omit: external_exports.array(sessionEventOmissionSchema).max(1).readonly().optional()
22251
22252
  }).readonly();
22252
22253
  var queuedPromptRequestEventLogSchema = external_exports.object({
@@ -22294,6 +22295,7 @@ var SESSION_PREVIEW_HISTORY_PAGE_LOADED_KIND = "session.preview-history.page.loa
22294
22295
  var pageRequestFields = {
22295
22296
  cursor: external_exports.string().min(1).max(512).nullable(),
22296
22297
  eventLimit: external_exports.number().int().min(1).max(1e4),
22298
+ // Decode old clients without rejecting their request; omission has no effect.
22297
22299
  omit: external_exports.array(sessionEventOmissionSchema).max(1).readonly().optional(),
22298
22300
  requestId: identifierStringSchema,
22299
22301
  sessionId: identifierStringSchema
@@ -22691,7 +22693,7 @@ import { fetch as fetch3 } from "undici";
22691
22693
  // package.json
22692
22694
  var package_default = {
22693
22695
  name: "@moxt-ai/mobius",
22694
- version: "0.0.307",
22696
+ version: "0.0.309",
22695
22697
  description: "Mobius CLI for pairing and running local AI agent services.",
22696
22698
  type: "module",
22697
22699
  bin: {
@@ -62173,11 +62175,11 @@ var SessionModeManager = class {
62173
62175
  }
62174
62176
  return modes;
62175
62177
  }
62176
- async trySyncMode(query, mode, errorMessage2) {
62178
+ async trySyncMode(query, mode, errorMessage) {
62177
62179
  try {
62178
62180
  await query.setPermissionMode(mode);
62179
62181
  } catch (error62) {
62180
- this.options.logError(errorMessage2, error62);
62182
+ this.options.logError(errorMessage, error62);
62181
62183
  }
62182
62184
  }
62183
62185
  };
@@ -66838,6 +66840,9 @@ import {
66838
66840
  PROTOCOL_VERSION
66839
66841
  } from "@agentclientprotocol/sdk";
66840
66842
 
66843
+ // src/acp/harness/codex/app-server-client.ts
66844
+ import { spawn as spawn4 } from "node:child_process";
66845
+
66841
66846
  // src/infra/operation-error.ts
66842
66847
  var OperationError = class extends Error {
66843
66848
  code;
@@ -66875,9 +66880,6 @@ var AcpConfigurationValueUnavailableError = class extends AcpExecutionError {
66875
66880
  }
66876
66881
  };
66877
66882
 
66878
- // src/acp/harness/codex/app-server-client.ts
66879
- import { spawn as spawn4 } from "node:child_process";
66880
-
66881
66883
  // src/acp/agent/in-process-endpoint.ts
66882
66884
  function acpEndpointTerminationError(termination) {
66883
66885
  switch (termination.kind) {
@@ -67129,6 +67131,7 @@ var threadStartResponseSchema = external_exports.object({
67129
67131
  var threadTurnSchema = external_exports.object({
67130
67132
  id: boundedText(256).optional(),
67131
67133
  status: turnStatusSchema.optional(),
67134
+ error: external_exports.object({ message: external_exports.string().transform((message) => message.slice(0, 4096)) }).nullish(),
67132
67135
  items: external_exports.array(external_exports.unknown()).max(1e5)
67133
67136
  });
67134
67137
  var threadTurnsSchema = external_exports.array(threadTurnSchema).max(1e5);
@@ -67596,12 +67599,12 @@ function presentToolItem(item) {
67596
67599
  };
67597
67600
  }
67598
67601
  if (item.type === "collabAgentToolCall") {
67599
- const spawn9 = item.tool === "spawnAgent";
67602
+ const spawn8 = item.tool === "spawnAgent";
67600
67603
  return {
67601
67604
  content: [],
67602
67605
  kind: "other",
67603
67606
  locations: [],
67604
- rawInput: spawn9 ? {
67607
+ rawInput: spawn8 ? {
67605
67608
  model: item.model,
67606
67609
  prompt: item.prompt,
67607
67610
  reasoningEffort: item.reasoningEffort,
@@ -67609,10 +67612,10 @@ function presentToolItem(item) {
67609
67612
  } : { receiverThreadIds: item.receiverThreadIds, senderThreadId: item.senderThreadId },
67610
67613
  rawOutput: {
67611
67614
  agentsStates: item.agentsStates,
67612
- ...spawn9 ? { receiverThreadIds: item.receiverThreadIds } : {}
67615
+ ...spawn8 ? { receiverThreadIds: item.receiverThreadIds } : {}
67613
67616
  },
67614
67617
  status: collaborationStatus(item.status),
67615
- title: spawn9 ? "Dispatch subagent" : "Wait for subagent"
67618
+ title: spawn8 ? "Dispatch subagent" : "Wait for subagent"
67616
67619
  };
67617
67620
  }
67618
67621
  if (item.type === "subAgentActivity" && item.kind === "started") {
@@ -67922,6 +67925,277 @@ var CodexBorrowedAcpAgent = class {
67922
67925
  };
67923
67926
  };
67924
67927
 
67928
+ // src/acp/harness/codex/history.ts
67929
+ import { createHash } from "node:crypto";
67930
+
67931
+ // src/acp/content/raster.ts
67932
+ import { basename as basename4, isAbsolute as isAbsolute9, normalize } from "node:path";
67933
+ import { fileURLToPath } from "node:url";
67934
+
67935
+ // src/storage/files/local-files.ts
67936
+ import { createReadStream as createReadStream2 } from "node:fs";
67937
+ import { mkdir as mkdir3, open as open4, readdir as readdir4, readFile as readFile5, realpath as realpath6, stat as stat5 } from "node:fs/promises";
67938
+ function entryKind(entry) {
67939
+ if (entry.isDirectory()) {
67940
+ return "directory";
67941
+ }
67942
+ if (entry.isFile()) {
67943
+ return "file";
67944
+ }
67945
+ if (entry.isSymbolicLink()) {
67946
+ return "symbolic-link";
67947
+ }
67948
+ if (entry.isBlockDevice() || entry.isCharacterDevice()) {
67949
+ return "device";
67950
+ }
67951
+ if (entry.isFIFO()) {
67952
+ return "fifo";
67953
+ }
67954
+ return entry.isSocket() ? "socket" : "unknown";
67955
+ }
67956
+ async function canonicalPath(path7) {
67957
+ return await realpath6(path7);
67958
+ }
67959
+ async function readPathMetadata(path7) {
67960
+ const metadata = await stat5(path7);
67961
+ return {
67962
+ kind: metadata.isDirectory() ? "directory" : metadata.isFile() ? "file" : "other",
67963
+ modifiedAt: metadata.mtime,
67964
+ modifiedMilliseconds: metadata.mtimeMs,
67965
+ size: metadata.size
67966
+ };
67967
+ }
67968
+ async function listDirectory(path7) {
67969
+ const entries = await readdir4(path7, { withFileTypes: true });
67970
+ return entries.map((entry) => ({ kind: entryKind(entry), name: entry.name }));
67971
+ }
67972
+ async function ensurePrivateDirectory(path7) {
67973
+ await mkdir3(path7, { mode: 448, recursive: true });
67974
+ }
67975
+ async function ensureCanonicalDirectory(path7) {
67976
+ await ensurePrivateDirectory(path7);
67977
+ const resolved = await realpath6(path7);
67978
+ return (await stat5(resolved)).isDirectory() ? resolved : null;
67979
+ }
67980
+ async function readFileStart(path7, byteLength) {
67981
+ const bytes = new Uint8Array(byteLength);
67982
+ const handle = await open4(path7, "r");
67983
+ try {
67984
+ await handle.read(bytes, 0, byteLength, 0);
67985
+ } finally {
67986
+ await handle.close();
67987
+ }
67988
+ return bytes;
67989
+ }
67990
+ async function readFileBytes(path7) {
67991
+ return await readFile5(path7);
67992
+ }
67993
+ function readFileChunks(path7, chunkBytes, signal) {
67994
+ return createReadStream2(path7, { highWaterMark: chunkBytes, signal });
67995
+ }
67996
+
67997
+ // src/acp/content/raster.ts
67998
+ var MAX_LOCAL_RASTER_BYTES = 128 * 1024 * 1024;
67999
+ var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
68000
+ var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
68001
+ var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
68002
+ var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
68003
+ var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
68004
+ var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
68005
+ var LocalRasterImage = class {
68006
+ mimeType;
68007
+ name;
68008
+ sourceUri;
68009
+ constructor(name2, mimeType, sourceUri) {
68010
+ this.mimeType = mimeType;
68011
+ this.name = name2;
68012
+ this.sourceUri = sourceUri;
68013
+ }
68014
+ base64 = async () => Buffer.from(await readFileBytes(this.sourceUri)).toString("base64");
68015
+ };
68016
+ function startsWith(bytes, signature, offset = 0) {
68017
+ if (bytes.byteLength < offset + signature.byteLength) {
68018
+ return false;
68019
+ }
68020
+ return signature.every((value, index2) => bytes[offset + index2] === value);
68021
+ }
68022
+ function sniffRasterMime(bytes) {
68023
+ if (startsWith(bytes, PNG_SIGNATURE)) {
68024
+ return "image/png";
68025
+ }
68026
+ if (startsWith(bytes, JPEG_SIGNATURE)) {
68027
+ return "image/jpeg";
68028
+ }
68029
+ if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
68030
+ return "image/gif";
68031
+ }
68032
+ if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
68033
+ return "image/webp";
68034
+ }
68035
+ return null;
68036
+ }
68037
+ async function resolveCanonicalPath(requested, signal) {
68038
+ signal.throwIfAborted();
68039
+ if (!isAbsolute9(requested) || requested.includes("\0") || normalize(requested) !== requested) {
68040
+ return null;
68041
+ }
68042
+ try {
68043
+ const target = await canonicalPath(requested);
68044
+ signal.throwIfAborted();
68045
+ if (!isAbsolute9(target) || normalize(target) !== target) {
68046
+ return null;
68047
+ }
68048
+ return target;
68049
+ } catch (cause) {
68050
+ signal.throwIfAborted();
68051
+ if (cause instanceof Error && cause.name === "AbortError") {
68052
+ throw cause;
68053
+ }
68054
+ return null;
68055
+ }
68056
+ }
68057
+ function parseLocalImageUri(uri) {
68058
+ const trimmed = uri.trim();
68059
+ if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
68060
+ return null;
68061
+ }
68062
+ if (trimmed.startsWith("data:")) {
68063
+ return null;
68064
+ }
68065
+ if (trimmed.startsWith("file:")) {
68066
+ try {
68067
+ const url2 = new URL(trimmed);
68068
+ if (url2.protocol !== "file:" || url2.host.length > 0) {
68069
+ return null;
68070
+ }
68071
+ return fileURLToPath(url2);
68072
+ } catch {
68073
+ return null;
68074
+ }
68075
+ }
68076
+ if (!isAbsolute9(trimmed) && /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
68077
+ return null;
68078
+ }
68079
+ return trimmed;
68080
+ }
68081
+ async function readLocalRaster(uri, signal) {
68082
+ signal.throwIfAborted();
68083
+ const requested = parseLocalImageUri(uri);
68084
+ if (requested === null) {
68085
+ return null;
68086
+ }
68087
+ const target = await resolveCanonicalPath(requested, signal);
68088
+ if (target === null) {
68089
+ return null;
68090
+ }
68091
+ const targetMetadata = await readPathMetadata(target);
68092
+ signal.throwIfAborted();
68093
+ if (targetMetadata.kind !== "file" || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
68094
+ return null;
68095
+ }
68096
+ const header = await readFileStart(target, 12);
68097
+ signal.throwIfAborted();
68098
+ const mimeType = sniffRasterMime(header);
68099
+ if (mimeType === null) {
68100
+ return null;
68101
+ }
68102
+ return new LocalRasterImage(basename4(target) || "Image", mimeType, target);
68103
+ }
68104
+
68105
+ // src/acp/native-history/codex/history-images.ts
68106
+ var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
68107
+ var DATA_IMAGE_HEADER = /^data:(image\/[a-z+]+);base64,/;
68108
+ var BASE_64 = /^[A-Za-z0-9+/]*={0,2}$/;
68109
+ var SESSION_HISTORY_IMAGE_CHARACTER_LIMIT = 4e6;
68110
+ function isRasterMime(value) {
68111
+ return value === "image/png" || value === "image/jpeg" || value === "image/gif" || value === "image/webp";
68112
+ }
68113
+ function parseNativeHistoryImage(uri) {
68114
+ const header = DATA_IMAGE_HEADER.exec(uri);
68115
+ if (header === null) {
68116
+ return null;
68117
+ }
68118
+ const mimeType = header[1] ?? "";
68119
+ const data = uri.slice(header[0].length);
68120
+ if (!isRasterMime(mimeType) || data.length < 4 || data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
68121
+ return null;
68122
+ }
68123
+ if (data.length % 4 !== 0 || !BASE_64.test(data)) {
68124
+ return null;
68125
+ }
68126
+ return { data, mimeType, name: "" };
68127
+ }
68128
+ async function embedLocalHistoryImages(history, signal) {
68129
+ if (history.status !== "available") {
68130
+ return history;
68131
+ }
68132
+ const messages = [];
68133
+ let imageCharacters = 0;
68134
+ for (const message of history.messages) {
68135
+ signal.throwIfAborted();
68136
+ const resolved = await resolveMessageImages(message, imageCharacters, signal);
68137
+ imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
68138
+ messages.push(resolved);
68139
+ }
68140
+ return {
68141
+ ...history,
68142
+ messages
68143
+ };
68144
+ }
68145
+ async function resolveMessageImages(message, usedCharacters, signal) {
68146
+ const images = [...message.images ?? []];
68147
+ let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
68148
+ const text2 = await replaceImageMarkers(message.text, async (uri) => {
68149
+ if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
68150
+ return "[Image unavailable]";
68151
+ }
68152
+ const embedded = parseNativeHistoryImage(uri);
68153
+ if (embedded !== null) {
68154
+ if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
68155
+ return "[Image unavailable]";
68156
+ }
68157
+ images.push({ ...embedded, name: `Image ${(images.length + 1).toString()}` });
68158
+ imageCharacters += embedded.data.length;
68159
+ return "";
68160
+ }
68161
+ const local = await readLocalRaster(uri, signal);
68162
+ if (local === null) {
68163
+ return "[Image unavailable]";
68164
+ }
68165
+ const data = await local.base64();
68166
+ if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
68167
+ return "[Image unavailable]";
68168
+ }
68169
+ images.push({
68170
+ data,
68171
+ mimeType: local.mimeType,
68172
+ name: local.name
68173
+ });
68174
+ imageCharacters += data.length;
68175
+ return "";
68176
+ });
68177
+ return {
68178
+ ...message,
68179
+ text: text2,
68180
+ ...images.length > 0 ? { images } : {}
68181
+ };
68182
+ }
68183
+ async function replaceImageMarkers(text2, replace) {
68184
+ const matches = [...text2.matchAll(IMAGE_MARKER)];
68185
+ if (matches.length === 0) {
68186
+ return text2;
68187
+ }
68188
+ let cursor = 0;
68189
+ let rewritten = "";
68190
+ for (const match of matches) {
68191
+ const index2 = match.index ?? 0;
68192
+ rewritten += text2.slice(cursor, index2);
68193
+ rewritten += await replace(match[1] ?? "");
68194
+ cursor = index2 + match[0].length;
68195
+ }
68196
+ return `${rewritten}${text2.slice(cursor)}`;
68197
+ }
68198
+
67925
68199
  // src/acp/harness/codex/owned-agent.ts
67926
68200
  import { randomUUID as randomUUID5 } from "node:crypto";
67927
68201
  import { setTimeout as delay } from "node:timers/promises";
@@ -68574,6 +68848,115 @@ var CodexOwnedAcpAgent = class {
68574
68848
  };
68575
68849
  };
68576
68850
 
68851
+ // src/acp/harness/codex/history.ts
68852
+ async function replayCodexHistory(client2, threadId, emit, signal) {
68853
+ const deadline = AbortSignal.any([signal, AbortSignal.timeout(6e4)]);
68854
+ const seenCursors = /* @__PURE__ */ new Set();
68855
+ let cursor = null;
68856
+ let turnIndex = 0;
68857
+ for (; ; ) {
68858
+ deadline.throwIfAborted();
68859
+ const page = threadTurnsPageSchema.parse(
68860
+ await client2.request(
68861
+ "thread/turns/list",
68862
+ {
68863
+ threadId,
68864
+ limit: CODEX_HISTORY_TURN_PAGE_LIMIT,
68865
+ sortDirection: "asc",
68866
+ itemsView: "full",
68867
+ ...cursor === null ? {} : { cursor }
68868
+ },
68869
+ deadline
68870
+ )
68871
+ );
68872
+ for (const turn of page.data) {
68873
+ for (const rawItem of turn.items) {
68874
+ deadline.throwIfAborted();
68875
+ const item = decodeThreadItem(rawItem);
68876
+ if (item === null) {
68877
+ continue;
68878
+ }
68879
+ if (item.type === "userMessage") {
68880
+ const text2 = item.content.flatMap((content) => {
68881
+ if (typeof content !== "object" || content === null) {
68882
+ return [];
68883
+ }
68884
+ const type = Reflect.get(content, "type");
68885
+ const text3 = Reflect.get(content, "text");
68886
+ const url2 = Reflect.get(content, "url");
68887
+ if (type === "image" && typeof url2 === "string") {
68888
+ return [`[@image](${url2})`];
68889
+ }
68890
+ return type === "text" && typeof text3 === "string" ? [text3] : [];
68891
+ }).join("");
68892
+ const history = await embedLocalHistoryImages(
68893
+ { status: "available", truncated: false, messages: [{ role: "user", text: text2 }] },
68894
+ deadline
68895
+ );
68896
+ if (history.status !== "available") {
68897
+ continue;
68898
+ }
68899
+ const message = history.messages[0];
68900
+ for (const image of message?.images ?? []) {
68901
+ await emit({
68902
+ content: { type: "image", data: image.data, mimeType: image.mimeType },
68903
+ messageId: item.id,
68904
+ sessionUpdate: "user_message_chunk"
68905
+ });
68906
+ }
68907
+ const restoredText = message?.text ?? "";
68908
+ if (restoredText.length > 0) {
68909
+ await emit({
68910
+ content: { text: restoredText, type: "text" },
68911
+ messageId: item.id,
68912
+ sessionUpdate: "user_message_chunk"
68913
+ });
68914
+ }
68915
+ } else if (item.type === "agentMessage") {
68916
+ await emit(agentMessageUpdate(item.id, item.text));
68917
+ } else if (item.type === "reasoning") {
68918
+ const text2 = reasoningText(item);
68919
+ if (text2 !== null && text2.length > 0) {
68920
+ await emit({
68921
+ content: { text: text2, type: "text" },
68922
+ messageId: item.id,
68923
+ sessionUpdate: "agent_thought_chunk"
68924
+ });
68925
+ }
68926
+ } else if (item.type === "contextCompaction") {
68927
+ await emit({ compactionId: item.id, sessionUpdate: "compaction_update", status: "completed" });
68928
+ } else {
68929
+ const update = toolCallUpdate(item, "snapshot");
68930
+ if (update !== null) {
68931
+ await emit({ ...update, sessionUpdate: "tool_call" });
68932
+ }
68933
+ }
68934
+ }
68935
+ if (turn.error != null) {
68936
+ const identity2 = createHash("sha256").update(threadId).update("\0").update(turn.id ?? turnIndex.toString()).digest("hex");
68937
+ await emit({
68938
+ sessionUpdate: "tool_call",
68939
+ toolCallId: `agent-error-${identity2}`,
68940
+ title: "Agent error",
68941
+ kind: "other",
68942
+ status: "failed",
68943
+ rawOutput: { message: turn.error.message },
68944
+ content: [{ type: "content", content: { type: "text", text: turn.error.message } }]
68945
+ });
68946
+ }
68947
+ turnIndex += 1;
68948
+ }
68949
+ if (page.nextCursor == null) {
68950
+ return;
68951
+ }
68952
+ if (page.data.length === 0 || seenCursors.has(page.nextCursor)) {
68953
+ throw new AcpExecutionError("Codex repeated a history page cursor", {}, "invalid_native_session_response");
68954
+ }
68955
+ seenCursors.add(page.nextCursor);
68956
+ cursor = page.nextCursor;
68957
+ }
68958
+ }
68959
+
68577
68960
  // src/acp/harness/codex/settings.ts
68578
68961
  var APPROVAL_TIMEOUT_MILLISECONDS2 = 36e5;
68579
68962
  var MODEL_SETTING_ID = "model";
@@ -69240,83 +69623,7 @@ var CodexAcpAgent = class {
69240
69623
  // ACP load requires chronological replay. Resume only restores execution;
69241
69624
  // native pages supply history without a single full-transcript response.
69242
69625
  #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
- }
69626
+ await replayCodexHistory(this.#appServer, this.#nativeSessionId, this.#emit, signal);
69320
69627
  };
69321
69628
  /** Announces the manual compact command after every session entry point —
69322
69629
  * new, load, resume, and fork — so clients on restored sessions discover
@@ -69364,7 +69671,7 @@ var CodexAgentSpecification = class extends InProcessAcpAgentSpecification {
69364
69671
  };
69365
69672
 
69366
69673
  // src/agent/specification/vendors/pi-agent.ts
69367
- import { createHash } from "node:crypto";
69674
+ import { createHash as createHash2 } from "node:crypto";
69368
69675
  import { join as join19 } from "node:path";
69369
69676
  import {
69370
69677
  methods as methods6
@@ -69377,7 +69684,7 @@ import { agent as createAgentApp2, methods as methods5 } from "@agentclientproto
69377
69684
  import { spawnSync } from "node:child_process";
69378
69685
  import { randomUUID as randomUUID7 } from "node:crypto";
69379
69686
  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";
69687
+ import { basename as basename5, dirname as dirname7, isAbsolute as isAbsolute12, join as join17 } from "node:path";
69381
69688
  import { RequestError as RequestError7 } from "@agentclientprotocol/sdk";
69382
69689
 
69383
69690
  // src/acp/harness/pi/upstream/dist/pi-rpc/process.js
@@ -69893,7 +70200,7 @@ function toAvailableCommandsFromPiGetCommands(data, opts) {
69893
70200
 
69894
70201
  // src/acp/harness/pi/upstream/dist/acp/pi-sessions.js
69895
70202
  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";
70203
+ import { isAbsolute as isAbsolute10, join as join14, resolve as resolve9 } from "node:path";
69897
70204
  var DEFAULT_TAIL_BYTES = 256 * 1024;
69898
70205
  var DEFAULT_HEAD_BYTES = 64 * 1024;
69899
70206
  function getPiAgentDir(environment) {
@@ -69915,7 +70222,7 @@ function readSessionDirFromSettings(agentDir) {
69915
70222
  if (typeof sessionDir !== "string" || !sessionDir.trim()) {
69916
70223
  return null;
69917
70224
  }
69918
- return isAbsolute9(sessionDir) ? sessionDir : resolve9(agentDir, sessionDir);
70225
+ return isAbsolute10(sessionDir) ? sessionDir : resolve9(agentDir, sessionDir);
69919
70226
  } catch {
69920
70227
  return null;
69921
70228
  }
@@ -70286,7 +70593,7 @@ function getQuietStartup(cwd, environment = process.env) {
70286
70593
  // src/acp/harness/pi/upstream/dist/acp/session.js
70287
70594
  import { randomUUID as randomUUID6 } from "node:crypto";
70288
70595
  import { readFileSync as readFileSync7 } from "node:fs";
70289
- import { isAbsolute as isAbsolute10, resolve as resolvePath } from "node:path";
70596
+ import { isAbsolute as isAbsolute11, resolve as resolvePath } from "node:path";
70290
70597
  import { RequestError as RequestError6 } from "@agentclientprotocol/sdk";
70291
70598
 
70292
70599
  // src/acp/harness/pi/upstream/dist/acp/extension-questions.js
@@ -70819,7 +71126,7 @@ function toToolCallLocations(args, cwd, line) {
70819
71126
  if (!path7) {
70820
71127
  return void 0;
70821
71128
  }
70822
- const resolvedPath = isAbsolute10(path7) ? path7 : resolvePath(cwd, path7);
71129
+ const resolvedPath = isAbsolute11(path7) ? path7 : resolvePath(cwd, path7);
70823
71130
  return [{ path: resolvedPath, ...typeof line === "number" ? { line } : {} }];
70824
71131
  }
70825
71132
  var SessionManager = class {
@@ -71359,7 +71666,7 @@ var PiAcpSession = class {
71359
71666
  const p = getToolPath(args);
71360
71667
  if (p) {
71361
71668
  try {
71362
- const abs = isAbsolute10(p) ? p : resolvePath(this.cwd, p);
71669
+ const abs = isAbsolute11(p) ? p : resolvePath(this.cwd, p);
71363
71670
  snapshotOldText = readFileSync7(abs, "utf8");
71364
71671
  this.fileSnapshots.set(toolCallId, { path: p, oldText: snapshotOldText });
71365
71672
  if (toolName === "edit") {
@@ -71442,7 +71749,7 @@ var PiAcpSession = class {
71442
71749
  let hasStructuredDiff = false;
71443
71750
  if (!isError && snapshot) {
71444
71751
  try {
71445
- const abs = isAbsolute10(snapshot.path) ? snapshot.path : resolvePath(this.cwd, snapshot.path);
71752
+ const abs = isAbsolute11(snapshot.path) ? snapshot.path : resolvePath(this.cwd, snapshot.path);
71446
71753
  const newText = readFileSync7(abs, "utf8");
71447
71754
  if (snapshot.oldText === null || newText !== snapshot.oldText) {
71448
71755
  hasStructuredDiff = true;
@@ -71836,7 +72143,7 @@ var PiAcpAgent = class {
71836
72143
  };
71837
72144
  }
71838
72145
  async newSession(params) {
71839
- if (!isAbsolute11(params.cwd)) {
72146
+ if (!isAbsolute12(params.cwd)) {
71840
72147
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
71841
72148
  }
71842
72149
  this.lastSessionCwd = params.cwd;
@@ -72433,7 +72740,7 @@ ${JSON.stringify(stats, null, 2)}`;
72433
72740
  return { sessions, nextCursor, _meta: {} };
72434
72741
  }
72435
72742
  async forkSession(params) {
72436
- if (!isAbsolute11(params.cwd)) {
72743
+ if (!isAbsolute12(params.cwd)) {
72437
72744
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
72438
72745
  }
72439
72746
  const source = this.findStoredSession(params.sessionId);
@@ -72499,7 +72806,7 @@ ${JSON.stringify(stats, null, 2)}`;
72499
72806
  return { sessionId: session.sessionId, configOptions, modes };
72500
72807
  }
72501
72808
  async resumeSession(params) {
72502
- if (!isAbsolute11(params.cwd)) {
72809
+ if (!isAbsolute12(params.cwd)) {
72503
72810
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
72504
72811
  }
72505
72812
  this.sessions.close(params.sessionId);
@@ -72570,7 +72877,7 @@ ${JSON.stringify(stats, null, 2)}`;
72570
72877
  return response;
72571
72878
  }
72572
72879
  async loadSession(params) {
72573
- if (!isAbsolute11(params.cwd)) {
72880
+ if (!isAbsolute12(params.cwd)) {
72574
72881
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
72575
72882
  }
72576
72883
  this.sessions.close(params.sessionId);
@@ -73064,7 +73371,7 @@ function buildStartupInfo(opts) {
73064
73371
  try {
73065
73372
  const prompts = readdirSync6(promptsDir).filter((f) => f.endsWith(".md"));
73066
73373
  for (const f of prompts) {
73067
- promptsItems.push(`/${basename4(f, ".md")}`);
73374
+ promptsItems.push(`/${basename5(f, ".md")}`);
73068
73375
  }
73069
73376
  } catch {
73070
73377
  }
@@ -73244,7 +73551,7 @@ var PiAgentSpecification = class extends InProcessAcpAgentSpecification {
73244
73551
  // The Pi ACP fork inlines embedded prompt resources into the turn message, so Mobius
73245
73552
  // keeps the adapter's opt-in capability flag enabled for every launch it owns.
73246
73553
  createLaunchEnvironment = async (_agent, context) => {
73247
- const workspaceHash = createHash("sha256").update(context.defaultWorkspace).digest("hex").slice(0, 24);
73554
+ const workspaceHash = createHash2("sha256").update(context.defaultWorkspace).digest("hex").slice(0, 24);
73248
73555
  const sessionDirectory = join19(
73249
73556
  readStateDirectory(context.environment),
73250
73557
  "agents",
@@ -73760,11 +74067,11 @@ function isAgentVersionSupported(reportedVersion, minimumSupportedVersion) {
73760
74067
  }
73761
74068
 
73762
74069
  // src/agent/discovery/executable-discovery.ts
73763
- import { isAbsolute as isAbsolute12 } from "node:path";
74070
+ import { isAbsolute as isAbsolute13 } from "node:path";
73764
74071
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveInstalled, context) {
73765
74072
  const override = context.environment[overrideVariable];
73766
74073
  if (override !== void 0) {
73767
- if (override.length === 0 || !isAbsolute12(override)) {
74074
+ if (override.length === 0 || !isAbsolute13(override)) {
73768
74075
  return [];
73769
74076
  }
73770
74077
  const executable = await resolveExecutablePath(override, context.platform);
@@ -74272,8 +74579,27 @@ var AdapterRegistry = class {
74272
74579
  import { randomUUID as randomUUID8 } from "node:crypto";
74273
74580
 
74274
74581
  // src/session/history/session-event-history-projection.ts
74582
+ var MAXIMUM_PROJECTED_REASONING_BYTES = 24 * 1024;
74583
+ function boundReasoning(payload) {
74584
+ if (payload.content.type !== "text" || Buffer.byteLength(payload.content.text, "utf8") <= MAXIMUM_PROJECTED_REASONING_BYTES) {
74585
+ return payload;
74586
+ }
74587
+ const bytes = Buffer.from(payload.content.text, "utf8");
74588
+ let start = bytes.length - MAXIMUM_PROJECTED_REASONING_BYTES;
74589
+ while (start < bytes.length && (bytes.readUInt8(start) & 192) === 128) {
74590
+ start += 1;
74591
+ }
74592
+ return {
74593
+ ...payload,
74594
+ content: { ...payload.content, text: bytes.toString("utf8", start) },
74595
+ meta: { ...payload.meta, truncated: true }
74596
+ };
74597
+ }
74275
74598
  function projectNewEvent(liveEvent2, eventId) {
74276
74599
  const { position: _position, eventId: _liveEventId, ...event } = liveEvent2;
74600
+ if (event.type === "acp" && event.payload.sessionUpdate === "agent_thought_chunk") {
74601
+ return { ...event, eventId, payload: boundReasoning(event.payload) };
74602
+ }
74277
74603
  return { ...event, eventId };
74278
74604
  }
74279
74605
  function replaceAcpPayload(event, payload) {
@@ -74324,11 +74650,11 @@ function mergeTextChunk(previous, incoming) {
74324
74650
  }
74325
74651
  const content = { text: `${previous.content.text}${incoming.content.text}`, type: "text" };
74326
74652
  if (previous.sessionUpdate === "agent_thought_chunk" && incoming.sessionUpdate === "agent_thought_chunk") {
74327
- return {
74653
+ return boundReasoning({
74328
74654
  ...previous,
74329
74655
  content,
74330
74656
  ...previous.meta?.truncated === true || incoming.meta?.truncated === true ? { meta: { ...previous.meta, ...incoming.meta, truncated: true } } : {}
74331
- };
74657
+ });
74332
74658
  }
74333
74659
  return { ...previous, content };
74334
74660
  }
@@ -75792,12 +76118,30 @@ function sessionConfigProtocolForAgent(_agentId) {
75792
76118
  }
75793
76119
 
75794
76120
  // src/acp/adapter/session-events.ts
76121
+ var MAXIMUM_REASONING_UPDATE_CHARACTERS = 1e6;
76122
+ function* reasoningWireUpdates(update) {
76123
+ if (update.sessionUpdate !== "agent_thought_chunk" || update.content.type !== "text" || update.content.text.length <= MAXIMUM_REASONING_UPDATE_CHARACTERS) {
76124
+ yield update;
76125
+ return;
76126
+ }
76127
+ const text2 = update.content.text;
76128
+ for (let start = 0; start < text2.length; ) {
76129
+ let end = Math.min(start + MAXIMUM_REASONING_UPDATE_CHARACTERS, text2.length);
76130
+ const last = text2.charCodeAt(end - 1);
76131
+ const next = text2.charCodeAt(end);
76132
+ if (last >= 55296 && last <= 56319 && next >= 56320 && next <= 57343) {
76133
+ end -= 1;
76134
+ }
76135
+ yield { ...update, content: { ...update.content, text: text2.slice(start, end) } };
76136
+ start = end;
76137
+ }
76138
+ }
75795
76139
  var AdapterSessionConnection = class {
75796
76140
  #connection;
75797
76141
  #updates;
75798
76142
  #lifetime = new AbortController();
75799
76143
  events;
75800
- constructor(options, externalizer) {
76144
+ constructor(options, externalizer, normalizeEvent) {
75801
76145
  const protocol = sessionConfigProtocolForAgent(options.agent.id);
75802
76146
  this.#updates = new AgentUpdateStream(async (notification) => {
75803
76147
  this.#lifetime.signal.throwIfAborted();
@@ -75805,58 +76149,60 @@ var AdapterSessionConnection = class {
75805
76149
  throw new AcpExecutionError("ACP agent referenced an unknown session", {}, "invalid_agent_session");
75806
76150
  }
75807
76151
  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) });
76152
+ for (const incoming of reasoningWireUpdates(notification.update)) {
76153
+ const externalized = await externalizer.update(options.sessionId(), incoming, signal);
76154
+ signal.throwIfAborted();
76155
+ const update = externalized.agent;
76156
+ const payload = decodeAcpSessionUpdate(JSON.stringify(normalizeEvent(externalized.event)));
76157
+ let event;
76158
+ switch (update.sessionUpdate) {
76159
+ case "available_commands_update":
76160
+ event = {
76161
+ kind: "commands",
76162
+ payload,
76163
+ commands: update.availableCommands.slice(0, 500).map((command) => ({
76164
+ description: truncate(command.description, 500),
76165
+ inputHint: truncate(command.input?.hint ?? "", 255),
76166
+ name: truncate(command.name, 128)
76167
+ })).filter((command) => command.name.length > 0)
76168
+ };
76169
+ break;
76170
+ case "config_option_update":
76171
+ event = {
76172
+ kind: "configuration",
76173
+ payload,
76174
+ configOptions: protocol.normalizeUpdate(options.configOptions(), update.configOptions)
76175
+ };
76176
+ break;
76177
+ case "current_mode_update":
76178
+ event = { kind: "mode", payload, modeId: update.currentModeId };
76179
+ break;
76180
+ case "session_info_update": {
76181
+ const changes = [];
76182
+ if (Object.hasOwn(update, "title")) {
76183
+ changes.push({ kind: "title", value: truncate(update.title ?? "", 500) });
76184
+ }
76185
+ if (Object.hasOwn(update, "updatedAt")) {
76186
+ changes.push({ kind: "updated-at", value: truncate(update.updatedAt ?? "", 128) });
76187
+ }
76188
+ event = { kind: "info", payload, changes };
76189
+ break;
75842
76190
  }
75843
- event = { kind: "info", payload, changes };
75844
- break;
76191
+ case "user_message_chunk":
76192
+ case "agent_message_chunk":
76193
+ case "agent_thought_chunk":
76194
+ case "tool_call":
76195
+ case "tool_call_update":
76196
+ case "plan":
76197
+ case "plan_update":
76198
+ case "plan_removed":
76199
+ event = { kind: "content", payload };
76200
+ break;
76201
+ default:
76202
+ event = { kind: "other", payload };
75845
76203
  }
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 };
76204
+ await options.onEvent(event);
75858
76205
  }
75859
- await options.onEvent(event);
75860
76206
  });
75861
76207
  this.events = this.#updates;
75862
76208
  const client2 = {
@@ -75903,10 +76249,12 @@ var AdapterSessionConnection = class {
75903
76249
  };
75904
76250
  var AcpSessionConnector = class {
75905
76251
  #externalizer;
75906
- constructor(externalizer) {
76252
+ #normalizeEvent;
76253
+ constructor(externalizer, normalizeEvent = (event) => event) {
75907
76254
  this.#externalizer = externalizer;
76255
+ this.#normalizeEvent = normalizeEvent;
75908
76256
  }
75909
- connectSession = (options) => new AdapterSessionConnection(options, this.#externalizer);
76257
+ connectSession = (options) => new AdapterSessionConnection(options, this.#externalizer, this.#normalizeEvent);
75910
76258
  connectQuerySession = (options) => {
75911
76259
  const rejectInteraction = async () => {
75912
76260
  throw new AcpExecutionError(
@@ -75924,7 +76272,8 @@ var AcpSessionConnector = class {
75924
76272
  onElicitationComplete: rejectInteraction
75925
76273
  }
75926
76274
  },
75927
- this.#externalizer
76275
+ this.#externalizer,
76276
+ this.#normalizeEvent
75928
76277
  );
75929
76278
  };
75930
76279
  };
@@ -75944,1042 +76293,8 @@ var ClaudeAdapter = class {
75944
76293
  close = async () => await this.#queryProcesses.close();
75945
76294
  };
75946
76295
 
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
- }
76296
+ // src/acp/adapter/codex/adapter.ts
76297
+ import { createHash as createHash4 } from "node:crypto";
76983
76298
 
76984
76299
  // src/storage/session/temporary-session-event-cache.ts
76985
76300
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
@@ -82189,13 +81504,85 @@ function openPreviewEventCache() {
82189
81504
  }
82190
81505
  }
82191
81506
 
81507
+ // src/acp/adapter/codex/tool-event.ts
81508
+ var toolEventSchema = external_exports.looseObject({
81509
+ sessionUpdate: external_exports.enum(["tool_call", "tool_call_update"]),
81510
+ rawInput: external_exports.unknown().optional(),
81511
+ rawOutput: external_exports.unknown().optional()
81512
+ });
81513
+ var TRUNCATED_TOOL_PAYLOAD_CHARACTER_LIMIT = 32768;
81514
+ var MAX_TOOL_PAYLOAD_DEPTH = 16;
81515
+ function payloadText(value) {
81516
+ let text2;
81517
+ try {
81518
+ text2 = JSON.stringify(value) ?? "";
81519
+ } catch {
81520
+ text2 = "Tool payload could not be represented as JSON.";
81521
+ }
81522
+ return text2.slice(0, TRUNCATED_TOOL_PAYLOAD_CHARACTER_LIMIT);
81523
+ }
81524
+ function fitNesting(value, depth = 0) {
81525
+ if (typeof value !== "object" || value === null) {
81526
+ return value;
81527
+ }
81528
+ if (depth === MAX_TOOL_PAYLOAD_DEPTH && Object.keys(value).length > 0) {
81529
+ return `[truncated: nesting depth] ${payloadText(value)}`;
81530
+ }
81531
+ if (Array.isArray(value)) {
81532
+ return value.map((child) => fitNesting(child, depth + 1));
81533
+ }
81534
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, fitNesting(child, depth + 1)]));
81535
+ }
81536
+ function prepareCodexToolUpdate(update) {
81537
+ if (update.sessionUpdate !== "tool_call" && update.sessionUpdate !== "tool_call_update") {
81538
+ return update;
81539
+ }
81540
+ return {
81541
+ ...update,
81542
+ ...update.rawOutput === void 0 ? {} : { rawOutput: fitNesting(update.rawOutput) },
81543
+ ...update._meta == null ? {} : {
81544
+ _meta: Object.fromEntries(
81545
+ Object.entries(update._meta).map(([key, child]) => [key, fitNesting(child, 1)])
81546
+ )
81547
+ }
81548
+ };
81549
+ }
81550
+ function fitPayload(value) {
81551
+ if (value === void 0 || boundedJsonSchema.safeParse(value).success) {
81552
+ return value;
81553
+ }
81554
+ return { truncated: true, text: payloadText(value) };
81555
+ }
81556
+ function fitCodexToolEvent(event) {
81557
+ const decoded = toolEventSchema.safeParse(event);
81558
+ if (!decoded.success) {
81559
+ return event;
81560
+ }
81561
+ return {
81562
+ ...decoded.data,
81563
+ rawInput: fitPayload(decoded.data.rawInput),
81564
+ rawOutput: fitPayload(decoded.data.rawOutput)
81565
+ };
81566
+ }
81567
+
82192
81568
  // src/acp/adapter/codex/adapter.ts
82193
81569
  var CodexAdapter = class {
82194
81570
  #queryProcesses;
82195
81571
  #connector;
81572
+ #dependencies;
81573
+ #contentExternalizer;
82196
81574
  #previewCache = null;
82197
81575
  constructor(dependencies) {
82198
- this.#connector = new AcpSessionConnector(dependencies.contentExternalizer);
81576
+ this.#dependencies = dependencies;
81577
+ this.#contentExternalizer = {
81578
+ update: async (sessionId, update, signal) => {
81579
+ signal.throwIfAborted();
81580
+ const prepared = prepareCodexToolUpdate(update);
81581
+ signal.throwIfAborted();
81582
+ return await dependencies.contentExternalizer.update(sessionId, prepared, signal);
81583
+ }
81584
+ };
81585
+ this.#connector = new AcpSessionConnector(this.#contentExternalizer, fitCodexToolEvent);
82199
81586
  this.#queryProcesses = new AgentQueryProcesses(dependencies.processes, this.#connector);
82200
81587
  }
82201
81588
  capabilities = async (query) => await this.#queryProcesses.capabilities(query);
@@ -82209,21 +81596,73 @@ var CodexAdapter = class {
82209
81596
  }
82210
81597
  };
82211
81598
  previewSessionEvents = async (query, request) => {
82212
- const { agent, cwd, signal } = query;
81599
+ const { agent, cwd } = query;
81600
+ const signal = AbortSignal.any([query.signal, AbortSignal.timeout(6e4)]);
82213
81601
  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);
81602
+ signal.throwIfAborted();
81603
+ nativeSessionIdSchema.parse(request.nativeSessionId);
81604
+ if (agent.id !== "codex") {
81605
+ throw new AcpExecutionError(
81606
+ "The Codex adapter cannot preview history for another agent.",
81607
+ {},
81608
+ "agent_adapter_mismatch"
81609
+ );
82218
81610
  }
82219
- return nativeHistoryEvents(
82220
- sessionId,
82221
- request.nativeSessionId,
82222
- snapshot.history,
82223
- request.eventLimit,
82224
- request.cursor,
82225
- this.#previewCache.events
81611
+ if (!await revalidateExecutable(agent.agentIdentity)) {
81612
+ throw new AcpExecutionError(
81613
+ "The local Codex executable changed. Restart Mobius to discover it again.",
81614
+ {},
81615
+ "agent_executable_changed"
81616
+ );
81617
+ }
81618
+ this.#previewCache ??= openPreviewEventCache();
81619
+ const events = [];
81620
+ await this.#dependencies.processes.runTransient(
81621
+ signal,
81622
+ async () => {
81623
+ const client2 = new CodexAppServerClient({
81624
+ command: agent.command,
81625
+ cwd,
81626
+ environment: agent.environment,
81627
+ handlers: {
81628
+ onNotification: async () => void 0,
81629
+ onServerRequest: async () => {
81630
+ throw new AcpExecutionError(
81631
+ "Unexpected request while reading saved history",
81632
+ {},
81633
+ "invalid_native_session_response"
81634
+ );
81635
+ }
81636
+ }
81637
+ });
81638
+ return {
81639
+ client: client2,
81640
+ closeProcess: async () => {
81641
+ client2.detach();
81642
+ await stopProcessTree(client2.child());
81643
+ }
81644
+ };
81645
+ },
81646
+ async ({ client: client2 }) => {
81647
+ await client2.initialize(signal);
81648
+ return await replayCodexHistory(
81649
+ client2,
81650
+ request.nativeSessionId,
81651
+ async (update) => {
81652
+ const externalized = await this.#contentExternalizer.update(sessionId, update, signal);
81653
+ events.push({
81654
+ type: "acp",
81655
+ payload: decodeAcpSessionUpdate(JSON.stringify(fitCodexToolEvent(externalized.event)))
81656
+ });
81657
+ },
81658
+ signal
81659
+ );
81660
+ },
81661
+ async (runtime) => await runtime.closeProcess()
82226
81662
  );
81663
+ const generationId = createHash4("sha256").update(request.nativeSessionId).update("\0").update(JSON.stringify(events)).digest("hex");
81664
+ this.#previewCache.events.materialize(sessionId, generationId, events);
81665
+ return this.#previewCache.events.page(sessionId, request.eventLimit, request.cursor);
82227
81666
  };
82228
81667
  };
82229
81668
 
@@ -82262,18 +81701,6 @@ var harnessAdapters = (agent, dependencies) => {
82262
81701
 
82263
81702
  // src/acp/content/content-externalizer.ts
82264
81703
  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
81704
  function decodeBase64(data) {
82278
81705
  if (data.length > MAXIMUM_ENCODED_CONTENT_CHARACTERS || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/u.test(data)) {
82279
81706
  throw new Error("The ACP embedded content is not valid bounded base64");
@@ -82469,24 +81896,7 @@ var AcpContentExternalizer = class {
82469
81896
  }
82470
81897
  update = async (sessionId, update, signal) => {
82471
81898
  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
- }
81899
+ case "agent_thought_chunk":
82490
81900
  case "user_message_chunk":
82491
81901
  case "agent_message_chunk":
82492
81902
  case "compaction_summary_chunk": {
@@ -82648,7 +82058,7 @@ import { randomUUID as randomUUID10 } from "node:crypto";
82648
82058
  import { resolve as resolve14 } from "node:path";
82649
82059
 
82650
82060
  // src/storage/installation/installation-files.ts
82651
- import { createHash as createHash4, randomUUID as randomUUID9 } from "node:crypto";
82061
+ import { createHash as createHash5, randomUUID as randomUUID9 } from "node:crypto";
82652
82062
  import { mkdir as mkdir4, open as open5, readdir as readdir5, rename as rename3, unlink as unlink3, writeFile } from "node:fs/promises";
82653
82063
  import { dirname as dirname9, join as join23 } from "node:path";
82654
82064
 
@@ -82675,7 +82085,7 @@ function connectionFilePath(connectionDirectory2, connectionId2) {
82675
82085
  return join23(connectionDirectory2, `${connectionId2}.json`);
82676
82086
  }
82677
82087
  function channelIndexFilePath(installationDirectory2, channelId) {
82678
- return join23(installationDirectory2, "channels", `mci_${createHash4("sha256").update(channelId).digest("hex")}.json`);
82088
+ return join23(installationDirectory2, "channels", `mci_${createHash5("sha256").update(channelId).digest("hex")}.json`);
82679
82089
  }
82680
82090
  async function readInstallationFile(path7) {
82681
82091
  let handle;
@@ -86984,7 +86394,7 @@ async function settleAbandonedTurn(projection, operations, cancellation) {
86984
86394
  }
86985
86395
 
86986
86396
  // src/session/turn/execution-receipts.ts
86987
- import { createHash as createHash5, randomUUID as randomUUID12 } from "node:crypto";
86397
+ import { createHash as createHash6, randomUUID as randomUUID12 } from "node:crypto";
86988
86398
  var MAX_TERMINAL_RECEIPTS = 1024;
86989
86399
  function isTerminal(state) {
86990
86400
  return state === "succeeded" || state === "failed" || state === "cancelled";
@@ -87100,7 +86510,7 @@ var ExecutionReceipts = class {
87100
86510
  ];
87101
86511
  });
87102
86512
  claimExecution = (commandId, sessionId, commandJson) => {
87103
- const commandHash = createHash5("sha256").update(commandJson).digest("hex");
86513
+ const commandHash = createHash6("sha256").update(commandJson).digest("hex");
87104
86514
  let existing = this.#executions.get(commandId);
87105
86515
  const previous = this.outcome(commandId);
87106
86516
  if (existing?.sessionId === sessionId && !existing.started && previous?.type === "lifecycle-metadata" && previous.payload.kind === "prompt.failed-before-start" && previous.payload.code === "runtime_restarted") {
@@ -87453,9 +86863,9 @@ var SessionTurns = class {
87453
86863
  #bySessionId = /* @__PURE__ */ new Map();
87454
86864
  #operations;
87455
86865
  #activity;
87456
- constructor(operations, activity2 = new RuntimeTurnActivity()) {
86866
+ constructor(operations, activity = new RuntimeTurnActivity()) {
87457
86867
  this.#operations = operations;
87458
- this.#activity = activity2;
86868
+ this.#activity = activity;
87459
86869
  }
87460
86870
  acceptsPrompts = () => this.#activity.acceptsPrompts();
87461
86871
  session = (sessionId) => {
@@ -87788,7 +87198,7 @@ function buildSessionLayer(options) {
87788
87198
  }
87789
87199
 
87790
87200
  // src/session/content/external-content-store.ts
87791
- import { createHash as createHash6 } from "node:crypto";
87201
+ import { createHash as createHash7 } from "node:crypto";
87792
87202
  import { join as join27 } from "node:path";
87793
87203
 
87794
87204
  // src/storage/files/scratch-directory.ts
@@ -87912,7 +87322,7 @@ var LocalExternalContentStore = class {
87912
87322
  const active = AbortSignal.any([signal, this.#lifetime.signal]);
87913
87323
  active.throwIfAborted();
87914
87324
  const metadata = metadataSchema.parse({ kind, mediaType, name: name2 });
87915
- const key = createHash6("sha256").update(bytes).digest("hex");
87325
+ const key = createHash7("sha256").update(bytes).digest("hex");
87916
87326
  const request = `mobius-content:${kind}:${key}`;
87917
87327
  const existing = this.#entries.get(request);
87918
87328
  if (existing !== void 0 && existing.expiresAt > Date.now()) {
@@ -88777,7 +88187,7 @@ var SessionError = class extends OperationError {
88777
88187
  };
88778
88188
 
88779
88189
  // src/session/settings/discover-agent-settings.ts
88780
- import { createHash as createHash7 } from "node:crypto";
88190
+ import { createHash as createHash8 } from "node:crypto";
88781
88191
 
88782
88192
  // src/agent/settings/agent-settings-base.ts
88783
88193
  var AgentSettingsLaunchSelectionResult = class {
@@ -89095,7 +88505,7 @@ function settingsRevision(agent, reportedAgentVersion, settings, modelEffort) {
89095
88505
  unsupportedModelIds: modelEffort.unsupportedModelIds,
89096
88506
  valuesByModel: {}
89097
88507
  };
89098
- return createHash7("sha256").update(
88508
+ return createHash8("sha256").update(
89099
88509
  JSON.stringify({
89100
88510
  adapterVersion: agent.kind === "acp-adapter-process" ? agent.adapterVersion : agent.agentVersion,
89101
88511
  agentId: agent.id,
@@ -89404,35 +88814,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId, ad
89404
88814
  }
89405
88815
 
89406
88816
  // 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) {
88817
+ async function loadHistoryPage(sessionId, eventLimit, initialCursor, queuedPromptRequests, load) {
89436
88818
  let cursor = initialCursor;
89437
88819
  let loaded = [];
89438
88820
  let sessionGenerationId = null;
@@ -89459,9 +88841,7 @@ async function loadHistoryPage(sessionId, eventLimit, initialCursor, omitReasoni
89459
88841
  });
89460
88842
  loaded = [...events, ...loaded];
89461
88843
  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) {
88844
+ if (loaded.length >= eventLimit) {
89465
88845
  break;
89466
88846
  }
89467
88847
  cursor = sourceNextCursor;
@@ -89469,8 +88849,7 @@ async function loadHistoryPage(sessionId, eventLimit, initialCursor, omitReasoni
89469
88849
  if (sessionGenerationId === null || throughPosition === null) {
89470
88850
  throw new SessionError("session_history_unavailable", "The Session history is unavailable");
89471
88851
  }
89472
- const visible = omitReasoning ? omitAgentReasoning(loaded) : loaded;
89473
- const orderedEvents = visible.slice(-eventLimit);
88852
+ const orderedEvents = loaded.slice(-eventLimit);
89474
88853
  const nextCursor = orderedEvents[0]?.cursor ?? null;
89475
88854
  return {
89476
88855
  events: {
@@ -89512,7 +88891,6 @@ async function executeSessionHistoryPageLoad(socket, command, config2, resolveAg
89512
88891
  command.sessionId,
89513
88892
  command.eventLimit,
89514
88893
  command.cursor,
89515
- command.omit?.includes("agent-reasoning") === true,
89516
88894
  recovery.queuedPromptRequests,
89517
88895
  async (eventLimit, cursor) => await sessions.loadSessionEvents(loadOptions, eventLimit, cursor)
89518
88896
  );
@@ -89559,7 +88937,6 @@ async function executeSessionPreviewHistoryPageLoad(socket, command, config2, re
89559
88937
  command.sessionId,
89560
88938
  command.eventLimit,
89561
88939
  command.cursor,
89562
- command.omit?.includes("agent-reasoning") === true,
89563
88940
  [],
89564
88941
  async (eventLimit, cursor) => await sessions.previewNativeSessionEvents(loadOptions, command.sessionId, eventLimit, cursor)
89565
88942
  );
@@ -90292,7 +89669,7 @@ async function executePrompt({
90292
89669
  }
90293
89670
 
90294
89671
  // src/runtime/relay/artifact-download.ts
90295
- import { createHash as createHash8 } from "node:crypto";
89672
+ import { createHash as createHash9 } from "node:crypto";
90296
89673
  import { fetch as fetch4 } from "undici";
90297
89674
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
90298
89675
  function downloadUrl(config2, artifact) {
@@ -90380,7 +89757,7 @@ async function downloadPromptArtifact(config2, artifact, signal) {
90380
89757
  );
90381
89758
  }
90382
89759
  const bytes = await responseBytes(response, artifact.byteLength, requestSignal);
90383
- if (createHash8("sha256").update(bytes).digest("hex") !== artifact.sha256) {
89760
+ if (createHash9("sha256").update(bytes).digest("hex") !== artifact.sha256) {
90384
89761
  throw new PromptArtifactError(
90385
89762
  "artifact_integrity_failed",
90386
89763
  "The prompt artifact failed integrity validation"