@openclaw/codex 2026.7.2-beta.7 → 2026.8.1-beta.2

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 (55) hide show
  1. package/README.md +2 -0
  2. package/dist/{app-server-policy-BSaO2JIT.js → app-server-policy-zcBDc1JU.js} +1 -1
  3. package/dist/attempt-client-cleanup-DMLXUfa8.js +735 -0
  4. package/dist/{notification-correlation-CU6_AnOb.js → binding-connection-I5Bo-AsX.js} +3 -37
  5. package/dist/{bounded-turn-D2ZAgZVz.js → bounded-turn-qgZmzy_4.js} +50 -49
  6. package/dist/{capabilities-BFDTVYr4.js → capabilities-CybGI1oz.js} +8 -2
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-C336eRVS.js → command-formatters-B1AEz8ZA.js} +18 -18
  9. package/dist/{command-handlers-DAHUSry9.js → command-handlers-Db8pu_ds.js} +484 -95
  10. package/dist/{compact-D_uvHurS.js → compact-LspQaGfl.js} +213 -199
  11. package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
  12. package/dist/doctor-contract-api.js +40 -43
  13. package/dist/{dynamic-tools-D2gYkSBO.js → dynamic-tools-BVdyWkUD.js} +2597 -1221
  14. package/dist/{effective-mcp-catalog-Bbd98Inw.js → effective-mcp-catalog-DIIhAtOZ.js} +20 -15
  15. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  16. package/dist/{attempt-notifications-AP-a-Q5k.js → event-projector-usage-e5huIQWu.js} +113 -29
  17. package/dist/harness.js +80 -14
  18. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  19. package/dist/index.js +591 -240
  20. package/dist/isolated-completion-C58NbL40.js +75 -0
  21. package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
  22. package/dist/media-understanding-provider.js +5 -5
  23. package/dist/{models-BBMKU4jA.js → models-BFlpn1Ex.js} +12 -17
  24. package/dist/native-subagent-monitor-DyTGmTUx.js +3111 -0
  25. package/dist/{plugin-app-cache-key-DztPafOA.js → plugin-app-cache-key-C3H2CVp6.js} +5 -5
  26. package/dist/plugin-marketplace-discovery-CzrGJdCR.js +385 -0
  27. package/dist/{computer-use-CYEc8U3w.js → plugin-metadata-cache-CNJPj4_b.js} +105 -5
  28. package/dist/protocol-validators-B4F7L8Rf.js +2346 -0
  29. package/dist/{rate-limits-CU-gVCCS.js → rate-limits-DZXmOL8-.js} +17 -35
  30. package/dist/{request-qKh331yu.js → request-BRl5_UfX.js} +3 -3
  31. package/dist/{run-attempt-CY9WlDLc.js → run-attempt-P8BdxC1I.js} +4837 -9047
  32. package/dist/{runtime-artifact-CmtG_t1L.js → runtime-artifact-BVSPdd6g.js} +8 -23
  33. package/dist/{sandbox-guard-NuhpXmPB.js → sandbox-guard-Cmwc9eIk.js} +6 -13
  34. package/dist/{session-binding-BXpo9ymA.js → session-binding-DPxIvMgE.js} +246 -265
  35. package/dist/{session-catalog-DyOgR4WH.js → session-catalog-xwNi_SDM.js} +159 -109
  36. package/dist/{session-cli-2PZaFLRh.js → session-cli-7hgXZDV7.js} +1 -1
  37. package/dist/session-retirement-DoMMJFKm.js +36 -0
  38. package/dist/{session-upstream-marker-B6U7tLw5.js → session-upstream-marker-CrIFX06J.js} +1 -1
  39. package/dist/{settled-turn-finalizer-CXY2Z9dT.js → settled-turn-finalizer-BRWBO4MO.js} +21 -13
  40. package/dist/{shared-client-DTbvH-XV.js → shared-client-kIBbGjk4.js} +587 -223
  41. package/dist/{side-question-_ulBk1AL.js → side-question-9HAL26l9.js} +101 -52
  42. package/dist/{thread-lifecycle-DF53ogiA.js → thread-lifecycle-Bu1BTDXr.js} +694 -753
  43. package/dist/thread-ownership-6kOQHlyC.js +92 -0
  44. package/dist/thread-resume-CPrJNQVM.js +30 -0
  45. package/dist/transcript-mirror-B9gGgnJS.js +570 -0
  46. package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DIImwDVS.js} +11 -0
  47. package/dist/upstream-prompt-provenance-ClRBije0.js +41 -0
  48. package/dist/{upstream-session-fork-Dy4Xvuoj.js → upstream-session-fork-CE-_LdnP.js} +5 -5
  49. package/dist/{usage-CQ6GhD5-.js → usage-CHlV0e-o.js} +3 -3
  50. package/dist/{web-search-provider.runtime-CCFhg2z5.js → web-search-provider.runtime-DRw2Vl42.js} +8 -9
  51. package/openclaw.plugin.json +18 -3
  52. package/package.json +5 -5
  53. package/dist/conversation-control-xsIeXbo4.js +0 -287
  54. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  55. package/dist/transcript-mirror-DzsdNCf5.js +0 -6924
@@ -1,30 +1,31 @@
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
- import { n as createCodexCliNodeConversationBindingData } from "./conversation-binding-data-BHRpYbX3.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";
1
+ import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, g as resolveCodexAppServerRuntimeOptions, y as resolveCodexSupervisionAppServerRuntimeOptions } from "./session-binding-DPxIvMgE.js";
2
+ import { R as resolveCodexAppServerClientInstanceId, _ as withTimeout, a as getLeasedSharedCodexAppServerClient, at as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, ct as isJsonObject, dt as resolveCodexAppServerLocalHomeDir, it as CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES, l as releaseLeasedSharedCodexAppServerClient, z as CodexAppServerRpcError } from "./shared-client-kIBbGjk4.js";
3
+ import { n as assertCodexThreadForkParams } from "./protocol-validators-B4F7L8Rf.js";
4
+ import { n as listCodexAppServerModels } from "./models-BFlpn1Ex.js";
5
+ import { t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-C3H2CVp6.js";
6
+ import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-B9gGgnJS.js";
7
+ import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-CybGI1oz.js";
8
+ import { r as formatCodexDisplayText } from "./command-formatters-B1AEz8ZA.js";
9
+ import { n as createCodexCliNodeConversationBindingData } from "./conversation-binding-data-CW2GuupV.js";
10
+ import { i as withCodexAppServerJsonClient, n as requestCodexAppServerClientJson, r as requestCodexAppServerJson } from "./request-BRl5_UfX.js";
11
+ import { i as createImportedCodexSession, n as codexUpstreamBaseline, r as codexUpstreamContinueResult, t as codexLastTerminalTurnId } from "./session-upstream-marker-CrIFX06J.js";
12
+ import { asFiniteNumber, isRecord, normalizeBoundedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
11
13
  import fs from "node:fs/promises";
12
14
  import path from "node:path";
13
15
  import { timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
14
16
  import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
15
17
  import { createHash } from "node:crypto";
16
- import { listAgentIds, resolveAllowedModelRef, resolveDefaultAgentDir, resolveDefaultAgentId, resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
17
18
  import os from "node:os";
19
+ import { listAgentIds, resolveAllowedModelRef, resolveDefaultAgentDir, resolveDefaultAgentId, resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
18
20
  import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
19
- import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
20
21
  import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "openclaw/plugin-sdk/windows-spawn";
21
22
  import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
22
23
  import { spawn } from "node:child_process";
23
24
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
24
25
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
26
+ import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
25
27
  import process$1 from "node:process";
26
28
  import { listSessionCatalogEntries } from "openclaw/plugin-sdk/session-catalog";
27
- import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
28
29
  import { decodeNodePtyResumeParams, resolveNodeHostExecutable, runNodePtyCommand } from "openclaw/plugin-sdk/node-host";
29
30
  //#region extensions/codex/src/jsonl-lines.ts
30
31
  const JSONL_STREAM_THRESHOLD_BYTES = 4 * 1024 * 1024;
@@ -578,61 +579,6 @@ function formatNodeLabel(node) {
578
579
  ].filter(Boolean).join(" / ") || "node";
579
580
  }
580
581
  //#endregion
581
- //#region extensions/codex/src/app-server/thread-archive-guard.ts
582
- const DESCENDANT_PAGE_LIMIT = 100;
583
- const MAX_DESCENDANT_PAGES = 100;
584
- const MAX_THREAD_ID_LENGTH = 256;
585
- const MAX_CURSOR_LENGTH$1 = 4096;
586
- function readBoundedId(value) {
587
- if (typeof value !== "string") return;
588
- const normalized = value.trim();
589
- return normalized && normalized.length <= MAX_THREAD_ID_LENGTH ? normalized : void 0;
590
- }
591
- function readNextCursor(value) {
592
- if (value === void 0 || value === null) return;
593
- if (typeof value !== "string" || !value.trim() || value.length > MAX_CURSOR_LENGTH$1) throw new Error("Codex app-server returned an invalid descendant-list cursor");
594
- return value;
595
- }
596
- /**
597
- * Native archive includes the spawned subtree. Enumerate that same subtree first so an
598
- * OpenClaw-owned descendant cannot be stopped as an undocumented side effect.
599
- */
600
- async function assertCodexArchiveDescendantsUnowned(params) {
601
- const ancestorThreadId = readBoundedId(params.threadId);
602
- if (!ancestorThreadId) throw new Error("cannot verify Codex archive descendants for an invalid thread id");
603
- const seenCursors = /* @__PURE__ */ new Set();
604
- const seenThreadIds = /* @__PURE__ */ new Set([ancestorThreadId]);
605
- let cursor;
606
- for (let pageIndex = 0; pageIndex < MAX_DESCENDANT_PAGES; pageIndex += 1) {
607
- const response = await params.listPage({
608
- ancestorThreadId,
609
- archived: false,
610
- limit: DESCENDANT_PAGE_LIMIT,
611
- sortKey: "created_at",
612
- sortDirection: "desc",
613
- useStateDbOnly: true,
614
- ...cursor ? { cursor } : {}
615
- });
616
- if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex app-server returned an invalid descendant-list response");
617
- if (response.data.length > DESCENDANT_PAGE_LIMIT) throw new Error("Codex app-server exceeded the descendant-list page limit");
618
- for (const value of response.data) {
619
- if (!isJsonObject(value)) throw new Error("Codex app-server returned an invalid descendant thread");
620
- const descendantThreadId = readBoundedId(value.id);
621
- if (!descendantThreadId) throw new Error("Codex app-server returned a descendant without a valid thread id");
622
- if (seenThreadIds.has(descendantThreadId)) throw new Error("Codex app-server returned a cyclic descendant thread list");
623
- seenThreadIds.add(descendantThreadId);
624
- await params.assertDescendantIdle(descendantThreadId);
625
- if (await params.bindingStore.hasOtherThreadOwner(descendantThreadId)) throw new Error("cannot archive a Codex thread while a spawned descendant is owned by an OpenClaw session");
626
- }
627
- const nextCursor = readNextCursor(response.nextCursor);
628
- if (!nextCursor) return;
629
- if (seenCursors.has(nextCursor)) throw new Error("Codex app-server returned a repeated descendant-list cursor");
630
- seenCursors.add(nextCursor);
631
- cursor = nextCursor;
632
- }
633
- throw new Error("Codex descendant enumeration exceeded its safety limit");
634
- }
635
- //#endregion
636
582
  //#region extensions/codex/src/command-rpc.ts
637
583
  function requestOptions(pluginConfig, limit, config, agentDir) {
638
584
  const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig });
@@ -645,10 +591,8 @@ function requestOptions(pluginConfig, limit, config, agentDir) {
645
591
  };
646
592
  }
647
593
  async function codexControlRequest(pluginConfig, method, requestParams, options = {}) {
648
- const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig });
649
- return await requestCodexAppServerJson({
650
- method,
651
- requestParams,
594
+ const runtime = options.startOptions ? resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig }) : resolveCodexAppServerRuntimeOptions({ pluginConfig });
595
+ const controlRequestOptions = {
652
596
  timeoutMs: options.timeoutMs ?? runtime.requestTimeoutMs,
653
597
  startOptions: options.startOptions ?? runtime.start,
654
598
  config: options.config,
@@ -657,6 +601,19 @@ async function codexControlRequest(pluginConfig, method, requestParams, options
657
601
  authProfileId: options.authProfileId,
658
602
  agentDir: options.agentDir,
659
603
  isolated: options.isolated
604
+ };
605
+ if (options.onResponse) return await withCodexAppServerJsonClient(controlRequestOptions, async (request, client) => {
606
+ const response = await request({
607
+ method,
608
+ requestParams
609
+ });
610
+ await options.onResponse(response, client);
611
+ return response;
612
+ });
613
+ return await requestCodexAppServerJson({
614
+ method,
615
+ requestParams,
616
+ ...controlRequestOptions
660
617
  });
661
618
  }
662
619
  async function safeCodexControlRequest(pluginConfig, method, requestParams, options = {}) {
@@ -707,6 +664,56 @@ async function safeValue(read) {
707
664
  }
708
665
  }
709
666
  //#endregion
667
+ //#region extensions/codex/src/app-server/thread-archive-guard.ts
668
+ const DESCENDANT_PAGE_LIMIT = 100;
669
+ const MAX_DESCENDANT_PAGES = 100;
670
+ const MAX_THREAD_ID_LENGTH = 256;
671
+ const MAX_CURSOR_LENGTH$1 = 4096;
672
+ function readNextCursor(value) {
673
+ if (value === void 0 || value === null) return;
674
+ if (typeof value !== "string" || !value.trim() || value.length > MAX_CURSOR_LENGTH$1) throw new Error("Codex app-server returned an invalid descendant-list cursor");
675
+ return value;
676
+ }
677
+ /**
678
+ * Native archive includes the spawned subtree. Enumerate that same subtree first so an
679
+ * OpenClaw-owned descendant cannot be stopped as an undocumented side effect.
680
+ */
681
+ async function assertCodexArchiveDescendantsUnowned(params) {
682
+ const ancestorThreadId = normalizeBoundedOptionalString(params.threadId, MAX_THREAD_ID_LENGTH);
683
+ if (!ancestorThreadId) throw new Error("cannot verify Codex archive descendants for an invalid thread id");
684
+ const seenCursors = /* @__PURE__ */ new Set();
685
+ const seenThreadIds = /* @__PURE__ */ new Set([ancestorThreadId]);
686
+ let cursor;
687
+ for (let pageIndex = 0; pageIndex < MAX_DESCENDANT_PAGES; pageIndex += 1) {
688
+ const response = await params.listPage({
689
+ ancestorThreadId,
690
+ archived: false,
691
+ limit: DESCENDANT_PAGE_LIMIT,
692
+ sortKey: "created_at",
693
+ sortDirection: "desc",
694
+ useStateDbOnly: true,
695
+ ...cursor ? { cursor } : {}
696
+ });
697
+ if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex app-server returned an invalid descendant-list response");
698
+ if (response.data.length > DESCENDANT_PAGE_LIMIT) throw new Error("Codex app-server exceeded the descendant-list page limit");
699
+ for (const value of response.data) {
700
+ if (!isJsonObject(value)) throw new Error("Codex app-server returned an invalid descendant thread");
701
+ const descendantThreadId = normalizeBoundedOptionalString(value.id, MAX_THREAD_ID_LENGTH);
702
+ if (!descendantThreadId) throw new Error("Codex app-server returned a descendant without a valid thread id");
703
+ if (seenThreadIds.has(descendantThreadId)) throw new Error("Codex app-server returned a cyclic descendant thread list");
704
+ seenThreadIds.add(descendantThreadId);
705
+ await params.assertDescendantIdle(descendantThreadId);
706
+ if (await params.bindingStore.hasOtherThreadOwner(descendantThreadId)) throw new Error("cannot archive a Codex thread while a spawned descendant is owned by an OpenClaw session");
707
+ }
708
+ const nextCursor = readNextCursor(response.nextCursor);
709
+ if (!nextCursor) return;
710
+ if (seenCursors.has(nextCursor)) throw new Error("Codex app-server returned a repeated descendant-list cursor");
711
+ seenCursors.add(nextCursor);
712
+ cursor = nextCursor;
713
+ }
714
+ throw new Error("Codex descendant enumeration exceeded its safety limit");
715
+ }
716
+ //#endregion
710
717
  //#region extensions/codex/src/session-catalog-create.ts
711
718
  const CODEX_AGENT_RUNTIME_ID = "codex";
712
719
  const CODEX_CATALOG_DEFAULT_MODEL_REF = "openai/gpt-5.6-sol";
@@ -813,7 +820,7 @@ function normalizeLimit(value, key) {
813
820
  if (!Number.isInteger(value) || value < 1 || value > 100) throw new CatalogParamsError(`${key} must be an integer from 1 to 100`);
814
821
  return value;
815
822
  }
816
- function readOptionalString(params, key, maxLength) {
823
+ function readBoundedOptionalString(params, key, maxLength) {
817
824
  const value = params[key];
818
825
  if (value === void 0) return;
819
826
  if (typeof value !== "string") throw new CatalogParamsError(`${key} must be a string`);
@@ -835,9 +842,9 @@ function readPageParams(value) {
835
842
  "searchTerm",
836
843
  "cwd"
837
844
  ]));
838
- const cursor = readOptionalString(params, "cursor", MAX_CURSOR_LENGTH);
839
- const searchTerm = readOptionalString(params, "searchTerm", MAX_SEARCH_LENGTH);
840
- const cwd = readOptionalString(params, "cwd", MAX_CWD_LENGTH);
845
+ const cursor = readBoundedOptionalString(params, "cursor", MAX_CURSOR_LENGTH);
846
+ const searchTerm = readBoundedOptionalString(params, "searchTerm", MAX_SEARCH_LENGTH);
847
+ const cwd = readBoundedOptionalString(params, "cwd", MAX_CWD_LENGTH);
841
848
  return {
842
849
  limit: normalizeLimit(params.limit, "limit"),
843
850
  ...cursor ? { cursor } : {},
@@ -854,7 +861,7 @@ function readGatewayParams(value) {
854
861
  "hostIds",
855
862
  "cursors"
856
863
  ]));
857
- const search = readOptionalString(params, "search", MAX_SEARCH_LENGTH);
864
+ const search = readBoundedOptionalString(params, "search", MAX_SEARCH_LENGTH);
858
865
  let hostIds;
859
866
  if (params.hostIds !== void 0) {
860
867
  if (!Array.isArray(params.hostIds) || params.hostIds.length > 100) throw new CatalogParamsError(`hostIds must contain at most 100 host ids`);
@@ -894,9 +901,6 @@ function parseJsonParams(paramsJSON) {
894
901
  throw new Error("Codex session catalog parameters must be valid JSON", { cause: error });
895
902
  }
896
903
  }
897
- function readFiniteNumber(value) {
898
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
899
- }
900
904
  function parseOptionalCatalogString(value, field, maxLength) {
901
905
  if (value === void 0) return;
902
906
  if (typeof value !== "string" || value.length > maxLength) throw new Error(`Codex session catalog returned an invalid ${field}`);
@@ -922,9 +926,9 @@ function parseCatalogSession(value, options = {}) {
922
926
  const cliVersion = parseOptionalCatalogString(value.cliVersion, "CLI version", MAX_METADATA_LENGTH);
923
927
  const gitBranch = parseOptionalCatalogString(value.gitBranch, "Git branch", MAX_METADATA_LENGTH);
924
928
  const sessionKey = options.allowSessionKey ? parseOptionalCatalogString(value.sessionKey, "OpenClaw session key", MAX_SESSION_KEY_LENGTH) : void 0;
925
- const createdAt = readFiniteNumber(value.createdAt);
926
- const updatedAt = readFiniteNumber(value.updatedAt);
927
- const recencyAt = value.recencyAt === null ? null : readFiniteNumber(value.recencyAt);
929
+ const createdAt = asFiniteNumber(value.createdAt);
930
+ const updatedAt = asFiniteNumber(value.updatedAt);
931
+ const recencyAt = value.recencyAt === null ? null : asFiniteNumber(value.recencyAt);
928
932
  return {
929
933
  threadId: value.threadId,
930
934
  status,
@@ -1415,6 +1419,12 @@ async function continueNodeCodexSession(params) {
1415
1419
  //#endregion
1416
1420
  //#region extensions/codex/src/session-catalog-terminal.ts
1417
1421
  const CODEX_TERMINAL_RESUME_COMMAND = "codex.terminal.resume.v1";
1422
+ function resolveCodexCatalogTerminalHome(sources) {
1423
+ const runtimeConfig = sources.getRuntimeConfig();
1424
+ if (!runtimeConfig) throw new Error("OpenClaw runtime config is unavailable");
1425
+ const startOptions = resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig: sources.getPluginConfig() }).start;
1426
+ return resolveCodexAppServerLocalHomeDir(startOptions, resolveDefaultAgentDir(runtimeConfig));
1427
+ }
1418
1428
  function resolveLocalCodexTerminalExecutable(env = process.env) {
1419
1429
  return resolveLocalCodexTerminalResolution(env)?.executable;
1420
1430
  }
@@ -1458,7 +1468,7 @@ async function findCatalogEligibleThread(control, threadId, forceRefresh) {
1458
1468
  }
1459
1469
  throw new CatalogParamsError("Codex session eligibility could not be verified");
1460
1470
  }
1461
- function createCodexTerminalNodeHostCommand(control) {
1471
+ function createCodexTerminalNodeHostCommand(control, configSources) {
1462
1472
  return {
1463
1473
  command: CODEX_TERMINAL_RESUME_COMMAND,
1464
1474
  cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
@@ -1486,6 +1496,7 @@ function createCodexTerminalNodeHostCommand(control) {
1486
1496
  file: resolution.executable,
1487
1497
  args: ["resume", resume.threadId],
1488
1498
  cwd: record.cwd,
1499
+ env: { CODEX_HOME: resolveCodexCatalogTerminalHome(configSources) },
1489
1500
  cols: resume.cols,
1490
1501
  rows: resume.rows
1491
1502
  }, io));
@@ -1533,6 +1544,7 @@ async function openCodexCatalogTerminal(params) {
1533
1544
  params.threadId
1534
1545
  ],
1535
1546
  ...record.cwd ? { cwd: record.cwd } : {},
1547
+ env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
1536
1548
  ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
1537
1549
  title
1538
1550
  };
@@ -1558,6 +1570,19 @@ async function openCodexCatalogTerminal(params) {
1558
1570
  title
1559
1571
  };
1560
1572
  }
1573
+ async function startCodexCatalogTerminal(params) {
1574
+ if (params.nodeId) throw new CatalogParamsError("Paired-node Codex terminal start is unavailable; omit hostId to start on the gateway host");
1575
+ const resolution = resolveLocalCodexTerminalResolution();
1576
+ if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable; install Codex or add codex to PATH, then try again");
1577
+ return {
1578
+ kind: "local",
1579
+ argv: [resolution.executable, ...params.initialMessage !== void 0 ? ["--", params.initialMessage] : []],
1580
+ cwd: params.cwd,
1581
+ env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
1582
+ ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
1583
+ title: "codex"
1584
+ };
1585
+ }
1561
1586
  //#endregion
1562
1587
  //#region extensions/codex/src/session-catalog-transcript-item.ts
1563
1588
  const CODEX_MESSAGE_TYPES = /* @__PURE__ */ new Map([
@@ -2044,7 +2069,7 @@ async function listGatewayHost(params) {
2044
2069
  async function listCodexSessionCatalog(params) {
2045
2070
  const query = readGatewayParams(params.query);
2046
2071
  const requestedHostIds = query.hostIds ? new Set(query.hostIds) : void 0;
2047
- const localHosts = !requestedHostIds || requestedHostIds.has("gateway:local") ? [listGatewayHost({
2072
+ const localHosts = params.includeLocal !== false && (!requestedHostIds || requestedHostIds.has("gateway:local")) ? [listGatewayHost({
2048
2073
  bindingStore: params.bindingStore,
2049
2074
  config: params.config,
2050
2075
  control: params.control,
@@ -2087,7 +2112,7 @@ async function listCodexSessionCatalog(params) {
2087
2112
  return { hosts: await Promise.all([...localHosts, ...nodeHosts]) };
2088
2113
  }
2089
2114
  /** Builds the node-local read-only Codex app-server catalog command. */
2090
- function createCodexSessionCatalogNodeHostCommands(control) {
2115
+ function createCodexSessionCatalogNodeHostCommands(control, configSources) {
2091
2116
  return [
2092
2117
  {
2093
2118
  command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
@@ -2125,7 +2150,7 @@ function createCodexSessionCatalogNodeHostCommands(control) {
2125
2150
  }
2126
2151
  }
2127
2152
  },
2128
- createCodexTerminalNodeHostCommand(control)
2153
+ createCodexTerminalNodeHostCommand(control, configSources)
2129
2154
  ];
2130
2155
  }
2131
2156
  function readNodeTranscriptParams(value) {
@@ -2135,9 +2160,9 @@ function readNodeTranscriptParams(value) {
2135
2160
  "cursor",
2136
2161
  "limit"
2137
2162
  ]));
2138
- const threadId = readOptionalString(value, "threadId", 256);
2163
+ const threadId = readBoundedOptionalString(value, "threadId", 256);
2139
2164
  if (!threadId) throw new CatalogParamsError("threadId is required");
2140
- const cursor = readOptionalString(value, "cursor", MAX_CURSOR_LENGTH);
2165
+ const cursor = readBoundedOptionalString(value, "cursor", MAX_CURSOR_LENGTH);
2141
2166
  return {
2142
2167
  threadId,
2143
2168
  limit: readBoundedLimit(value.limit, "limit", 20, 50),
@@ -2239,7 +2264,6 @@ async function listAdoptedSessionEntries(params) {
2239
2264
  async function findAdoptedSessionEntry(params) {
2240
2265
  return (await listAdoptedSessionEntries(params)).get(params.threadId);
2241
2266
  }
2242
- var CodexAdoptionBindingCleanupError = class extends AggregateError {};
2243
2267
  async function clearCreatedAdoptionBinding(params) {
2244
2268
  let cleared = false;
2245
2269
  let clearError;
@@ -2257,14 +2281,14 @@ async function clearCreatedAdoptionBinding(params) {
2257
2281
  try {
2258
2282
  current = await params.bindingStore.read(params.identity);
2259
2283
  } catch (readError) {
2260
- throw new CodexAdoptionBindingCleanupError([
2284
+ throw new AggregateError([
2261
2285
  params.cause,
2262
2286
  ...clearError ? [clearError] : [],
2263
2287
  readError
2264
- ], `OpenClaw session creation failed and the Codex binding could not be verified for ${params.sourceThreadId}`);
2288
+ ], `OpenClaw session creation failed and the Codex binding could not be verified for ${params.sourceThreadId}`, { cause: readError });
2265
2289
  }
2266
2290
  if (!matchesPendingSupervisionOwner(current, params.expectedPending)) return;
2267
- throw new CodexAdoptionBindingCleanupError([params.cause, ...clearError ? [clearError] : []], `OpenClaw session creation failed and the Codex binding could not be cleared for ${params.sourceThreadId}`);
2291
+ throw new AggregateError([params.cause, ...clearError ? [clearError] : []], `OpenClaw session creation failed and the Codex binding could not be cleared for ${params.sourceThreadId}`, { cause: params.cause });
2268
2292
  }
2269
2293
  function matchesPendingAdoptionBinding(binding, expected) {
2270
2294
  const historyCoveredThrough = binding?.historyCoveredThrough;
@@ -2576,13 +2600,22 @@ function toGenericCatalogHost(host, localTerminalAvailable) {
2576
2600
  };
2577
2601
  }
2578
2602
  function registerCodexSessionCatalog(params) {
2579
- const provider = {
2603
+ const usesProcessHomeFallback = () => {
2604
+ const start = resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig: params.getPluginConfig() }).start;
2605
+ return start.transport === "stdio" && start.homeScope === "user" && !process.env.CODEX_HOME?.trim();
2606
+ };
2607
+ const assertLocalAccess = (hostId, allowProcessHomeFallback) => {
2608
+ if (hostId === "gateway:local" && allowProcessHomeFallback === false && usesProcessHomeFallback()) throw new CatalogParamsError("local Codex sessions are unavailable in isolated state");
2609
+ };
2610
+ const checkUpstreamActivity = createChecker(params);
2611
+ params.api.registerSessionCatalog({
2580
2612
  id: "codex",
2581
2613
  label: "Codex",
2614
+ supportsProcessHomeIsolation: true,
2582
2615
  resolveCreateSession: ({ agentId }) => resolveCodexCatalogCreateSession(params.getRuntimeConfig() ?? params.api.config, agentId),
2583
2616
  list: async (query) => {
2584
2617
  const localTerminalAvailable = resolveLocalCodexTerminalExecutable() !== void 0;
2585
- const { listNodes, onHost, sessionEntries, ...gatewayQuery } = query;
2618
+ const { allowProcessHomeFallback, listNodes, onHost, sessionEntries, ...gatewayQuery } = query;
2586
2619
  const mapHost = (host) => toGenericCatalogHost(host, localTerminalAvailable);
2587
2620
  return (await listCodexSessionCatalog({
2588
2621
  bindingStore: params.bindingStore,
@@ -2592,17 +2625,20 @@ function registerCodexSessionCatalog(params) {
2592
2625
  query: gatewayQuery,
2593
2626
  listNodes,
2594
2627
  sessionEntries,
2628
+ includeLocal: allowProcessHomeFallback !== false || !usesProcessHomeFallback(),
2595
2629
  ...onHost ? { onHost: (host) => onHost(mapHost(host)) } : {}
2596
2630
  })).hosts.map(mapHost);
2597
2631
  },
2598
2632
  read: async (request) => {
2633
+ const { allowProcessHomeFallback, ...catalogRequest } = request;
2634
+ assertLocalAccess(catalogRequest.hostId, allowProcessHomeFallback);
2599
2635
  const page = await readCodexSessionTranscript({
2600
2636
  runtime: params.api.runtime,
2601
2637
  control: params.control,
2602
- hostId: request.hostId,
2603
- threadId: request.threadId,
2604
- cursor: request.cursor,
2605
- limit: request.limit ?? 20
2638
+ hostId: catalogRequest.hostId,
2639
+ threadId: catalogRequest.threadId,
2640
+ cursor: catalogRequest.cursor,
2641
+ limit: catalogRequest.limit ?? 20
2606
2642
  });
2607
2643
  return {
2608
2644
  ...page,
@@ -2610,6 +2646,7 @@ function registerCodexSessionCatalog(params) {
2610
2646
  };
2611
2647
  },
2612
2648
  continueSession: async (request) => {
2649
+ assertLocalAccess(request.hostId, request.allowProcessHomeFallback);
2613
2650
  const config = params.getRuntimeConfig();
2614
2651
  if (!config) throw new Error("OpenClaw runtime config is unavailable");
2615
2652
  if (request.hostId.startsWith("node:")) return await continueNodeCodexSession({
@@ -2632,8 +2669,9 @@ function registerCodexSessionCatalog(params) {
2632
2669
  }
2633
2670
  })).sessionKey, request.threadId, upstreamBaseline);
2634
2671
  },
2635
- checkUpstreamActivity: createChecker(params),
2672
+ checkUpstreamActivity: (probes, policy) => checkUpstreamActivity(probes.filter((probe) => probe.hostId !== "gateway:local" || policy?.allowProcessHomeFallback !== false || !usesProcessHomeFallback())),
2636
2673
  archive: async (request) => {
2674
+ assertLocalAccess(request.hostId, request.allowProcessHomeFallback);
2637
2675
  if (request.confirmNoOtherRunner !== true) throw new CatalogParamsError("archive requires confirmation that no other runner is active");
2638
2676
  if (request.hostId !== "gateway:local") throw new CatalogParamsError("paired-node Codex sessions are view-only");
2639
2677
  const config = params.getRuntimeConfig();
@@ -2647,14 +2685,26 @@ function registerCodexSessionCatalog(params) {
2647
2685
  });
2648
2686
  return { ok: true };
2649
2687
  },
2650
- openTerminal: (request) => openCodexCatalogTerminal({
2651
- api: params.api,
2652
- control: params.control,
2653
- parseCatalogPage,
2654
- ...request
2655
- })
2656
- };
2657
- params.api.registerSessionCatalog(provider);
2688
+ openTerminal: async (request) => {
2689
+ assertLocalAccess(request.hostId, request.allowProcessHomeFallback);
2690
+ return await openCodexCatalogTerminal({
2691
+ api: params.api,
2692
+ control: params.control,
2693
+ getPluginConfig: params.getPluginConfig,
2694
+ getRuntimeConfig: params.getRuntimeConfig,
2695
+ parseCatalogPage,
2696
+ ...request
2697
+ });
2698
+ },
2699
+ startTerminalSession: async (request) => {
2700
+ assertLocalAccess(request.nodeId ? `node:${request.nodeId}` : CODEX_LOCAL_SESSION_HOST_ID, request.allowProcessHomeFallback);
2701
+ return await startCodexCatalogTerminal({
2702
+ getPluginConfig: params.getPluginConfig,
2703
+ getRuntimeConfig: params.getRuntimeConfig,
2704
+ ...request
2705
+ });
2706
+ }
2707
+ });
2658
2708
  }
2659
2709
  const codexSessionCatalogRuntime = {
2660
2710
  register: registerCodexSessionCatalog,
@@ -2665,4 +2715,4 @@ const codexSessionCatalogRuntime = {
2665
2715
  archiveLocal: archiveLocalCodexSession
2666
2716
  };
2667
2717
  //#endregion
2668
- export { CODEX_LOCAL_SESSION_HOST_ID as a, requestOptions as c, createCodexCliSessionNodeHostCommands as d, createCodexCliSessionNodeInvokePolicies as f, resumeCodexCliSessionOnNode as g, resolveCodexCliSessionForBindingOnNode as h, createCodexSessionCatalogNodeInvokePolicies as i, safeCodexControlRequest as l, listCodexCliSessionsOnNode as m, createCodexSessionCatalogControl as n, codexControlRequest as o, formatCodexCliSessions as p, createCodexSessionCatalogNodeHostCommands as r, readCodexStatusProbes as s, codexSessionCatalogRuntime as t, assertCodexArchiveDescendantsUnowned as u };
2718
+ export { CODEX_LOCAL_SESSION_HOST_ID as a, readCodexStatusProbes as c, createCodexCliSessionNodeHostCommands as d, createCodexCliSessionNodeInvokePolicies as f, resumeCodexCliSessionOnNode as g, resolveCodexCliSessionForBindingOnNode as h, createCodexSessionCatalogNodeInvokePolicies as i, requestOptions as l, listCodexCliSessionsOnNode as m, createCodexSessionCatalogControl as n, assertCodexArchiveDescendantsUnowned as o, formatCodexCliSessions as p, createCodexSessionCatalogNodeHostCommands as r, codexControlRequest as s, codexSessionCatalogRuntime as t, safeCodexControlRequest as u };
@@ -1,4 +1,4 @@
1
- import { a as CODEX_LOCAL_SESSION_HOST_ID } from "./session-catalog-DyOgR4WH.js";
1
+ import { a as CODEX_LOCAL_SESSION_HOST_ID } from "./session-catalog-xwNi_SDM.js";
2
2
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
4
4
  import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
@@ -0,0 +1,36 @@
1
+ import { K as releaseCodexAppServerLiveThread, d as retainSharedCodexAppServerClientByInstanceId } from "./shared-client-kIBbGjk4.js";
2
+ import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-DMLXUfa8.js";
3
+ import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
4
+ import { t as codexNativeSubagentMonitorRuntime } from "./native-subagent-monitor-DyTGmTUx.js";
5
+ //#region extensions/codex/src/app-server/session-retirement.ts
6
+ /** Retire binding and native subscription under the same generation/physical-client ownership fence. */
7
+ async function retireCodexAppServerSessionGeneration(params) {
8
+ const retireGeneration = () => params.mode === "reset" ? params.bindingStore.resetSessionGeneration(params.identity) : params.bindingStore.retireSessionGeneration(params.identity);
9
+ const expectedBinding = await params.bindingStore.read(params.identity);
10
+ if (!expectedBinding) return await retireGeneration();
11
+ return await params.bindingStore.withLease(params.identity, async () => {
12
+ const binding = await params.bindingStore.read(params.identity);
13
+ if (binding?.threadId !== expectedBinding.threadId) return "conflict";
14
+ const result = await retireGeneration();
15
+ if (result !== "applied" || !binding?.clientId) return result;
16
+ const clientLease = retainSharedCodexAppServerClientByInstanceId(binding.clientId);
17
+ if (!clientLease) return result;
18
+ try {
19
+ codexNativeSubagentMonitorRuntime.retireParent(clientLease.client, binding.threadId);
20
+ if (!await releaseCodexAppServerLiveThread(clientLease.client, binding.threadId) && isIncognitoSessionKey(params.identity.sessionKey)) {
21
+ if (!await unsubscribeCodexThreadBestEffort(clientLease.client, {
22
+ threadId: binding.threadId,
23
+ timeoutMs: 5e3
24
+ })) {
25
+ await closeCodexStartupClientBestEffort(clientLease.client);
26
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex retired session subscription could not be released: ${binding.threadId}`);
27
+ }
28
+ }
29
+ } finally {
30
+ clientLease.release();
31
+ }
32
+ return result;
33
+ });
34
+ }
35
+ //#endregion
36
+ export { retireCodexAppServerSessionGeneration };
@@ -1,4 +1,4 @@
1
- import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-DzsdNCf5.js";
1
+ import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-B9gGgnJS.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,8 +1,9 @@
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";
4
- import { n as createAssistantMessage } from "./event-projector-assistant-message-DTgnPPVF.js";
5
- import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
1
+ import { ct as isJsonObject } from "./shared-client-kIBbGjk4.js";
2
+ import { i as readUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-ClRBije0.js";
3
+ import { c as readCodexMirrorSourceFingerprint, s as fingerprintCodexMirrorSourceMessage, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-B9gGgnJS.js";
4
+ import { t as runBoundedCodexAppServerTurn } from "./bounded-turn-qgZmzy_4.js";
5
+ import { n as createAssistantMessage } from "./event-projector-assistant-message-BwxV4d6N.js";
6
+ import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
7
  import { Buffer } from "node:buffer";
7
8
  import { isSilentReplyText } from "openclaw/plugin-sdk/reply-runtime";
8
9
  //#region extensions/codex/src/app-server/settled-turn-projection.ts
@@ -11,9 +12,6 @@ const MAX_PROJECTION_BYTES = 512 * 1024;
11
12
  const MAX_TEXT_BYTES = 64 * 1024;
12
13
  const TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,128}$/u;
13
14
  const TOOL_ERROR_STATUS_PREFIX = "[Tool result status: error]\n";
14
- function readNonEmptyString(value) {
15
- return typeof value === "string" ? value.trim() || void 0 : void 0;
16
- }
17
15
  function readBoundedText(value, label, maxBytes = MAX_TEXT_BYTES) {
18
16
  if (typeof value !== "string" || !value.trim()) return;
19
17
  if (Buffer.byteLength(value, "utf8") > maxBytes) throw new Error(`Codex settled-turn projection found oversized ${label}`);
@@ -28,12 +26,12 @@ function responseItemBytes(item) {
28
26
  return Buffer.byteLength(JSON.stringify(item), "utf8");
29
27
  }
30
28
  function requireCallId(value) {
31
- const callId = readNonEmptyString(value);
29
+ const callId = normalizeOptionalString(value);
32
30
  if (!callId || callId.length > 256) throw new Error("Codex settled-turn projection found an invalid tool call id");
33
31
  return callId;
34
32
  }
35
33
  function requireToolName(value) {
36
- const name = readNonEmptyString(value);
34
+ const name = normalizeOptionalString(value);
37
35
  if (!name || !TOOL_NAME_PATTERN.test(name)) throw new Error("Codex settled-turn projection found an invalid tool name");
38
36
  return name;
39
37
  }
@@ -152,7 +150,7 @@ function projectToolResult(message) {
152
150
  for (const value of message.content) {
153
151
  if (!isRecord(value)) throw new Error("Codex settled-turn projection found malformed tool result content");
154
152
  if (value.type === "image") {
155
- const mimeType = readNonEmptyString(value.mimeType) ?? "unknown type";
153
+ const mimeType = normalizeOptionalString(value.mimeType) ?? "unknown type";
156
154
  parts.push(`[Image tool result: ${mimeType}]`);
157
155
  continue;
158
156
  }
@@ -246,6 +244,7 @@ async function runCodexSettledTurnFinalization(operation, options) {
246
244
  mode: "required",
247
245
  id: attempt.modelId
248
246
  },
247
+ modelProvider: "openai",
249
248
  profile: attempt.authProfileId,
250
249
  timeoutMs: attempt.runTimeoutOverrideMs ?? attempt.timeoutMs,
251
250
  signal: attempt.abortSignal,
@@ -262,7 +261,8 @@ async function runCodexSettledTurnFinalization(operation, options) {
262
261
  requiredModalities: ["text"],
263
262
  isolation: "private-stdio",
264
263
  historyItems,
265
- requireNoExternalCapabilities: true
264
+ requireNoExternalCapabilities: true,
265
+ allowEmptyText: true
266
266
  });
267
267
  let promptEchoSeen = false;
268
268
  let unexpectedItem;
@@ -281,7 +281,15 @@ async function runCodexSettledTurnFinalization(operation, options) {
281
281
  }
282
282
  if (unexpectedItem) throw new Error(`Codex settled-turn finalization returned unexpected native item: ${unexpectedItem.type}`);
283
283
  const text = bounded.text.trim();
284
- if (!text || isSilentReplyText(text)) throw new Error("Codex settled-turn finalization completed without a visible answer");
284
+ if (!text) return {
285
+ assistant: createAssistantMessage(attempt, "", {
286
+ tokenUsage: bounded.usage,
287
+ aborted: false,
288
+ promptError: null
289
+ }),
290
+ ...bounded.usage ? { usage: bounded.usage } : {}
291
+ };
292
+ if (isSilentReplyText(text)) throw new Error("Codex settled-turn finalization completed without a visible answer");
285
293
  const mirrorIdentity = `settled-finalizer:${attempt.runId}`;
286
294
  const assistant = attachCodexMirrorIdentity(createAssistantMessage(attempt, text, {
287
295
  tokenUsage: bounded.usage,