@openclaw/codex 2026.8.1-beta.3 → 2026.8.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 (69) hide show
  1. package/dist/api.js +5 -6
  2. package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CpVfwctT.js} +47 -5
  3. package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
  4. package/dist/{binding-connection-DAvZwp96.js → binding-connection-CF7BmrDk.js} +2 -2
  5. package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-DRC3hcjm.js} +16 -20
  6. package/dist/{capabilities-CH3K57v4.js → capabilities-D6m_TdVy.js} +1 -1
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-D0nZ3qtd.js → command-formatters--UToCokS.js} +4 -3
  9. package/dist/{command-handlers-DC86lgT4.js → command-handlers-CLFx2Ypa.js} +114 -79
  10. package/dist/{compact-COqgBRny.js → compact-5xqW1oCh.js} +13 -12
  11. package/dist/{config-CpNeo5AE.js → config-CcYL77O6.js} +350 -288
  12. package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
  13. package/dist/doctor-contract-api.js +121 -16
  14. package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BmeXjwNZ.js} +243 -1002
  15. package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-XXQKgK1U.js} +2 -2
  16. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  17. package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-B2r5vhWH.js} +9 -14
  18. package/dist/{harness-DoKQcF8n.js → harness-BgeB7LnD.js} +42 -52
  19. package/dist/harness.js +1 -1
  20. package/dist/index.js +308 -306
  21. package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-CxTus3vZ.js} +4 -4
  22. package/dist/launch-args-sXOAg0SX.js +84 -0
  23. package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
  24. package/dist/media-understanding-provider.js +1 -1
  25. package/dist/model-catalog-DULBcniB.js +101 -0
  26. package/dist/{models-CZw1wClT.js → models-DaWfETQk.js} +27 -29
  27. package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-vXYUZH37.js} +226 -129
  28. package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DirKVZ5h.js} +9 -6
  29. package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-CCWQGlAI.js} +2 -1
  30. package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-BXjIFEiw.js} +38 -46
  31. package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-DQQm4gWT.js} +163 -136
  32. package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
  33. package/dist/{rate-limits-BI1dMHDG.js → rate-limits-BqHEHXQJ.js} +3 -2
  34. package/dist/{sandbox-guard-C1qEeZ5C.js → request-BWxweEdK.js} +183 -2
  35. package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BVLE4Gbi.js} +706 -517
  36. package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-D9pYp4zL.js} +3 -3
  37. package/dist/{session-binding-BTrLf9Qm.js → session-binding-D0zinCP1.js} +195 -122
  38. package/dist/{session-catalog-ezP_UcRM.js → session-catalog-eMhVm0Ql.js} +448 -313
  39. package/dist/session-catalog-home-id-Dt2GiG5o.js +112 -0
  40. package/dist/{session-cli-B1hKvfkI.js → session-cli-B2lyjJA0.js} +1 -1
  41. package/dist/session-history-C5J1AKzG.js +87 -0
  42. package/dist/session-permission-policy-ScnAyG90.js +160 -0
  43. package/dist/session-retirement-CtUtUTr9.js +90 -0
  44. package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-gqrYIRHk.js} +2 -3
  45. package/dist/settled-turn-context-Bk3IUwod.js +290 -0
  46. package/dist/settled-turn-finalizer-BXLN9PfJ.js +104 -0
  47. package/dist/{shared-client-Dw-rzii0.js → shared-client-B1tT5U6r.js} +1738 -806
  48. package/dist/{side-question-DbXkJZzg.js → side-question-CZ-mCw-t.js} +76 -43
  49. package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-CGGKP720.js} +991 -455
  50. package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-RkaoZCmQ.js} +18 -8
  51. package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-BFt1-ZDa.js} +55 -8
  52. package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-1ep4XjzF.js} +124 -18
  53. package/dist/transport-stdio-NT_Dpd9V.js +724 -0
  54. package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
  55. package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-Dc8BFExw.js} +76 -90
  56. package/dist/{usage-9dKJCgcy.js → usage-DUhd58gI.js} +3 -3
  57. package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-BEmlE7ov.js} +3 -3
  58. package/openclaw.plugin.json +19 -1
  59. package/package.json +8 -8
  60. package/dist/app-server-policy-bg5QPSVP.js +0 -25
  61. package/dist/command-rpc-xUIIonsO.js +0 -90
  62. package/dist/incognito-session-ET_ufDH-.js +0 -2
  63. package/dist/model-catalog-CmGoqVKB.js +0 -48
  64. package/dist/request-DSK0W6YI.js +0 -157
  65. package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
  66. package/dist/session-retirement-CE4iMiLh.js +0 -36
  67. package/dist/settled-turn-finalizer-Dx1onIqg.js +0 -328
  68. package/dist/thread-resume-CdJk2Ehf.js +0 -30
  69. package/dist/transport-stdio-DhoGy33Z.js +0 -99
@@ -1,40 +1,44 @@
1
- import { h as readCodexPluginConfig, s as resolveCodexSupervisionAppServerRuntimeOptions, x as resolveCodexAppServerUserHomeDir } from "./config-CpNeo5AE.js";
2
- import { B as CodexAppServerRpcError, R as resolveCodexAppServerClientInstanceId, _ as withTimeout, a as getLeasedSharedCodexAppServerClient, ft as resolveCodexAppServerHomeDir, l as releaseLeasedSharedCodexAppServerClient, ot as CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES, pt as resolveCodexAppServerLocalHomeDir, st as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, ut as isJsonObject } from "./shared-client-Dw-rzii0.js";
3
- import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity } from "./session-binding-BTrLf9Qm.js";
4
- import { n as assertCodexThreadForkParams } from "./protocol-validators-VAVyEnDp.js";
5
- import { i as replaceCodexCatalogConnectionHomes, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-DMNQ8Zi8.js";
6
- import { n as codexCatalogHomeId, t as canonicalCodexCatalogHome } from "./session-catalog-home-id-BNwAJ9D7.js";
7
- import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-BU0_LKAL.js";
8
- import { t as CODEX_CONTROL_METHODS } from "./capabilities-CH3K57v4.js";
9
- import { r as formatCodexDisplayText } from "./command-formatters-D0nZ3qtd.js";
10
- import { n as createCodexCliNodeConversationBindingData } from "./conversation-binding-data-CW2GuupV.js";
11
- import { n as requestCodexAppServerClientJson } from "./request-DSK0W6YI.js";
12
- import { t as codexControlRequest } from "./command-rpc-xUIIonsO.js";
13
- import { i as createImportedCodexSession, n as codexUpstreamBaseline, r as codexUpstreamContinueResult, t as codexLastTerminalTurnId } from "./session-upstream-marker-D_2npHlA.js";
1
+ import { F as resolveCodexAppServerLocalHomeDir, I as resolveCodexAppServerUserHomeDir, P as resolveCodexAppServerHomeDir, T as readCodexPluginConfig, i as resolveCodexAppServerRuntimeOptions, s as resolveCodexSupervisionAppServerRuntimeOptions } from "./config-CcYL77O6.js";
2
+ import { $ as CodexAppServerRpcError, Et as withTimeout, Ht as isJsonObject, Lt as resolveCodexAppServerPreparedAuthHandoff, Mt as resolveCodexAppServerAuthProfileId, Pt as resolveCodexAppServerAuthProfileStore, Q as resolveCodexAppServerClientInstanceId, Rt as CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES, c as getLeasedSharedCodexAppServerClient, h as releaseLeasedSharedCodexAppServerClient, zt as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS } from "./shared-client-B1tT5U6r.js";
3
+ import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity } from "./session-binding-D0zinCP1.js";
4
+ import { i as assertCodexThreadForkParams } from "./protocol-validators-Bg5rpNxk.js";
5
+ import { a as closeCodexStartupClientBestEffort } from "./attempt-client-cleanup-CpVfwctT.js";
6
+ import { n as listCodexAppServerModels } from "./models-DaWfETQk.js";
7
+ import { a as replaceCodexCatalogConnectionHomes, n as buildCodexAppServerConnectionFingerprint, t as resumeCodexAppServerThread } from "./thread-resume-BFt1-ZDa.js";
8
+ import { i as readCodexSessionMeta, n as codexCatalogHomeId, r as isOpenClawManagedCodexThread, t as canonicalCodexCatalogHome } from "./session-catalog-home-id-Dt2GiG5o.js";
9
+ import { i as requestCodexAppServerJson, o as withCodexAppServerJsonClient, r as requestCodexAppServerClientJson } from "./request-BWxweEdK.js";
10
+ import { m as projectCodexUserItemText, r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-1ep4XjzF.js";
11
+ import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-D6m_TdVy.js";
12
+ import { r as formatCodexDisplayText } from "./command-formatters--UToCokS.js";
13
+ import { n as createCodexCliNodeConversationBindingData } from "./conversation-binding-data-BiodpIzq.js";
14
+ import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-Ds_QVm-X.js";
15
+ import { i as createImportedCodexSession, n as codexUpstreamBaseline, r as codexUpstreamContinueResult, t as codexLastTerminalTurnId } from "./session-upstream-marker-gqrYIRHk.js";
14
16
  import { asFiniteNumber, isRecord, normalizeBoundedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
15
17
  import fs from "node:fs/promises";
16
18
  import path from "node:path";
17
19
  import { timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
18
20
  import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
21
+ import { prepareAgentRuntimeAuth } from "openclaw/plugin-sdk/agent-harness-runtime";
19
22
  import fsSync from "node:fs";
20
23
  import os from "node:os";
21
- import { listAgentIds, resolveAgentDir, resolveAllowedModelRef, resolveDefaultAgentDir, resolveDefaultAgentId, resolveDefaultModelForAgent, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
22
- import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
24
+ import { listAgentIds, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir, resolveAllowedModelRef, resolveDefaultAgentDir, resolveDefaultAgentId, resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
23
25
  import { runCommandBuffered } from "openclaw/plugin-sdk/process-runtime";
26
+ import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
24
27
  import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "openclaw/plugin-sdk/windows-spawn";
25
- import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
28
+ import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
26
29
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
27
30
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
28
31
  import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
29
32
  import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
30
- import { root } from "openclaw/plugin-sdk/file-access-runtime";
31
33
  import process$1 from "node:process";
34
+ import { resolveSessionModelRef } from "openclaw/plugin-sdk/model-session-runtime";
35
+ import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime";
32
36
  import { createSessionCatalogAdoptionCoordinator, listSessionCatalogEntries, sessionCatalogAdoptedSessionKey, sessionCatalogAdoptedSourceKey } from "openclaw/plugin-sdk/session-catalog";
33
37
  import { decodeNodePtyResumeParams, resolveNodeHostExecutable, runNodePtyCommand } from "openclaw/plugin-sdk/node-host";
34
- import { createZstdDecompress } from "node:zlib";
38
+ import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
35
39
  //#region extensions/codex/src/jsonl-lines.ts
36
- const JSONL_STREAM_THRESHOLD_BYTES = 4 * 1024 * 1024;
37
- const JSONL_READ_CHUNK_BYTES = 1024 * 1024;
40
+ const JSONL_STREAM_THRESHOLD_BYTES = 4194304;
41
+ const JSONL_READ_CHUNK_BYTES = 1048576;
38
42
  async function visitJsonlLines(file, visitor, chunkBytes = JSONL_READ_CHUNK_BYTES) {
39
43
  let size;
40
44
  try {
@@ -134,7 +138,7 @@ const CODEX_CLI_SESSIONS_LIST_COMMAND = "codex.cli.sessions.list";
134
138
  const CODEX_CLI_SESSION_RESUME_COMMAND = "codex.cli.session.resume";
135
139
  const DEFAULT_SESSION_LIMIT = 10;
136
140
  const MAX_SESSION_LIMIT = 50;
137
- const DEFAULT_RESUME_TIMEOUT_MS = 20 * 6e4;
141
+ const DEFAULT_RESUME_TIMEOUT_MS = 12e5;
138
142
  const SESSION_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
139
143
  const activeResumeSessions = /* @__PURE__ */ new Set();
140
144
  function createCodexCliSessionNodeHostCommands() {
@@ -525,7 +529,7 @@ function normalizeLimit$1(value) {
525
529
  return typeof value === "number" && Number.isFinite(value) ? Math.min(MAX_SESSION_LIMIT, Math.max(1, Math.floor(value))) : DEFAULT_SESSION_LIMIT;
526
530
  }
527
531
  function normalizeTimeoutMs(value) {
528
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.min(60 * 6e4, Math.floor(value)) : DEFAULT_RESUME_TIMEOUT_MS;
532
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.min(36e5, Math.floor(value)) : DEFAULT_RESUME_TIMEOUT_MS;
529
533
  }
530
534
  function truncateText(value, max) {
531
535
  if (value.length <= max) return value;
@@ -546,6 +550,197 @@ function formatNodeLabel(node) {
546
550
  ].filter(Boolean).join(" / ") || "node";
547
551
  }
548
552
  //#endregion
553
+ //#region extensions/codex/src/command-rpc.ts
554
+ async function prepareControlAuth(options, startOptions) {
555
+ if (!options.onResponse || !options.config || !options.sessionKey || options.authProfileId === null || startOptions.homeScope === "user") return {
556
+ authProfileId: options.authProfileId ?? void 0,
557
+ clientOptions: { authProfileId: options.authProfileId }
558
+ };
559
+ const config = options.config;
560
+ const { sessionAgentId } = resolveSessionAgentIdsStrict({
561
+ config,
562
+ sessionKey: options.sessionKey,
563
+ agentId: options.agentId
564
+ });
565
+ const agentDir = options.agentDir ?? resolveAgentDir$1(config, sessionAgentId);
566
+ const workspaceDir = resolveAgentWorkspaceDir(config, sessionAgentId);
567
+ const entry = getSessionEntry({
568
+ agentId: sessionAgentId,
569
+ storePath: resolveStorePath(config.session?.store, { agentId: sessionAgentId }),
570
+ sessionKey: options.sessionKey,
571
+ hydrateSkillPromptRefs: false,
572
+ readConsistency: "latest"
573
+ });
574
+ const model = resolveSessionModelRef(config, entry, sessionAgentId);
575
+ const store = resolveCodexAppServerAuthProfileStore({
576
+ agentDir,
577
+ config
578
+ });
579
+ const { plan, attempts } = prepareAgentRuntimeAuth({
580
+ provider: model.provider,
581
+ modelId: model.model,
582
+ config,
583
+ agentDir,
584
+ workspaceDir,
585
+ authProfileStore: store,
586
+ sessionAuthProfileId: entry?.authProfileOverride ?? options.authProfileId,
587
+ sessionAuthProfileSource: entry?.authProfileOverrideSource,
588
+ harnessId: "codex",
589
+ harnessAuthBootstrap: "harness"
590
+ });
591
+ const route = plan.modelRoute;
592
+ const resolvedAuth = route ? await resolveApiKeyForProvider({
593
+ provider: route.provider,
594
+ modelId: route.modelId,
595
+ modelApi: route.api,
596
+ cfg: config,
597
+ agentDir,
598
+ workspaceDir,
599
+ store,
600
+ profileId: attempts[0]?.profileId,
601
+ lockedProfile: plan.forwardedAuthProfileSource === "user",
602
+ allowAuthProfileFallback: attempts[0]?.allowAuthProfileFallback,
603
+ skipSetupProviderFallback: true
604
+ }) : void 0;
605
+ const handoff = await resolveCodexAppServerPreparedAuthHandoff({
606
+ authRequirement: route?.authRequirement,
607
+ resolvedApiKey: resolvedAuth?.apiKey,
608
+ authProfileId: route ? plan.forwardedAuthProfileId : resolveCodexAppServerAuthProfileId({
609
+ authProfileId: plan.forwardedAuthProfileId,
610
+ store,
611
+ config
612
+ }),
613
+ authProfileStore: store,
614
+ agentDir,
615
+ homeScope: startOptions.homeScope ?? "agent",
616
+ config,
617
+ subscriptionProfileRequiredError: "Prepared Codex subscription route requires a forwarded OpenAI OAuth or token profile.",
618
+ subscriptionProfileUnusableError: "Prepared Codex subscription auth profile is unusable."
619
+ });
620
+ const binding = handoff.authProfileId ? await prepareCodexAppServerAuthBinding({
621
+ authProfileId: handoff.authProfileId,
622
+ authProfileStore: store,
623
+ agentDir,
624
+ config
625
+ }) : void 0;
626
+ return {
627
+ authProfileId: handoff.authProfileId,
628
+ clientOptions: {
629
+ ...handoff.preparedAuth ? { preparedAuth: handoff.preparedAuth } : { authProfileId: handoff.authProfileId },
630
+ authRequirement: route?.authRequirement,
631
+ authProfileStore: binding?.authProfileStore ?? store,
632
+ authBindingFingerprint: binding?.fingerprint,
633
+ agentDir
634
+ }
635
+ };
636
+ }
637
+ function requestOptions(pluginConfig, limit, config, agentDir) {
638
+ const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig });
639
+ return {
640
+ limit,
641
+ timeoutMs: runtime.requestTimeoutMs,
642
+ startOptions: runtime.start,
643
+ config,
644
+ agentDir
645
+ };
646
+ }
647
+ async function codexControlRequest(pluginConfig, method, requestParams, options = {}) {
648
+ const runtime = options.startOptions ? resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig }) : resolveCodexAppServerRuntimeOptions({ pluginConfig });
649
+ const startOptions = options.startOptions ?? runtime.start;
650
+ const auth = await prepareControlAuth(options, startOptions);
651
+ const controlRequestOptions = {
652
+ timeoutMs: options.timeoutMs ?? runtime.requestTimeoutMs,
653
+ startOptions,
654
+ config: options.config,
655
+ sessionKey: options.sessionKey,
656
+ sessionId: options.sessionId,
657
+ agentDir: options.agentDir,
658
+ isolated: options.isolated,
659
+ ...auth.clientOptions
660
+ };
661
+ if (options.onResponse || options.beforeRequest) return await withCodexAppServerJsonClient(controlRequestOptions, async (request, client, scope) => {
662
+ await options.beforeRequest?.(request);
663
+ scope.assertCurrent();
664
+ let response;
665
+ if (method === "thread/resume") {
666
+ if (!isJsonObject(requestParams) || typeof requestParams.threadId !== "string") throw new Error("Codex thread/resume requires a thread id.");
667
+ response = await resumeCodexAppServerThread({
668
+ client,
669
+ request: {
670
+ ...requestParams,
671
+ threadId: requestParams.threadId
672
+ },
673
+ requestResume: () => request({
674
+ method,
675
+ requestParams
676
+ }),
677
+ abandonClient: () => closeCodexStartupClientBestEffort(client)
678
+ });
679
+ } else response = await request({
680
+ method,
681
+ requestParams
682
+ });
683
+ await options.onResponse?.(response, client, {
684
+ authProfileId: auth.authProfileId,
685
+ assertCurrent: scope.assertCurrent
686
+ });
687
+ scope.assertCurrent();
688
+ return response;
689
+ });
690
+ return await requestCodexAppServerJson({
691
+ method,
692
+ requestParams,
693
+ ...controlRequestOptions
694
+ });
695
+ }
696
+ async function safeCodexControlRequest(pluginConfig, method, requestParams, options = {}) {
697
+ return await safeValue(async () => await codexControlRequest(pluginConfig, method, requestParams, options));
698
+ }
699
+ async function safeCodexModelList(pluginConfig, limit, config, agentDir) {
700
+ return await safeValue(async () => await listCodexAppServerModels(requestOptions(pluginConfig, limit, config, agentDir)));
701
+ }
702
+ async function readCodexStatusProbes(pluginConfig, config, agentDir) {
703
+ const [models, account, limits, mcps, skills] = await Promise.all([
704
+ safeCodexModelList(pluginConfig, 20, config, agentDir),
705
+ safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.account, { refreshToken: false }, {
706
+ config,
707
+ agentDir
708
+ }),
709
+ safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.rateLimits, void 0, {
710
+ config,
711
+ agentDir
712
+ }),
713
+ safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.listMcpServers, { limit: 100 }, {
714
+ config,
715
+ agentDir
716
+ }),
717
+ safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.listSkills, {}, {
718
+ config,
719
+ agentDir
720
+ })
721
+ ]);
722
+ return {
723
+ models,
724
+ account,
725
+ limits,
726
+ mcps,
727
+ skills
728
+ };
729
+ }
730
+ async function safeValue(read) {
731
+ try {
732
+ return {
733
+ ok: true,
734
+ value: await read()
735
+ };
736
+ } catch (error) {
737
+ return {
738
+ ok: false,
739
+ error: describeControlFailure(error)
740
+ };
741
+ }
742
+ }
743
+ //#endregion
549
744
  //#region extensions/codex/src/app-server/thread-archive-guard.ts
550
745
  const DESCENDANT_PAGE_LIMIT = 100;
551
746
  const MAX_DESCENDANT_PAGES = 100;
@@ -613,7 +808,7 @@ const MAX_SESSION_PREVIEW_LENGTH = 500;
613
808
  const MAX_SESSION_KEY_LENGTH = 1024;
614
809
  const MAX_METADATA_LENGTH = 500;
615
810
  const MAX_ACTIVE_FLAGS = 16;
616
- const MAX_TRANSCRIPT_PAGE_BYTES = 20 * 1024 * 1024;
811
+ const MAX_TRANSCRIPT_PAGE_BYTES = 20971520;
617
812
  var CatalogParamsError = class extends Error {};
618
813
  function readControlCursor(value, label) {
619
814
  if (value === void 0 || value === null) return;
@@ -821,7 +1016,7 @@ function filterCatalogPageByTitle(page, searchTerm) {
821
1016
  if (!searchTerm) return page;
822
1017
  return {
823
1018
  ...page,
824
- sessions: page.sessions.filter((session) => session.name?.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase()))
1019
+ sessions: page.sessions.filter((session) => (session.name ?? session.fallbackName)?.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase()))
825
1020
  };
826
1021
  }
827
1022
  function unwrapNodeInvokePayload(value) {
@@ -997,7 +1192,7 @@ async function createOrReuseNodeAdoptedSession(params) {
997
1192
  key: nodeAdoptionSessionKey(params.hostId, params.record.threadId),
998
1193
  agentId: params.agentId,
999
1194
  recoverMatchingInitialEntry: true,
1000
- ...params.record.name?.trim() ? { label: params.record.name.trim() } : {},
1195
+ displayName: params.record.name ?? void 0,
1001
1196
  ...params.record.cwd?.trim() ? { spawnedCwd: params.record.cwd.trim() } : {},
1002
1197
  initialEntry: {
1003
1198
  agentHarnessId: "codex",
@@ -1040,182 +1235,6 @@ async function createOrReuseNodeAdoptedSession(params) {
1040
1235
  }
1041
1236
  }
1042
1237
  //#endregion
1043
- //#region extensions/codex/src/session-catalog-terminal.ts
1044
- const CODEX_TERMINAL_RESUME_COMMAND = "codex.terminal.resume.v1";
1045
- function resolveCodexCatalogTerminalHome(sources) {
1046
- const runtimeConfig = sources.getRuntimeConfig();
1047
- if (!runtimeConfig) throw new Error("OpenClaw runtime config is unavailable");
1048
- const agentDir = sources.source?.agentDir ?? (sources.agentId ? resolveAgentDir(runtimeConfig, sources.agentId) : resolveDefaultAgentDir(runtimeConfig));
1049
- return resolveCodexAppServerLocalHomeDir(sources.source?.appServer.start ?? resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig: sources.getPluginConfig() }).start, agentDir);
1050
- }
1051
- function resolveLocalCodexTerminalExecutable(env = process.env) {
1052
- return resolveLocalCodexTerminalResolution(env)?.executable;
1053
- }
1054
- function resolveLocalCodexTerminalResolution(env = process.env) {
1055
- return resolveNodeHostExecutable("codex", {
1056
- env,
1057
- pathEnv: env.PATH ?? env.Path ?? "",
1058
- strategy: "fallback"
1059
- });
1060
- }
1061
- function codexNodeTerminalCapability(node) {
1062
- const commands = node.invocableCommands ?? node.commands;
1063
- return node.connected === true && commands?.includes("codex.terminal.resume.v1") === true ? { canOpenTerminalCodex: true } : {};
1064
- }
1065
- async function requireCatalogEligibleThread(control, threadId) {
1066
- const cached = await findCatalogEligibleThread(control, threadId, false);
1067
- if (cached) return cached;
1068
- const refreshed = await findCatalogEligibleThread(control, threadId, true);
1069
- if (refreshed) return refreshed;
1070
- throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
1071
- }
1072
- async function findCatalogEligibleThread(control, threadId, forceRefresh) {
1073
- let cursor;
1074
- const seenCursors = /* @__PURE__ */ new Set();
1075
- for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
1076
- const page = await control.listPage({
1077
- limit: 100,
1078
- ...cursor ? { cursor } : {},
1079
- ...forceRefresh ? { forceRefresh: true } : {}
1080
- });
1081
- const candidate = page.sessions.find((session) => session.threadId === threadId);
1082
- if (candidate) {
1083
- if (isInteractiveThreadSource(candidate.source)) return candidate;
1084
- throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
1085
- }
1086
- const nextCursor = page.nextCursor?.trim();
1087
- if (!nextCursor) return;
1088
- if (seenCursors.has(nextCursor)) throw new CatalogParamsError("Codex session eligibility could not be verified");
1089
- seenCursors.add(nextCursor);
1090
- cursor = nextCursor;
1091
- }
1092
- throw new CatalogParamsError("Codex session eligibility could not be verified");
1093
- }
1094
- function createCodexTerminalNodeHostCommand(bindRequest, configSources) {
1095
- return {
1096
- command: CODEX_TERMINAL_RESUME_COMMAND,
1097
- cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
1098
- dangerous: false,
1099
- duplex: true,
1100
- isAvailable: ({ env }) => Boolean(resolveNodeHostExecutable("codex", {
1101
- env,
1102
- pathEnv: env.PATH ?? env.Path ?? "",
1103
- strategy: "direct"
1104
- })),
1105
- handle: async (paramsJSON, io) => {
1106
- if (!io) throw new Error("Codex terminal command requires duplex transport");
1107
- const request = bindRequest(paramsJSON);
1108
- const resume = decodeNodePtyResumeParams(request.paramsJSON, (value) => {
1109
- if (typeof value !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(value)) throw new CatalogParamsError("threadId must be a UUID");
1110
- return value;
1111
- });
1112
- const record = await requireCatalogEligibleThread(request.control, resume.threadId);
1113
- const resolution = resolveNodeHostExecutable("codex", {
1114
- env: process.env,
1115
- pathEnv: process.env.PATH ?? process.env.Path ?? "",
1116
- strategy: "direct"
1117
- });
1118
- if (!resolution) throw new Error("Codex CLI is unavailable");
1119
- return JSON.stringify(await runNodePtyCommand({
1120
- file: resolution.executable,
1121
- args: ["resume", resume.threadId],
1122
- cwd: record.cwd,
1123
- env: { CODEX_HOME: resolveCodexCatalogTerminalHome({
1124
- ...configSources,
1125
- agentId: request.agentId
1126
- }) },
1127
- cols: resume.cols,
1128
- rows: resume.rows
1129
- }, io));
1130
- }
1131
- };
1132
- }
1133
- async function resolveNodeCatalogEligibleThread(params) {
1134
- let cursor;
1135
- const seenCursors = /* @__PURE__ */ new Set();
1136
- for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
1137
- const raw = await params.runtime.nodes.invoke({
1138
- nodeId: params.nodeId,
1139
- command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
1140
- params: {
1141
- agentId: params.agentId,
1142
- limit: 100,
1143
- ...cursor ? { cursor } : {}
1144
- },
1145
- timeoutMs: NODE_INVOKE_TIMEOUT_MS,
1146
- scopes: ["operator.write"]
1147
- });
1148
- const page = params.parseCatalogPage(unwrapNodeInvokePayload(raw));
1149
- const record = page.sessions.find((candidate) => candidate.threadId === params.threadId);
1150
- if (record) {
1151
- if (isInteractiveThreadSource(record.source)) return record;
1152
- break;
1153
- }
1154
- const nextCursor = page.nextCursor?.trim();
1155
- if (!nextCursor || seenCursors.has(nextCursor)) break;
1156
- seenCursors.add(nextCursor);
1157
- cursor = nextCursor;
1158
- }
1159
- throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
1160
- }
1161
- async function openCodexCatalogTerminal(params) {
1162
- const title = `codex resume ${params.threadId.slice(0, 8)}…`;
1163
- if (params.hostId === "gateway:local" || params.hostId.startsWith(`gateway:local:`)) {
1164
- const record = await requireCatalogEligibleThread(params.control, params.threadId);
1165
- const resolution = resolveLocalCodexTerminalResolution();
1166
- if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable");
1167
- return {
1168
- kind: "local",
1169
- argv: [
1170
- resolution.executable,
1171
- "resume",
1172
- params.threadId
1173
- ],
1174
- ...record.cwd ? { cwd: record.cwd } : {},
1175
- env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
1176
- ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
1177
- title
1178
- };
1179
- }
1180
- if (!params.hostId.startsWith("node:")) throw new CatalogParamsError("hostId is invalid");
1181
- const nodeId = params.hostId.slice(5);
1182
- if (!(await params.api.runtime.nodes.list()).nodes.find((candidate) => {
1183
- const commands = candidate.invocableCommands ?? candidate.commands;
1184
- return candidate.nodeId === nodeId && candidate.connected === true && commands?.includes("codex.appServer.threads.list.v1") === true && commands.includes("codex.terminal.resume.v1");
1185
- })) throw new CatalogParamsError("paired-node Codex terminal is unavailable");
1186
- const record = await resolveNodeCatalogEligibleThread({
1187
- agentId: params.agentId,
1188
- runtime: params.api.runtime,
1189
- nodeId,
1190
- threadId: params.threadId,
1191
- parseCatalogPage: params.parseCatalogPage
1192
- });
1193
- return {
1194
- kind: "node",
1195
- nodeId,
1196
- command: CODEX_TERMINAL_RESUME_COMMAND,
1197
- paramsJSON: JSON.stringify({
1198
- agentId: params.agentId,
1199
- threadId: params.threadId
1200
- }),
1201
- ...record.cwd ? { cwd: record.cwd } : {},
1202
- title
1203
- };
1204
- }
1205
- async function startCodexCatalogTerminal(params) {
1206
- if (params.nodeId) throw new CatalogParamsError("Paired-node Codex terminal start is unavailable; omit hostId to start on the gateway host");
1207
- const resolution = resolveLocalCodexTerminalResolution();
1208
- if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable; install Codex or add codex to PATH, then try again");
1209
- return {
1210
- kind: "local",
1211
- argv: [resolution.executable, ...params.initialMessage !== void 0 ? ["--", params.initialMessage] : []],
1212
- cwd: params.cwd,
1213
- env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
1214
- ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
1215
- title: "codex"
1216
- };
1217
- }
1218
- //#endregion
1219
1238
  //#region extensions/codex/src/session-catalog-adoption.ts
1220
1239
  const CODEX_SUPERVISION_SESSION_KEY_PREFIX = "harness:codex:supervision:";
1221
1240
  const boundCatalogSessionId = (value) => boundedCatalogString(value, 256);
@@ -1377,6 +1396,7 @@ async function createOrReuseAdoptedSession(params) {
1377
1396
  config: params.config,
1378
1397
  key: adoptionSessionKey(params.sourceThread.id, params.sourceHomeId),
1379
1398
  agentId: params.agentId,
1399
+ displayName: params.sourceThread.name ?? void 0,
1380
1400
  thread: params.sourceThread,
1381
1401
  throughTurnId: pendingLastTurnId ?? null,
1382
1402
  recoverMatchingInitialEntry: true,
@@ -1439,7 +1459,7 @@ async function createOrReuseAdoptedSession(params) {
1439
1459
  }
1440
1460
  }
1441
1461
  async function continueLocalCodexSessionInner(params) {
1442
- await requireCatalogEligibleThread(params.control, params.threadId);
1462
+ await params.control.requireEligibleThread(params.threadId);
1443
1463
  const existing = await findAdoptedSessionEntry({
1444
1464
  ...params,
1445
1465
  runtime: params.api.runtime
@@ -1532,8 +1552,8 @@ async function archiveLocalCodexSession(params) {
1532
1552
  return await runSessionActionExclusive(sessionCatalogAdoptedSourceKey(params.hostId ?? "gateway:local", params.threadId), async () => {
1533
1553
  return await params.bindingStore.withThreadArchiveFence(async () => {
1534
1554
  const run = async (control) => {
1535
- await requireCatalogEligibleThread(control, params.threadId);
1536
1555
  await assertNoPendingSupervisionBranch(params);
1556
+ await control.requireEligibleThread(params.threadId);
1537
1557
  const thread = await control.readThread(params.threadId, false);
1538
1558
  if (thread.id !== params.threadId) throw new Error("Codex app-server returned a different thread than requested");
1539
1559
  requireIdleThread(thread, "archive");
@@ -1720,6 +1740,7 @@ async function readNodeCodexHistory(params) {
1720
1740
  id: params.record.threadId,
1721
1741
  createdAt: params.record.createdAt ?? 0,
1722
1742
  modelProvider: params.record.modelProvider ?? "openai",
1743
+ projectId: null,
1723
1744
  turns: page.data.toReversed()
1724
1745
  };
1725
1746
  return {
@@ -1783,7 +1804,7 @@ async function continueNodeCodexSessionInner(params) {
1783
1804
  detachHint: "Start a new chat to leave the paired-node Codex session.",
1784
1805
  data: createCodexCliNodeConversationBindingData({
1785
1806
  nodeId,
1786
- sessionId: record.sessionId?.trim() || params.threadId,
1807
+ sessionId: params.threadId,
1787
1808
  agentId: adopted.agentId,
1788
1809
  cwd: record.cwd
1789
1810
  })
@@ -1799,10 +1820,10 @@ async function continueNodeCodexSession(params) {
1799
1820
  if (params.clientScopes?.includes("operator.admin") !== true) throw new CatalogParamsError("continuing a paired-node Codex session requires operator.admin");
1800
1821
  const nodeId = params.hostId.slice(5).trim();
1801
1822
  if (!nodeId || params.hostId !== `node:${nodeId}`) throw new CatalogParamsError("Codex session catalog hostId is invalid");
1802
- const agentId = resolveSessionAgentIds({
1823
+ const agentId = resolveSessionAgentIdsStrict({
1803
1824
  config: params.config,
1804
1825
  agentId: params.agentId
1805
- }).defaultAgentId;
1826
+ }).sessionAgentId;
1806
1827
  const sourceKey = sessionCatalogAdoptedSourceKey(`node:${nodeId}`, params.threadId);
1807
1828
  const operationKey = sessionCatalogAdoptedSourceKey(agentId, sourceKey);
1808
1829
  return await continueNodeAdoption({
@@ -1816,6 +1837,154 @@ async function continueNodeCodexSession(params) {
1816
1837
  });
1817
1838
  }
1818
1839
  //#endregion
1840
+ //#region extensions/codex/src/session-catalog-terminal.ts
1841
+ const CODEX_TERMINAL_RESUME_COMMAND = "codex.terminal.resume.v1";
1842
+ function resolveCodexCatalogTerminalHome(sources) {
1843
+ const runtimeConfig = sources.getRuntimeConfig();
1844
+ if (!runtimeConfig) throw new Error("OpenClaw runtime config is unavailable");
1845
+ const agentDir = sources.source?.agentDir ?? (sources.agentId ? resolveAgentDir$1(runtimeConfig, sources.agentId) : resolveDefaultAgentDir(runtimeConfig));
1846
+ const startOptions = sources.source?.appServer.start ?? resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig: sources.getPluginConfig() }).start;
1847
+ return resolveCodexAppServerLocalHomeDir(startOptions, agentDir);
1848
+ }
1849
+ function resolveLocalCodexTerminalExecutable(env = process.env) {
1850
+ return resolveLocalCodexTerminalResolution(env)?.executable;
1851
+ }
1852
+ function resolveLocalCodexTerminalResolution(env = process.env) {
1853
+ return resolveNodeHostExecutable("codex", {
1854
+ env,
1855
+ pathEnv: env.PATH ?? env.Path ?? "",
1856
+ strategy: "fallback"
1857
+ });
1858
+ }
1859
+ function codexNodeTerminalCapability(node) {
1860
+ const commands = node.invocableCommands ?? node.commands;
1861
+ return node.connected === true && commands?.includes("codex.terminal.resume.v1") === true ? { canOpenTerminalCodex: true } : {};
1862
+ }
1863
+ function createCodexTerminalNodeHostCommand(bindRequest, configSources) {
1864
+ return {
1865
+ command: CODEX_TERMINAL_RESUME_COMMAND,
1866
+ cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
1867
+ dangerous: false,
1868
+ duplex: true,
1869
+ isAvailable: ({ env }) => Boolean(resolveNodeHostExecutable("codex", {
1870
+ env,
1871
+ pathEnv: env.PATH ?? env.Path ?? "",
1872
+ strategy: "direct"
1873
+ })),
1874
+ handle: async (paramsJSON, io) => {
1875
+ if (!io) throw new Error("Codex terminal command requires duplex transport");
1876
+ const request = bindRequest(paramsJSON);
1877
+ const resume = decodeNodePtyResumeParams(request.paramsJSON, (value) => {
1878
+ if (typeof value !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(value)) throw new CatalogParamsError("threadId must be a UUID");
1879
+ return value;
1880
+ });
1881
+ const record = await request.control.requireEligibleThread(resume.threadId);
1882
+ const resolution = resolveNodeHostExecutable("codex", {
1883
+ env: process.env,
1884
+ pathEnv: process.env.PATH ?? process.env.Path ?? "",
1885
+ strategy: "direct"
1886
+ });
1887
+ if (!resolution) throw new Error("Codex CLI is unavailable");
1888
+ return JSON.stringify(await runNodePtyCommand({
1889
+ file: resolution.executable,
1890
+ args: ["resume", resume.threadId],
1891
+ ...record.cwd ? { cwd: record.cwd } : {},
1892
+ env: { CODEX_HOME: resolveCodexCatalogTerminalHome({
1893
+ ...configSources,
1894
+ agentId: request.agentId
1895
+ }) },
1896
+ cols: resume.cols,
1897
+ rows: resume.rows
1898
+ }, io));
1899
+ }
1900
+ };
1901
+ }
1902
+ async function resolveNodeCatalogEligibleThread(params) {
1903
+ let cursor;
1904
+ const seenCursors = /* @__PURE__ */ new Set();
1905
+ for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
1906
+ const raw = await params.runtime.nodes.invoke({
1907
+ nodeId: params.nodeId,
1908
+ command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
1909
+ params: {
1910
+ agentId: params.agentId,
1911
+ limit: 100,
1912
+ ...cursor ? { cursor } : {}
1913
+ },
1914
+ timeoutMs: NODE_INVOKE_TIMEOUT_MS,
1915
+ scopes: ["operator.write"]
1916
+ });
1917
+ const page = params.parseCatalogPage(unwrapNodeInvokePayload(raw));
1918
+ const record = page.sessions.find((candidate) => candidate.threadId === params.threadId);
1919
+ if (record) {
1920
+ if (isInteractiveThreadSource(record.source)) return record;
1921
+ break;
1922
+ }
1923
+ const nextCursor = page.nextCursor?.trim();
1924
+ if (!nextCursor || seenCursors.has(nextCursor)) break;
1925
+ seenCursors.add(nextCursor);
1926
+ cursor = nextCursor;
1927
+ }
1928
+ throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
1929
+ }
1930
+ async function openCodexCatalogTerminal(params) {
1931
+ const title = `codex resume ${params.threadId.slice(0, 8)}…`;
1932
+ if (params.hostId === "gateway:local" || params.hostId.startsWith(`gateway:local:`)) {
1933
+ const record = await params.control.requireEligibleThread(params.threadId);
1934
+ const resolution = resolveLocalCodexTerminalResolution();
1935
+ if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable");
1936
+ return {
1937
+ kind: "local",
1938
+ argv: [
1939
+ resolution.executable,
1940
+ "resume",
1941
+ params.threadId
1942
+ ],
1943
+ ...record.cwd ? { cwd: record.cwd } : {},
1944
+ env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
1945
+ ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
1946
+ title
1947
+ };
1948
+ }
1949
+ if (!params.hostId.startsWith("node:")) throw new CatalogParamsError("hostId is invalid");
1950
+ const nodeId = params.hostId.slice(5);
1951
+ if (!(await params.api.runtime.nodes.list()).nodes.find((candidate) => {
1952
+ const commands = candidate.invocableCommands ?? candidate.commands;
1953
+ return candidate.nodeId === nodeId && candidate.connected === true && commands?.includes("codex.appServer.threads.list.v1") === true && commands.includes("codex.terminal.resume.v1");
1954
+ })) throw new CatalogParamsError("paired-node Codex terminal is unavailable");
1955
+ const record = await resolveNodeCatalogEligibleThread({
1956
+ agentId: params.agentId,
1957
+ runtime: params.api.runtime,
1958
+ nodeId,
1959
+ threadId: params.threadId,
1960
+ parseCatalogPage: params.parseCatalogPage
1961
+ });
1962
+ return {
1963
+ kind: "node",
1964
+ nodeId,
1965
+ command: CODEX_TERMINAL_RESUME_COMMAND,
1966
+ paramsJSON: JSON.stringify({
1967
+ agentId: params.agentId,
1968
+ threadId: params.threadId
1969
+ }),
1970
+ ...record.cwd ? { cwd: record.cwd } : {},
1971
+ title
1972
+ };
1973
+ }
1974
+ async function startCodexCatalogTerminal(params) {
1975
+ if (params.nodeId) throw new CatalogParamsError("Paired-node Codex terminal start is unavailable; omit hostId to start on the gateway host");
1976
+ const resolution = resolveLocalCodexTerminalResolution();
1977
+ if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable; install Codex or add codex to PATH, then try again");
1978
+ return {
1979
+ kind: "local",
1980
+ argv: [resolution.executable, ...params.initialMessage !== void 0 ? ["--", params.initialMessage] : []],
1981
+ cwd: params.cwd,
1982
+ env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
1983
+ ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
1984
+ title: "codex"
1985
+ };
1986
+ }
1987
+ //#endregion
1819
1988
  //#region extensions/codex/src/session-catalog-listing.ts
1820
1989
  async function listVisiblePage(params) {
1821
1990
  const excluded = params.excludedThreadIds;
@@ -1903,7 +2072,7 @@ async function listGatewayHost(params) {
1903
2072
  }
1904
2073
  /** Lists Gateway-local and paired-node Codex sessions with per-host failures. */
1905
2074
  async function listCodexSessionCatalog(params) {
1906
- const agentId = resolveSessionAgentIds({
2075
+ const agentId = resolveSessionAgentIdsStrict({
1907
2076
  config: params.config ?? {},
1908
2077
  agentId: params.agentId
1909
2078
  }).sessionAgentId;
@@ -1977,7 +2146,7 @@ function createCodexSessionCatalogNodeHostCommands(controlFactory, configSources
1977
2146
  if (!isRecord(parsed)) throw new CatalogParamsError("Codex session catalog parameters must be an object");
1978
2147
  const requestedAgentId = readBoundedOptionalString(parsed, "agentId", 256);
1979
2148
  const config = configSources.getRuntimeConfig() ?? {};
1980
- const agentId = resolveSessionAgentIds({
2149
+ const agentId = resolveSessionAgentIdsStrict({
1981
2150
  config,
1982
2151
  agentId: requestedAgentId
1983
2152
  }).sessionAgentId;
@@ -2034,7 +2203,7 @@ function createCodexSessionCatalogNodeHostCommands(controlFactory, configSources
2034
2203
  const request = bindRequest(paramsJSON);
2035
2204
  const action = readNodeTranscriptParams(request.params);
2036
2205
  try {
2037
- await requireCatalogEligibleThread(request.control, action.threadId);
2206
+ await request.control.requireEligibleThread(action.threadId);
2038
2207
  const page = parseTranscriptPage(await request.control.listTurnPage({
2039
2208
  threadId: action.threadId,
2040
2209
  limit: action.limit,
@@ -2079,7 +2248,7 @@ function flattenTranscriptPageDesc(page) {
2079
2248
  /** Reads the persisted transcript for a Gateway-local or paired-node Codex session. */
2080
2249
  async function readCodexSessionTranscript(params) {
2081
2250
  if (params.source || params.hostId === "gateway:local") {
2082
- await requireCatalogEligibleThread(params.control, params.threadId);
2251
+ await params.control.requireEligibleThread(params.threadId);
2083
2252
  const listParams = {
2084
2253
  threadId: params.threadId,
2085
2254
  limit: params.limit,
@@ -2145,7 +2314,7 @@ function toGenericTranscriptItem(item) {
2145
2314
  const fallback = item.title ?? item.name ?? item.tool ?? item.command ?? item.query ?? void 0;
2146
2315
  const resultText = item.aggregatedOutput || (item.result === void 0 ? void 0 : JSON.stringify(item.result, null, 2));
2147
2316
  const changesText = Array.isArray(item.changes) ? item.changes.map((change) => `${change.kind}: ${change.path}`).join("\n") || void 0 : void 0;
2148
- const text = item.text || resultText || changesText || fallback;
2317
+ const text = item.type === "userMessage" ? projectCodexUserItemText(item) : item.text || resultText || changesText || fallback;
2149
2318
  return {
2150
2319
  id: item.id,
2151
2320
  type,
@@ -2310,7 +2479,7 @@ function existingCatalogHomeCandidates(value, label) {
2310
2479
  /** Resolves every local Codex store the operator already owns, without path disclosure. */
2311
2480
  function resolveCodexCatalogHomes(params) {
2312
2481
  const { config, env, ownerAgentId, pluginConfig } = params;
2313
- const ownerAgentDir = resolveAgentDir(config, ownerAgentId, env);
2482
+ const ownerAgentDir = resolveAgentDir$1(config, ownerAgentId, env);
2314
2483
  const configuredHomes = readCodexPluginConfig(pluginConfig).sessionCatalog?.homes ?? [];
2315
2484
  const base = resolveCodexSupervisionAppServerRuntimeOptions({
2316
2485
  pluginConfig,
@@ -2333,7 +2502,7 @@ function resolveCodexCatalogHomes(params) {
2333
2502
  usesProcessHomeFallback: !processHomeConfigured
2334
2503
  });
2335
2504
  const agentIds = listAgentIds(config).toSorted((left, right) => left === ownerAgentId ? -1 : right === ownerAgentId ? 1 : left.localeCompare(right));
2336
- candidates.push(...agentIds.flatMap((agentId) => existingCatalogHomeCandidates(resolveCodexAppServerHomeDir(resolveAgentDir(config, agentId, env)), agentId)), ...configuredHomes.flatMap((entry) => {
2505
+ candidates.push(...agentIds.flatMap((agentId) => existingCatalogHomeCandidates(resolveCodexAppServerHomeDir(resolveAgentDir$1(config, agentId, env)), agentId)), ...configuredHomes.flatMap((entry) => {
2337
2506
  const { path: home, label } = typeof entry === "string" ? { path: entry } : entry;
2338
2507
  return existingCatalogHomeCandidates(home, label);
2339
2508
  }));
@@ -2399,96 +2568,6 @@ function createCodexCatalogHomeResolver(params) {
2399
2568
  } };
2400
2569
  }
2401
2570
  //#endregion
2402
- //#region extensions/codex/src/session-catalog-provenance.ts
2403
- const MAX_SESSION_META_BYTES = 1024 * 1024;
2404
- const SESSION_META_READ_CHUNK_BYTES = 64 * 1024;
2405
- const MAX_PROVENANCE_CACHE_ENTRIES = 2e4;
2406
- const provenanceByPath = /* @__PURE__ */ new Map();
2407
- function cacheProvenance(key, value) {
2408
- provenanceByPath.delete(key);
2409
- provenanceByPath.set(key, value);
2410
- while (provenanceByPath.size > MAX_PROVENANCE_CACHE_ENTRIES) {
2411
- const oldest = provenanceByPath.keys().next().value;
2412
- if (oldest === void 0) break;
2413
- provenanceByPath.delete(oldest);
2414
- }
2415
- }
2416
- /** Undefined means the metadata line is not durable enough to cache yet. */
2417
- async function readOpenClawOriginator(sessionsRoot, rolloutPath, threadId) {
2418
- let safeRoot;
2419
- try {
2420
- safeRoot = await root(sessionsRoot, {
2421
- hardlinks: "reject",
2422
- maxBytes: Number.MAX_SAFE_INTEGER,
2423
- symlinks: "reject"
2424
- });
2425
- } catch {
2426
- return;
2427
- }
2428
- const candidates = rolloutPath.endsWith(".zst") ? [rolloutPath, rolloutPath.slice(0, -4)] : [rolloutPath, `${rolloutPath}.zst`];
2429
- for (const candidate of candidates) {
2430
- let opened;
2431
- try {
2432
- opened = await safeRoot.open(path.relative(sessionsRoot, candidate));
2433
- } catch {
2434
- continue;
2435
- }
2436
- const input = opened.handle.createReadStream({
2437
- autoClose: false,
2438
- highWaterMark: SESSION_META_READ_CHUNK_BYTES
2439
- });
2440
- const reader = candidate.endsWith(".zst") ? input.pipe(createZstdDecompress()) : input;
2441
- try {
2442
- const chunks = [];
2443
- let bytesReadTotal = 0;
2444
- let line;
2445
- for await (const value of reader) {
2446
- const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
2447
- const remaining = MAX_SESSION_META_BYTES - bytesReadTotal;
2448
- if (remaining <= 0) break;
2449
- const bounded = chunk.subarray(0, remaining);
2450
- bytesReadTotal += bounded.length;
2451
- const newline = bounded.indexOf(10);
2452
- chunks.push(newline >= 0 ? bounded.subarray(0, newline) : bounded);
2453
- if (newline >= 0) {
2454
- line = Buffer.concat(chunks).toString("utf8");
2455
- break;
2456
- }
2457
- }
2458
- if (!line) continue;
2459
- let parsed;
2460
- try {
2461
- parsed = JSON.parse(line);
2462
- } catch {
2463
- continue;
2464
- }
2465
- if (!isRecord(parsed) || parsed.type !== "session_meta" || !isRecord(parsed.payload)) return false;
2466
- const payload = parsed.payload;
2467
- return (payload.id ?? payload.session_id) === threadId && payload.originator === "openclaw";
2468
- } catch {
2469
- continue;
2470
- } finally {
2471
- reader.destroy();
2472
- input.destroy();
2473
- await opened.handle.close().catch(() => void 0);
2474
- }
2475
- }
2476
- }
2477
- /**
2478
- * Codex 0.147 reports OpenClaw app-server rollouts as `vscode`, so the rollout's
2479
- * immutable session metadata is the authoritative historical provenance.
2480
- */
2481
- async function isOpenClawManagedCodexThread(thread, localSessionsRoot) {
2482
- const rolloutPath = typeof thread.path === "string" ? thread.path.trim() : "";
2483
- if (!localSessionsRoot || !rolloutPath) return false;
2484
- const cacheKey = `${localSessionsRoot}\0${rolloutPath}`;
2485
- const cached = provenanceByPath.get(cacheKey);
2486
- if (cached !== void 0) return cached;
2487
- const managed = await readOpenClawOriginator(localSessionsRoot, rolloutPath, thread.id);
2488
- if (managed !== void 0) cacheProvenance(cacheKey, managed);
2489
- return managed ?? false;
2490
- }
2491
- //#endregion
2492
2571
  //#region extensions/codex/src/session-catalog-control.ts
2493
2572
  const CODEX_SESSION_CATALOG_LIST_TTL_MS = 32e3;
2494
2573
  const CODEX_SESSION_CATALOG_LIST_CACHE_MAX_ENTRIES = 32;
@@ -2508,10 +2587,10 @@ function createCodexCatalogRequestSnapshot(requestTimeoutMs, request) {
2508
2587
  listThreads: (params, timeoutMs) => request(CODEX_CONTROL_METHODS.listThreads, params, timeoutMs),
2509
2588
  listThreadTurns: (params) => request(CODEX_CONTROL_METHODS.listThreadTurns, params),
2510
2589
  forkThread: (params) => request(CODEX_CONTROL_METHODS.forkThread, assertCodexThreadForkParams(params)),
2511
- readThread: async (threadId, includeTurns) => (await request(CODEX_CONTROL_METHODS.readThread, {
2590
+ readThread: async (threadId, includeTurns, timeoutMs) => (await request(CODEX_CONTROL_METHODS.readThread, {
2512
2591
  threadId,
2513
2592
  includeTurns
2514
- })).thread,
2593
+ }, timeoutMs)).thread,
2515
2594
  archiveThread: async (threadId) => {
2516
2595
  await request(CODEX_CONTROL_METHODS.archiveThread, { threadId });
2517
2596
  }
@@ -2522,6 +2601,58 @@ function createCodexSessionCatalogControlFromRequests(params) {
2522
2601
  ...params.clientId ? { clientId: params.clientId } : {},
2523
2602
  ...params.connectionFingerprint ? { connectionFingerprint: params.connectionFingerprint } : {},
2524
2603
  withPinnedConnection: params.withPinnedConnection,
2604
+ async requireEligibleThread(threadId) {
2605
+ const requests = params.createRequestSnapshot();
2606
+ const deadline = params.now() + requests.requestTimeoutMs;
2607
+ const unverified = () => new CatalogParamsError("Codex session eligibility could not be verified. Refresh the catalog and verify the session in its native Codex home before retrying.");
2608
+ const remaining = () => {
2609
+ const timeoutMs = Math.ceil(deadline - params.now());
2610
+ if (timeoutMs <= 0) throw unverified();
2611
+ return timeoutMs;
2612
+ };
2613
+ const verify = async () => {
2614
+ if (params.sourceHomeId && await params.managedThreads?.has(params.sourceHomeId, threadId)) throw unverified();
2615
+ const root = params.localSessionsRoot;
2616
+ const thread = root ? await requests.readThread(threadId, false, remaining()) : void 0;
2617
+ if (root && (!thread || thread.id !== threadId || !isInteractiveThreadSource(thread.source))) throw unverified();
2618
+ let cursor;
2619
+ const seenCursors = /* @__PURE__ */ new Set();
2620
+ for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
2621
+ const page = await requests.listThreads({
2622
+ archived: false,
2623
+ limit: 100,
2624
+ modelProviders: [],
2625
+ sortKey: root ? "recency_at" : "updated_at",
2626
+ sortDirection: "desc",
2627
+ ...root ? {
2628
+ useStateDbOnly: true,
2629
+ ...thread?.cwd ? { cwd: thread.cwd } : {}
2630
+ } : {},
2631
+ ...cursor ? { cursor } : {}
2632
+ }, remaining());
2633
+ remaining();
2634
+ const candidate = page.data.find((value) => value.id === threadId);
2635
+ if (candidate) {
2636
+ if (!isInteractiveThreadSource(candidate.source)) throw unverified();
2637
+ if (root && thread) {
2638
+ const rolloutPath = thread.path;
2639
+ if (!rolloutPath || !candidate.path || rolloutPath.replace(/\.zst$/u, "") !== candidate.path.replace(/\.zst$/u, "")) throw unverified();
2640
+ const metadata = await readCodexSessionMeta(root, rolloutPath, threadId);
2641
+ remaining();
2642
+ if (!metadata || !isInteractiveThreadSource(metadata.source) || metadata.originator === "openclaw") throw unverified();
2643
+ return thread;
2644
+ }
2645
+ return candidate;
2646
+ }
2647
+ const nextCursor = readControlCursor(page.nextCursor, "next response");
2648
+ if (!nextCursor || seenCursors.has(nextCursor)) throw unverified();
2649
+ seenCursors.add(nextCursor);
2650
+ cursor = nextCursor;
2651
+ }
2652
+ throw unverified();
2653
+ };
2654
+ return await withTimeout(verify(), requests.requestTimeoutMs, "Codex session eligibility could not be verified", unverified);
2655
+ },
2525
2656
  async listPage(pageParams) {
2526
2657
  const limit = normalizeLimit(pageParams.limit, "limit");
2527
2658
  const search = pageParams.searchTerm?.trim().toLocaleLowerCase() || void 0;
@@ -2558,7 +2689,7 @@ function createCodexSessionCatalogControlFromRequests(params) {
2558
2689
  continue;
2559
2690
  }
2560
2691
  const session = toCatalogSession(thread, false);
2561
- if (session && (!search || session.name?.toLocaleLowerCase().includes(search))) sessions.push(session);
2692
+ if (session && (!search || (session.name ?? session.fallbackName)?.toLocaleLowerCase().includes(search))) sessions.push(session);
2562
2693
  }
2563
2694
  nextCursor = readControlCursor(response.nextCursor, "next response");
2564
2695
  if (!nextCursor || sessions.length >= limit) break;
@@ -2605,7 +2736,7 @@ function createCodexSessionCatalogControl(params) {
2605
2736
  const catalogPagesByConfig = /* @__PURE__ */ new WeakMap();
2606
2737
  const resolveRequestOptions = (startOptions, agentId, source) => {
2607
2738
  const runtimeConfig = params.getRuntimeConfig();
2608
- const agentDir = source?.agentDir ?? resolveAgentDir(runtimeConfig ?? {}, agentId);
2739
+ const agentDir = source?.agentDir ?? resolveAgentDir$1(runtimeConfig ?? {}, agentId);
2609
2740
  const resolvedStartOptions = source?.appServer.start ?? startOptions;
2610
2741
  if (!runtimeConfig) return {
2611
2742
  agentDir,
@@ -2661,6 +2792,8 @@ function createCodexSessionCatalogControl(params) {
2661
2792
  connectionFingerprint: buildCodexAppServerConnectionFingerprint(runtime, agentDir),
2662
2793
  createRequestSnapshot: () => requests,
2663
2794
  ...source?.localSessionsRoot ? { localSessionsRoot: source.localSessionsRoot } : {},
2795
+ sourceHomeId: source?.sourceHomeId,
2796
+ managedThreads: params.managedThreads,
2664
2797
  now,
2665
2798
  withPinnedConnection: async (nestedRun) => await nestedRun(pinnedControl)
2666
2799
  });
@@ -2677,6 +2810,7 @@ function createCodexSessionCatalogControl(params) {
2677
2810
  });
2678
2811
  return {
2679
2812
  ...control,
2813
+ requireEligibleThread: (threadId) => withPinnedConnection((pinned) => pinned.requireEligibleThread(threadId)),
2680
2814
  async listPage(pageParams) {
2681
2815
  const runtimeConfig = params.getRuntimeConfig();
2682
2816
  if (!runtimeConfig) return await control.listPage(pageParams);
@@ -2687,7 +2821,7 @@ function createCodexSessionCatalogControl(params) {
2687
2821
  }
2688
2822
  const key = codexCatalogPageCacheKey(pageParams, agentId, source);
2689
2823
  const cached = cache.get(key);
2690
- if (pageParams.forceRefresh !== true && cached) {
2824
+ if (cached) {
2691
2825
  cache.delete(key);
2692
2826
  cache.set(key, cached);
2693
2827
  if (cached.expiresAt > now()) return cached.value ?? await cached.page;
@@ -2718,7 +2852,7 @@ function createCodexSessionCatalogControl(params) {
2718
2852
  });
2719
2853
  else cache.delete(key);
2720
2854
  };
2721
- if (pageParams.forceRefresh !== true && staleValue) {
2855
+ if (staleValue) {
2722
2856
  page.then(settle, restore);
2723
2857
  return staleValue;
2724
2858
  }
@@ -2812,7 +2946,7 @@ function registerCodexSessionCatalog(params) {
2812
2946
  const homes = params.control.homesForAgent(agentId);
2813
2947
  return allowProcessHomeFallback === false ? homes.filter((home) => !home.usesProcessHomeFallback) : homes;
2814
2948
  };
2815
- const resolveRequestAgentId = (agentId) => resolveSessionAgentIds({
2949
+ const resolveRequestAgentId = (agentId) => resolveSessionAgentIdsStrict({
2816
2950
  config: params.getRuntimeConfig() ?? params.api.config,
2817
2951
  agentId
2818
2952
  }).sessionAgentId;
@@ -2893,7 +3027,7 @@ function registerCodexSessionCatalog(params) {
2893
3027
  if (!isLocalCodexCatalogHost(request.hostId)) throw new CatalogParamsError("Codex session catalog hostId is invalid");
2894
3028
  const { agentId, source, control } = bindLocalRequest(request);
2895
3029
  let upstreamBaseline;
2896
- return codexUpstreamContinueResult((await continueLocalCodexSession({
3030
+ const continued = await continueLocalCodexSession({
2897
3031
  agentId,
2898
3032
  api: params.api,
2899
3033
  bindingStore: params.bindingStore,
@@ -2906,7 +3040,8 @@ function registerCodexSessionCatalog(params) {
2906
3040
  onContinued: (baseline) => {
2907
3041
  upstreamBaseline = baseline;
2908
3042
  }
2909
- })).sessionKey, request.threadId, upstreamBaseline);
3043
+ });
3044
+ return codexUpstreamContinueResult(continued.sessionKey, request.threadId, upstreamBaseline);
2910
3045
  },
2911
3046
  checkUpstreamActivity: (probes, policy) => checkUpstreamActivity(probes.filter((probe) => !isLocalCodexCatalogHost(probe.hostId) || policy?.allowProcessHomeFallback !== false || catalogHomes(probe.agentId, false).some((home) => home.hostId === probe.hostId))),
2912
3047
  archive: async (request) => {
@@ -2960,4 +3095,4 @@ const codexSessionCatalogRuntime = {
2960
3095
  archiveLocal: archiveLocalCodexSession
2961
3096
  };
2962
3097
  //#endregion
2963
- export { CODEX_LOCAL_SESSION_HOST_ID as a, createCodexCliSessionNodeInvokePolicies as c, resolveCodexCliSessionForBindingOnNode as d, resumeCodexCliSessionOnNode as f, createCodexSessionCatalogNodeHostCommands as i, formatCodexCliSessions as l, createCodexSessionCatalogNodeInvokePolicies as n, assertCodexArchiveDescendantsUnowned as o, createCodexSessionCatalogControl as r, createCodexCliSessionNodeHostCommands as s, codexSessionCatalogRuntime as t, listCodexCliSessionsOnNode as u };
3098
+ export { CODEX_LOCAL_SESSION_HOST_ID as a, readCodexStatusProbes as c, createCodexCliSessionNodeHostCommands as d, createCodexCliSessionNodeInvokePolicies as f, resumeCodexCliSessionOnNode as g, resolveCodexCliSessionForBindingOnNode as h, createCodexSessionCatalogNodeHostCommands as i, requestOptions as l, listCodexCliSessionsOnNode as m, createCodexSessionCatalogNodeInvokePolicies as n, assertCodexArchiveDescendantsUnowned as o, formatCodexCliSessions as p, createCodexSessionCatalogControl as r, codexControlRequest as s, codexSessionCatalogRuntime as t, safeCodexControlRequest as u };