@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,15 +1,28 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
+ import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
1
3
  import path from "node:path";
2
4
  import { resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
3
- import { createHash, createHmac, randomBytes } from "node:crypto";
5
+ import { createHash, createHmac, randomBytes, randomUUID } from "node:crypto";
4
6
  import { readFileSync } from "node:fs";
5
7
  import { homedir, hostname } from "node:os";
6
- import { resolveProviderIdForAuth } from "openclaw/plugin-sdk/agent-runtime";
8
+ import { ensureAuthProfileStore, resolveDefaultAgentDir, resolveProviderIdForAuth, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
7
9
  import { resolveExecApprovalsFromFile } from "openclaw/plugin-sdk/exec-approvals-runtime";
8
10
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
9
11
  import { buildSecretInputSchema, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
10
12
  import { normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
11
13
  import { detectWindowsSpawnCommandInlineArgs } from "openclaw/plugin-sdk/windows-spawn";
14
+ import { parse } from "smol-toml";
12
15
  import { z } from "zod";
16
+ import { embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
17
+ import { AsyncLocalStorage } from "node:async_hooks";
18
+ import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
19
+ //#region extensions/codex/src/app-server/session-discovery-config.ts
20
+ const codexSessionCatalogConfigSchema = z.object({ enabled: z.boolean().optional() }).strict();
21
+ const codexDiscoveryConfigSchema = z.object({
22
+ enabled: z.boolean().optional(),
23
+ timeoutMs: z.number().positive().optional()
24
+ }).strict();
25
+ //#endregion
13
26
  //#region extensions/codex/src/app-server/config.ts
14
27
  const START_OPTIONS_KEY_SECRET_SYMBOL = Symbol.for("openclaw.codexAppServerStartOptionsKeySecret");
15
28
  const START_OPTIONS_KEY_SECRET = getStartOptionsKeySecret();
@@ -19,14 +32,22 @@ const CODEX_APP_SERVER_HOME_DIRNAME = "codex-home";
19
32
  const CODEX_CONFIG_TOML_FILENAME = "config.toml";
20
33
  const PLAIN_DECIMAL_NUMBER_RE = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))$/;
21
34
  const CODEX_PLUGINS_MARKETPLACE_NAME = "openai-curated";
35
+ const CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME = "workspace-directory";
22
36
  function shouldAutoApproveCodexAppServerApprovals(appServer) {
23
37
  return appServer.networkProxy === void 0 && appServer.approvalPolicy === "never" && appServer.sandbox === "danger-full-access";
24
38
  }
25
39
  const DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME = "computer-use";
26
40
  const DEFAULT_CODEX_COMPUTER_USE_MCP_SERVER_NAME = "computer-use";
27
41
  const DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS = 6e4;
42
+ const DEFAULT_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS = 6e4;
43
+ const DEFAULT_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS = 6e4;
44
+ const DEFAULT_CODEX_COMPUTER_USE_HEALTH_CHECK_INTERVAL_MINUTES = 60;
28
45
  const DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX = "openclaw-network";
29
- const codexAppServerTransportSchema = z.enum(["stdio", "websocket"]);
46
+ const codexAppServerTransportSchema = z.enum([
47
+ "stdio",
48
+ "websocket",
49
+ "unix"
50
+ ]);
30
51
  const codexAppServerHomeScopeSchema = z.enum(["agent", "user"]);
31
52
  const SecretInputSchema = buildSecretInputSchema();
32
53
  const codexAppServerPolicyModeSchema = z.enum(["yolo", "guardian"]);
@@ -46,6 +67,13 @@ const codexAppServerApprovalsReviewerSchema = z.enum([
46
67
  "guardian_subagent"
47
68
  ]);
48
69
  const codexDynamicToolsLoadingSchema = z.enum(["searchable", "direct"]);
70
+ const codexComputerUseHealthIntervalSchema = z.union([
71
+ z.literal(30),
72
+ z.literal(60),
73
+ z.literal(120),
74
+ z.literal(240)
75
+ ]);
76
+ const codexComputerUsePluginCacheModeSchema = z.enum(["shared", "independent"]);
49
77
  const codexPluginDestructivePolicySchema = z.union([
50
78
  z.boolean(),
51
79
  z.literal("auto"),
@@ -74,7 +102,7 @@ const codexAppServerNetworkProxySchema = z.object({
74
102
  }).strict();
75
103
  const codexPluginEntryConfigSchema = z.object({
76
104
  enabled: z.boolean().optional(),
77
- marketplaceName: z.literal(CODEX_PLUGINS_MARKETPLACE_NAME).optional(),
105
+ marketplaceName: z.enum([CODEX_PLUGINS_MARKETPLACE_NAME, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME]).optional(),
78
106
  pluginName: z.string().trim().min(1).optional(),
79
107
  allow_destructive_actions: codexPluginDestructivePolicySchema.optional()
80
108
  }).strict();
@@ -84,17 +112,42 @@ const codexPluginsConfigSchema = z.object({
84
112
  allow_destructive_actions: codexPluginDestructivePolicySchema.optional(),
85
113
  plugins: z.record(z.string(), codexPluginEntryConfigSchema).optional()
86
114
  }).strict();
115
+ const codexSupervisionEndpointSchema = z.union([z.object({
116
+ id: z.string().optional(),
117
+ label: z.string().optional(),
118
+ transport: z.literal("stdio-proxy").optional(),
119
+ command: z.string().optional(),
120
+ args: z.array(z.string()).optional(),
121
+ cwd: z.string().optional()
122
+ }).strict(), z.object({
123
+ id: z.string().optional(),
124
+ label: z.string().optional(),
125
+ transport: z.literal("websocket"),
126
+ url: z.string(),
127
+ authTokenEnv: z.string().optional()
128
+ }).strict()]);
129
+ const codexSupervisionConfigSchema = z.object({
130
+ enabled: z.boolean().optional(),
131
+ endpoints: z.array(codexSupervisionEndpointSchema).optional(),
132
+ allowRawTranscripts: z.boolean().optional(),
133
+ allowWriteControls: z.boolean().optional()
134
+ }).strict();
87
135
  const codexPluginConfigSchema = z.object({
88
136
  codexDynamicToolsLoading: codexDynamicToolsLoadingSchema.optional(),
89
137
  codexDynamicToolsExclude: z.array(z.string()).optional(),
90
- discovery: z.object({
91
- enabled: z.boolean().optional(),
92
- timeoutMs: z.number().positive().optional()
93
- }).strict().optional(),
138
+ sessionCatalog: codexSessionCatalogConfigSchema.optional(),
139
+ discovery: codexDiscoveryConfigSchema.optional(),
94
140
  computerUse: z.object({
95
141
  enabled: z.boolean().optional(),
96
142
  autoInstall: z.boolean().optional(),
97
143
  marketplaceDiscoveryTimeoutMs: z.number().positive().optional(),
144
+ liveTestTimeoutMs: z.number().positive().optional(),
145
+ toolCallTimeoutMs: z.number().positive().optional(),
146
+ healthCheckEnabled: z.boolean().optional(),
147
+ healthCheckIntervalMinutes: codexComputerUseHealthIntervalSchema.optional(),
148
+ pluginCacheMode: codexComputerUsePluginCacheModeSchema.optional(),
149
+ strictReadiness: z.boolean().optional(),
150
+ autoRepair: z.boolean().optional(),
98
151
  marketplaceSource: z.string().optional(),
99
152
  marketplacePath: z.string().optional(),
100
153
  marketplaceName: z.string().optional(),
@@ -102,6 +155,7 @@ const codexPluginConfigSchema = z.object({
102
155
  mcpServerName: z.string().optional()
103
156
  }).strict().optional(),
104
157
  codexPlugins: z.unknown().optional(),
158
+ supervision: codexSupervisionConfigSchema.optional(),
105
159
  appServer: z.object({
106
160
  mode: codexAppServerPolicyModeSchema.optional(),
107
161
  transport: codexAppServerTransportSchema.optional(),
@@ -114,6 +168,7 @@ const codexPluginConfigSchema = z.object({
114
168
  clearEnv: z.array(z.string()).optional(),
115
169
  remoteWorkspaceRoot: codexAppServerRemoteWorkspaceRootSchema.optional(),
116
170
  codeModeOnly: z.boolean().optional(),
171
+ loopDetectionPreToolUseRelay: z.boolean().optional(),
117
172
  requestTimeoutMs: z.number().positive().optional(),
118
173
  turnCompletionIdleTimeoutMs: z.number().positive().optional(),
119
174
  postToolRawAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
@@ -153,11 +208,11 @@ function resolveCodexPluginsPolicy(pluginConfig) {
153
208
  const enabled = config?.enabled === true;
154
209
  const destructivePolicy = resolveCodexPluginDestructivePolicy(config?.allow_destructive_actions ?? true);
155
210
  const pluginPolicies = Object.entries(config?.plugins ?? {}).flatMap(([configKey, entry]) => {
156
- if (entry.marketplaceName !== "openai-curated" || !entry.pluginName) return [];
211
+ if (!isCodexPluginMarketplaceName(entry.marketplaceName) || !entry.pluginName) return [];
157
212
  const entryDestructivePolicy = resolveCodexPluginDestructivePolicy(entry.allow_destructive_actions ?? config?.allow_destructive_actions ?? true);
158
213
  return [{
159
214
  configKey,
160
- marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
215
+ marketplaceName: entry.marketplaceName,
161
216
  pluginName: entry.pluginName,
162
217
  enabled: enabled && entry.enabled !== false,
163
218
  allowDestructiveActions: entryDestructivePolicy.allowDestructiveActions,
@@ -173,6 +228,9 @@ function resolveCodexPluginsPolicy(pluginConfig) {
173
228
  pluginPolicies
174
229
  };
175
230
  }
231
+ function isCodexPluginMarketplaceName(value) {
232
+ return value === "openai-curated" || value === "workspace-directory";
233
+ }
176
234
  function resolveCodexPluginDestructivePolicy(policy) {
177
235
  if (policy === "auto" || policy === "ask") return {
178
236
  allowDestructiveActions: true,
@@ -187,7 +245,7 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
187
245
  const env = params.env ?? process.env;
188
246
  const config = readCodexPluginConfig(params.pluginConfig).appServer ?? {};
189
247
  const transport = resolveTransport(config.transport);
190
- const homeScope = config.homeScope === "user" ? "user" : "agent";
248
+ const homeScope = config.homeScope ?? "agent";
191
249
  const configCommand = readNonEmptyString(config.command);
192
250
  const envCommand = readNonEmptyString(env.OPENCLAW_CODEX_APP_SERVER_BIN);
193
251
  const command = configCommand ?? envCommand ?? "codex";
@@ -203,7 +261,7 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
203
261
  value: config.authToken,
204
262
  path: "plugins.entries.codex.config.appServer.authToken"
205
263
  });
206
- const url = readNonEmptyString(config.url);
264
+ const url = readNonEmptyString(config.url) ?? (transport === "unix" ? "unix://" : void 0);
207
265
  const connectionClass = inferCodexAppServerConnectionClass({
208
266
  transport,
209
267
  url
@@ -264,9 +322,12 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
264
322
  const serviceTier = normalizeCodexServiceTier(config.serviceTier);
265
323
  const resolvedSandbox = forcedPolicy?.sandbox ?? configuredSandbox ?? defaultPolicy?.sandbox ?? (policyMode === "guardian" ? "workspace-write" : "danger-full-access");
266
324
  if (transport === "websocket" && !url) throw new Error("plugins.entries.codex.config.appServer.url is required when appServer.transport is websocket");
267
- if (transport === "websocket" && homeScope === "user") throw new Error("plugins.entries.codex.config.appServer.homeScope=user requires appServer.transport=stdio");
268
- assertCodexAppServerConnectionClassConfig({
269
- connectionClass,
325
+ if (transport === "websocket" && homeScope === "user") throw new Error("plugins.entries.codex.config.appServer.homeScope=user requires appServer.transport=stdio or unix");
326
+ if (transport === "unix" && homeScope !== "user") throw new Error("plugins.entries.codex.config.appServer.transport=unix requires appServer.homeScope=user");
327
+ if (transport === "unix" && !url?.startsWith("unix://")) throw new Error("plugins.entries.codex.config.appServer.url must use unix:// when appServer.transport is unix");
328
+ assertCodexAppServerConnectionSecurity({
329
+ transport,
330
+ url,
270
331
  authToken,
271
332
  headers
272
333
  });
@@ -274,12 +335,21 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
274
335
  const envApprovalPolicy = resolveApprovalPolicy(env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY);
275
336
  const approvalPolicy = configApprovalPolicy ?? envApprovalPolicy ?? defaultPolicy?.approvalPolicy ?? (policyMode === "guardian" ? "on-request" : "never");
276
337
  const approvalPolicySource = configApprovalPolicy ? "config" : envApprovalPolicy ? "env" : defaultPolicy?.approvalPolicy ? "requirements" : "implicit";
338
+ const computerUseConfig = resolveCodexComputerUseConfig({
339
+ pluginConfig: params.pluginConfig,
340
+ env
341
+ });
342
+ const managedCommandOrder = params.managedCommandOrder ?? (homeScope === "user" || computerUseConfig.enabled ? "desktop-first" : "package-first");
343
+ const includeManagedCommandOrder = commandSource === "managed" && (managedCommandOrder === "desktop-first" || params.managedCommandOrder === "package-first");
344
+ const managedComputerUsePluginNames = [.../* @__PURE__ */ new Set([DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME, computerUseConfig.pluginName])];
277
345
  return {
278
346
  start: {
279
347
  transport,
280
348
  homeScope,
281
349
  command,
282
350
  commandSource,
351
+ ...includeManagedCommandOrder ? { managedCommandOrder } : {},
352
+ ...commandSource === "managed" ? { managedComputerUsePluginNames } : {},
283
353
  args: args.length > 0 ? args : [
284
354
  "app-server",
285
355
  "--listen",
@@ -294,6 +364,7 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
294
364
  remoteAppsSubstrate,
295
365
  ...remoteWorkspaceRoot ? { remoteWorkspaceRoot } : {},
296
366
  codeModeOnly: config.codeModeOnly === true,
367
+ loopDetectionPreToolUseRelay: config.loopDetectionPreToolUseRelay !== false,
297
368
  requestTimeoutMs: normalizePositiveNumber(config.requestTimeoutMs, 6e4),
298
369
  turnCompletionIdleTimeoutMs: normalizePositiveNumber(config.turnCompletionIdleTimeoutMs, 6e4),
299
370
  ...config.postToolRawAssistantCompletionIdleTimeoutMs !== void 0 ? { postToolRawAssistantCompletionIdleTimeoutMs: normalizePositiveNumber(config.postToolRawAssistantCompletionIdleTimeoutMs, 6e4) } : {},
@@ -305,6 +376,28 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
305
376
  ...resolveCodexAppServerNetworkProxy(config.networkProxy, resolvedSandbox)
306
377
  };
307
378
  }
379
+ /**
380
+ * Rechecks Codex-owned plugin state at the final spawn boundary, where the
381
+ * effective agent home is known, so Computer Use keeps the desktop app's TCC ownership.
382
+ */
383
+ function resolveCodexAppServerStartOptionsForAgent(params) {
384
+ const startOptions = params.startOptions;
385
+ if (startOptions.transport !== "stdio" || startOptions.commandSource !== "managed" || startOptions.managedCommandOrder !== void 0) return startOptions;
386
+ if (startOptions.homeScope === "user") return {
387
+ ...startOptions,
388
+ managedCommandOrder: "desktop-first"
389
+ };
390
+ return codexConfigEnablesNativeComputerUse({
391
+ agentDir: params.agentDir,
392
+ codexConfigToml: params.codexConfigToml,
393
+ env: params.env,
394
+ homeScope: "agent",
395
+ pluginNames: startOptions.managedComputerUsePluginNames ?? [DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME]
396
+ }) ? {
397
+ ...startOptions,
398
+ managedCommandOrder: "desktop-first"
399
+ } : startOptions;
400
+ }
308
401
  function isCodexAppServerApprovalPolicyAllowedByRequirements(policy, params = {}) {
309
402
  const content = readCodexRequirementsToml(params);
310
403
  if (content === void 0) return true;
@@ -359,32 +452,58 @@ function resolveCodexComputerUseConfig(params = {}) {
359
452
  const marketplaceSource = readNonEmptyString(params.overrides?.marketplaceSource) ?? readNonEmptyString(config.marketplaceSource) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_SOURCE);
360
453
  const marketplacePath = readNonEmptyString(params.overrides?.marketplacePath) ?? readNonEmptyString(config.marketplacePath) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_PATH);
361
454
  const marketplaceName = readNonEmptyString(params.overrides?.marketplaceName) ?? readNonEmptyString(config.marketplaceName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_NAME);
455
+ const configuredPluginName = readNonEmptyString(params.overrides?.pluginName) ?? readNonEmptyString(config.pluginName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_NAME);
456
+ const configuredMcpServerName = readNonEmptyString(params.overrides?.mcpServerName) ?? readNonEmptyString(config.mcpServerName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MCP_SERVER_NAME);
362
457
  const autoInstall = params.overrides?.autoInstall ?? config.autoInstall ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_AUTO_INSTALL) ?? false;
363
458
  const marketplaceDiscoveryTimeoutMs = normalizePositiveNumber(params.overrides?.marketplaceDiscoveryTimeoutMs ?? config.marketplaceDiscoveryTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS);
459
+ const liveTestTimeoutMs = normalizePositiveNumber(params.overrides?.liveTestTimeoutMs ?? config.liveTestTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS);
460
+ const toolCallTimeoutMs = normalizePositiveNumber(params.overrides?.toolCallTimeoutMs ?? config.toolCallTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS);
461
+ const healthCheckIntervalMinutes = normalizeComputerUseHealthCheckIntervalMinutes(params.overrides?.healthCheckIntervalMinutes ?? config.healthCheckIntervalMinutes ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_HEALTH_CHECK_INTERVAL_MINUTES));
462
+ const healthCheckEnabled = params.overrides?.healthCheckEnabled ?? config.healthCheckEnabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_HEALTH_CHECK_ENABLED) ?? false;
463
+ const pluginCacheMode = normalizeComputerUsePluginCacheMode(params.overrides?.pluginCacheMode) ?? normalizeComputerUsePluginCacheMode(config.pluginCacheMode) ?? normalizeComputerUsePluginCacheMode(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_CACHE_MODE) ?? "independent";
464
+ const strictReadiness = params.overrides?.strictReadiness ?? config.strictReadiness ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_STRICT_READINESS) ?? false;
465
+ const autoRepair = params.overrides?.autoRepair ?? config.autoRepair ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_AUTO_REPAIR) ?? false;
364
466
  return {
365
- enabled: params.overrides?.enabled ?? config.enabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE) ?? Boolean(autoInstall || marketplaceSource || marketplacePath || marketplaceName),
467
+ enabled: params.overrides?.enabled ?? config.enabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE) ?? Boolean(autoInstall || marketplaceSource || marketplacePath || marketplaceName || configuredPluginName || configuredMcpServerName),
366
468
  autoInstall,
367
469
  marketplaceDiscoveryTimeoutMs,
368
- pluginName: readNonEmptyString(params.overrides?.pluginName) ?? readNonEmptyString(config.pluginName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_NAME) ?? DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME,
369
- mcpServerName: readNonEmptyString(params.overrides?.mcpServerName) ?? readNonEmptyString(config.mcpServerName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MCP_SERVER_NAME) ?? DEFAULT_CODEX_COMPUTER_USE_MCP_SERVER_NAME,
470
+ liveTestTimeoutMs,
471
+ toolCallTimeoutMs,
472
+ healthCheckEnabled,
473
+ healthCheckIntervalMinutes,
474
+ pluginCacheMode,
475
+ strictReadiness,
476
+ autoRepair,
477
+ pluginName: configuredPluginName ?? DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME,
478
+ mcpServerName: configuredMcpServerName ?? DEFAULT_CODEX_COMPUTER_USE_MCP_SERVER_NAME,
370
479
  ...marketplaceSource ? { marketplaceSource } : {},
371
480
  ...marketplacePath ? { marketplacePath } : {},
372
481
  ...marketplaceName ? { marketplaceName } : {}
373
482
  };
374
483
  }
484
+ function normalizeComputerUseHealthCheckIntervalMinutes(value) {
485
+ return value === 30 || value === 60 || value === 120 || value === 240 ? value : DEFAULT_CODEX_COMPUTER_USE_HEALTH_CHECK_INTERVAL_MINUTES;
486
+ }
487
+ function normalizeComputerUsePluginCacheMode(value) {
488
+ return value === "shared" || value === "independent" ? value : null;
489
+ }
375
490
  function codexAppServerStartOptionsKey(options, params = {}) {
376
491
  return JSON.stringify({
377
492
  transport: options.transport,
378
493
  command: options.command,
379
494
  commandSource: options.commandSource ?? null,
495
+ managedCommandOrder: options.managedCommandOrder ?? "package-first",
496
+ managedComputerUsePluginNames: [...options.managedComputerUsePluginNames ?? []].toSorted(),
380
497
  managedFallbackCommandPaths: [...options.managedFallbackCommandPaths ?? []],
381
498
  args: options.args,
499
+ cwd: options.cwd ?? null,
382
500
  url: options.url ?? null,
383
501
  authToken: hashSecretForKey(options.authToken, "authToken"),
384
502
  headers: Object.entries(options.headers).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `header:${key}`)]),
385
503
  env: Object.entries(options.env ?? {}).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `env:${key}`)]),
386
504
  clearEnv: [...options.clearEnv ?? []].toSorted(),
387
505
  authProfileId: params.authProfileId ?? null,
506
+ authBindingFingerprint: params.authBindingFingerprint ?? null,
388
507
  agentDir: params.agentDir ?? null,
389
508
  fallbackApiKeyCacheKey: params.fallbackApiKeyCacheKey ?? null
390
509
  });
@@ -403,6 +522,23 @@ function codexSandboxPolicyForTurn(mode, cwd) {
403
522
  excludeSlashTmp: false
404
523
  };
405
524
  }
525
+ /** Resolves the passive supervision control connection without changing harness defaults. */
526
+ function resolveCodexSupervisionAppServerRuntimeOptions(params = {}) {
527
+ const pluginConfig = readCodexPluginConfig(params.pluginConfig);
528
+ const appServer = pluginConfig.appServer ?? {};
529
+ const transport = resolveTransport(appServer.transport);
530
+ const homeScope = appServer.homeScope ?? (transport === "websocket" ? "agent" : "user");
531
+ return resolveCodexAppServerRuntimeOptions({
532
+ ...params,
533
+ pluginConfig: {
534
+ ...pluginConfig,
535
+ appServer: {
536
+ ...appServer,
537
+ homeScope
538
+ }
539
+ }
540
+ });
541
+ }
406
542
  function resolveCodexAppServerNetworkProxy(config, sandbox) {
407
543
  if (config?.enabled !== true) return {};
408
544
  const fileSystemMode = config.baseProfile === "read-only" || !config.baseProfile && sandbox === "read-only" ? "read" : "write";
@@ -484,7 +620,7 @@ function withMcpElicitationsApprovalPolicy(policy) {
484
620
  } };
485
621
  }
486
622
  function resolveTransport(value) {
487
- return value === "websocket" ? "websocket" : "stdio";
623
+ return value === "websocket" || value === "unix" ? value : "stdio";
488
624
  }
489
625
  function normalizeRemoteWorkspaceRoot(value) {
490
626
  return readNonEmptyString(value);
@@ -499,6 +635,14 @@ function assertCodexAppServerConnectionClassConfig(params) {
499
635
  headers: params.headers
500
636
  })) throw new Error("remote Codex app-server WebSocket URLs require appServer.authToken or an Authorization header");
501
637
  }
638
+ /** Applies the canonical remote-auth boundary to any Codex AppServer transport. */
639
+ function assertCodexAppServerConnectionSecurity(params) {
640
+ assertCodexAppServerConnectionClassConfig({
641
+ connectionClass: inferCodexAppServerConnectionClass(params),
642
+ authToken: params.authToken,
643
+ headers: params.headers
644
+ });
645
+ }
502
646
  function isLoopbackWebSocketUrl(value) {
503
647
  let parsed;
504
648
  try {
@@ -603,12 +747,18 @@ function parseTopLevelRequirementsStringArray(content, key) {
603
747
  return parseRequirementsStringArray(stripTomlLineComments(content).slice(0, firstTomlTableOffset(content)), key);
604
748
  }
605
749
  function parseTomlStringValue(content, key) {
606
- const match = parseTomlStringAssignment(content, tomlDottedKeyPattern(key));
607
- return match ? match[1] ?? match[2] ?? "" : void 0;
750
+ return parseTomlStringAssignmentValue(content, tomlDottedKeyPattern(key));
608
751
  }
609
752
  function parseInlineOpenAIModelProviderBaseUrl(content) {
610
- const match = parseTomlStringAssignment(content, `${tomlKeyPattern("model_providers")}\\s*=\\s*\\{[\\s\\S]*?${tomlKeyPattern("openai")}\\s*=\\s*\\{[\\s\\S]*?${tomlKeyPattern("base_url")}`);
611
- return match ? match[1] ?? match[2] ?? "" : void 0;
753
+ return parseTomlStringAssignmentValue(content, `${tomlKeyPattern("model_providers")}\\s*=\\s*\\{[\\s\\S]*?${tomlKeyPattern("openai")}\\s*=\\s*\\{[\\s\\S]*?${tomlKeyPattern("base_url")}`);
754
+ }
755
+ function parseTomlStringAssignmentValue(content, keyPattern) {
756
+ const assignment = content.match(new RegExp(`(?:^|\\n)\\s*${keyPattern}\\s*=\\s*([^\\r\\n]*)`));
757
+ if (!assignment) return;
758
+ const rawValue = assignment[1]?.trimStart() ?? "";
759
+ if (rawValue.startsWith("\"\"\"") || rawValue.startsWith("'''")) return false;
760
+ const match = parseTomlStringAssignment(content, keyPattern);
761
+ return match ? match[1] ?? match[2] ?? "" : false;
612
762
  }
613
763
  function parseTomlStringAssignment(content, keyPattern) {
614
764
  return content.match(new RegExp(`(?:^|\\n)\\s*${keyPattern}\\s*=\\s*(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|'([^']*)')`));
@@ -759,14 +909,19 @@ function readCodexBaseUrlOverridesForModelBackedReview(params) {
759
909
  };
760
910
  const topLevelContent = stripTomlLineComments(configToml).slice(0, firstTomlTableOffset(configToml));
761
911
  const modelProviderOpenAISection = parseTomlTableSection(configToml, "model_providers.openai");
912
+ const openAIBaseUrl = parseTomlStringValue(topLevelContent, "openai_base_url");
913
+ const chatGPTBaseUrl = parseTomlStringValue(topLevelContent, "chatgpt_base_url");
914
+ const openAI = [
915
+ openAIBaseUrl,
916
+ parseTomlStringValue(topLevelContent, "model_providers.openai.base_url"),
917
+ parseInlineOpenAIModelProviderBaseUrl(topLevelContent),
918
+ modelProviderOpenAISection ? parseTomlStringValue(modelProviderOpenAISection, "base_url") : void 0
919
+ ];
920
+ const chatGPT = [chatGPTBaseUrl];
921
+ if ([...openAI, ...chatGPT].includes(false)) return false;
762
922
  return {
763
- openAI: [
764
- parseTomlStringValue(topLevelContent, "openai_base_url"),
765
- parseTomlStringValue(topLevelContent, "model_providers.openai.base_url"),
766
- parseInlineOpenAIModelProviderBaseUrl(topLevelContent),
767
- modelProviderOpenAISection ? parseTomlStringValue(modelProviderOpenAISection, "base_url") : void 0
768
- ].filter((entry) => entry !== void 0),
769
- chatGPT: [parseTomlStringValue(topLevelContent, "chatgpt_base_url")].filter((entry) => entry !== void 0)
923
+ openAI: openAI.filter((entry) => typeof entry === "string"),
924
+ chatGPT: chatGPT.filter((entry) => typeof entry === "string")
770
925
  };
771
926
  }
772
927
  function readCodexAppServerConfigToml(params) {
@@ -779,6 +934,29 @@ function readCodexAppServerConfigToml(params) {
779
934
  return readErrorCode(error) === "ENOENT" ? void 0 : false;
780
935
  }
781
936
  }
937
+ function codexConfigEnablesNativeComputerUse(params) {
938
+ const configToml = readCodexAppServerConfigToml(params);
939
+ if (configToml === false) return true;
940
+ if (configToml === void 0) return false;
941
+ let parsedConfig;
942
+ try {
943
+ parsedConfig = parse(configToml, { integersAsBigInt: true });
944
+ } catch {
945
+ return true;
946
+ }
947
+ const rawPlugins = parsedConfig.plugins;
948
+ if (rawPlugins === void 0) return false;
949
+ const plugins = readRecord(rawPlugins);
950
+ if (!plugins) return true;
951
+ for (const [pluginId, rawPluginConfig] of Object.entries(plugins)) {
952
+ if (!params.pluginNames.some((pluginName) => pluginId === pluginName || pluginId.startsWith(`${pluginName}@`))) continue;
953
+ const pluginConfig = readRecord(rawPluginConfig);
954
+ if (!pluginConfig) return true;
955
+ if (pluginConfig.enabled === false) continue;
956
+ return true;
957
+ }
958
+ return false;
959
+ }
782
960
  function resolveCodexAppServerConfigPath(params) {
783
961
  if (params.homeScope === "user") return path.join(resolveCodexAppServerUserHomeDir(params.env), CODEX_CONFIG_TOML_FILENAME);
784
962
  const agentDir = readNonEmptyString(params.agentDir);
@@ -1135,4 +1313,780 @@ function splitShellWords(value) {
1135
1313
  return words;
1136
1314
  }
1137
1315
  //#endregion
1138
- export { shouldAutoApproveCodexAppServerApprovals as _, isCodexAppServerApprovalPolicyAllowedByRequirements as a, isTrustedCodexModelBackedOpenAIProvider as c, resolveCodexAppServerRuntimeOptions as d, resolveCodexAppServerUserHomeDir as f, resolveOpenClawExecPolicyForCodexAppServer as g, resolveCodexPluginsPolicy as h, codexSandboxPolicyForTurn as i, normalizeCodexServiceTier as l, resolveCodexModelBackedReviewerPolicyContext as m, canUseCodexModelBackedApprovalsReviewerForModel as n, isCodexFastServiceTier as o, resolveCodexComputerUseConfig as p, codexAppServerStartOptionsKey as r, isCodexSandboxExecServerEnabled as s, CODEX_PLUGINS_MARKETPLACE_NAME as t, readCodexPluginConfig as u, withMcpElicitationsApprovalPolicy as v };
1316
+ //#region extensions/codex/src/app-server/session-binding.ts
1317
+ /** SQLite-backed Codex app-server thread bindings. */
1318
+ var session_binding_exports = /* @__PURE__ */ __exportAll({
1319
+ CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS: () => CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS,
1320
+ CODEX_APP_SERVER_BINDING_MAX_ENTRIES: () => CODEX_APP_SERVER_BINDING_MAX_ENTRIES,
1321
+ CODEX_APP_SERVER_BINDING_NAMESPACE: () => CODEX_APP_SERVER_BINDING_NAMESPACE,
1322
+ CodexSupervisionBindingReplacementError: () => CodexSupervisionBindingReplacementError,
1323
+ assertCodexBindingMayBeReplaced: () => assertCodexBindingMayBeReplaced,
1324
+ bindingStoreKey: () => bindingStoreKey,
1325
+ createCodexAppServerBindingStore: () => createCodexAppServerBindingStore,
1326
+ createStoredCodexAppServerBinding: () => createStoredCodexAppServerBinding,
1327
+ hashCodexAppServerBindingFingerprint: () => hashCodexAppServerBindingFingerprint,
1328
+ isCodexAppServerNativeAuthProfile: () => isCodexAppServerNativeAuthProfile,
1329
+ normalizeCodexAppServerBindingModelProvider: () => normalizeCodexAppServerBindingModelProvider,
1330
+ normalizeStoredCodexAppServerBindingFingerprints: () => normalizeStoredCodexAppServerBindingFingerprints,
1331
+ readCodexAppServerThreadBinding: () => readCodexAppServerThreadBinding,
1332
+ readStoredCodexAppServerBinding: () => readStoredCodexAppServerBinding,
1333
+ reclaimCurrentCodexSessionGeneration: () => reclaimCurrentCodexSessionGeneration,
1334
+ resolveCodexAppServerBindingModelProvider: () => resolveCodexAppServerBindingModelProvider,
1335
+ sessionBindingIdentity: () => sessionBindingIdentity
1336
+ });
1337
+ const CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER = "openai";
1338
+ const PUBLIC_OPENAI_MODEL_PROVIDER = "openai";
1339
+ const BINDING_LEASE_RETRY_INTERVAL_MS = 1e3;
1340
+ const BOUNDED_BINDING_FINGERPRINT_PATTERN = /^sha256:[a-f0-9]{64}$/i;
1341
+ const CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS = 6e4;
1342
+ const BINDING_LEASE_STALE_MS = 65e3;
1343
+ const BINDING_LEASE_WAIT_MS = 7e4;
1344
+ const BINDING_LEASE_RENEW_INTERVAL_MS = Math.floor(BINDING_LEASE_STALE_MS / 3);
1345
+ const PHYSICAL_SESSION_RETIRE_TTL_MS = BINDING_LEASE_WAIT_MS;
1346
+ /** Resolves the same agent scope OpenClaw uses for transcript/session ownership. */
1347
+ function sessionBindingIdentity(params) {
1348
+ const { sessionAgentId } = resolveSessionAgentIds(params);
1349
+ const sessionKey = params.sessionKey?.trim();
1350
+ return {
1351
+ kind: "session",
1352
+ agentId: sessionAgentId,
1353
+ sessionId: params.sessionId,
1354
+ ...sessionKey ? { sessionKey } : {}
1355
+ };
1356
+ }
1357
+ const optionalStringSchema = z.string().optional().catch(void 0);
1358
+ const optionalBooleanSchema = z.boolean().optional().catch(void 0);
1359
+ const optionalNonBlankStringSchema = z.string().refine((value) => Boolean(value.trim())).optional().catch(void 0);
1360
+ const optionalTimestampSchema = z.string().refine((value) => Number.isFinite(Date.parse(value))).optional().catch(void 0);
1361
+ const pendingSupervisionBranchSchema = z.object({
1362
+ sourceThreadId: z.string().trim().min(1),
1363
+ connectionFingerprint: z.string().trim().min(1).optional(),
1364
+ lastTurnId: z.string().trim().min(1).optional(),
1365
+ cleanupThreadIds: z.array(z.string().trim().min(1)).max(2).optional()
1366
+ }).strict().superRefine((pending, context) => {
1367
+ const cleanupThreadIds = pending.cleanupThreadIds ?? [];
1368
+ if (new Set(cleanupThreadIds).size !== cleanupThreadIds.length) context.addIssue({
1369
+ code: "custom",
1370
+ message: "pending supervision cleanup thread ids must be unique"
1371
+ });
1372
+ if (cleanupThreadIds.includes(pending.sourceThreadId)) context.addIssue({
1373
+ code: "custom",
1374
+ message: "pending supervision cleanup cannot target its source"
1375
+ });
1376
+ });
1377
+ const contextEngineProjectionSchema = z.object({
1378
+ schemaVersion: z.literal(1),
1379
+ mode: z.literal("thread_bootstrap"),
1380
+ epoch: z.string().refine((value) => Boolean(value.trim())),
1381
+ fingerprint: optionalStringSchema
1382
+ }).strict();
1383
+ const contextEngineSchema = z.object({
1384
+ schemaVersion: z.literal(1),
1385
+ engineId: z.string(),
1386
+ policyFingerprint: z.string(),
1387
+ projection: contextEngineProjectionSchema.optional().catch(void 0)
1388
+ }).strict();
1389
+ const destructiveApprovalModeSchema = z.enum([
1390
+ "allow",
1391
+ "deny",
1392
+ "auto",
1393
+ "ask"
1394
+ ]).optional().catch(void 0);
1395
+ const accountAppPolicyEntrySchema = z.object({
1396
+ source: z.literal("account"),
1397
+ appName: z.string(),
1398
+ allowDestructiveActions: z.boolean(),
1399
+ destructiveApprovalMode: destructiveApprovalModeSchema,
1400
+ mcpServerNames: z.array(z.string())
1401
+ }).strict();
1402
+ const pluginAppPolicyEntrySchema = z.object({
1403
+ source: z.literal("plugin").optional(),
1404
+ configKey: z.string(),
1405
+ marketplaceName: z.enum([CODEX_PLUGINS_MARKETPLACE_NAME, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME]),
1406
+ pluginName: z.string(),
1407
+ allowDestructiveActions: z.boolean(),
1408
+ destructiveApprovalMode: destructiveApprovalModeSchema,
1409
+ mcpServerNames: z.array(z.string())
1410
+ }).strict();
1411
+ const pluginAppPolicyContextSchema = z.object({
1412
+ fingerprint: z.string(),
1413
+ apps: z.record(z.string(), z.union([accountAppPolicyEntrySchema, pluginAppPolicyEntrySchema])),
1414
+ pluginAppIds: z.record(z.string(), z.array(z.string())).default({})
1415
+ }).strict();
1416
+ const threadBindingSchema = z.object({
1417
+ threadId: z.string().refine((value) => Boolean(value.trim())),
1418
+ clientId: optionalStringSchema,
1419
+ cwd: z.string(),
1420
+ connectionScope: z.literal("supervision").optional(),
1421
+ supervisionSourceThreadId: z.string().trim().min(1).optional(),
1422
+ authProfileId: optionalStringSchema,
1423
+ model: optionalStringSchema,
1424
+ preserveNativeModel: z.literal(true).optional().catch(void 0),
1425
+ pendingSupervisionBranch: pendingSupervisionBranchSchema.optional(),
1426
+ modelProvider: z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0),
1427
+ approvalPolicy: z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
1428
+ "never",
1429
+ "on-request",
1430
+ "untrusted"
1431
+ ]).optional()).catch(void 0),
1432
+ sandbox: z.enum([
1433
+ "read-only",
1434
+ "workspace-write",
1435
+ "danger-full-access"
1436
+ ]).optional().catch(void 0),
1437
+ serviceTier: z.preprocess(normalizeCodexServiceTier, z.custom((value) => typeof value === "string").optional()).optional().catch(void 0),
1438
+ networkProxyProfileName: optionalStringSchema,
1439
+ networkProxyConfigFingerprint: optionalStringSchema,
1440
+ dynamicToolsFingerprint: optionalStringSchema,
1441
+ dynamicToolsContainDeferred: optionalBooleanSchema,
1442
+ webSearchThreadConfigFingerprint: optionalStringSchema,
1443
+ userMcpServersFingerprint: optionalStringSchema,
1444
+ mcpServersFingerprint: optionalStringSchema,
1445
+ ringZeroConfigFingerprint: optionalStringSchema,
1446
+ ringZeroClientInstanceId: optionalStringSchema,
1447
+ nativeHookRelayGeneration: optionalNonBlankStringSchema,
1448
+ appServerRuntimeFingerprint: optionalStringSchema,
1449
+ pluginAppsFingerprint: optionalStringSchema,
1450
+ pluginAppsInputFingerprint: optionalStringSchema,
1451
+ pluginAppPolicyContext: pluginAppPolicyContextSchema.optional().catch(void 0),
1452
+ contextEngine: contextEngineSchema.optional().catch(void 0),
1453
+ environmentSelectionFingerprint: optionalStringSchema,
1454
+ conversationStartId: optionalStringSchema,
1455
+ conversationSourceTransferComplete: z.literal(true).optional().catch(void 0),
1456
+ historyCoveredThrough: optionalTimestampSchema
1457
+ }).superRefine((binding, context) => {
1458
+ if (binding.connectionScope === "supervision") {
1459
+ if (!binding.supervisionSourceThreadId) context.addIssue({
1460
+ code: "custom",
1461
+ message: "supervision connection ownership requires its native source thread id"
1462
+ });
1463
+ if (binding.preserveNativeModel !== true) context.addIssue({
1464
+ code: "custom",
1465
+ message: "supervision connection ownership requires native model ownership"
1466
+ });
1467
+ if (binding.conversationSourceTransferComplete !== true) context.addIssue({
1468
+ code: "custom",
1469
+ message: "supervision connection ownership requires a completed source transfer"
1470
+ });
1471
+ if (!binding.pendingSupervisionBranch && (!binding.model?.trim() || !binding.modelProvider)) context.addIssue({
1472
+ code: "custom",
1473
+ message: "materialized supervision bindings require a native model and provider"
1474
+ });
1475
+ }
1476
+ if (binding.supervisionSourceThreadId && binding.connectionScope !== "supervision") context.addIssue({
1477
+ code: "custom",
1478
+ message: "a supervision source thread id requires supervision connection ownership"
1479
+ });
1480
+ if (!binding.pendingSupervisionBranch) return;
1481
+ if (binding.threadId !== binding.pendingSupervisionBranch.sourceThreadId) context.addIssue({
1482
+ code: "custom",
1483
+ message: "pending supervision source must match the provisional thread binding"
1484
+ });
1485
+ if (binding.supervisionSourceThreadId !== binding.pendingSupervisionBranch.sourceThreadId) context.addIssue({
1486
+ code: "custom",
1487
+ message: "pending supervision source must match its durable source identity"
1488
+ });
1489
+ if (binding.preserveNativeModel !== true) context.addIssue({
1490
+ code: "custom",
1491
+ message: "pending supervision bindings must defer model selection to Codex App Server"
1492
+ });
1493
+ if (binding.connectionScope !== "supervision") context.addIssue({
1494
+ code: "custom",
1495
+ message: "pending supervision bindings require supervision connection ownership"
1496
+ });
1497
+ });
1498
+ var CodexSupervisionBindingReplacementError = class extends Error {
1499
+ constructor(threadId, operation) {
1500
+ super(`Refusing to replace supervised Codex thread ${threadId} while ${operation}; its native user-home connection and model ownership must be preserved`);
1501
+ this.name = "CodexSupervisionBindingReplacementError";
1502
+ }
1503
+ };
1504
+ function assertCodexBindingMayBeReplaced(binding, operation) {
1505
+ if (binding?.connectionScope === "supervision") throw new CodexSupervisionBindingReplacementError(binding.threadId, operation);
1506
+ }
1507
+ const bindingLeaseSchema = z.object({
1508
+ token: z.string().refine((value) => Boolean(value.trim())),
1509
+ expiresAt: z.number().finite()
1510
+ });
1511
+ const storedSessionIdSchema = z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0);
1512
+ const storedBindingSchema = z.discriminatedUnion("state", [z.object({
1513
+ version: z.literal(1),
1514
+ state: z.literal("active"),
1515
+ binding: threadBindingSchema,
1516
+ sessionId: storedSessionIdSchema,
1517
+ lease: bindingLeaseSchema.optional().catch(void 0)
1518
+ }), z.object({
1519
+ version: z.literal(1),
1520
+ state: z.literal("cleared"),
1521
+ sessionId: storedSessionIdSchema,
1522
+ lease: bindingLeaseSchema.optional().catch(void 0),
1523
+ retired: z.literal(true).optional().catch(void 0)
1524
+ })]);
1525
+ function hashCodexAppServerBindingFingerprint(canonical) {
1526
+ return `sha256:${createHash("sha256").update(canonical).digest("hex")}`;
1527
+ }
1528
+ function normalizeLegacyBindingFingerprint(value) {
1529
+ if (typeof value !== "string" || value === "" || value === "[]" || BOUNDED_BINDING_FINGERPRINT_PATTERN.test(value)) return value;
1530
+ return hashCodexAppServerBindingFingerprint(value);
1531
+ }
1532
+ function normalizeLegacyBindingFingerprints(record) {
1533
+ let normalized = record;
1534
+ for (const key of ["dynamicToolsFingerprint", "userMcpServersFingerprint"]) {
1535
+ const value = record[key];
1536
+ const next = normalizeLegacyBindingFingerprint(value);
1537
+ if (next === value) continue;
1538
+ if (normalized === record) normalized = { ...record };
1539
+ normalized[key] = next;
1540
+ }
1541
+ return normalized;
1542
+ }
1543
+ function normalizeStoredCodexAppServerBindingFingerprints(value) {
1544
+ const stored = readStoredCodexAppServerBinding(value);
1545
+ if (!stored || stored.state !== "active") return stored;
1546
+ const binding = normalizeLegacyBindingFingerprints(stored.binding);
1547
+ return binding === stored.binding ? stored : readStoredCodexAppServerBinding({
1548
+ ...stored,
1549
+ binding
1550
+ });
1551
+ }
1552
+ /** Encodes a migrated sidecar binding as one canonical plugin-state row. */
1553
+ function createStoredCodexAppServerBinding(value, options = {}) {
1554
+ const rawRecord = asRecord(value);
1555
+ if (!rawRecord) return;
1556
+ const record = normalizeLegacyBindingFingerprints(rawRecord);
1557
+ if (record.schemaVersion !== 1 && record.schemaVersion !== 2) return;
1558
+ const pluginAppPolicyContext = readPluginAppPolicyContext(record.pluginAppPolicyContext, record.schemaVersion);
1559
+ const historyCoveredThrough = readTimestamp(record.historyCoveredThrough) ?? readTimestamp(record.updatedAt) ?? readTimestamp(record.createdAt) ?? readTimestamp(options.now) ?? (/* @__PURE__ */ new Date()).toISOString();
1560
+ const authProfileId = typeof record.authProfileId === "string" ? record.authProfileId : void 0;
1561
+ const binding = readCodexAppServerThreadBinding({
1562
+ ...record,
1563
+ modelProvider: normalizeCodexAppServerBindingModelProvider({
1564
+ ...options.lookup,
1565
+ authProfileId,
1566
+ modelProvider: typeof record.modelProvider === "string" ? record.modelProvider : void 0
1567
+ }),
1568
+ cwd: typeof record.cwd === "string" ? record.cwd : "",
1569
+ pluginAppPolicyContext,
1570
+ historyCoveredThrough
1571
+ });
1572
+ return binding ? {
1573
+ version: 1,
1574
+ state: "active",
1575
+ binding: stripUndefinedBinding(binding)
1576
+ } : void 0;
1577
+ }
1578
+ function bindingLeaseLostError(key, cause) {
1579
+ return new Error(`Lost Codex binding lease: ${key}`, cause === void 0 ? void 0 : { cause });
1580
+ }
1581
+ /** Lets the authoritative OpenClaw session generation claim a stale stable binding row. */
1582
+ async function reclaimCurrentCodexSessionGeneration(params) {
1583
+ const sessionKey = params.identity.sessionKey?.trim();
1584
+ if (!sessionKey) return true;
1585
+ const plan = await params.bindingStore.prepareSessionGenerationReclaim(params.identity);
1586
+ if (plan.kind === "resolved") return plan.result;
1587
+ try {
1588
+ const storePath = resolveStorePath(params.config?.session?.store, { agentId: params.identity.agentId });
1589
+ if (getSessionEntry({
1590
+ agentId: params.identity.agentId,
1591
+ hydrateSkillPromptRefs: false,
1592
+ readConsistency: "latest",
1593
+ sessionKey,
1594
+ storePath
1595
+ })?.sessionId !== params.identity.sessionId) return false;
1596
+ } catch {
1597
+ return false;
1598
+ }
1599
+ return await params.bindingStore.mutate(params.identity, {
1600
+ kind: "reclaim-generation",
1601
+ expectedPreviousSessionId: plan.expectedPreviousSessionId
1602
+ });
1603
+ }
1604
+ /** Creates the single binding facade owned by the Codex plugin runtime. */
1605
+ function createCodexAppServerBindingStore(state) {
1606
+ const update = state.update?.bind(state);
1607
+ if (!update) throw new Error("Codex app-server bindings require atomic plugin-state updates");
1608
+ const leaseContext = new AsyncLocalStorage();
1609
+ const archiveContext = new AsyncLocalStorage();
1610
+ let activeBindingMutations = 0;
1611
+ let pendingArchives = 0;
1612
+ let archiveTail = Promise.resolve();
1613
+ let bindingMutationsDrained = [];
1614
+ const waitForBindingMutations = async () => {
1615
+ if (activeBindingMutations === 0) return;
1616
+ await new Promise((resolve) => {
1617
+ bindingMutationsDrained.push(resolve);
1618
+ });
1619
+ };
1620
+ const runBindingMutation = async (run) => {
1621
+ if (archiveContext.getStore() === true) return await run();
1622
+ if (pendingArchives > 0) throw new Error("Codex binding mutation blocked while a native archive is in progress; retry");
1623
+ activeBindingMutations += 1;
1624
+ try {
1625
+ return await run();
1626
+ } finally {
1627
+ activeBindingMutations -= 1;
1628
+ if (activeBindingMutations === 0) {
1629
+ const drained = bindingMutationsDrained;
1630
+ bindingMutationsDrained = [];
1631
+ for (const resolve of drained) resolve();
1632
+ }
1633
+ }
1634
+ };
1635
+ const renewLease = (key, owner) => {
1636
+ if (owner.failure) return;
1637
+ try {
1638
+ let renewed = false;
1639
+ const stored = update(key, (raw) => {
1640
+ const current = readStoredCodexAppServerBinding(raw);
1641
+ if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
1642
+ const lease = current?.lease;
1643
+ const now = Date.now();
1644
+ if (!lease || lease.token !== owner.token || lease.expiresAt <= now) return;
1645
+ renewed = true;
1646
+ return {
1647
+ ...current,
1648
+ lease: {
1649
+ token: owner.token,
1650
+ expiresAt: now + BINDING_LEASE_STALE_MS
1651
+ }
1652
+ };
1653
+ });
1654
+ if (!renewed || !stored) owner.failure = bindingLeaseLostError(key);
1655
+ } catch (error) {
1656
+ owner.failure = bindingLeaseLostError(key, error);
1657
+ }
1658
+ };
1659
+ const transactKey = async (key, apply, ttlMs) => {
1660
+ const deadline = Date.now() + BINDING_LEASE_WAIT_MS;
1661
+ while (true) {
1662
+ let busy = false;
1663
+ let leaseLost = false;
1664
+ let result;
1665
+ const ownedLease = leaseContext.getStore()?.get(key);
1666
+ if (ownedLease?.failure) throw ownedLease.failure;
1667
+ const ownedToken = ownedLease?.token;
1668
+ update(key, (raw) => {
1669
+ const current = readStoredCodexAppServerBinding(raw);
1670
+ if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
1671
+ const activeLease = current?.lease;
1672
+ const now = Date.now();
1673
+ if (ownedToken && (!activeLease || activeLease.token !== ownedToken || activeLease.expiresAt <= now)) {
1674
+ leaseLost = true;
1675
+ return;
1676
+ }
1677
+ if (activeLease && activeLease.token !== ownedToken && activeLease.expiresAt > now) {
1678
+ busy = true;
1679
+ return;
1680
+ }
1681
+ const applied = apply(current, ownedToken);
1682
+ result = applied.result;
1683
+ return applied.next;
1684
+ }, ttlMs == null ? void 0 : { ttlMs });
1685
+ if (leaseLost) {
1686
+ const failure = bindingLeaseLostError(key);
1687
+ if (ownedLease) ownedLease.failure = failure;
1688
+ throw failure;
1689
+ }
1690
+ if (!busy) return result;
1691
+ if (Date.now() >= deadline) throw new Error(`Timed out waiting for Codex binding lease: ${key}`);
1692
+ await sleep(BINDING_LEASE_RETRY_INTERVAL_MS);
1693
+ }
1694
+ };
1695
+ return {
1696
+ async read(identity) {
1697
+ const key = bindingStoreKey(identity);
1698
+ const raw = state.lookup(key);
1699
+ const stored = readStoredCodexAppServerBinding(raw);
1700
+ if (raw !== void 0 && !stored) throw new Error(`Invalid Codex app-server binding row: ${key}`);
1701
+ return stored?.state === "active" && ownsStoredSessionGeneration(identity, stored) ? stored.binding : void 0;
1702
+ },
1703
+ async hasOtherThreadOwner(threadId, currentIdentity) {
1704
+ const currentKey = currentIdentity ? bindingStoreKey(currentIdentity) : void 0;
1705
+ return state.entries().some(({ key, value }) => {
1706
+ const stored = readStoredCodexAppServerBinding(value);
1707
+ if (!stored) throw new Error(`Invalid Codex app-server binding row: ${key}`);
1708
+ const isCurrentOwner = currentIdentity !== void 0 && key === currentKey && (currentIdentity.kind === "conversation" || stored.sessionId === currentIdentity.sessionId.trim());
1709
+ if (stored.state !== "active" || stored.binding.threadId !== threadId || isCurrentOwner) return false;
1710
+ return true;
1711
+ });
1712
+ },
1713
+ async prepareSessionGenerationReclaim(identity) {
1714
+ const key = bindingStoreKey(identity);
1715
+ const raw = state.lookup(key);
1716
+ const current = readStoredCodexAppServerBinding(raw);
1717
+ if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
1718
+ if (!current) return {
1719
+ kind: "resolved",
1720
+ result: true
1721
+ };
1722
+ const currentSessionId = current.sessionId;
1723
+ if (!currentSessionId || currentSessionId === identity.sessionId) return {
1724
+ kind: "resolved",
1725
+ result: current.state !== "cleared" || current.retired !== true
1726
+ };
1727
+ return {
1728
+ kind: "verify",
1729
+ expectedPreviousSessionId: currentSessionId
1730
+ };
1731
+ },
1732
+ async mutate(identity, mutation) {
1733
+ return await runBindingMutation(async () => {
1734
+ const key = bindingStoreKey(identity);
1735
+ const retainLegacyClear = mutation.kind === "clear" && key.startsWith("conversation:legacy-");
1736
+ return await transactKey(key, (current, leaseToken) => {
1737
+ const ownsGeneration = ownsStoredSessionGeneration(identity, current);
1738
+ const ownedLease = current?.lease && current.lease.token === leaseToken ? { lease: current.lease } : {};
1739
+ if (mutation.kind === "reclaim-generation") {
1740
+ if (identity.kind !== "session" || !identity.sessionKey?.trim()) return { result: false };
1741
+ if (!current) return { result: true };
1742
+ if (ownsGeneration) return { result: current.state !== "cleared" || current.retired !== true };
1743
+ if (current.sessionId !== mutation.expectedPreviousSessionId) return { result: false };
1744
+ if (current.state === "active" && current.binding.connectionScope === "supervision") return { result: false };
1745
+ return {
1746
+ result: true,
1747
+ next: {
1748
+ version: 1,
1749
+ state: "cleared",
1750
+ sessionId: identity.sessionId,
1751
+ ...ownedLease
1752
+ }
1753
+ };
1754
+ }
1755
+ const storedActive = current?.state === "active" ? current : void 0;
1756
+ const active = ownsGeneration ? storedActive : void 0;
1757
+ const retiredGeneration = current?.state === "cleared" && current.retired === true && ownsGeneration;
1758
+ const preservesSupervisionOwner = mutation.kind === "set" && active?.binding.connectionScope === "supervision" && isSameSupervisionOwner(active.binding, mutation.binding);
1759
+ const clearsPendingSupervisionOwner = mutation.kind === "clear" && active?.binding.connectionScope === "supervision" && matchesPendingSupervisionClear(active.binding, mutation.threadId, mutation.expectedPendingSupervisionBranch);
1760
+ if (mutation.kind === "set" && (mutation.if?.kind === "absent" && storedActive || current !== void 0 && !ownsGeneration || retiredGeneration || active?.binding.connectionScope === "supervision" && !preservesSupervisionOwner) || mutation.kind === "patch" && active?.binding.threadId !== mutation.threadId || (mutation.kind === "patch-pending-supervision-branch" || mutation.kind === "commit-pending-supervision-branch") && !matchesPendingSupervisionBranch(active?.binding, mutation.expected) || mutation.kind === "clear" && (mutation.threadId !== void 0 && active?.binding.threadId !== mutation.threadId || !ownsGeneration || active?.binding.connectionScope === "supervision" && !clearsPendingSupervisionOwner)) return { result: false };
1761
+ if (mutation.kind === "clear" && retiredGeneration) return { result: true };
1762
+ if (mutation.kind === "clear") return {
1763
+ result: true,
1764
+ next: {
1765
+ version: 1,
1766
+ state: "cleared",
1767
+ ...storedSessionGeneration(identity, current),
1768
+ ...ownedLease
1769
+ }
1770
+ };
1771
+ let binding;
1772
+ if (mutation.kind === "set") binding = validateBindingForWrite(mutation.binding);
1773
+ else if (mutation.kind === "patch-pending-supervision-branch") binding = validateBindingForWrite({
1774
+ ...active.binding,
1775
+ pendingSupervisionBranch: mutation.pending
1776
+ });
1777
+ else if (mutation.kind === "commit-pending-supervision-branch") binding = validateBindingForWrite({
1778
+ ...active.binding,
1779
+ ...mutation.patch,
1780
+ threadId: mutation.threadId,
1781
+ pendingSupervisionBranch: void 0
1782
+ });
1783
+ else binding = validateBindingForWrite({
1784
+ ...active.binding,
1785
+ ...mutation.patch,
1786
+ threadId: mutation.threadId
1787
+ });
1788
+ return {
1789
+ result: true,
1790
+ next: {
1791
+ version: 1,
1792
+ state: "active",
1793
+ binding,
1794
+ ...storedSessionGeneration(identity, current),
1795
+ ...ownedLease
1796
+ }
1797
+ };
1798
+ }, mutation.kind === "clear" && !retainLegacyClear && !leaseContext.getStore()?.has(key) ? 1 : void 0);
1799
+ });
1800
+ },
1801
+ async adoptSessionGeneration(identity, expectedPreviousSessionId) {
1802
+ return await runBindingMutation(async () => {
1803
+ const key = bindingStoreKey(identity);
1804
+ const expectedSessionId = expectedPreviousSessionId.trim();
1805
+ const targetSessionId = identity.sessionId.trim();
1806
+ if (!expectedSessionId) throw new Error("Codex session generation adoption requires the previous session id");
1807
+ return await transactKey(key, (current) => {
1808
+ if (current?.state !== "active") return { result: "absent" };
1809
+ if (current.sessionId === targetSessionId) return { result: "current" };
1810
+ if (current.sessionId !== expectedSessionId) return { result: "conflict" };
1811
+ return {
1812
+ result: "adopted",
1813
+ next: {
1814
+ ...current,
1815
+ sessionId: targetSessionId
1816
+ }
1817
+ };
1818
+ });
1819
+ });
1820
+ },
1821
+ async retireSessionGeneration(identity) {
1822
+ return await runBindingMutation(async () => {
1823
+ const key = bindingStoreKey(identity);
1824
+ return await transactKey(key, (current, leaseToken) => {
1825
+ if (!current) return { result: "absent" };
1826
+ if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
1827
+ if (current.state === "cleared" && current.retired === true) return { result: "applied" };
1828
+ return {
1829
+ result: "applied",
1830
+ next: {
1831
+ version: 1,
1832
+ state: "cleared",
1833
+ retired: true,
1834
+ ...storedSessionGeneration(identity, current),
1835
+ ...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
1836
+ }
1837
+ };
1838
+ }, identity.sessionKey?.trim() ? void 0 : PHYSICAL_SESSION_RETIRE_TTL_MS);
1839
+ });
1840
+ },
1841
+ async withThreadArchiveFence(run) {
1842
+ pendingArchives += 1;
1843
+ const operation = archiveTail.then(async () => {
1844
+ await waitForBindingMutations();
1845
+ return await archiveContext.run(true, run);
1846
+ });
1847
+ archiveTail = operation.then(() => void 0, () => void 0);
1848
+ try {
1849
+ return await operation;
1850
+ } finally {
1851
+ pendingArchives -= 1;
1852
+ }
1853
+ },
1854
+ async withLease(identity, run) {
1855
+ const key = bindingStoreKey(identity);
1856
+ const owned = leaseContext.getStore();
1857
+ const existingOwner = owned?.get(key);
1858
+ if (existingOwner) {
1859
+ const failureBeforeRun = existingOwner.failure;
1860
+ if (failureBeforeRun) throw failureBeforeRun;
1861
+ const result = await run();
1862
+ const failureAfterRun = existingOwner.failure;
1863
+ if (failureAfterRun) throw failureAfterRun;
1864
+ return result;
1865
+ }
1866
+ const token = randomUUID();
1867
+ if (!await transactKey(key, (current) => {
1868
+ if (current?.state === "cleared" && current.retired === true && ownsStoredSessionGeneration(identity, current)) return { result: false };
1869
+ const lease = {
1870
+ token,
1871
+ expiresAt: Date.now() + BINDING_LEASE_STALE_MS
1872
+ };
1873
+ if (current?.state === "active") return {
1874
+ result: true,
1875
+ next: {
1876
+ ...current,
1877
+ ...preservedSessionGeneration(identity, current),
1878
+ lease
1879
+ }
1880
+ };
1881
+ if (current?.state === "cleared" && current.retired === true) return {
1882
+ result: true,
1883
+ next: {
1884
+ ...current,
1885
+ lease
1886
+ }
1887
+ };
1888
+ return {
1889
+ result: true,
1890
+ next: {
1891
+ version: 1,
1892
+ state: "cleared",
1893
+ ...preservedSessionGeneration(identity, current),
1894
+ lease
1895
+ }
1896
+ };
1897
+ })) throw new Error(`Codex binding generation was retired: ${key}`);
1898
+ const owner = { token };
1899
+ const nested = new Map(owned);
1900
+ nested.set(key, owner);
1901
+ const heartbeat = setInterval(() => renewLease(key, owner), BINDING_LEASE_RENEW_INTERVAL_MS);
1902
+ heartbeat.unref();
1903
+ try {
1904
+ const result = await leaseContext.run(nested, run);
1905
+ if (owner.failure) throw owner.failure;
1906
+ return result;
1907
+ } finally {
1908
+ clearInterval(heartbeat);
1909
+ try {
1910
+ const removeOwnedLease = (raw, matches) => {
1911
+ const current = readStoredCodexAppServerBinding(raw);
1912
+ if (!current || !matches(current) || current.lease?.token !== token) return;
1913
+ const { lease: _lease, ...released } = current;
1914
+ return released;
1915
+ };
1916
+ if (!update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "active"))) {
1917
+ if (!update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "cleared" && current.retired === true), key.startsWith("session:") ? { ttlMs: PHYSICAL_SESSION_RETIRE_TTL_MS } : void 0)) update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "cleared"), { ttlMs: 1 });
1918
+ }
1919
+ } catch (error) {
1920
+ embeddedAgentLog.warn("failed to release codex app-server binding lease", {
1921
+ key,
1922
+ error
1923
+ });
1924
+ }
1925
+ }
1926
+ }
1927
+ };
1928
+ }
1929
+ function matchesPendingSupervisionBranch(binding, expected) {
1930
+ const pending = binding?.pendingSupervisionBranch;
1931
+ if (!pending || binding?.threadId !== expected.sourceThreadId) return false;
1932
+ if (pending.sourceThreadId !== expected.sourceThreadId || pending.connectionFingerprint !== expected.connectionFingerprint || pending.lastTurnId !== expected.lastTurnId) return false;
1933
+ const currentCleanup = pending.cleanupThreadIds ?? [];
1934
+ const expectedCleanup = expected.cleanupThreadIds ?? [];
1935
+ return currentCleanup.length === expectedCleanup.length && currentCleanup.every((threadId, index) => threadId === expectedCleanup[index]);
1936
+ }
1937
+ function isSameSupervisionOwner(current, replacement) {
1938
+ return replacement.connectionScope === "supervision" && replacement.threadId === current.threadId && replacement.supervisionSourceThreadId === current.supervisionSourceThreadId;
1939
+ }
1940
+ function matchesPendingSupervisionClear(binding, threadId, expected) {
1941
+ if (!expected) return false;
1942
+ const sourceThreadId = expected.sourceThreadId;
1943
+ return threadId === sourceThreadId && binding.supervisionSourceThreadId === sourceThreadId && matchesPendingSupervisionBranch(binding, expected);
1944
+ }
1945
+ /** Stable plugin-state key for one current binding owner. */
1946
+ function bindingStoreKey(identity) {
1947
+ if (identity.kind === "session") {
1948
+ const rawAgentId = identity.agentId.trim();
1949
+ const sessionId = identity.sessionId.trim();
1950
+ if (!rawAgentId) throw new Error("Codex app-server binding requires an agent id");
1951
+ if (!sessionId) throw new Error("Codex app-server binding requires a session id");
1952
+ const agentId = resolveSessionAgentIds({ agentId: rawAgentId }).sessionAgentId;
1953
+ const sessionKey = identity.sessionKey?.trim();
1954
+ if (sessionKey) return `session-key:${agentId}:${createHash("sha256").update(sessionKey).digest("base64url")}`;
1955
+ return `session:${agentId}:${sessionId}`;
1956
+ }
1957
+ const bindingId = identity.bindingId.trim();
1958
+ if (!bindingId) throw new Error("Codex app-server conversation binding requires a binding id");
1959
+ return `conversation:${bindingId}`;
1960
+ }
1961
+ function readStoredCodexAppServerBinding(value) {
1962
+ const result = storedBindingSchema.safeParse(value);
1963
+ return result.success ? stripUndefinedValue(result.data) : void 0;
1964
+ }
1965
+ function storedSessionGeneration(identity, current) {
1966
+ if (identity.kind === "session") return { sessionId: identity.sessionId };
1967
+ return current?.sessionId ? { sessionId: current.sessionId } : {};
1968
+ }
1969
+ function preservedSessionGeneration(identity, current) {
1970
+ if (current?.sessionId) return { sessionId: current.sessionId };
1971
+ return storedSessionGeneration(identity, current);
1972
+ }
1973
+ function ownsStoredSessionGeneration(identity, current) {
1974
+ return identity.kind !== "session" || !current?.sessionId || current.sessionId === identity.sessionId;
1975
+ }
1976
+ function validateBindingForWrite(binding) {
1977
+ const validated = readCodexAppServerThreadBinding(binding);
1978
+ if (!validated) throw new Error("Invalid Codex app-server thread binding");
1979
+ return stripUndefinedBinding(validated);
1980
+ }
1981
+ /** Parses stored or shipped sidecar data into the current domain value. */
1982
+ function readCodexAppServerThreadBinding(value) {
1983
+ const result = threadBindingSchema.safeParse(value);
1984
+ if (!result.success) return;
1985
+ return result.data;
1986
+ }
1987
+ function stripUndefinedBinding(binding) {
1988
+ return stripUndefinedValue(binding);
1989
+ }
1990
+ function stripUndefinedValue(value) {
1991
+ if (Array.isArray(value)) return value.map(stripUndefinedValue);
1992
+ if (!value || typeof value !== "object") return value;
1993
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, stripUndefinedValue(entry)]));
1994
+ }
1995
+ function asRecord(value) {
1996
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1997
+ }
1998
+ function readTimestamp(value) {
1999
+ return optionalTimestampSchema.parse(value);
2000
+ }
2001
+ function readPluginAppPolicyContext(value, bindingSchemaVersion) {
2002
+ const record = asRecord(value);
2003
+ if (!record || typeof record.fingerprint !== "string") return;
2004
+ const apps = asRecord(record.apps);
2005
+ if (!apps) return;
2006
+ const parsedApps = {};
2007
+ for (const [appId, rawEntry] of Object.entries(apps)) {
2008
+ const entry = asRecord(rawEntry);
2009
+ if (!entry) return;
2010
+ const destructiveApprovalMode = readDestructiveApprovalMode(entry.destructiveApprovalMode, bindingSchemaVersion);
2011
+ const mcpServerNamesValid = Array.isArray(entry.mcpServerNames) && entry.mcpServerNames.every((serverName) => typeof serverName === "string");
2012
+ if (entry.source === "account") {
2013
+ if ("appId" in entry || typeof entry.appName !== "string" || typeof entry.allowDestructiveActions !== "boolean" || destructiveApprovalMode === "invalid" || !mcpServerNamesValid) return;
2014
+ parsedApps[appId] = {
2015
+ source: "account",
2016
+ appName: entry.appName,
2017
+ allowDestructiveActions: entry.allowDestructiveActions,
2018
+ ...destructiveApprovalMode ? { destructiveApprovalMode } : {},
2019
+ mcpServerNames: entry.mcpServerNames
2020
+ };
2021
+ continue;
2022
+ }
2023
+ if ("appId" in entry || entry.source !== void 0 && entry.source !== "plugin" || typeof entry.configKey !== "string" || entry.marketplaceName !== "openai-curated" && entry.marketplaceName !== "workspace-directory" || typeof entry.pluginName !== "string" || typeof entry.allowDestructiveActions !== "boolean" || destructiveApprovalMode === "invalid" || !mcpServerNamesValid) return;
2024
+ parsedApps[appId] = {
2025
+ configKey: entry.configKey,
2026
+ marketplaceName: entry.marketplaceName,
2027
+ pluginName: entry.pluginName,
2028
+ allowDestructiveActions: entry.allowDestructiveActions,
2029
+ ...destructiveApprovalMode ? { destructiveApprovalMode } : {},
2030
+ mcpServerNames: entry.mcpServerNames
2031
+ };
2032
+ }
2033
+ const parsedPluginAppIds = {};
2034
+ if (record.pluginAppIds !== void 0 && (!record.pluginAppIds || typeof record.pluginAppIds !== "object" || Array.isArray(record.pluginAppIds))) return;
2035
+ if (record.pluginAppIds && typeof record.pluginAppIds === "object") for (const [configKey, appIds] of Object.entries(record.pluginAppIds)) {
2036
+ if (!Array.isArray(appIds) || appIds.some((appId) => typeof appId !== "string")) return;
2037
+ parsedPluginAppIds[configKey] = appIds;
2038
+ }
2039
+ return {
2040
+ fingerprint: record.fingerprint,
2041
+ apps: parsedApps,
2042
+ pluginAppIds: parsedPluginAppIds
2043
+ };
2044
+ }
2045
+ function readDestructiveApprovalMode(value, bindingSchemaVersion) {
2046
+ if (value === void 0) return;
2047
+ if (value === "allow" || value === "deny") return value;
2048
+ if (value === "auto") return bindingSchemaVersion === 1 ? "allow" : "auto";
2049
+ if (value === "ask" && bindingSchemaVersion === 2) return "ask";
2050
+ if (value === "on-request" && bindingSchemaVersion === 1) return "auto";
2051
+ return "invalid";
2052
+ }
2053
+ function sleep(ms) {
2054
+ return new Promise((resolve) => {
2055
+ setTimeout(resolve, ms);
2056
+ });
2057
+ }
2058
+ /** Returns true when an auth profile uses native Codex/OpenAI app-server auth. */
2059
+ function isCodexAppServerNativeAuthProfile(lookup) {
2060
+ const authProfileId = lookup.authProfileId?.trim();
2061
+ if (!authProfileId) return false;
2062
+ try {
2063
+ const credential = (lookup.authProfileStore ?? ensureAuthProfileStore(lookup.agentDir?.trim() || resolveDefaultAgentDir(lookup.config ?? {}), {
2064
+ allowKeychainPrompt: false,
2065
+ config: lookup.config,
2066
+ externalCliProviderIds: [CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER],
2067
+ externalCliProfileIds: [authProfileId]
2068
+ })).profiles[authProfileId];
2069
+ if (!credential || credential.type === "api_key") return false;
2070
+ const provider = credential.provider?.trim();
2071
+ return Boolean(provider && resolveProviderIdForAuth(provider, { config: lookup.config }) === CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER);
2072
+ } catch (error) {
2073
+ embeddedAgentLog.debug("failed to resolve codex app-server auth profile provider", {
2074
+ authProfileId,
2075
+ error
2076
+ });
2077
+ return false;
2078
+ }
2079
+ }
2080
+ /** Hides redundant OpenAI provider attribution for native Codex auth bindings. */
2081
+ function normalizeCodexAppServerBindingModelProvider(params) {
2082
+ const modelProvider = params.modelProvider?.trim();
2083
+ if (!modelProvider) return;
2084
+ if (isCodexAppServerNativeAuthProfile(params) && modelProvider.toLowerCase() === PUBLIC_OPENAI_MODEL_PROVIDER) return;
2085
+ return modelProvider;
2086
+ }
2087
+ /** Restores the sole provider intentionally omitted from canonical binding rows. */
2088
+ function resolveCodexAppServerBindingModelProvider(params) {
2089
+ return params.modelProvider?.trim() || (isCodexAppServerNativeAuthProfile(params) ? PUBLIC_OPENAI_MODEL_PROVIDER : void 0);
2090
+ }
2091
+ //#endregion
2092
+ export { resolveCodexComputerUseConfig as C, resolveOpenClawExecPolicyForCodexAppServer as D, resolveCodexSupervisionAppServerRuntimeOptions as E, shouldAutoApproveCodexAppServerApprovals as O, resolveCodexAppServerUserHomeDir as S, resolveCodexPluginsPolicy as T, isCodexFastServiceTier as _, isCodexAppServerNativeAuthProfile as a, resolveCodexAppServerRuntimeOptions as b, sessionBindingIdentity as c, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME as d, assertCodexAppServerConnectionSecurity as f, isCodexAppServerApprovalPolicyAllowedByRequirements as g, codexSandboxPolicyForTurn as h, hashCodexAppServerBindingFingerprint as i, withMcpElicitationsApprovalPolicy as k, session_binding_exports as l, codexAppServerStartOptionsKey as m, assertCodexBindingMayBeReplaced as n, normalizeCodexAppServerBindingModelProvider as o, canUseCodexModelBackedApprovalsReviewerForModel as p, bindingStoreKey as r, reclaimCurrentCodexSessionGeneration as s, CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS as t, CODEX_PLUGINS_MARKETPLACE_NAME as u, isCodexSandboxExecServerEnabled as v, resolveCodexModelBackedReviewerPolicyContext as w, resolveCodexAppServerStartOptionsForAgent as x, readCodexPluginConfig as y };