@openclaw/codex 2026.7.2-beta.4 → 2026.7.2-beta.7

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 (40) hide show
  1. package/dist/{app-server-policy-BO3jYBkv.js → app-server-policy-BSaO2JIT.js} +1 -1
  2. package/dist/{attempt-notifications-DdmnBMUp.js → attempt-notifications-AP-a-Q5k.js} +1 -1
  3. package/dist/{bounded-turn-CaQL96kg.js → bounded-turn-D2ZAgZVz.js} +54 -24
  4. package/dist/{capabilities-CLICvTxf.js → capabilities-BFDTVYr4.js} +1 -1
  5. package/dist/cli-metadata.js +1 -1
  6. package/dist/{command-formatters-DgADqnHa.js → command-formatters-C336eRVS.js} +2 -2
  7. package/dist/{command-handlers-l_lVPNlB.js → command-handlers-DAHUSry9.js} +1233 -1222
  8. package/dist/{compact-CC5KhBzX.js → compact-D_uvHurS.js} +8 -8
  9. package/dist/{computer-use-Ip1-QGa-.js → computer-use-CYEc8U3w.js} +123 -115
  10. package/dist/{conversation-control-sNPsbTCP.js → conversation-control-xsIeXbo4.js} +6 -6
  11. package/dist/doctor-contract-api.js +24 -86
  12. package/dist/{dynamic-tools-CQI3UwqY.js → dynamic-tools-D2gYkSBO.js} +482 -91
  13. package/dist/effective-mcp-catalog-Bbd98Inw.js +114 -0
  14. package/dist/{event-projector-usage-D6tE7_qD.js → event-projector-usage-Xp4AlR2k.js} +20 -3
  15. package/dist/harness.js +19 -14
  16. package/dist/index.js +292 -328
  17. package/dist/media-understanding-provider.js +6 -1
  18. package/dist/{models-BNeMlHgg.js → models-BBMKU4jA.js} +2 -2
  19. package/dist/{notification-correlation-BGLixv5_.js → notification-correlation-CU6_AnOb.js} +3 -3
  20. package/dist/{plugin-app-cache-key-CvzvmBRz.js → plugin-app-cache-key-DztPafOA.js} +135 -42
  21. package/dist/{rate-limits-D0IJT-a6.js → rate-limits-CU-gVCCS.js} +1 -1
  22. package/dist/{request-BTccUTD3.js → request-qKh331yu.js} +3 -3
  23. package/dist/{run-attempt--858NXDl.js → run-attempt-CY9WlDLc.js} +1060 -402
  24. package/dist/{runtime-artifact-C2ITXdhM.js → runtime-artifact-CmtG_t1L.js} +90 -24
  25. package/dist/{sandbox-guard-D1Wky__S.js → sandbox-guard-NuhpXmPB.js} +4 -0
  26. package/dist/{session-binding-ZSMX1omP.js → session-binding-BXpo9ymA.js} +1006 -891
  27. package/dist/{session-catalog-DsKaezgR.js → session-catalog-DyOgR4WH.js} +289 -56
  28. package/dist/{session-cli-CYJTfRLG.js → session-cli-2PZaFLRh.js} +2 -2
  29. package/dist/{session-upstream-marker-D7XlI9us.js → session-upstream-marker-B6U7tLw5.js} +1 -1
  30. package/dist/{settled-turn-finalizer-DHltNgtF.js → settled-turn-finalizer-CXY2Z9dT.js} +19 -6
  31. package/dist/{shared-client-wmgNFNYp.js → shared-client-DTbvH-XV.js} +1993 -1720
  32. package/dist/{side-question-BfFZCsJ-.js → side-question-_ulBk1AL.js} +12 -10
  33. package/dist/{thread-lifecycle-cqrOlJkq.js → thread-lifecycle-DF53ogiA.js} +980 -346
  34. package/dist/{transcript-mirror-2p7kl6e4.js → transcript-mirror-DzsdNCf5.js} +80 -41
  35. package/dist/{upstream-session-fork-vPjwkT1i.js → upstream-session-fork-Dy4Xvuoj.js} +3 -3
  36. package/dist/{usage-DM_I3mPT.js → usage-CQ6GhD5-.js} +3 -3
  37. package/dist/{web-search-provider.runtime-Bx6HAc_k.js → web-search-provider.runtime-CCFhg2z5.js} +3 -3
  38. package/package.json +6 -8
  39. package/npm-shrinkwrap.json +0 -202
  40. package/dist/{auth-binding-C1czuHPA.js → auth-binding-B4FfbcCg.js} +1 -1
@@ -1,30 +1,128 @@
1
- import { J as CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES, Q as isJsonObject, R as CodexAppServerRpcError, Y as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, a as getLeasedSharedCodexAppServerClient, c as releaseLeasedSharedCodexAppServerClient, m as withTimeout, q as resolveCodexAppServerClientInstanceId } from "./shared-client-wmgNFNYp.js";
2
- import { D as resolveCodexSupervisionAppServerRuntimeOptions, c as reclaimCurrentCodexSessionGeneration, l as sessionBindingIdentity, x as resolveCodexAppServerRuntimeOptions } from "./session-binding-ZSMX1omP.js";
3
- import { m as assertCodexThreadForkParams, r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-2p7kl6e4.js";
4
- import { n as listCodexAppServerModels } from "./models-BNeMlHgg.js";
5
- import { t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-CvzvmBRz.js";
6
- import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-CLICvTxf.js";
7
- import { r as formatCodexDisplayText } from "./command-formatters-DgADqnHa.js";
1
+ import { B as CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES, D as resolveCodexAppServerClientInstanceId, V as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, W as isJsonObject, a as getLeasedSharedCodexAppServerClient, g as withTimeout, l as releaseLeasedSharedCodexAppServerClient, v as CodexAppServerRpcError } from "./shared-client-DTbvH-XV.js";
2
+ import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, g as resolveCodexAppServerRuntimeOptions, y as resolveCodexSupervisionAppServerRuntimeOptions } from "./session-binding-BXpo9ymA.js";
3
+ import { m as assertCodexThreadForkParams, r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-DzsdNCf5.js";
4
+ import { n as listCodexAppServerModels } from "./models-BBMKU4jA.js";
5
+ import { t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-DztPafOA.js";
6
+ import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-BFDTVYr4.js";
7
+ import { r as formatCodexDisplayText } from "./command-formatters-C336eRVS.js";
8
8
  import { n as createCodexCliNodeConversationBindingData } from "./conversation-binding-data-BHRpYbX3.js";
9
- import { n as requestCodexAppServerClientJson, r as requestCodexAppServerJson } from "./request-BTccUTD3.js";
10
- import { i as createImportedCodexSession, n as codexUpstreamBaseline, r as codexUpstreamContinueResult, t as codexLastTerminalTurnId } from "./session-upstream-marker-D7XlI9us.js";
9
+ import { n as requestCodexAppServerClientJson, r as requestCodexAppServerJson } from "./request-qKh331yu.js";
10
+ import { i as createImportedCodexSession, n as codexUpstreamBaseline, r as codexUpstreamContinueResult, t as codexLastTerminalTurnId } from "./session-upstream-marker-B6U7tLw5.js";
11
11
  import fs from "node:fs/promises";
12
12
  import path from "node:path";
13
13
  import { timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
14
14
  import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
15
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
16
15
  import { createHash } from "node:crypto";
17
- import os from "node:os";
18
16
  import { listAgentIds, resolveAllowedModelRef, resolveDefaultAgentDir, resolveDefaultAgentId, resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
17
+ import os from "node:os";
19
18
  import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
20
19
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
21
20
  import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "openclaw/plugin-sdk/windows-spawn";
22
- import { spawn } from "node:child_process";
23
21
  import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
22
+ import { spawn } from "node:child_process";
23
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
24
24
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
25
25
  import process$1 from "node:process";
26
+ import { listSessionCatalogEntries } from "openclaw/plugin-sdk/session-catalog";
26
27
  import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
27
28
  import { decodeNodePtyResumeParams, resolveNodeHostExecutable, runNodePtyCommand } from "openclaw/plugin-sdk/node-host";
29
+ //#region extensions/codex/src/jsonl-lines.ts
30
+ const JSONL_STREAM_THRESHOLD_BYTES = 4 * 1024 * 1024;
31
+ const JSONL_READ_CHUNK_BYTES = 1024 * 1024;
32
+ async function visitJsonlLines(file, visitor, chunkBytes = JSONL_READ_CHUNK_BYTES) {
33
+ let size;
34
+ try {
35
+ size = (await fs.stat(file)).size;
36
+ } catch {
37
+ return {
38
+ ok: false,
39
+ lineCount: 0
40
+ };
41
+ }
42
+ if (size <= JSONL_STREAM_THRESHOLD_BYTES) {
43
+ let content;
44
+ try {
45
+ content = await fs.readFile(file, "utf8");
46
+ } catch {
47
+ return {
48
+ ok: false,
49
+ lineCount: 0
50
+ };
51
+ }
52
+ if (content.length === 0) return {
53
+ ok: true,
54
+ lineCount: 0
55
+ };
56
+ let lineCount = 0;
57
+ for (const line of content.split(/\r?\n/u)) {
58
+ lineCount += 1;
59
+ if (visitor(line) === false) break;
60
+ }
61
+ return {
62
+ ok: true,
63
+ lineCount
64
+ };
65
+ }
66
+ let handle;
67
+ try {
68
+ handle = await fs.open(file, "r");
69
+ } catch {
70
+ return {
71
+ ok: false,
72
+ lineCount: 0
73
+ };
74
+ }
75
+ const buffer = Buffer.allocUnsafe(chunkBytes);
76
+ const decoder = new TextDecoder();
77
+ let pendingFragments = [];
78
+ let lineCount = 0;
79
+ try {
80
+ while (true) {
81
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, null);
82
+ if (bytesRead === 0) break;
83
+ const content = decoder.decode(buffer.subarray(0, bytesRead), { stream: true });
84
+ let lineStart = 0;
85
+ while (true) {
86
+ const newline = content.indexOf("\n", lineStart);
87
+ if (newline === -1) break;
88
+ let rawLine = content.slice(lineStart, newline);
89
+ if (pendingFragments.length > 0) {
90
+ pendingFragments.push(rawLine);
91
+ rawLine = pendingFragments.join("");
92
+ pendingFragments = [];
93
+ }
94
+ const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
95
+ lineCount += 1;
96
+ if (visitor(line) === false) return {
97
+ ok: true,
98
+ lineCount
99
+ };
100
+ lineStart = newline + 1;
101
+ }
102
+ if (lineStart < content.length) pendingFragments.push(content.slice(lineStart));
103
+ }
104
+ const decoderTail = decoder.decode();
105
+ if (decoderTail.length > 0) pendingFragments.push(decoderTail);
106
+ if (pendingFragments.length > 0) {
107
+ const rawLine = pendingFragments.join("");
108
+ const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
109
+ lineCount += 1;
110
+ visitor(line);
111
+ }
112
+ return {
113
+ ok: true,
114
+ lineCount
115
+ };
116
+ } catch {
117
+ return {
118
+ ok: false,
119
+ lineCount: 0
120
+ };
121
+ } finally {
122
+ await handle.close().catch(() => void 0);
123
+ }
124
+ }
125
+ //#endregion
28
126
  //#region extensions/codex/src/node-cli-sessions.ts
29
127
  const CODEX_CLI_SESSIONS_LIST_COMMAND = "codex.cli.sessions.list";
30
128
  const CODEX_CLI_SESSION_RESUME_COMMAND = "codex.cli.session.resume";
@@ -247,20 +345,18 @@ function resolveCodexCliResumeSpawnInvocation(args, runtime = DEFAULT_RESUME_SPA
247
345
  }
248
346
  async function readHistorySessions(codexHome) {
249
347
  const summaries = /* @__PURE__ */ new Map();
250
- const content = await readFileIfExists(path.join(codexHome, "history.jsonl"));
251
- if (!content) return summaries;
252
- for (const line of content.split(/\r?\n/u)) {
348
+ if (!(await visitJsonlLines(path.join(codexHome, "history.jsonl"), (line) => {
253
349
  const trimmed = line.trim();
254
- if (!trimmed) continue;
350
+ if (!trimmed) return;
255
351
  let parsed;
256
352
  try {
257
353
  parsed = JSON.parse(trimmed);
258
354
  } catch {
259
- continue;
355
+ return;
260
356
  }
261
- if (!isRecord(parsed) || typeof parsed.session_id !== "string") continue;
357
+ if (!isRecord(parsed) || typeof parsed.session_id !== "string") return;
262
358
  const sessionId = parsed.session_id.trim();
263
- if (!sessionId) continue;
359
+ if (!sessionId) return;
264
360
  const entry = summaries.get(sessionId) ?? {
265
361
  sessionId,
266
362
  messageCount: 0
@@ -269,7 +365,7 @@ async function readHistorySessions(codexHome) {
269
365
  if (typeof parsed.text === "string" && parsed.text.trim()) entry.lastMessage = truncateText(parsed.text.trim(), 140);
270
366
  if (typeof parsed.ts === "number") entry.updatedAt = timestampMsToIsoString(parsed.ts * 1e3) ?? entry.updatedAt;
271
367
  summaries.set(sessionId, entry);
272
- }
368
+ })).ok) return /* @__PURE__ */ new Map();
273
369
  return summaries;
274
370
  }
275
371
  async function hydrateSessionFiles(codexHome, summaries) {
@@ -307,35 +403,35 @@ async function hydrateSessionsFromSessionFiles(codexHome, summaries) {
307
403
  }
308
404
  }
309
405
  async function readSessionFileSummary(file) {
310
- const content = await readFileIfExists(file);
311
- if (!content) return null;
312
406
  let sessionId = "";
313
407
  let cwd;
314
408
  let updatedAt;
315
409
  let lastMessage;
316
410
  let messageCount = 0;
317
- for (const line of content.split(/\r?\n/u)) {
411
+ const result = await visitJsonlLines(file, (line) => {
318
412
  const trimmed = line.trim();
319
- if (!trimmed) continue;
413
+ if (!trimmed) return;
320
414
  let parsed;
321
415
  try {
322
416
  parsed = JSON.parse(trimmed);
323
417
  } catch {
324
- continue;
418
+ return;
325
419
  }
326
- if (!isRecord(parsed)) continue;
420
+ if (!isRecord(parsed)) return;
327
421
  if (typeof parsed.timestamp === "string" && parsed.timestamp.trim()) updatedAt = parsed.timestamp.trim();
328
422
  if (parsed.type === "session_meta" && isRecord(parsed.payload)) {
329
423
  if (typeof parsed.payload.id === "string" && parsed.payload.id.trim()) sessionId = parsed.payload.id.trim();
330
424
  if (typeof parsed.payload.cwd === "string" && parsed.payload.cwd.trim()) cwd = parsed.payload.cwd.trim();
331
- continue;
425
+ return;
332
426
  }
333
427
  const messageText = readResponseItemMessageText(parsed);
334
428
  if (messageText) {
335
429
  messageCount += 1;
336
430
  lastMessage = truncateText(messageText, 140);
337
431
  }
338
- }
432
+ });
433
+ if (!result.ok) return null;
434
+ if (result.lineCount === 0) return null;
339
435
  if (!sessionId) sessionId = readSessionIdFromFilename(file) ?? "";
340
436
  if (!sessionId) return null;
341
437
  return {
@@ -443,15 +539,12 @@ function readRecordParam(paramsJSON) {
443
539
  function resolveCodexHome() {
444
540
  return process$1.env.CODEX_HOME?.trim() || path.join(os.homedir(), ".codex");
445
541
  }
446
- async function readFileIfExists(file) {
447
- try {
448
- return await fs.readFile(file, "utf8");
449
- } catch {
450
- return;
451
- }
452
- }
453
542
  async function readFirstLine(file) {
454
- return (await readFileIfExists(file))?.split(/\r?\n/u)[0];
543
+ let firstLine;
544
+ return (await visitJsonlLines(file, (line) => {
545
+ firstLine = line;
546
+ return false;
547
+ }, 65536)).ok ? firstLine : void 0;
455
548
  }
456
549
  async function readFileMtimeIso(file) {
457
550
  try {
@@ -965,9 +1058,10 @@ function readNodeSessionMarker(entry) {
965
1058
  }
966
1059
  function listNodeAdoptedSessionEntries(params) {
967
1060
  const adopted = /* @__PURE__ */ new Map();
968
- for (const agentId of listSupervisionAgentIds(params.config ?? {})) for (const { entry, sessionKey } of params.runtime.agent.session.listSessionEntries({
969
- agentId,
970
- readOnly: true
1061
+ for (const { agentId, entry, sessionKey } of listSessionCatalogEntries({
1062
+ config: params.config ?? {},
1063
+ runtime: params.runtime,
1064
+ sessionEntries: params.sessionEntries
971
1065
  })) {
972
1066
  const marker = readNodeSessionMarker(entry);
973
1067
  const sessionId = entry.sessionId?.trim();
@@ -1336,12 +1430,20 @@ function codexNodeTerminalCapability(node) {
1336
1430
  return node.connected === true && commands?.includes("codex.terminal.resume.v1") === true ? { canOpenTerminalCodex: true } : {};
1337
1431
  }
1338
1432
  async function requireCatalogEligibleThread(control, threadId) {
1433
+ const cached = await findCatalogEligibleThread(control, threadId, false);
1434
+ if (cached) return cached;
1435
+ const refreshed = await findCatalogEligibleThread(control, threadId, true);
1436
+ if (refreshed) return refreshed;
1437
+ throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
1438
+ }
1439
+ async function findCatalogEligibleThread(control, threadId, forceRefresh) {
1339
1440
  let cursor;
1340
1441
  const seenCursors = /* @__PURE__ */ new Set();
1341
1442
  for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
1342
1443
  const page = await control.listPage({
1343
1444
  limit: 100,
1344
- ...cursor ? { cursor } : {}
1445
+ ...cursor ? { cursor } : {},
1446
+ ...forceRefresh ? { forceRefresh: true } : {}
1345
1447
  });
1346
1448
  const candidate = page.sessions.find((session) => session.threadId === threadId);
1347
1449
  if (candidate) {
@@ -1349,7 +1451,7 @@ async function requireCatalogEligibleThread(control, threadId) {
1349
1451
  throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
1350
1452
  }
1351
1453
  const nextCursor = page.nextCursor?.trim();
1352
- if (!nextCursor) throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
1454
+ if (!nextCursor) return;
1353
1455
  if (seenCursors.has(nextCursor)) throw new CatalogParamsError("Codex session eligibility could not be verified");
1354
1456
  seenCursors.add(nextCursor);
1355
1457
  cursor = nextCursor;
@@ -1615,6 +1717,16 @@ function createChecker(params) {
1615
1717
  //#region extensions/codex/src/session-catalog.ts
1616
1718
  const boundCatalogSessionId = (value) => boundedCatalogString(value, 256);
1617
1719
  const CODEX_SUPERVISION_SESSION_KEY_PREFIX = "harness:codex:supervision:";
1720
+ const CODEX_SESSION_CATALOG_LIST_TTL_MS = 32e3;
1721
+ const CODEX_SESSION_CATALOG_LIST_CACHE_MAX_ENTRIES = 32;
1722
+ function codexCatalogPageCacheKey(params) {
1723
+ return JSON.stringify([
1724
+ params.cursor ?? null,
1725
+ params.limit ?? null,
1726
+ params.searchTerm?.trim().toLocaleLowerCase() || null,
1727
+ params.cwd?.trim() || null
1728
+ ]);
1729
+ }
1618
1730
  function createCodexSessionCatalogControlFromRequests(params) {
1619
1731
  return {
1620
1732
  ...params.clientId ? { clientId: params.clientId } : {},
@@ -1684,13 +1796,27 @@ function createCodexSessionCatalogControlFromRequests(params) {
1684
1796
  function createCodexSessionCatalogControl(params) {
1685
1797
  const now = params.now ?? Date.now;
1686
1798
  const getPluginConfig = () => params.getPluginConfig();
1799
+ const requestOptionsByConfig = /* @__PURE__ */ new WeakMap();
1800
+ const catalogPagesByConfig = /* @__PURE__ */ new WeakMap();
1801
+ const resolveRequestOptions = (startOptions) => {
1802
+ const runtimeConfig = params.getRuntimeConfig();
1803
+ if (!runtimeConfig) return {
1804
+ config: void 0,
1805
+ startOptions: structuredClone(startOptions)
1806
+ };
1807
+ const cached = requestOptionsByConfig.get(runtimeConfig);
1808
+ if (cached) return cached;
1809
+ const resolved = {
1810
+ config: structuredClone(runtimeConfig),
1811
+ startOptions: structuredClone(startOptions)
1812
+ };
1813
+ requestOptionsByConfig.set(runtimeConfig, resolved);
1814
+ return resolved;
1815
+ };
1687
1816
  const createRequestSnapshot = () => {
1688
1817
  const pluginConfig = getPluginConfig();
1689
1818
  const runtime = resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig });
1690
- const requestOptions = {
1691
- config: structuredClone(params.getRuntimeConfig()),
1692
- startOptions: structuredClone(runtime.start)
1693
- };
1819
+ const requestOptions = resolveRequestOptions(runtime.start);
1694
1820
  return {
1695
1821
  requestTimeoutMs: runtime.requestTimeoutMs,
1696
1822
  listThreads: async (listParams, timeoutMs) => await codexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.listThreads, listParams, {
@@ -1710,10 +1836,10 @@ function createCodexSessionCatalogControl(params) {
1710
1836
  };
1711
1837
  const withPinnedConnection = async (run) => {
1712
1838
  const runtime = resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig: getPluginConfig() });
1713
- const runtimeConfig = structuredClone(params.getRuntimeConfig());
1839
+ const { config: runtimeConfig, startOptions } = resolveRequestOptions(runtime.start);
1714
1840
  const client = await getLeasedSharedCodexAppServerClient({
1715
1841
  config: runtimeConfig,
1716
- startOptions: structuredClone(runtime.start),
1842
+ startOptions,
1717
1843
  timeoutMs: runtime.requestTimeoutMs
1718
1844
  });
1719
1845
  try {
@@ -1772,11 +1898,112 @@ function createCodexSessionCatalogControl(params) {
1772
1898
  releaseLeasedSharedCodexAppServerClient(client);
1773
1899
  }
1774
1900
  };
1775
- return createCodexSessionCatalogControlFromRequests({
1901
+ const control = createCodexSessionCatalogControlFromRequests({
1776
1902
  createRequestSnapshot,
1777
1903
  now,
1778
1904
  withPinnedConnection
1779
1905
  });
1906
+ return {
1907
+ ...control,
1908
+ async listPage(pageParams) {
1909
+ const runtimeConfig = params.getRuntimeConfig();
1910
+ if (!runtimeConfig) return await control.listPage(pageParams);
1911
+ let cache = catalogPagesByConfig.get(runtimeConfig);
1912
+ if (!cache) {
1913
+ cache = /* @__PURE__ */ new Map();
1914
+ catalogPagesByConfig.set(runtimeConfig, cache);
1915
+ }
1916
+ const key = codexCatalogPageCacheKey(pageParams);
1917
+ const cached = cache.get(key);
1918
+ if (pageParams.forceRefresh !== true && cached) {
1919
+ cache.delete(key);
1920
+ cache.set(key, cached);
1921
+ if (cached.stalePage) return await cached.stalePage;
1922
+ if (cached.expiresAt > now()) return await cached.page;
1923
+ const stalePage = cached.settledPage;
1924
+ if (!stalePage) return await cached.page;
1925
+ const page = control.listPage(pageParams);
1926
+ const entry = {
1927
+ expiresAt: Number.POSITIVE_INFINITY,
1928
+ page,
1929
+ settledPage: stalePage,
1930
+ stalePage
1931
+ };
1932
+ cache.set(key, entry);
1933
+ page.then(() => {
1934
+ if (cache.get(key) === entry) {
1935
+ delete entry.stalePage;
1936
+ entry.settledPage = page;
1937
+ entry.expiresAt = now() + CODEX_SESSION_CATALOG_LIST_TTL_MS;
1938
+ }
1939
+ }, async () => {
1940
+ let stale;
1941
+ try {
1942
+ stale = await stalePage;
1943
+ } catch {}
1944
+ if (cache.get(key) !== entry) return;
1945
+ if (stale) {
1946
+ cache.delete(key);
1947
+ const settledPage = Promise.resolve(stale);
1948
+ cache.set(key, {
1949
+ expiresAt: now(),
1950
+ page: settledPage,
1951
+ settledPage
1952
+ });
1953
+ } else cache.delete(key);
1954
+ });
1955
+ return await stalePage;
1956
+ }
1957
+ if (cached) cache.delete(key);
1958
+ const serveStaleOnError = pageParams.forceRefresh !== true;
1959
+ const page = control.listPage(pageParams);
1960
+ const stalePage = cached?.settledPage;
1961
+ const entry = {
1962
+ expiresAt: Number.POSITIVE_INFINITY,
1963
+ page,
1964
+ ...stalePage ? {
1965
+ stalePage,
1966
+ settledPage: stalePage
1967
+ } : {}
1968
+ };
1969
+ cache.set(key, entry);
1970
+ while (cache.size > CODEX_SESSION_CATALOG_LIST_CACHE_MAX_ENTRIES) {
1971
+ const oldest = cache.keys().next();
1972
+ if (oldest.done) break;
1973
+ cache.delete(oldest.value);
1974
+ }
1975
+ try {
1976
+ const result = await page;
1977
+ if (cache.get(key) === entry) {
1978
+ delete entry.stalePage;
1979
+ entry.settledPage = page;
1980
+ entry.expiresAt = now() + CODEX_SESSION_CATALOG_LIST_TTL_MS;
1981
+ }
1982
+ return result;
1983
+ } catch (error) {
1984
+ if (stalePage) {
1985
+ let stale;
1986
+ try {
1987
+ stale = await stalePage;
1988
+ } catch {}
1989
+ if (stale) {
1990
+ if (cache.get(key) === entry) {
1991
+ cache.delete(key);
1992
+ const settledPage = Promise.resolve(stale);
1993
+ cache.set(key, {
1994
+ expiresAt: now(),
1995
+ page: settledPage,
1996
+ settledPage
1997
+ });
1998
+ }
1999
+ if (serveStaleOnError) return stale;
2000
+ }
2001
+ }
2002
+ if (cache.get(key) === entry) cache.delete(key);
2003
+ throw error;
2004
+ }
2005
+ }
2006
+ };
1780
2007
  }
1781
2008
  async function listGatewayHost(params) {
1782
2009
  try {
@@ -1788,7 +2015,8 @@ async function listGatewayHost(params) {
1788
2015
  const adoptedSessions = await listAdoptedSessionEntries({
1789
2016
  bindingStore: params.bindingStore,
1790
2017
  config: params.config,
1791
- runtime: params.runtime
2018
+ runtime: params.runtime,
2019
+ sessionEntries: params.sessionEntries
1792
2020
  });
1793
2021
  return {
1794
2022
  hostId: CODEX_LOCAL_SESSION_HOST_ID,
@@ -1821,13 +2049,14 @@ async function listCodexSessionCatalog(params) {
1821
2049
  config: params.config,
1822
2050
  control: params.control,
1823
2051
  query,
1824
- runtime: params.runtime
2052
+ runtime: params.runtime,
2053
+ sessionEntries: params.sessionEntries
1825
2054
  })] : [];
1826
2055
  for (const host of localHosts) if (params.onHost) host.then(params.onHost).catch(() => void 0);
1827
2056
  if (!(!requestedHostIds || query.hostIds?.some((hostId) => hostId.startsWith("node:")))) return { hosts: await Promise.all(localHosts) };
1828
2057
  let nodes;
1829
2058
  try {
1830
- nodes = (await params.runtime.nodes.list()).nodes.filter((node) => node.commands?.includes("codex.appServer.threads.list.v1") && (!requestedHostIds || requestedHostIds.has(`node:${node.nodeId}`))).slice(0, 100 - localHosts.length);
2059
+ nodes = (await (params.listNodes?.() ?? params.runtime.nodes.list())).nodes.filter((node) => node.gatewayLocal !== true && node.commands?.includes("codex.appServer.threads.list.v1") && (!requestedHostIds || requestedHostIds.has(`node:${node.nodeId}`))).slice(0, 100 - localHosts.length);
1831
2060
  } catch (error) {
1832
2061
  const registryHost = {
1833
2062
  hostId: "node:registry",
@@ -1842,7 +2071,8 @@ async function listCodexSessionCatalog(params) {
1842
2071
  }
1843
2072
  const adoptedNodeSessions = listNodeAdoptedSessionEntries({
1844
2073
  config: params.config,
1845
- runtime: params.runtime
2074
+ runtime: params.runtime,
2075
+ sessionEntries: params.sessionEntries
1846
2076
  });
1847
2077
  const nodeHosts = nodes.toSorted(compareNodeLabels).map(async (node) => {
1848
2078
  const host = await listPairedNode({
@@ -1979,9 +2209,10 @@ function isAdoptionSessionKeyForThread(sessionKey, threadId) {
1979
2209
  }
1980
2210
  async function listAdoptedSessionEntries(params) {
1981
2211
  const adopted = /* @__PURE__ */ new Map();
1982
- for (const agentId of listSupervisionAgentIds(params.config ?? {})) for (const { entry, sessionKey } of params.runtime.agent.session.listSessionEntries({
1983
- agentId,
1984
- readOnly: true
2212
+ for (const { agentId, entry, sessionKey } of listSessionCatalogEntries({
2213
+ config: params.config ?? {},
2214
+ runtime: params.runtime,
2215
+ sessionEntries: params.sessionEntries
1985
2216
  })) {
1986
2217
  const sessionKeyRest = adoptionSessionKeyRest(sessionKey);
1987
2218
  if (!sessionKeyRest.startsWith(CODEX_SUPERVISION_SESSION_KEY_PREFIX) || entry.initializationPending === true || entry.agentHarnessId !== "codex" || entry.modelSelectionLocked !== true) continue;
@@ -2351,7 +2582,7 @@ function registerCodexSessionCatalog(params) {
2351
2582
  resolveCreateSession: ({ agentId }) => resolveCodexCatalogCreateSession(params.getRuntimeConfig() ?? params.api.config, agentId),
2352
2583
  list: async (query) => {
2353
2584
  const localTerminalAvailable = resolveLocalCodexTerminalExecutable() !== void 0;
2354
- const { onHost, ...gatewayQuery } = query;
2585
+ const { listNodes, onHost, sessionEntries, ...gatewayQuery } = query;
2355
2586
  const mapHost = (host) => toGenericCatalogHost(host, localTerminalAvailable);
2356
2587
  return (await listCodexSessionCatalog({
2357
2588
  bindingStore: params.bindingStore,
@@ -2359,6 +2590,8 @@ function registerCodexSessionCatalog(params) {
2359
2590
  runtime: params.api.runtime,
2360
2591
  control: params.control,
2361
2592
  query: gatewayQuery,
2593
+ listNodes,
2594
+ sessionEntries,
2362
2595
  ...onHost ? { onHost: (host) => onHost(mapHost(host)) } : {}
2363
2596
  })).hosts.map(mapHost);
2364
2597
  },
@@ -1,6 +1,6 @@
1
- import { a as CODEX_LOCAL_SESSION_HOST_ID } from "./session-catalog-DsKaezgR.js";
2
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
1
+ import { a as CODEX_LOCAL_SESSION_HOST_ID } from "./session-catalog-DyOgR4WH.js";
3
2
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
4
4
  import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
5
5
  import { addGatewayClientOptions, callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime";
6
6
  //#region extensions/codex/src/session-cli.ts
@@ -1,4 +1,4 @@
1
- import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-2p7kl6e4.js";
1
+ import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-DzsdNCf5.js";
2
2
  import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
3
3
  //#region extensions/codex/src/app-server/session-history-import.ts
4
4
  /** Creates a session whose transcript is derived from one verified Codex thread snapshot. */
@@ -1,6 +1,8 @@
1
- import { c as fingerprintCodexMirrorSourceMessage, d as attachCodexMirrorIdentity, f as readMirrorIdentity, l as readCodexMirrorSourceFingerprint, p as readUpstreamUserText, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-2p7kl6e4.js";
2
- import { t as runBoundedCodexAppServerTurn } from "./bounded-turn-CaQL96kg.js";
1
+ import { W as isJsonObject } from "./shared-client-DTbvH-XV.js";
2
+ import { c as fingerprintCodexMirrorSourceMessage, d as attachCodexMirrorIdentity, f as readMirrorIdentity, l as readCodexMirrorSourceFingerprint, p as readUpstreamUserText, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-DzsdNCf5.js";
3
+ import { t as runBoundedCodexAppServerTurn } from "./bounded-turn-D2ZAgZVz.js";
3
4
  import { n as createAssistantMessage } from "./event-projector-assistant-message-DTgnPPVF.js";
5
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
4
6
  import { Buffer } from "node:buffer";
5
7
  import { isSilentReplyText } from "openclaw/plugin-sdk/reply-runtime";
6
8
  //#region extensions/codex/src/app-server/settled-turn-projection.ts
@@ -9,9 +11,6 @@ const MAX_PROJECTION_BYTES = 512 * 1024;
9
11
  const MAX_TEXT_BYTES = 64 * 1024;
10
12
  const TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,128}$/u;
11
13
  const TOOL_ERROR_STATUS_PREFIX = "[Tool result status: error]\n";
12
- function isRecord(value) {
13
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
14
- }
15
14
  function readNonEmptyString(value) {
16
15
  return typeof value === "string" ? value.trim() || void 0 : void 0;
17
16
  }
@@ -265,7 +264,21 @@ async function runCodexSettledTurnFinalization(operation, options) {
265
264
  historyItems,
266
265
  requireNoExternalCapabilities: true
267
266
  });
268
- const unexpectedItem = bounded.items.find((item) => !FINALIZER_PASSIVE_ITEM_TYPES.has(item.type));
267
+ let promptEchoSeen = false;
268
+ let unexpectedItem;
269
+ for (const item of bounded.items) {
270
+ if (FINALIZER_PASSIVE_ITEM_TYPES.has(item.type)) continue;
271
+ if (item.type === "userMessage" && !promptEchoSeen) {
272
+ const content = Array.isArray(item.content) ? item.content : [];
273
+ const input = content[0];
274
+ if (content.length === 1 && isJsonObject(input) && input.type === "text" && input.text === attempt.prompt) {
275
+ promptEchoSeen = true;
276
+ continue;
277
+ }
278
+ }
279
+ unexpectedItem = item;
280
+ break;
281
+ }
269
282
  if (unexpectedItem) throw new Error(`Codex settled-turn finalization returned unexpected native item: ${unexpectedItem.type}`);
270
283
  const text = bounded.text.trim();
271
284
  if (!text || isSilentReplyText(text)) throw new Error("Codex settled-turn finalization completed without a visible answer");