@openclaw/codex 2026.7.1 → 2026.7.2-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 (48) hide show
  1. package/README.md +27 -3
  2. package/dist/app-server-policy-Scc-Wevo.js +49 -0
  3. package/dist/{attempt-notifications-BGsEIIDI.js → attempt-notifications-BFmNhqFl.js} +3 -6
  4. package/dist/auth-binding-C1czuHPA.js +62 -0
  5. package/dist/cli-metadata.js +20 -0
  6. package/dist/{app-server-policy-C968Kgin.js → command-formatters-Dq9InZUK.js} +39 -51
  7. package/dist/{command-handlers-Dv-pzAmg.js → command-handlers-IgqmL_kv.js} +161 -61
  8. package/dist/{compact-4mVBriKT.js → compact-DCTmg3id.js} +39 -10
  9. package/dist/computer-use-CPcU8TjG.js +685 -0
  10. package/dist/conversation-control-CGkBlfc5.js +286 -0
  11. package/dist/doctor-contract-api.js +120 -81
  12. package/dist/{provider-capabilities-CDnHbmUZ.js → dynamic-tools-C_1tEs34.js} +6109 -5725
  13. package/dist/harness.js +59 -15
  14. package/dist/index.js +1460 -269
  15. package/dist/{media-understanding-provider-BHOu9-Gg.js → media-understanding-provider-D31dOJwb.js} +32 -15
  16. package/dist/media-understanding-provider.js +1 -1
  17. package/dist/{models-DDmO1zwd.js → models-uh26C8QU.js} +5 -9
  18. package/dist/notification-correlation-KmfV4EkP.js +67 -0
  19. package/dist/plugin-app-cache-key-Ceb-lm2c.js +315 -0
  20. package/dist/{provider-zjPfx5Fs.js → rate-limits-DyXaYAxU.js} +10 -266
  21. package/dist/request-B_oQsCXy.js +157 -0
  22. package/dist/{run-attempt-FUyOjGCV.js → run-attempt-MLzoMe_m.js} +7395 -6430
  23. package/dist/runtime-artifact-C2ITXdhM.js +488 -0
  24. package/dist/{sandbox-guard-DA2TQfZW.js → sandbox-guard-D1Wky__S.js} +10 -1
  25. package/dist/{config-CYEDnLJ2.js → session-binding-h1mmCGnl.js} +985 -31
  26. package/dist/session-catalog-CEvoXWHA.js +2412 -0
  27. package/dist/session-cli-XsEuWb_C.js +175 -0
  28. package/dist/{shared-client-4ICy3U6d.js → shared-client-JiAnW6pc.js} +2193 -1319
  29. package/dist/{side-question-N4OaDer2.js → side-question-DqDvIwSU.js} +140 -70
  30. package/dist/{thread-lifecycle-qWE88Dn2.js → thread-lifecycle-CN_pPtPh.js} +1826 -1188
  31. package/dist/{protocol-validators-dZQ-UTOa.js → transcript-mirror-D9rTxx2P.js} +485 -2
  32. package/dist/transport-stdio-DXgGZ7Ib.js +88 -0
  33. package/dist/usage-D5Rohxoc.js +25 -0
  34. package/dist/{web-search-provider.runtime-BSlriav6.js → web-search-provider.runtime-CKVBn3fP.js} +3 -3
  35. package/npm-shrinkwrap.json +56 -30
  36. package/openclaw.plugin.json +177 -14
  37. package/package.json +8 -6
  38. package/dist/command-rpc-eLM_mtC7.js +0 -784
  39. package/dist/computer-use-Bmaz333N.js +0 -377
  40. package/dist/notification-correlation-Bo7KB3ks.js +0 -35
  41. package/dist/plugin-app-cache-key-BrhVdeEf.js +0 -98
  42. package/dist/prompt-overlay.js +0 -15
  43. package/dist/protocol-2POPqAY4.js +0 -13
  44. package/dist/provider-catalog.js +0 -79
  45. package/dist/provider-discovery.js +0 -34
  46. package/dist/provider.js +0 -2
  47. package/dist/request-BcJyl8KL.js +0 -36
  48. package/dist/session-binding-C1ZXdP-x.js +0 -627
@@ -1,27 +1,31 @@
1
- import { r as isJsonObject } from "./protocol-2POPqAY4.js";
2
- import { o as isCodexFastServiceTier } from "./config-CYEDnLJ2.js";
3
- import { n as assertCodexThreadResumeResponse } from "./protocol-validators-dZQ-UTOa.js";
4
- import { t as listAllCodexAppServerModels } from "./models-DDmO1zwd.js";
5
- import { p as summarizeCodexAccountUsage } from "./provider-zjPfx5Fs.js";
6
- import { y as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-4ICy3U6d.js";
7
- import { a as normalizeCodexAppServerBindingModelProvider, n as bindingStoreKey, o as reclaimCurrentCodexSessionGeneration, s as sessionBindingIdentity } from "./session-binding-C1ZXdP-x.js";
8
- import { r as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-BrhVdeEf.js";
9
- import { a as formatCodexDisplayText, c as formatList, d as formatThreads, f as readString$1, i as formatAccount, l as formatModels, o as formatCodexStatus, r as buildHelp, s as formatComputerUseStatus, u as formatSkills } from "./app-server-policy-C968Kgin.js";
10
- import { n as resolveCodexNativeExecutionBlock, r as resolveCodexNativeSandboxBlock } from "./sandbox-guard-DA2TQfZW.js";
11
- import { S as canMutateCodexHost, _ as setCodexConversationPermissions, d as formatPermissionsMode, f as parseCodexFastModeArg, g as setCodexConversationModel, h as setCodexConversationFastMode, i as safeCodexControlRequest, m as readCodexConversationActiveTurn, n as readCodexStatusProbes, p as parseCodexPermissionsModeArg, r as requestOptions, s as formatCodexCliSessions, t as codexControlRequest, v as steerCodexConversationTurn, x as CODEX_NATIVE_EXECUTION_AUTH_ERROR, y as stopCodexConversationTurn } from "./command-rpc-eLM_mtC7.js";
1
+ import { S as resolveCodexAppServerAuthProfileIdForAgent, Z as isJsonObject } from "./shared-client-JiAnW6pc.js";
2
+ import { _ as isCodexFastServiceTier, c as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced, o as normalizeCodexAppServerBindingModelProvider, r as bindingStoreKey, s as reclaimCurrentCodexSessionGeneration } from "./session-binding-h1mmCGnl.js";
3
+ import { u as assertCodexThreadResumeResponse } from "./transcript-mirror-D9rTxx2P.js";
4
+ import { t as listAllCodexAppServerModels } from "./models-uh26C8QU.js";
5
+ import { a as formatComputerUseStatus, c as formatSkills, d as CODEX_CONTROL_METHODS, i as formatCodexStatus, l as formatThreads, n as formatAccount, o as formatList, r as formatCodexDisplayText, s as formatModels, t as buildHelp, u as readString$1 } from "./command-formatters-Dq9InZUK.js";
6
+ import { s as summarizeCodexAccountUsage } from "./rate-limits-DyXaYAxU.js";
7
+ import { n as resolveCodexNativeExecutionBlock, r as resolveCodexNativeSandboxBlock } from "./sandbox-guard-D1Wky__S.js";
8
+ import { a as setCodexConversationFastMode, c as steerCodexConversationTurn, d as CODEX_NATIVE_EXECUTION_AUTH_ERROR, f as canMutateCodexHost, i as readCodexConversationActiveTurn, l as stopCodexConversationTurn, n as parseCodexFastModeArg, o as setCodexConversationModel, r as parseCodexPermissionsModeArg, s as setCodexConversationPermissions, t as formatPermissionsMode } from "./conversation-control-CGkBlfc5.js";
12
9
  import { i as readCodexConversationBindingData, n as createCodexCliNodeConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-BHRpYbX3.js";
13
- import { n as installCodexComputerUse, r as readCodexComputerUseStatus } from "./computer-use-Bmaz333N.js";
10
+ import { a as resolveCodexBindingAppServerConnection } from "./notification-correlation-KmfV4EkP.js";
11
+ import { c as requestOptions, l as safeCodexControlRequest, o as codexControlRequest, p as formatCodexCliSessions, s as readCodexStatusProbes } from "./session-catalog-CEvoXWHA.js";
12
+ import { i as readCodexComputerUseStatus, n as installCodexComputerUse } from "./computer-use-CPcU8TjG.js";
14
13
  import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
14
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
15
15
  import crypto from "node:crypto";
16
- import { ensureAuthProfileStore, findNormalizedProviderValue, resolveAgentDir, resolveAuthProfileEligibility, resolveAuthProfileOrder, resolveDefaultAgentDir, resolveProfileUnusableUntilForDisplay, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
16
+ import { ensureAuthProfileStore, findNormalizedProviderValue, resolveAgentDir, resolveAuthProfileEligibility, resolveAuthProfileOrder, resolveProfileUnusableUntilForDisplay, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
17
17
  import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
18
18
  import { normalizeOptionalString, normalizeUniqueStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
19
+ import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
20
+ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
21
+ import { MODEL_SELECTION_LOCKED_MESSAGE, isModelSelectionLocked } from "openclaw/plugin-sdk/model-session-runtime";
19
22
  //#region extensions/codex/src/command-account.ts
20
23
  const OPENAI_PROVIDER_ID = "openai";
21
24
  const OPENAI_CODEX_PROVIDER_ID = OPENAI_PROVIDER_ID;
22
25
  async function readCodexAccountAuthOverview(params) {
23
26
  const config = params.ctx.config;
24
- const store = ensureAuthProfileStore(resolveDefaultAgentDir(config), {
27
+ const agentDir = params.agentDir;
28
+ const store = ensureAuthProfileStore(agentDir, {
25
29
  allowKeychainPrompt: false,
26
30
  config
27
31
  });
@@ -45,6 +49,7 @@ async function readCodexAccountAuthOverview(params) {
45
49
  const activeUsage = activeIsSubscription && params.limits.ok ? summarizeCodexAccountUsage(params.limits.value, now) : void 0;
46
50
  const subscriptionUsage = subscriptionProfileId && (!activeIsSubscription || subscriptionProfileId !== activeProfileId) ? await readSubscriptionUsage({
47
51
  ...params,
52
+ agentDir,
48
53
  config,
49
54
  subscriptionProfileId,
50
55
  now
@@ -149,7 +154,7 @@ function resolveLiveAccountProfileId(params) {
149
154
  if (!email) return firstSubscription;
150
155
  return params.order.find((profileId) => {
151
156
  const credential = params.store.profiles[profileId];
152
- if (!isChatGptSubscriptionProfile(credential)) return false;
157
+ if (!credential || !isChatGptSubscriptionProfile(credential)) return false;
153
158
  return (credential.email?.trim().toLowerCase() ?? extractEmailFromProfileId(profileId))?.toLowerCase() === email;
154
159
  }) ?? firstSubscription;
155
160
  }
@@ -161,6 +166,7 @@ function shouldInferApiKeyActiveFromRateLimitProbe(limits) {
161
166
  async function readSubscriptionUsage(params) {
162
167
  const limits = await params.safeCodexControlRequest(params.pluginConfig, CODEX_CONTROL_METHODS.rateLimits, void 0, {
163
168
  config: params.config,
169
+ agentDir: params.agentDir,
164
170
  authProfileId: params.subscriptionProfileId,
165
171
  isolated: true
166
172
  });
@@ -308,6 +314,21 @@ function formatRelativeReset(untilMs, nowMs) {
308
314
  return `in ${days} ${days === 1 ? "day" : "days"}`;
309
315
  }
310
316
  //#endregion
317
+ //#region extensions/codex/src/command-diagnostics-state.ts
318
+ /** Runtime state for diagnostics upload throttling and confirmation handshakes. */
319
+ const codexDiagnosticsFeedbackState = {
320
+ lastUploadByThread: /* @__PURE__ */ new Map(),
321
+ lastUploadByScope: /* @__PURE__ */ new Map(),
322
+ pendingConfirmations: /* @__PURE__ */ new Map(),
323
+ pendingTokensByScope: /* @__PURE__ */ new Map(),
324
+ clear() {
325
+ this.lastUploadByThread.clear();
326
+ this.lastUploadByScope.clear();
327
+ this.pendingConfirmations.clear();
328
+ this.pendingTokensByScope.clear();
329
+ }
330
+ };
331
+ //#endregion
311
332
  //#region extensions/codex/src/command-presentation.ts
312
333
  function buildCodexCommandPickerPresentation(title, prompt, buttons) {
313
334
  return {
@@ -526,10 +547,7 @@ const CODEX_NATIVE_CONTROL_SUBCOMMANDS = /* @__PURE__ */ new Set([
526
547
  "unbind",
527
548
  "stop"
528
549
  ]);
529
- const lastCodexDiagnosticsUploadByThread = /* @__PURE__ */ new Map();
530
- const lastCodexDiagnosticsUploadByScope = /* @__PURE__ */ new Map();
531
- const pendingCodexDiagnosticsConfirmations = /* @__PURE__ */ new Map();
532
- const pendingCodexDiagnosticsConfirmationTokensByScope = /* @__PURE__ */ new Map();
550
+ const { lastUploadByThread: lastCodexDiagnosticsUploadByThread, lastUploadByScope: lastCodexDiagnosticsUploadByScope, pendingConfirmations: pendingCodexDiagnosticsConfirmations, pendingTokensByScope: pendingCodexDiagnosticsConfirmationTokensByScope } = codexDiagnosticsFeedbackState;
533
551
  /**
534
552
  * No-arg `/codex` picker. Codex owns the command tree; channels render the
535
553
  * portable command actions as inline controls when their transport can.
@@ -672,11 +690,13 @@ async function handleCodexSubcommand(ctx, options) {
672
690
  }
673
691
  if (normalized === "status") {
674
692
  if (rest.length > 0) return { text: "Usage: /codex status" };
675
- return { text: formatCodexStatus(await deps.readCodexStatusProbes(options.pluginConfig, ctx.config)) };
693
+ const { agentDir } = resolveCodexConversationControlScope(ctx);
694
+ return { text: formatCodexStatus(await deps.readCodexStatusProbes(options.pluginConfig, ctx.config, agentDir)) };
676
695
  }
677
696
  if (normalized === "models") {
678
697
  if (rest.length > 0) return { text: "Usage: /codex models" };
679
- return { text: formatModels(await deps.listCodexAppServerModels(deps.requestOptions(options.pluginConfig, 100, ctx.config))) };
698
+ const { agentDir } = resolveCodexConversationControlScope(ctx);
699
+ return { text: formatModels(await deps.listCodexAppServerModels(deps.requestOptions(options.pluginConfig, 100, ctx.config, agentDir))) };
680
700
  }
681
701
  if (normalized === "threads") return { text: await buildThreads(deps, ctx, options.pluginConfig, rest.join(" ")) };
682
702
  if (normalized === "sessions") return { text: await buildCodexCliSessions(deps, rest) };
@@ -713,7 +733,7 @@ async function handleCodexSubcommand(ctx, options) {
713
733
  }
714
734
  if (normalized === "mcp") {
715
735
  if (rest.length > 0) return { text: "Usage: /codex mcp" };
716
- const scope = await resolveCommandAppServerScope(deps, ctx);
736
+ const scope = await resolveCommandAppServerScope(deps, ctx, options.pluginConfig);
717
737
  return { text: formatList(await deps.codexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.listMcpServers, { limit: 100 }, {
718
738
  config: ctx.config,
719
739
  ...scope
@@ -721,7 +741,7 @@ async function handleCodexSubcommand(ctx, options) {
721
741
  }
722
742
  if (normalized === "skills") {
723
743
  if (rest.length > 0) return { text: "Usage: /codex skills" };
724
- const scope = await resolveCommandAppServerScope(deps, ctx);
744
+ const scope = await resolveCommandAppServerScope(deps, ctx, options.pluginConfig);
725
745
  return { text: formatSkills(await deps.codexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.listSkills, {}, {
726
746
  config: ctx.config,
727
747
  ...scope
@@ -729,7 +749,7 @@ async function handleCodexSubcommand(ctx, options) {
729
749
  }
730
750
  if (normalized === "account") {
731
751
  if (rest.length > 0) return { text: "Usage: /codex account" };
732
- const scope = await resolveCommandAppServerScope(deps, ctx);
752
+ const scope = await resolveCommandAppServerScope(deps, ctx, options.pluginConfig);
733
753
  const requestScope = {
734
754
  config: ctx.config,
735
755
  ...scope
@@ -737,6 +757,7 @@ async function handleCodexSubcommand(ctx, options) {
737
757
  const [account, limits] = await Promise.all([deps.safeCodexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.account, { refreshToken: false }, requestScope), deps.safeCodexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.rateLimits, void 0, requestScope)]);
738
758
  return { text: formatAccount(account, limits, await readCodexAccountAuthOverview({
739
759
  ctx,
760
+ agentDir: scope.agentDir,
740
761
  pluginConfig: options.pluginConfig,
741
762
  safeCodexControlRequest: deps.safeCodexControlRequest,
742
763
  account,
@@ -745,6 +766,16 @@ async function handleCodexSubcommand(ctx, options) {
745
766
  }
746
767
  return { text: `Unknown Codex command: ${formatCodexDisplayText(subcommand)}\n\n${buildHelp()}` };
747
768
  }
769
+ function isCurrentSessionModelSelectionLocked(ctx) {
770
+ const sessionKey = ctx.sessionKey?.trim();
771
+ if (!sessionKey) return false;
772
+ return isModelSelectionLocked(getSessionEntry({
773
+ storePath: resolveStorePath(ctx.config.session?.store, { agentId: ctx.agentId }),
774
+ sessionKey,
775
+ hydrateSkillPromptRefs: false,
776
+ readConsistency: "latest"
777
+ }));
778
+ }
748
779
  function resolveCodexNativeCommandSandboxBlock(ctx, subcommand, args) {
749
780
  if (!CODEX_NATIVE_EXECUTION_SUBCOMMANDS.has(subcommand)) return;
750
781
  if (returnsBeforeNativeCodexExecution(subcommand, args)) return;
@@ -793,9 +824,13 @@ function returnsBeforeNativeCodexResume(args) {
793
824
  async function handleComputerUseCommand(deps, ctx, pluginConfig, args) {
794
825
  const parsed = parseComputerUseArgs(args);
795
826
  if (parsed.help) return ["Usage: /codex computer-use [status|install] [--source <marketplace-source>] [--marketplace-path <path>] [--marketplace <name>]", "Checks or installs the configured Codex Computer Use plugin through app-server."].join("\n");
827
+ if (Object.keys(parsed.persistentIdentity).length > 0) return formatComputerUsePersistentIdentityMigration(parsed);
796
828
  if (parsed.action === "install" && !canMutateCodexHost(ctx)) return "Only an owner or operator.admin gateway client can configure Codex Computer Use.";
829
+ const { agentDir } = resolveCodexConversationControlScope(ctx);
797
830
  const params = {
798
831
  pluginConfig,
832
+ config: ctx.config,
833
+ agentDir,
799
834
  forceEnable: parsed.action === "install" || parsed.hasOverrides,
800
835
  ...Object.keys(parsed.overrides).length > 0 ? { overrides: parsed.overrides } : {}
801
836
  };
@@ -805,6 +840,7 @@ async function handleComputerUseCommand(deps, ctx, pluginConfig, args) {
805
840
  async function bindConversation(deps, ctx, pluginConfig, args) {
806
841
  const parsed = parseBindArgs(args);
807
842
  if (parsed.help) return { text: "Usage: /codex bind [thread-id] [--cwd <path>] [--model <model>] [--provider <provider>]" };
843
+ if (isCurrentSessionModelSelectionLocked(ctx)) return { text: MODEL_SELECTION_LOCKED_MESSAGE };
808
844
  const scope = resolveCodexConversationControlScope(ctx);
809
845
  const workspaceDir = parsed.cwd ?? deps.resolveCodexDefaultWorkspaceDir(pluginConfig);
810
846
  const currentConversation = await ctx.getCurrentConversationBinding();
@@ -818,6 +854,7 @@ async function bindConversation(deps, ctx, pluginConfig, args) {
818
854
  }) : void 0;
819
855
  const currentOwner = currentConversationData?.kind === "codex-app-server-session" ? conversationBindingIdentity(currentConversationData.bindingId) : sessionOwner;
820
856
  const existingBinding = currentOwner ? await deps.bindingStore.read(currentOwner) : void 0;
857
+ assertCodexBindingMayBeReplaced(existingBinding, "binding this conversation to another thread");
821
858
  const sessionSource = sessionOwner && existingBinding ? {
822
859
  agentId: sessionOwner.agentId,
823
860
  sessionId: sessionOwner.sessionId,
@@ -850,7 +887,9 @@ async function bindConversation(deps, ctx, pluginConfig, args) {
850
887
  return { text: `Bound this conversation to ${formatCodexDisplayText(threadLabel)} in ${formatCodexDisplayText(workspaceDir)}. The next message will initialize it.` };
851
888
  }
852
889
  async function detachConversation(deps, ctx) {
890
+ if (isCurrentSessionModelSelectionLocked(ctx)) return MODEL_SELECTION_LOCKED_MESSAGE;
853
891
  const data = readCodexConversationBindingData(await ctx.getCurrentConversationBinding());
892
+ if (data?.kind === "codex-app-server-session") assertCodexBindingMayBeReplaced(await deps.bindingStore.read(conversationBindingIdentity(data.bindingId)), "detaching its conversation binding");
854
893
  const detached = await ctx.detachConversationBinding();
855
894
  if (data?.kind === "codex-app-server-session") await deps.bindingStore.mutate(conversationBindingIdentity(data.bindingId), { kind: "clear" });
856
895
  return detached.removed ? "Detached this conversation from Codex." : "No Codex conversation binding was attached.";
@@ -882,7 +921,7 @@ async function describeConversationBinding(deps, ctx) {
882
921
  ].join("\n");
883
922
  }
884
923
  async function buildThreads(deps, ctx, pluginConfig, filter) {
885
- const scope = await resolveCommandAppServerScope(deps, ctx);
924
+ const scope = await resolveCommandAppServerScope(deps, ctx, pluginConfig);
886
925
  return formatThreads(await deps.codexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.listThreads, {
887
926
  limit: 10,
888
927
  ...filter.trim() ? { searchTerm: filter.trim() } : {}
@@ -906,6 +945,7 @@ async function resumeThread(deps, ctx, pluginConfig, args) {
906
945
  if (parsed.help) return args.includes("--help") || args.includes("-h") || parsed.host ? "Usage: /codex resume <thread-id>\nUsage: /codex resume <session-id> --host <node> --bind here" : "Usage: /codex resume <thread-id>";
907
946
  if (parsed.host) return await bindCodexCliNodeSession(deps, ctx, parsed);
908
947
  if (!normalizedThreadId || args.length !== 1) return "Usage: /codex resume <thread-id>";
948
+ if (isCurrentSessionModelSelectionLocked(ctx)) return MODEL_SELECTION_LOCKED_MESSAGE;
909
949
  if (!ctx.sessionId) return "Cannot attach a Codex thread because this command did not include an OpenClaw session id.";
910
950
  const scope = resolveCodexConversationControlScope(ctx);
911
951
  const identity = sessionBindingIdentity({
@@ -920,8 +960,10 @@ async function resumeThread(deps, ctx, pluginConfig, args) {
920
960
  identity,
921
961
  config: ctx.config
922
962
  })) throw new Error(`Codex session generation is no longer current: ${identity.sessionId}`);
963
+ const currentBinding = await deps.bindingStore.read(identity);
964
+ assertCodexBindingMayBeReplaced(currentBinding, "attaching a different resumed thread");
923
965
  const authProfileId = resolveCodexAppServerAuthProfileIdForAgent({
924
- authProfileId: (await deps.bindingStore.read(identity))?.authProfileId,
966
+ authProfileId: currentBinding?.authProfileId,
925
967
  agentDir: scope.agentDir,
926
968
  config: ctx.config
927
969
  });
@@ -945,6 +987,7 @@ async function resumeThread(deps, ctx, pluginConfig, args) {
945
987
  agentDir: scope.agentDir,
946
988
  config: ctx.config
947
989
  });
990
+ assertCodexBindingMayBeReplaced(await deps.bindingStore.read(identity), "committing a different resumed thread");
948
991
  if (!await deps.bindingStore.mutate(identity, {
949
992
  kind: "set",
950
993
  binding: {
@@ -961,6 +1004,16 @@ async function resumeThread(deps, ctx, pluginConfig, args) {
961
1004
  }
962
1005
  async function bindCodexCliNodeSession(deps, ctx, parsed) {
963
1006
  if (!parsed.threadId || !parsed.host || parsed.bindHere !== true) return "Usage: /codex resume <session-id> --host <node> --bind here";
1007
+ if (isCurrentSessionModelSelectionLocked(ctx)) return MODEL_SELECTION_LOCKED_MESSAGE;
1008
+ if (ctx.sessionId) {
1009
+ const scope = resolveCodexConversationControlScope(ctx);
1010
+ assertCodexBindingMayBeReplaced(await deps.bindingStore.read(sessionBindingIdentity({
1011
+ sessionId: ctx.sessionId,
1012
+ sessionKey: ctx.sessionKey,
1013
+ agentId: scope.agentId,
1014
+ config: ctx.config
1015
+ })), "binding a Codex CLI node session");
1016
+ }
964
1017
  const resolved = await deps.resolveCodexCliSessionForBindingOnNode({
965
1018
  requestedNode: parsed.host,
966
1019
  sessionId: parsed.threadId
@@ -1010,10 +1063,11 @@ async function steerConversationTurn(deps, ctx, pluginConfig, message) {
1010
1063
  }
1011
1064
  async function setConversationModel(deps, ctx, pluginConfig, args) {
1012
1065
  if (args.length > 1) return "Usage: /codex model <model>";
1013
- const target = await resolveControlTarget(ctx);
1014
- if (!target) return "Cannot set Codex model because this command did not include a stable binding identity.";
1015
1066
  const [model = ""] = args;
1016
1067
  const normalized = model.trim();
1068
+ if (normalized && isCurrentSessionModelSelectionLocked(ctx)) return MODEL_SELECTION_LOCKED_MESSAGE;
1069
+ const target = await resolveControlTarget(ctx);
1070
+ if (!target) return "Cannot set Codex model because this command did not include a stable binding identity.";
1017
1071
  if (!normalized) {
1018
1072
  const binding = await deps.bindingStore.read(target.identity);
1019
1073
  return binding?.model ? `Codex model: ${formatCodexDisplayText(binding.model)}` : "Usage: /codex model <model>";
@@ -1073,19 +1127,25 @@ async function resolveControlTarget(ctx) {
1073
1127
  agentDir: scope.agentDir
1074
1128
  } : void 0;
1075
1129
  }
1076
- async function resolveCommandAppServerScope(deps, ctx) {
1130
+ async function resolveCommandAppServerScope(deps, ctx, pluginConfig) {
1077
1131
  const target = await resolveControlTarget(ctx);
1078
1132
  const fallback = resolveCodexConversationControlScope(ctx);
1079
1133
  const agentDir = target?.agentDir ?? fallback.agentDir;
1080
- const authProfileId = resolveCodexAppServerAuthProfileIdForAgent({
1081
- authProfileId: (target ? await deps.bindingStore.read(target.identity) : void 0)?.authProfileId ?? target?.requestedAuthProfileId,
1082
- agentDir,
1083
- config: ctx.config
1134
+ const binding = target ? await deps.bindingStore.read(target.identity) : void 0;
1135
+ const connection = resolveCodexBindingAppServerConnection({
1136
+ binding,
1137
+ authProfileId: binding?.connectionScope === "supervision" ? void 0 : resolveCodexAppServerAuthProfileIdForAgent({
1138
+ authProfileId: binding?.authProfileId ?? target?.requestedAuthProfileId,
1139
+ agentDir,
1140
+ config: ctx.config
1141
+ }),
1142
+ pluginConfig
1084
1143
  });
1085
1144
  return {
1086
1145
  agentId: target?.agentId ?? fallback.agentId,
1087
1146
  agentDir,
1088
- ...authProfileId ? { authProfileId } : {},
1147
+ ...connection.clientAuthProfileId !== void 0 ? { authProfileId: connection.clientAuthProfileId } : {},
1148
+ ...connection.usesSupervisionConnection ? { startOptions: connection.appServer.start } : {},
1089
1149
  ...ctx.sessionKey ? { sessionKey: ctx.sessionKey } : {},
1090
1150
  ...ctx.sessionId ? { sessionId: ctx.sessionId } : {}
1091
1151
  };
@@ -1233,6 +1293,20 @@ async function sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, n
1233
1293
  const sent = [];
1234
1294
  const failed = [];
1235
1295
  for (const target of targets) {
1296
+ let connection;
1297
+ try {
1298
+ connection = resolveCodexBindingAppServerConnection({
1299
+ binding: target,
1300
+ authProfileId: target.authProfileId,
1301
+ pluginConfig
1302
+ });
1303
+ } catch (error) {
1304
+ failed.push({
1305
+ target,
1306
+ error: error instanceof Error ? error.message : String(error)
1307
+ });
1308
+ continue;
1309
+ }
1236
1310
  const response = await deps.safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.feedback, {
1237
1311
  classification: "bug",
1238
1312
  threadId: target.threadId,
@@ -1242,7 +1316,8 @@ async function sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, n
1242
1316
  }, {
1243
1317
  config: ctx.config,
1244
1318
  agentDir: target.agentDir,
1245
- ...target.authProfileId ? { authProfileId: target.authProfileId } : {},
1319
+ ...connection.clientAuthProfileId !== void 0 ? { authProfileId: connection.clientAuthProfileId } : {},
1320
+ ...connection.usesSupervisionConnection ? { startOptions: connection.appServer.start } : {},
1246
1321
  ...target.sessionId ? { sessionId: target.sessionId } : {},
1247
1322
  ...target.sessionKey ? { sessionKey: target.sessionKey } : {}
1248
1323
  });
@@ -1325,13 +1400,31 @@ async function resolvePendingCodexDiagnosticsTargets(deps, targets, config) {
1325
1400
  return resolved;
1326
1401
  }
1327
1402
  function resolveCodexDiagnosticsTarget(target, binding, config) {
1403
+ const candidate = {
1404
+ identity: target.identity,
1405
+ agentDir: target.agentDir,
1406
+ sessionKey: target.sessionKey,
1407
+ sessionId: target.sessionId,
1408
+ channel: target.channel,
1409
+ channelId: target.channelId,
1410
+ accountId: target.accountId,
1411
+ messageThreadId: target.messageThreadId,
1412
+ threadParentId: target.threadParentId
1413
+ };
1414
+ if (binding.connectionScope === "supervision") return {
1415
+ ...candidate,
1416
+ threadId: binding.threadId,
1417
+ connectionScope: binding.connectionScope,
1418
+ appServerRuntimeFingerprint: binding.appServerRuntimeFingerprint,
1419
+ pendingSupervisionBranch: binding.pendingSupervisionBranch
1420
+ };
1328
1421
  const authProfileId = resolveCodexAppServerAuthProfileIdForAgent({
1329
1422
  authProfileId: binding.authProfileId,
1330
1423
  agentDir: target.agentDir,
1331
1424
  config
1332
1425
  });
1333
1426
  return {
1334
- ...target,
1427
+ ...candidate,
1335
1428
  threadId: binding.threadId,
1336
1429
  authProfileId
1337
1430
  };
@@ -1340,6 +1433,8 @@ function codexDiagnosticsTargetsMatch(expected, actual) {
1340
1433
  const fingerprint = (target) => JSON.stringify([
1341
1434
  bindingStoreKey(target.identity),
1342
1435
  target.threadId,
1436
+ target.connectionScope ?? null,
1437
+ target.pendingSupervisionBranch?.connectionFingerprint ?? target.appServerRuntimeFingerprint ?? null,
1343
1438
  target.authProfileId ?? null
1344
1439
  ]);
1345
1440
  const expectedTargets = expected.map(fingerprint).toSorted();
@@ -1387,7 +1482,7 @@ function formatCodexDiagnosticsTargetLine(target) {
1387
1482
  }
1388
1483
  function normalizeDiagnosticsReason(note) {
1389
1484
  const normalized = normalizeOptionalString(note);
1390
- return normalized ? normalized.slice(0, CODEX_DIAGNOSTICS_REASON_MAX_CHARS) : void 0;
1485
+ return normalized ? truncateUtf16Safe(normalized, CODEX_DIAGNOSTICS_REASON_MAX_CHARS) : void 0;
1391
1486
  }
1392
1487
  function parseDiagnosticsArgs(args) {
1393
1488
  const [action, token, ...extra] = splitArgs(args);
@@ -1590,7 +1685,7 @@ function pruneCodexDiagnosticsCooldownMap(map, now) {
1590
1685
  for (const [key, lastSentAt] of map) if (now - lastSentAt >= CODEX_DIAGNOSTICS_COOLDOWN_MS) map.delete(key);
1591
1686
  }
1592
1687
  function formatCodexErrorForDisplay(error) {
1593
- return escapeCodexChatText(formatCodexTextForDisplay(error).slice(0, CODEX_DIAGNOSTICS_ERROR_MAX_CHARS)) || "unknown error";
1688
+ return escapeCodexChatText(truncateUtf16Safe(formatCodexTextForDisplay(error), CODEX_DIAGNOSTICS_ERROR_MAX_CHARS)) || "unknown error";
1594
1689
  }
1595
1690
  function formatCodexResumeCommandForDisplay(threadId) {
1596
1691
  const safeThreadId = formatCodexTextForDisplay(threadId);
@@ -1613,13 +1708,19 @@ async function startThreadAction(deps, ctx, pluginConfig, kind, args) {
1613
1708
  if (!target) return `Cannot start Codex ${label} because this command did not include a stable binding identity.`;
1614
1709
  const binding = await deps.bindingStore.read(target.identity);
1615
1710
  if (!binding?.threadId) return `No Codex thread is attached to this OpenClaw session yet.`;
1711
+ const connection = resolveCodexBindingAppServerConnection({
1712
+ binding,
1713
+ authProfileId: binding.authProfileId,
1714
+ pluginConfig
1715
+ });
1616
1716
  await deps.codexControlRequest(pluginConfig, kind === "compact" ? CODEX_CONTROL_METHODS.compact : CODEX_CONTROL_METHODS.review, kind === "review" ? {
1617
1717
  threadId: binding.threadId,
1618
1718
  target: { type: "uncommittedChanges" }
1619
1719
  } : { threadId: binding.threadId }, {
1620
1720
  agentDir: target.agentDir,
1621
- authProfileId: binding.authProfileId,
1622
- config: ctx.config
1721
+ authProfileId: connection.clientAuthProfileId,
1722
+ config: ctx.config,
1723
+ ...connection.usesSupervisionConnection ? { startOptions: connection.appServer.start } : {}
1623
1724
  });
1624
1725
  return `Started Codex ${label} for thread ${formatCodexDisplayText(binding.threadId)}.`;
1625
1726
  }
@@ -1671,7 +1772,7 @@ function splitArgs(value) {
1671
1772
  function parseBindArgs(args) {
1672
1773
  const parsed = {};
1673
1774
  for (let index = 0; index < args.length; index += 1) {
1674
- const arg = args[index];
1775
+ const arg = expectDefined(args[index], "current Codex bind argument");
1675
1776
  if (arg === "--help" || arg === "-h") {
1676
1777
  parsed.help = true;
1677
1778
  continue;
@@ -1722,7 +1823,7 @@ function parseCodexCliSessionsArgs(args) {
1722
1823
  const parsed = { filter: "" };
1723
1824
  const filter = [];
1724
1825
  for (let index = 0; index < args.length; index += 1) {
1725
- const arg = args[index];
1826
+ const arg = expectDefined(args[index], "current Codex sessions argument");
1726
1827
  if (arg === "--help" || arg === "-h") {
1727
1828
  parsed.help = true;
1728
1829
  continue;
@@ -1760,7 +1861,7 @@ function parseCodexCliSessionsArgs(args) {
1760
1861
  function parseResumeArgs(args) {
1761
1862
  const parsed = {};
1762
1863
  for (let index = 0; index < args.length; index += 1) {
1763
- const arg = args[index];
1864
+ const arg = expectDefined(args[index], "current Codex resume argument");
1764
1865
  if (arg === "--help" || arg === "-h") {
1765
1866
  parsed.help = true;
1766
1867
  continue;
@@ -1798,7 +1899,8 @@ function parseComputerUseArgs(args) {
1798
1899
  const parsed = {
1799
1900
  action: "status",
1800
1901
  overrides: {},
1801
- hasOverrides: false
1902
+ hasOverrides: false,
1903
+ persistentIdentity: {}
1802
1904
  };
1803
1905
  let sawAction = false;
1804
1906
  for (let index = 0; index < args.length; index += 1) {
@@ -1846,23 +1948,14 @@ function parseComputerUseArgs(args) {
1846
1948
  index += 1;
1847
1949
  continue;
1848
1950
  }
1849
- if (arg === "--plugin") {
1850
- const value = readRequiredOptionValue(args, index);
1851
- if (!value || parsed.overrides.pluginName !== void 0) {
1852
- parsed.help = true;
1853
- continue;
1854
- }
1855
- parsed.overrides.pluginName = value;
1856
- index += 1;
1857
- continue;
1858
- }
1859
- if (arg === "--server" || arg === "--mcp-server") {
1951
+ if (arg === "--plugin" || arg === "--server" || arg === "--mcp-server") {
1860
1952
  const value = readRequiredOptionValue(args, index);
1861
- if (!value || parsed.overrides.mcpServerName !== void 0) {
1953
+ const configKey = arg === "--plugin" ? "pluginName" : "mcpServerName";
1954
+ if (!value || parsed.persistentIdentity[configKey] !== void 0) {
1862
1955
  parsed.help = true;
1863
1956
  continue;
1864
1957
  }
1865
- parsed.overrides.mcpServerName = value;
1958
+ parsed.persistentIdentity[configKey] = value.trim();
1866
1959
  index += 1;
1867
1960
  continue;
1868
1961
  }
@@ -1872,6 +1965,17 @@ function parseComputerUseArgs(args) {
1872
1965
  parsed.hasOverrides = Object.values(parsed.overrides).some(Boolean);
1873
1966
  return parsed;
1874
1967
  }
1968
+ function formatComputerUsePersistentIdentityMigration(parsed) {
1969
+ const configPrefix = "plugins.entries.codex.config.computerUse";
1970
+ const settings = [parsed.persistentIdentity.pluginName ? `${configPrefix}.pluginName = ${JSON.stringify(parsed.persistentIdentity.pluginName)}` : void 0, parsed.persistentIdentity.mcpServerName ? `${configPrefix}.mcpServerName = ${JSON.stringify(parsed.persistentIdentity.mcpServerName)}` : void 0].filter((setting) => Boolean(setting));
1971
+ const retryArgs = [
1972
+ `/codex computer-use ${parsed.action}`,
1973
+ parsed.overrides.marketplaceSource ? `--source ${JSON.stringify(parsed.overrides.marketplaceSource)}` : void 0,
1974
+ parsed.overrides.marketplacePath ? `--marketplace-path ${JSON.stringify(parsed.overrides.marketplacePath)}` : void 0,
1975
+ parsed.overrides.marketplaceName ? `--marketplace ${JSON.stringify(parsed.overrides.marketplaceName)}` : void 0
1976
+ ].filter((arg) => Boolean(arg));
1977
+ return ["One-off Computer Use plugin/server overrides are no longer supported.", `Set ${settings.join(" and ")} persistently, then rerun ${retryArgs.join(" ")}.`].join(" ");
1978
+ }
1875
1979
  function readRequiredOptionValue(args, index) {
1876
1980
  const value = args[index + 1];
1877
1981
  const normalized = value?.trim();
@@ -1886,10 +1990,6 @@ function normalizeComputerUseStringOverrides(overrides) {
1886
1990
  if (marketplacePath) normalized.marketplacePath = marketplacePath;
1887
1991
  const marketplaceName = normalizeOptionalString(overrides.marketplaceName);
1888
1992
  if (marketplaceName) normalized.marketplaceName = marketplaceName;
1889
- const pluginName = normalizeOptionalString(overrides.pluginName);
1890
- if (pluginName) normalized.pluginName = pluginName;
1891
- const mcpServerName = normalizeOptionalString(overrides.mcpServerName);
1892
- if (mcpServerName) normalized.mcpServerName = mcpServerName;
1893
1993
  return normalized;
1894
1994
  }
1895
1995
  //#endregion
@@ -1,10 +1,9 @@
1
- import { r as isJsonObject } from "./protocol-2POPqAY4.js";
2
- import { _ as readCodexNotificationItem } from "./attempt-notifications-BGsEIIDI.js";
3
- import { d as resolveCodexAppServerRuntimeOptions } from "./config-CYEDnLJ2.js";
4
- import { a as getLeasedSharedCodexAppServerClient, o as releaseLeasedSharedCodexAppServerClient, u as CodexAppServerRpcError } from "./shared-client-4ICy3U6d.js";
5
- import { s as sessionBindingIdentity, t as CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS } from "./session-binding-C1ZXdP-x.js";
6
- import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-DA2TQfZW.js";
7
- import { n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-Bo7KB3ks.js";
1
+ import { R as CodexAppServerRpcError, Z as isJsonObject, a as getLeasedSharedCodexAppServerClient, c as releaseLeasedSharedCodexAppServerClient } from "./shared-client-JiAnW6pc.js";
2
+ import { _ as readCodexNotificationItem } from "./attempt-notifications-BFmNhqFl.js";
3
+ import { c as sessionBindingIdentity, t as CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS } from "./session-binding-h1mmCGnl.js";
4
+ import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-D1Wky__S.js";
5
+ import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-KmfV4EkP.js";
6
+ import { resolveAgentDir, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
8
7
  import { embeddedAgentLog, resolveCompactionTimeoutMs } from "openclaw/plugin-sdk/agent-harness-runtime";
9
8
  //#region extensions/codex/src/app-server/compact.ts
10
9
  /**
@@ -331,7 +330,6 @@ async function compactCodexNativeThread(params, options) {
331
330
  compacted: false,
332
331
  reason: nativeExecutionBlock
333
332
  };
334
- const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig: options.pluginConfig });
335
333
  const bindingIdentity = sessionBindingIdentity({
336
334
  sessionId: params.sessionId,
337
335
  sessionKey: params.sessionKey,
@@ -345,18 +343,48 @@ async function compactCodexNativeThread(params, options) {
345
343
  });
346
344
  let binding = initialBinding;
347
345
  const requestedAuthProfileId = params.authProfileId?.trim() || void 0;
348
- if (requestedAuthProfileId && binding.authProfileId && binding.authProfileId !== requestedAuthProfileId) return {
346
+ let connection;
347
+ try {
348
+ const config = params.config ?? {};
349
+ const agentId = params.agentId ?? readAgentIdFromSessionKey(params.sessionKey) ?? resolveDefaultAgentId(config);
350
+ connection = resolveCodexBindingAppServerConnection({
351
+ binding,
352
+ authProfileId: requestedAuthProfileId ?? binding.authProfileId,
353
+ pluginConfig: options.pluginConfig,
354
+ config,
355
+ agentDir: resolveAgentDir(config, agentId)
356
+ });
357
+ } catch (error) {
358
+ return {
359
+ ok: false,
360
+ compacted: false,
361
+ reason: formatCompactionError(error)
362
+ };
363
+ }
364
+ const { appServer, usesSupervisionConnection } = connection;
365
+ if (!usesSupervisionConnection && requestedAuthProfileId && binding.authProfileId && binding.authProfileId !== requestedAuthProfileId) return {
349
366
  ok: false,
350
367
  compacted: false,
351
368
  reason: "auth profile mismatch for session binding"
352
369
  };
353
370
  const shouldReleaseDefaultLease = !options.clientFactory;
354
371
  const clientFactory = options.clientFactory ?? getLeasedSharedCodexAppServerClient;
372
+ const runtimeAuthPlan = params.runtimeAuthPlan ?? params.runtimePlan?.auth;
373
+ const usesPreparedApiKey = !usesSupervisionConnection && runtimeAuthPlan?.modelRoute?.authRequirement === "api-key";
374
+ const preparedApiKey = usesPreparedApiKey ? params.resolvedApiKey?.trim() : void 0;
375
+ if (usesPreparedApiKey && !preparedApiKey) return {
376
+ ok: false,
377
+ compacted: false,
378
+ reason: "Prepared Codex Platform compaction route is missing its resolved API key."
379
+ };
355
380
  try {
356
381
  return await runExclusiveCodexNativeCompaction(binding.threadId, params.abortSignal, async () => {
357
382
  const client = await clientFactory({
358
383
  startOptions: appServer.start,
359
- authProfileId: requestedAuthProfileId ?? binding.authProfileId,
384
+ ...preparedApiKey ? { preparedAuth: {
385
+ kind: "api-key",
386
+ apiKey: preparedApiKey
387
+ } } : { authProfileId: connection.clientAuthProfileId },
360
388
  agentDir: params.agentDir,
361
389
  config: params.config
362
390
  });
@@ -375,6 +403,7 @@ async function compactCodexNativeThread(params, options) {
375
403
  if (transportStopped) return;
376
404
  throw new Error("failed to stop unconfirmed codex app-server process");
377
405
  }
406
+ if (usesSupervisionConnection) throw new Error("cannot detach an unconfirmed supervised codex thread");
378
407
  if (await options.bindingStore.mutate(bindingIdentity, {
379
408
  kind: "clear",
380
409
  threadId: binding.threadId