@openclaw/codex 2026.8.1-beta.2 → 2026.8.1
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.
- package/dist/api.js +146 -0
- package/dist/{attempt-client-cleanup-DMLXUfa8.js → attempt-client-cleanup-CVPvp9dL.js} +47 -5
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-I5Bo-AsX.js → binding-connection-CCQFs8lf.js} +15 -3
- package/dist/{bounded-turn-qgZmzy_4.js → bounded-turn-rq5tiSXk.js} +27 -26
- package/dist/{capabilities-CybGI1oz.js → capabilities-CGm_94eL.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-B1AEz8ZA.js → command-formatters-C54Yg3eA.js} +2 -2
- package/dist/{command-handlers-Db8pu_ds.js → command-handlers-BvOAHTrA.js} +111 -67
- package/dist/{compact-LspQaGfl.js → compact-Hd7SAc0N.js} +35 -30
- package/dist/{session-binding-DPxIvMgE.js → config-Cxw3Cl3k.js} +361 -1161
- package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
- package/dist/doctor-contract-api.js +128 -26
- package/dist/{dynamic-tools-BVdyWkUD.js → dynamic-tools-BFoUcRdx.js} +1341 -1464
- package/dist/{effective-mcp-catalog-DIIhAtOZ.js → effective-mcp-catalog-BTJHnDSx.js} +2 -2
- package/dist/elicitation-input-DMkeki8d.js +71 -0
- package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
- package/dist/{event-projector-usage-e5huIQWu.js → event-projector-usage-D3PHFFXh.js} +18 -18
- package/dist/harness-DVfUQBlQ.js +248 -0
- package/dist/harness.js +2 -226
- package/dist/index.js +405 -299
- package/dist/{isolated-completion-C58NbL40.js → isolated-completion-Cbbx_5Ed.js} +4 -4
- package/dist/launch-args-sXOAg0SX.js +84 -0
- package/dist/managed-binary-ZkGodW19.js +248 -0
- package/dist/media-understanding-provider.js +2 -2
- package/dist/model-catalog-o6Cgjoss.js +101 -0
- package/dist/{models-BFlpn1Ex.js → models-DgFWSuxA.js} +25 -28
- package/dist/{native-subagent-monitor-DyTGmTUx.js → native-subagent-monitor-CwFyoylz.js} +385 -94
- package/dist/node-exec-server.runtime-DXrqpw1c.js +195 -0
- package/dist/plugin-approval-roundtrip-D80UZiJ_.js +95 -0
- package/dist/{plugin-marketplace-discovery-CzrGJdCR.js → plugin-marketplace-discovery-mdmScYOj.js} +60 -55
- package/dist/{plugin-metadata-cache-CNJPj4_b.js → plugin-metadata-cache-CulOABwu.js} +164 -134
- package/dist/{protocol-validators-B4F7L8Rf.js → protocol-validators-Bg5rpNxk.js} +203 -7
- package/dist/{rate-limits-DZXmOL8-.js → rate-limits-hFtzt2Up.js} +1 -1
- package/dist/{sandbox-guard-Cmwc9eIk.js → request-CCm4LaED.js} +207 -20
- package/dist/{run-attempt-P8BdxC1I.js → run-attempt-BwNQDH2u.js} +1506 -836
- package/dist/{runtime-artifact-BVSPdd6g.js → runtime-artifact-DeBvleJw.js} +4 -7
- package/dist/session-binding-q2WSTVmC.js +947 -0
- package/dist/{session-catalog-xwNi_SDM.js → session-catalog-C2Tae4rI.js} +1698 -1346
- package/dist/session-catalog-home-id-DAKUrm3C.js +112 -0
- package/dist/{session-cli-7hgXZDV7.js → session-cli-BuDjm5Ou.js} +20 -7
- package/dist/session-permission-policy-gLm40Vtq.js +160 -0
- package/dist/session-retirement-CdkI0bvb.js +90 -0
- package/dist/{session-upstream-marker-CrIFX06J.js → session-upstream-marker-Bcy33kam.js} +2 -3
- package/dist/{settled-turn-finalizer-BRWBO4MO.js → settled-turn-finalizer-B8JJcxCi.js} +27 -22
- package/dist/{shared-client-kIBbGjk4.js → shared-client-kNkljY-R.js} +2023 -607
- package/dist/{side-question-9HAL26l9.js → side-question-GwD73tX6.js} +109 -57
- package/dist/{thread-lifecycle-Bu1BTDXr.js → thread-lifecycle-Ss-uwnC4.js} +1208 -497
- package/dist/{thread-ownership-6kOQHlyC.js → thread-ownership-CeYBqg_4.js} +18 -8
- package/dist/{plugin-app-cache-key-C3H2CVp6.js → thread-resume-DF54hagX.js} +64 -6
- package/dist/{transcript-mirror-B9gGgnJS.js → transcript-mirror-CkEQIna-.js} +158 -41
- package/dist/transport-stdio-C7-s9TLG.js +708 -0
- package/dist/{upstream-prompt-provenance-ClRBije0.js → upstream-prompt-provenance-CFmsKwr9.js} +12 -14
- package/dist/{upstream-session-fork-CE-_LdnP.js → upstream-session-fork-BACGlOFa.js} +86 -88
- package/dist/{usage-CHlV0e-o.js → usage-C2l8Mils.js} +3 -3
- package/dist/{web-search-provider.runtime-DRw2Vl42.js → web-search-provider.runtime-B2XgRdFv.js} +3 -3
- package/openclaw.plugin.json +50 -2
- package/package.json +9 -8
- package/dist/app-server-policy-zcBDc1JU.js +0 -49
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/request-BRl5_UfX.js +0 -157
- package/dist/session-retirement-DoMMJFKm.js +0 -36
- package/dist/thread-resume-CPrJNQVM.js +0 -30
- package/dist/transport-stdio-DIImwDVS.js +0 -99
|
@@ -1,22 +1,52 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import {
|
|
3
|
-
import { asOptionalRecord, asOptionalRecord as readRecord, normalizeOptionalString as readNonEmptyString, normalizeTrimmedStringList, parseBooleanValue } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
1
|
+
import { n as readCodexAppServerConfigOptions, t as normalizeCodexAppServerArgs } from "./launch-args-sXOAg0SX.js";
|
|
2
|
+
import { asNullableRecord, asOptionalRecord as readRecord, normalizeOptionalString, normalizeOptionalString as readNonEmptyString, normalizeTrimmedStringList, parseBooleanValue } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
import { resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
6
|
-
import { AgentHarnessPreflightError
|
|
7
|
-
import { createHash, createHmac, randomBytes
|
|
5
|
+
import { AgentHarnessPreflightError } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
6
|
+
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
8
7
|
import { readFileSync } from "node:fs";
|
|
9
8
|
import { homedir, hostname } from "node:os";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { resolveProviderIdForAuth } from "openclaw/plugin-sdk/agent-runtime";
|
|
10
|
+
import { resolveAgentConfig as resolveAgentConfig$1 } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
12
11
|
import { resolveExecApprovalsFromFile } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
13
|
-
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
14
12
|
import { buildSecretInputSchema, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
15
13
|
import { detectWindowsSpawnCommandInlineArgs } from "openclaw/plugin-sdk/windows-spawn";
|
|
16
14
|
import { z } from "zod";
|
|
15
|
+
import { parse } from "smol-toml";
|
|
17
16
|
import { isLoopbackHost } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
//#region extensions/codex/src/app-server/auth-start-options.ts
|
|
18
|
+
const CODEX_APP_SERVER_HOME_DIRNAME = "codex-home";
|
|
19
|
+
const CODEX_EPHEMERAL_AUTH_STORE_OVERRIDE = "cli_auth_credentials_store=\"ephemeral\"";
|
|
20
|
+
function resolveCodexAppServerHomeDir(agentDir) {
|
|
21
|
+
return path.join(path.resolve(agentDir), CODEX_APP_SERVER_HOME_DIRNAME);
|
|
22
|
+
}
|
|
23
|
+
/** Resolves the native user Codex home used by Desktop and the CLI. */
|
|
24
|
+
function resolveCodexAppServerUserHomeDir(env = process.env, homedir$1 = homedir) {
|
|
25
|
+
const configured = normalizeOptionalString(env.CODEX_HOME);
|
|
26
|
+
return path.resolve(configured ?? path.join(homedir$1(), ".codex"));
|
|
27
|
+
}
|
|
28
|
+
/** Resolves the local CODEX_HOME used when starting one app-server connection. */
|
|
29
|
+
function resolveCodexAppServerLocalHomeDir(startOptions, agentDir, env = process.env) {
|
|
30
|
+
const configured = startOptions.env?.CODEX_HOME;
|
|
31
|
+
if (configured?.trim()) return configured;
|
|
32
|
+
return startOptions.homeScope === "user" ? resolveCodexAppServerUserHomeDir(env) : resolveCodexAppServerHomeDir(agentDir);
|
|
33
|
+
}
|
|
34
|
+
/** Forces OpenClaw-owned Codex auth to remain process-local. */
|
|
35
|
+
function withEphemeralCodexAuthStore(params) {
|
|
36
|
+
const { startOptions } = params;
|
|
37
|
+
if (!params.preparedAuth && params.authProfileId === null) return startOptions;
|
|
38
|
+
const args = normalizeCodexAppServerArgs(startOptions.args, CODEX_EPHEMERAL_AUTH_STORE_OVERRIDE);
|
|
39
|
+
return args === startOptions.args ? startOptions : {
|
|
40
|
+
...startOptions,
|
|
41
|
+
args
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region extensions/codex/src/app-server/config-contracts.ts
|
|
46
|
+
const CODEX_PLUGINS_MARKETPLACE_NAME = "openai-curated";
|
|
47
|
+
const CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME = "workspace-directory";
|
|
48
|
+
const CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
49
|
+
//#endregion
|
|
20
50
|
//#region extensions/codex/src/app-server/config-utils.ts
|
|
21
51
|
const START_OPTIONS_KEY_SECRET_SYMBOL = Symbol.for("openclaw.codexAppServerStartOptionsKeySecret");
|
|
22
52
|
const START_OPTIONS_KEY_SECRET = getStartOptionsKeySecret();
|
|
@@ -122,8 +152,9 @@ function selectGuardianSandbox(allowedSandboxModes) {
|
|
|
122
152
|
return "workspace-write";
|
|
123
153
|
}
|
|
124
154
|
function resolveApprovalPolicy(value) {
|
|
155
|
+
if (value === "untrusted") throw new Error("Codex app-server approval policy \"untrusted\" is retired; run \"openclaw doctor --fix\" and use \"on-request\".");
|
|
125
156
|
if (value === "on-failure") return "on-request";
|
|
126
|
-
return value === "on-request" || value === "
|
|
157
|
+
return value === "on-request" || value === "never" ? value : void 0;
|
|
127
158
|
}
|
|
128
159
|
function resolveSandbox(value) {
|
|
129
160
|
return value === "read-only" || value === "workspace-write" || value === "danger-full-access" ? value : void 0;
|
|
@@ -132,20 +163,16 @@ function resolveApprovalsReviewer(value) {
|
|
|
132
163
|
return value === "auto_review" || value === "guardian_subagent" || value === "user" ? value : void 0;
|
|
133
164
|
}
|
|
134
165
|
function resolveOpenClawExecPolicyFromConfig(params) {
|
|
135
|
-
const
|
|
136
|
-
const globalExec = readRecord(readRecord(root?.tools)?.exec);
|
|
166
|
+
const globalExec = readRecord(params.config?.tools?.exec);
|
|
137
167
|
const globalPolicy = applyOpenClawExecPolicyLayer(createDefaultOpenClawExecPolicy(), globalExec);
|
|
138
168
|
const agentId = params.agentId?.trim();
|
|
139
|
-
|
|
140
|
-
const agents = readRecord(root?.agents);
|
|
141
|
-
const agentList = Array.isArray(agents?.list) ? agents.list : [];
|
|
142
|
-
const normalizedAgentId = normalizeAgentId(agentId);
|
|
143
|
-
return applyOpenClawExecPolicyLayer(globalPolicy, readRecord(readRecord(readRecord(agentList.find((entry) => {
|
|
144
|
-
const id = readRecord(entry)?.id;
|
|
145
|
-
return typeof id === "string" && normalizeAgentId(id) === normalizedAgentId;
|
|
146
|
-
}))?.tools)?.exec));
|
|
169
|
+
return applyOpenClawExecPolicyLayer(globalPolicy, agentId ? readRecord(resolveAgentConfig$1(params.config ?? {}, agentId)?.tools?.exec) : void 0);
|
|
147
170
|
}
|
|
148
171
|
function resolveOpenClawExecPolicyForCodexAppServer(params) {
|
|
172
|
+
if (params.permissionMode === "full") return {
|
|
173
|
+
...resolveOpenClawExecPolicyForMode("full"),
|
|
174
|
+
touched: true
|
|
175
|
+
};
|
|
149
176
|
const overridePolicy = applyOpenClawExecPolicyLayer(resolveOpenClawExecPolicyFromConfig({
|
|
150
177
|
config: params.config,
|
|
151
178
|
agentId: params.agentId
|
|
@@ -169,8 +196,7 @@ function assertCodexAppServerAllowedForOpenClawExecMode(mode) {
|
|
|
169
196
|
}
|
|
170
197
|
function createDefaultOpenClawExecPolicy() {
|
|
171
198
|
return {
|
|
172
|
-
|
|
173
|
-
ask: "off",
|
|
199
|
+
...resolveOpenClawExecPolicyForMode("full"),
|
|
174
200
|
touched: false
|
|
175
201
|
};
|
|
176
202
|
}
|
|
@@ -274,15 +300,232 @@ function readExecMode(value) {
|
|
|
274
300
|
return value === "deny" || value === "allowlist" || value === "ask" || value === "auto" || value === "full" ? value : void 0;
|
|
275
301
|
}
|
|
276
302
|
//#endregion
|
|
303
|
+
//#region extensions/codex/src/app-server/session-discovery-config.ts
|
|
304
|
+
const codexSessionCatalogHomeSchema = z.union([z.string().trim().min(1), z.object({
|
|
305
|
+
path: z.string().trim().min(1),
|
|
306
|
+
label: z.string().trim().min(1).optional()
|
|
307
|
+
}).strict()]);
|
|
308
|
+
const codexSessionCatalogConfigSchema = z.object({
|
|
309
|
+
enabled: z.boolean().optional(),
|
|
310
|
+
homes: z.array(codexSessionCatalogHomeSchema).optional()
|
|
311
|
+
}).strict();
|
|
312
|
+
const codexDiscoveryConfigSchema = z.object({
|
|
313
|
+
enabled: z.boolean().optional(),
|
|
314
|
+
timeoutMs: z.number().positive().optional()
|
|
315
|
+
}).strict();
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region extensions/codex/src/app-server/config-parsing.ts
|
|
318
|
+
const DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME = "computer-use";
|
|
319
|
+
const DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS = 6e4;
|
|
320
|
+
const DEFAULT_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS = 6e4;
|
|
321
|
+
const DEFAULT_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS = 6e4;
|
|
322
|
+
const DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX = "openclaw-network";
|
|
323
|
+
const codexAppServerTransportSchema = z.enum([
|
|
324
|
+
"stdio",
|
|
325
|
+
"websocket",
|
|
326
|
+
"unix"
|
|
327
|
+
]);
|
|
328
|
+
const codexAppServerHomeScopeSchema = z.enum(["agent", "user"]);
|
|
329
|
+
const SecretInputSchema = buildSecretInputSchema();
|
|
330
|
+
const codexAppServerPolicyModeSchema = z.enum(["yolo", "guardian"]);
|
|
331
|
+
const codexAppServerApprovalPolicySchema = z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum(["never", "on-request"]));
|
|
332
|
+
const codexAppServerSandboxSchema = z.enum([
|
|
333
|
+
"read-only",
|
|
334
|
+
"workspace-write",
|
|
335
|
+
"danger-full-access"
|
|
336
|
+
]);
|
|
337
|
+
const codexAppServerApprovalsReviewerSchema = z.enum([
|
|
338
|
+
"user",
|
|
339
|
+
"auto_review",
|
|
340
|
+
"guardian_subagent"
|
|
341
|
+
]);
|
|
342
|
+
const codexDynamicToolsLoadingSchema = z.enum(["searchable", "direct"]);
|
|
343
|
+
const codexComputerUseHealthIntervalSchema = z.union([
|
|
344
|
+
z.literal(30),
|
|
345
|
+
z.literal(60),
|
|
346
|
+
z.literal(120),
|
|
347
|
+
z.literal(240)
|
|
348
|
+
]);
|
|
349
|
+
const codexComputerUsePluginCacheModeSchema = z.enum(["shared", "independent"]);
|
|
350
|
+
const codexPluginDestructivePolicySchema = z.union([
|
|
351
|
+
z.boolean(),
|
|
352
|
+
z.literal("auto"),
|
|
353
|
+
z.literal("ask")
|
|
354
|
+
]);
|
|
355
|
+
const codexAppServerServiceTierSchema = z.preprocess((value) => value === null ? null : normalizeCodexServiceTier(value), z.string().trim().min(1).nullable().optional()).optional();
|
|
356
|
+
const codexAppServerExperimentalSchema = z.object({ sandboxExecServer: z.boolean().optional() }).strict();
|
|
357
|
+
const codexAppServerRemoteWorkspaceRootSchema = z.string().trim().min(1);
|
|
358
|
+
const codexAppServerNetworkProxyDomainPermissionSchema = z.enum(["allow", "deny"]);
|
|
359
|
+
const codexAppServerNetworkProxyUnixSocketPermissionSchema = z.enum(["allow", "none"]);
|
|
360
|
+
const codexAppServerNetworkProxySchema = z.object({
|
|
361
|
+
enabled: z.boolean().optional(),
|
|
362
|
+
profileName: z.string().trim().min(1).optional(),
|
|
363
|
+
baseProfile: z.enum(["read-only", "workspace"]).optional(),
|
|
364
|
+
mode: z.enum(["limited", "full"]).optional(),
|
|
365
|
+
domains: z.record(z.string(), codexAppServerNetworkProxyDomainPermissionSchema).optional(),
|
|
366
|
+
unixSockets: z.record(z.string(), codexAppServerNetworkProxyUnixSocketPermissionSchema).optional(),
|
|
367
|
+
proxyUrl: z.string().trim().min(1).optional(),
|
|
368
|
+
socksUrl: z.string().trim().min(1).optional(),
|
|
369
|
+
enableSocks5: z.boolean().optional(),
|
|
370
|
+
enableSocks5Udp: z.boolean().optional(),
|
|
371
|
+
allowUpstreamProxy: z.boolean().optional(),
|
|
372
|
+
allowLocalBinding: z.boolean().optional(),
|
|
373
|
+
dangerouslyAllowNonLoopbackProxy: z.boolean().optional(),
|
|
374
|
+
dangerouslyAllowAllUnixSockets: z.boolean().optional()
|
|
375
|
+
}).strict();
|
|
376
|
+
const codexPluginEntryConfigSchema = z.object({
|
|
377
|
+
enabled: z.boolean().optional(),
|
|
378
|
+
marketplaceName: z.string().regex(CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN).optional(),
|
|
379
|
+
pluginName: z.string().trim().min(1).optional(),
|
|
380
|
+
allow_destructive_actions: codexPluginDestructivePolicySchema.optional()
|
|
381
|
+
}).strict();
|
|
382
|
+
const codexPluginsConfigSchema = z.object({
|
|
383
|
+
enabled: z.boolean().optional(),
|
|
384
|
+
allow_all_plugins: z.boolean().optional(),
|
|
385
|
+
allow_destructive_actions: codexPluginDestructivePolicySchema.optional(),
|
|
386
|
+
plugins: z.record(z.string(), codexPluginEntryConfigSchema).optional()
|
|
387
|
+
}).strict();
|
|
388
|
+
const codexSupervisionEndpointSchema = z.union([z.object({
|
|
389
|
+
id: z.string().optional(),
|
|
390
|
+
label: z.string().optional(),
|
|
391
|
+
transport: z.literal("stdio-proxy").optional(),
|
|
392
|
+
command: z.string().optional(),
|
|
393
|
+
args: z.array(z.string()).optional(),
|
|
394
|
+
cwd: z.string().optional()
|
|
395
|
+
}).strict(), z.object({
|
|
396
|
+
id: z.string().optional(),
|
|
397
|
+
label: z.string().optional(),
|
|
398
|
+
transport: z.literal("websocket"),
|
|
399
|
+
url: z.string(),
|
|
400
|
+
authTokenEnv: z.string().optional()
|
|
401
|
+
}).strict()]);
|
|
402
|
+
const codexSupervisionConfigSchema = z.object({
|
|
403
|
+
enabled: z.boolean().optional(),
|
|
404
|
+
endpoints: z.array(codexSupervisionEndpointSchema).optional(),
|
|
405
|
+
allowRawTranscripts: z.boolean().optional(),
|
|
406
|
+
allowWriteControls: z.boolean().optional()
|
|
407
|
+
}).strict();
|
|
408
|
+
const codexPluginConfigSchema = z.object({
|
|
409
|
+
codexDynamicToolsLoading: codexDynamicToolsLoadingSchema.optional(),
|
|
410
|
+
codexDynamicToolsExclude: z.array(z.string()).optional(),
|
|
411
|
+
sessionCatalog: codexSessionCatalogConfigSchema.optional(),
|
|
412
|
+
discovery: codexDiscoveryConfigSchema.optional(),
|
|
413
|
+
computerUse: z.object({
|
|
414
|
+
enabled: z.boolean().optional(),
|
|
415
|
+
autoInstall: z.boolean().optional(),
|
|
416
|
+
marketplaceDiscoveryTimeoutMs: z.number().positive().optional(),
|
|
417
|
+
liveTestTimeoutMs: z.number().positive().optional(),
|
|
418
|
+
toolCallTimeoutMs: z.number().positive().optional(),
|
|
419
|
+
healthCheckEnabled: z.boolean().optional(),
|
|
420
|
+
healthCheckIntervalMinutes: codexComputerUseHealthIntervalSchema.optional(),
|
|
421
|
+
pluginCacheMode: codexComputerUsePluginCacheModeSchema.optional(),
|
|
422
|
+
strictReadiness: z.boolean().optional(),
|
|
423
|
+
autoRepair: z.boolean().optional(),
|
|
424
|
+
marketplaceSource: z.string().optional(),
|
|
425
|
+
marketplacePath: z.string().optional(),
|
|
426
|
+
marketplaceName: z.string().optional(),
|
|
427
|
+
pluginName: z.string().optional(),
|
|
428
|
+
mcpServerName: z.string().optional()
|
|
429
|
+
}).strict().optional(),
|
|
430
|
+
codexPlugins: z.unknown().optional(),
|
|
431
|
+
supervision: codexSupervisionConfigSchema.optional(),
|
|
432
|
+
appServer: z.object({
|
|
433
|
+
mode: codexAppServerPolicyModeSchema.optional(),
|
|
434
|
+
transport: codexAppServerTransportSchema.optional(),
|
|
435
|
+
homeScope: codexAppServerHomeScopeSchema.optional(),
|
|
436
|
+
command: z.string().optional(),
|
|
437
|
+
args: z.union([z.array(z.string()), z.string()]).optional(),
|
|
438
|
+
url: z.string().optional(),
|
|
439
|
+
authToken: SecretInputSchema.optional(),
|
|
440
|
+
headers: z.record(z.string(), SecretInputSchema).optional(),
|
|
441
|
+
clearEnv: z.array(z.string()).optional(),
|
|
442
|
+
remoteWorkspaceRoot: codexAppServerRemoteWorkspaceRootSchema.optional(),
|
|
443
|
+
codeModeOnly: z.boolean().optional(),
|
|
444
|
+
loopDetectionPreToolUseRelay: z.boolean().optional(),
|
|
445
|
+
requestTimeoutMs: z.number().positive().optional(),
|
|
446
|
+
turnCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
447
|
+
turnAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
448
|
+
postToolRawAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
449
|
+
approvalPolicy: codexAppServerApprovalPolicySchema.optional(),
|
|
450
|
+
sandbox: codexAppServerSandboxSchema.optional(),
|
|
451
|
+
approvalsReviewer: codexAppServerApprovalsReviewerSchema.optional(),
|
|
452
|
+
serviceTier: codexAppServerServiceTierSchema,
|
|
453
|
+
networkProxy: codexAppServerNetworkProxySchema.optional(),
|
|
454
|
+
defaultWorkspaceDir: z.string().optional(),
|
|
455
|
+
experimental: codexAppServerExperimentalSchema.optional()
|
|
456
|
+
}).strict().optional()
|
|
457
|
+
}).strict();
|
|
458
|
+
function readCodexPluginConfig(value) {
|
|
459
|
+
if (asNullableRecord(asNullableRecord(value)?.appServer)?.approvalPolicy === "untrusted") throw new Error("plugins.entries.codex.config.appServer.approvalPolicy=\"untrusted\" is retired; run \"openclaw doctor --fix\" to migrate it to \"on-request\".");
|
|
460
|
+
const parsed = codexPluginConfigSchema.safeParse(value);
|
|
461
|
+
if (!parsed.success) return {};
|
|
462
|
+
const { codexPlugins: rawCodexPlugins, ...config } = parsed.data;
|
|
463
|
+
const plugins = codexPluginsConfigSchema.safeParse(rawCodexPlugins);
|
|
464
|
+
if (!plugins.success) return config;
|
|
465
|
+
return {
|
|
466
|
+
...config,
|
|
467
|
+
...plugins.data ? { codexPlugins: plugins.data } : {}
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
function isCodexSandboxExecServerEnabled(pluginConfig, sandbox) {
|
|
471
|
+
return isCodexRemoteExecPlacementSandbox(sandbox) || readCodexPluginConfig(pluginConfig).appServer?.experimental?.sandboxExecServer === true;
|
|
472
|
+
}
|
|
473
|
+
function isCodexRemoteExecPlacementSandbox(sandbox) {
|
|
474
|
+
return typeof sandbox === "object" && sandbox !== null && "placementExecutionMode" in sandbox && sandbox.placementExecutionMode === "remote-exec";
|
|
475
|
+
}
|
|
476
|
+
function isCodexPairedNodeRemoteExecPlacementSandbox(sandbox) {
|
|
477
|
+
return isCodexRemoteExecPlacementSandbox(sandbox) && typeof sandbox === "object" && sandbox !== null && "placementNodeId" in sandbox && typeof sandbox.placementNodeId === "string" && sandbox.placementNodeId.length > 0;
|
|
478
|
+
}
|
|
479
|
+
function assertCodexAppServerCommandHasNoInlineArgs(params) {
|
|
480
|
+
const inlineArgs = detectWindowsSpawnCommandInlineArgs(params.command);
|
|
481
|
+
if (!inlineArgs) return;
|
|
482
|
+
const sourceLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_BIN" : "plugins.entries.codex.config.appServer.command";
|
|
483
|
+
const argsLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_ARGS" : "plugins.entries.codex.config.appServer.args";
|
|
484
|
+
throw new Error(`${sourceLabel} must be only the Codex app-server executable path; "${inlineArgs.executable}" was configured with inline arguments "${inlineArgs.arguments}". Move those arguments to ${argsLabel}, or remove the override to use the managed Codex startup path.`);
|
|
485
|
+
}
|
|
486
|
+
function resolveCodexPluginsPolicy(pluginConfig) {
|
|
487
|
+
const config = readCodexPluginConfig(pluginConfig).codexPlugins;
|
|
488
|
+
const configured = config !== void 0;
|
|
489
|
+
const enabled = config?.enabled === true;
|
|
490
|
+
const destructivePolicy = resolveCodexPluginDestructivePolicy(config?.allow_destructive_actions ?? true);
|
|
491
|
+
const pluginPolicies = Object.entries(config?.plugins ?? {}).flatMap(([configKey, entry]) => {
|
|
492
|
+
if (!isCodexPluginMarketplaceName(entry.marketplaceName) || !entry.pluginName) return [];
|
|
493
|
+
const entryDestructivePolicy = resolveCodexPluginDestructivePolicy(entry.allow_destructive_actions ?? config?.allow_destructive_actions ?? true);
|
|
494
|
+
return [{
|
|
495
|
+
configKey,
|
|
496
|
+
marketplaceName: entry.marketplaceName,
|
|
497
|
+
pluginName: entry.pluginName,
|
|
498
|
+
enabled: enabled && entry.enabled !== false,
|
|
499
|
+
allowDestructiveActions: entryDestructivePolicy.allowDestructiveActions,
|
|
500
|
+
destructiveApprovalMode: entryDestructivePolicy.destructiveApprovalMode
|
|
501
|
+
}];
|
|
502
|
+
}).toSorted((left, right) => left.configKey.localeCompare(right.configKey));
|
|
503
|
+
return {
|
|
504
|
+
configured,
|
|
505
|
+
enabled,
|
|
506
|
+
allowAllPlugins: enabled && config?.allow_all_plugins === true,
|
|
507
|
+
allowDestructiveActions: destructivePolicy.allowDestructiveActions,
|
|
508
|
+
destructiveApprovalMode: destructivePolicy.destructiveApprovalMode,
|
|
509
|
+
pluginPolicies
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
function isCodexPluginMarketplaceName(value) {
|
|
513
|
+
return typeof value === "string" && CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN.test(value);
|
|
514
|
+
}
|
|
515
|
+
function resolveCodexPluginDestructivePolicy(policy) {
|
|
516
|
+
if (policy === "auto" || policy === "ask") return {
|
|
517
|
+
allowDestructiveActions: true,
|
|
518
|
+
destructiveApprovalMode: policy
|
|
519
|
+
};
|
|
520
|
+
return {
|
|
521
|
+
allowDestructiveActions: policy,
|
|
522
|
+
destructiveApprovalMode: policy ? "allow" : "deny"
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
//#endregion
|
|
277
526
|
//#region extensions/codex/src/app-server/config-requirements.ts
|
|
278
527
|
const UNIX_CODEX_REQUIREMENTS_PATH = "/etc/codex/requirements.toml";
|
|
279
528
|
const WINDOWS_CODEX_REQUIREMENTS_SUFFIX = "\\OpenAI\\Codex\\requirements.toml";
|
|
280
|
-
function isCodexAppServerApprovalPolicyAllowedByRequirements(policy, params = {}) {
|
|
281
|
-
const content = readCodexRequirementsToml(params);
|
|
282
|
-
if (content === void 0) return true;
|
|
283
|
-
const allowedApprovalPolicies = parseAllowedApprovalPoliciesFromCodexRequirements(content);
|
|
284
|
-
return allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has(policy);
|
|
285
|
-
}
|
|
286
529
|
function readCodexRequirementsToml(params) {
|
|
287
530
|
if (params.requirementsToml !== void 0) return params.requirementsToml ?? void 0;
|
|
288
531
|
const requirementsPath = readNonEmptyString(params.requirementsPath) ?? resolveCodexRequirementsPath(params.env ?? process.env, params.platform ?? process.platform);
|
|
@@ -449,6 +692,7 @@ function globPatternMatches(value, pattern) {
|
|
|
449
692
|
function normalizeRequirementsApprovalPolicy(value) {
|
|
450
693
|
const normalized = value.trim().toLowerCase();
|
|
451
694
|
if (normalized === "on-failure") return "on-request";
|
|
695
|
+
if (normalized === "untrusted") return normalized;
|
|
452
696
|
return resolveApprovalPolicy(normalized);
|
|
453
697
|
}
|
|
454
698
|
function normalizeRequirementsApprovalsReviewer(value) {
|
|
@@ -456,8 +700,8 @@ function normalizeRequirementsApprovalsReviewer(value) {
|
|
|
456
700
|
}
|
|
457
701
|
function selectGuardianApprovalPolicy(allowedApprovalPolicies, execModeRequiringPromptingApprovals) {
|
|
458
702
|
if (allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has("on-request")) return "on-request";
|
|
459
|
-
if (execModeRequiringPromptingApprovals) throw new Error(`tools.exec.mode=${execModeRequiringPromptingApprovals} requires Codex app-server prompting approvals`);
|
|
460
703
|
if (allowedApprovalPolicies.has("untrusted")) return "untrusted";
|
|
704
|
+
if (execModeRequiringPromptingApprovals) throw new Error(`tools.exec.mode=${execModeRequiringPromptingApprovals} requires Codex app-server prompting approvals`);
|
|
461
705
|
if (allowedApprovalPolicies.has("never")) return "never";
|
|
462
706
|
return "on-request";
|
|
463
707
|
}
|
|
@@ -474,14 +718,30 @@ function selectUserApprovalsReviewer(allowedApprovalsReviewers, execModeRequirin
|
|
|
474
718
|
}
|
|
475
719
|
//#endregion
|
|
476
720
|
//#region extensions/codex/src/app-server/config-reviewer.ts
|
|
477
|
-
const CODEX_APP_SERVER_HOME_DIRNAME = "codex-home";
|
|
478
721
|
const CODEX_CONFIG_TOML_FILENAME = "config.toml";
|
|
722
|
+
/** Cloud/system config can redirect reviews after local home/profile checks have passed. */
|
|
723
|
+
async function assertCodexModelBackedReviewerEffectiveConfig(params) {
|
|
724
|
+
if (params.approvalsReviewer !== "auto_review" && params.approvalsReviewer !== "guardian_subagent") return;
|
|
725
|
+
const effectiveConfig = readRecord(readRecord(await params.client.request("config/read", {
|
|
726
|
+
cwd: path.resolve(params.cwd),
|
|
727
|
+
includeLayers: false
|
|
728
|
+
}, { signal: params.signal }))?.config);
|
|
729
|
+
if (!effectiveConfig) throw new Error("Codex config/read returned an invalid model-backed reviewer config");
|
|
730
|
+
const modelProvider = effectiveConfig.model_provider;
|
|
731
|
+
const providers = effectiveConfig.model_providers;
|
|
732
|
+
const providerRecords = providers == null ? void 0 : readRecord(providers);
|
|
733
|
+
const provider = providerRecords?.openai;
|
|
734
|
+
const openAIProvider = provider == null ? void 0 : readRecord(provider);
|
|
735
|
+
if (modelProvider != null && modelProvider !== "openai" || providers != null && !providerRecords || provider != null && !openAIProvider || !isTrustedOptionalReviewerEndpoint(effectiveConfig.openai_base_url, isNativeOpenAIBaseUrl) || !isTrustedOptionalReviewerEndpoint(effectiveConfig.chatgpt_base_url, isNativeChatGPTBaseUrl) || !isTrustedOptionalReviewerEndpoint(openAIProvider?.base_url, isNativeOpenAIBaseUrl)) throw new Error("Codex model-backed approval reviewer requires the running server to use a trusted OpenAI endpoint");
|
|
736
|
+
}
|
|
737
|
+
function isTrustedOptionalReviewerEndpoint(value, isTrusted) {
|
|
738
|
+
return value == null || typeof value === "string" && isTrusted(value);
|
|
739
|
+
}
|
|
479
740
|
function canUseCodexModelBackedApprovalsReviewerForModel(params) {
|
|
480
741
|
const explicitProvider = params.modelProvider?.trim().toLowerCase();
|
|
481
742
|
const inferredProvider = inferProviderFromModelRef(params.model);
|
|
482
|
-
if (explicitProvider && explicitProvider !== "codex"
|
|
483
|
-
|
|
484
|
-
return isTrustedCodexModelBackedApprovalsReviewerProvider(explicitProvider, params);
|
|
743
|
+
if (explicitProvider && explicitProvider !== "codex" && explicitProvider !== "openai") return false;
|
|
744
|
+
return (inferredProvider ?? explicitProvider) === "openai" && isTrustedCodexModelBackedOpenAIProvider(params);
|
|
485
745
|
}
|
|
486
746
|
function isTrustedCodexModelBackedOpenAIProvider(params) {
|
|
487
747
|
if (!openAIBaseUrlEnvOverridesAreTrustedForModelBackedReview(params.env)) return false;
|
|
@@ -518,43 +778,50 @@ function resolveCodexModelBackedReviewerPolicyContext(params) {
|
|
|
518
778
|
model: params.model ?? params.bindingModel
|
|
519
779
|
};
|
|
520
780
|
}
|
|
521
|
-
function isCodexModelBackedApprovalsReviewerProvider(provider) {
|
|
522
|
-
return provider?.trim().toLowerCase() === "openai";
|
|
523
|
-
}
|
|
524
|
-
function isTrustedCodexModelBackedApprovalsReviewerProvider(provider, params) {
|
|
525
|
-
return isCodexModelBackedApprovalsReviewerProvider(provider) && isTrustedCodexModelBackedOpenAIProvider({
|
|
526
|
-
config: params.config,
|
|
527
|
-
env: params.env,
|
|
528
|
-
model: params.model,
|
|
529
|
-
agentDir: params.agentDir,
|
|
530
|
-
codexConfigToml: params.codexConfigToml,
|
|
531
|
-
homeScope: params.homeScope
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
781
|
function readCodexBaseUrlOverridesForModelBackedReview(params) {
|
|
535
782
|
const configToml = readCodexAppServerConfigToml(params);
|
|
536
783
|
if (configToml === false) return false;
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const
|
|
542
|
-
const
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
parseInlineOpenAIModelProviderBaseUrl(topLevelContent),
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
const chatGPT = [chatGPTBaseUrl];
|
|
784
|
+
const configTomls = configToml === void 0 ? [] : [configToml];
|
|
785
|
+
const nativeOverrides = readNativeCodexReviewerConfigOverrides(params);
|
|
786
|
+
if (nativeOverrides === false) return false;
|
|
787
|
+
configTomls.push(...nativeOverrides);
|
|
788
|
+
const openAI = [];
|
|
789
|
+
const chatGPT = [];
|
|
790
|
+
for (const content of configTomls) {
|
|
791
|
+
const topLevelContent = stripTomlLineComments(content).slice(0, firstTomlTableOffset(content));
|
|
792
|
+
const modelProviderOpenAISection = parseTomlTableSection(content, "model_providers.openai");
|
|
793
|
+
const modelProvider = parseTomlStringValue(topLevelContent, "model_provider");
|
|
794
|
+
if (modelProvider === false || modelProvider && modelProvider !== "openai") return false;
|
|
795
|
+
openAI.push(parseTomlStringValue(topLevelContent, "openai_base_url"), parseTomlStringValue(topLevelContent, "model_providers.openai.base_url"), parseInlineOpenAIModelProviderBaseUrl(topLevelContent), modelProviderOpenAISection ? parseTomlStringValue(modelProviderOpenAISection, "base_url") : void 0);
|
|
796
|
+
chatGPT.push(parseTomlStringValue(topLevelContent, "chatgpt_base_url"));
|
|
797
|
+
}
|
|
552
798
|
if ([...openAI, ...chatGPT].includes(false)) return false;
|
|
553
799
|
return {
|
|
554
800
|
openAI: openAI.filter((entry) => typeof entry === "string"),
|
|
555
801
|
chatGPT: chatGPT.filter((entry) => typeof entry === "string")
|
|
556
802
|
};
|
|
557
803
|
}
|
|
804
|
+
function readNativeCodexReviewerConfigOverrides(params) {
|
|
805
|
+
if (params.codexArgs?.some((arg) => !arg)) return false;
|
|
806
|
+
const overrides = [];
|
|
807
|
+
let profile;
|
|
808
|
+
for (const { name, value } of readCodexAppServerConfigOptions(params.codexArgs ?? [])) {
|
|
809
|
+
if (!value) return false;
|
|
810
|
+
if (name === "--profile" || name === "-p") profile = value;
|
|
811
|
+
else overrides.push(`${value}\n`);
|
|
812
|
+
}
|
|
813
|
+
if (profile) {
|
|
814
|
+
if (path.basename(profile) !== profile || profile === "." || profile === "..") return false;
|
|
815
|
+
const configPath = resolveCodexAppServerConfigPath(params);
|
|
816
|
+
if (!configPath) return false;
|
|
817
|
+
try {
|
|
818
|
+
overrides.unshift(readFileSync(path.join(path.dirname(configPath), `${profile}.config.toml`), "utf8"));
|
|
819
|
+
} catch (error) {
|
|
820
|
+
if (readErrorCode(error) !== "ENOENT") return false;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return overrides;
|
|
824
|
+
}
|
|
558
825
|
function readCodexAppServerConfigToml(params) {
|
|
559
826
|
if (params.codexConfigToml !== void 0) return params.codexConfigToml ?? void 0;
|
|
560
827
|
const configPath = resolveCodexAppServerConfigPath(params);
|
|
@@ -591,13 +858,7 @@ function codexConfigEnablesNativeComputerUse(params) {
|
|
|
591
858
|
function resolveCodexAppServerConfigPath(params) {
|
|
592
859
|
if (params.homeScope === "user") return path.join(resolveCodexAppServerUserHomeDir(params.env), CODEX_CONFIG_TOML_FILENAME);
|
|
593
860
|
const agentDir = readNonEmptyString(params.agentDir);
|
|
594
|
-
|
|
595
|
-
return codexHome ? path.join(codexHome, CODEX_CONFIG_TOML_FILENAME) : void 0;
|
|
596
|
-
}
|
|
597
|
-
/** Resolves the native user Codex home used by Desktop and the CLI. */
|
|
598
|
-
function resolveCodexAppServerUserHomeDir(env = process.env, homedir$1 = homedir) {
|
|
599
|
-
const configured = readNonEmptyString(env.CODEX_HOME);
|
|
600
|
-
return path.resolve(configured ?? path.join(homedir$1(), ".codex"));
|
|
861
|
+
return agentDir ? path.join(resolveCodexAppServerHomeDir(agentDir), CODEX_CONFIG_TOML_FILENAME) : void 0;
|
|
601
862
|
}
|
|
602
863
|
function readErrorCode(error) {
|
|
603
864
|
return error && typeof error === "object" && "code" in error ? String(error.code) : void 0;
|
|
@@ -671,227 +932,6 @@ function inferProviderFromModelRef(model) {
|
|
|
671
932
|
return slashIndex > 0 ? normalized?.slice(0, slashIndex) : void 0;
|
|
672
933
|
}
|
|
673
934
|
//#endregion
|
|
674
|
-
//#region extensions/codex/src/app-server/config-contracts.ts
|
|
675
|
-
const CODEX_PLUGINS_MARKETPLACE_NAME = "openai-curated";
|
|
676
|
-
const CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME = "workspace-directory";
|
|
677
|
-
const CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
678
|
-
//#endregion
|
|
679
|
-
//#region extensions/codex/src/app-server/session-discovery-config.ts
|
|
680
|
-
const codexSessionCatalogConfigSchema = z.object({ enabled: z.boolean().optional() }).strict();
|
|
681
|
-
const codexDiscoveryConfigSchema = z.object({
|
|
682
|
-
enabled: z.boolean().optional(),
|
|
683
|
-
timeoutMs: z.number().positive().optional()
|
|
684
|
-
}).strict();
|
|
685
|
-
//#endregion
|
|
686
|
-
//#region extensions/codex/src/app-server/config-parsing.ts
|
|
687
|
-
const DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME = "computer-use";
|
|
688
|
-
const DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS = 6e4;
|
|
689
|
-
const DEFAULT_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS = 6e4;
|
|
690
|
-
const DEFAULT_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS = 6e4;
|
|
691
|
-
const DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX = "openclaw-network";
|
|
692
|
-
const codexAppServerTransportSchema = z.enum([
|
|
693
|
-
"stdio",
|
|
694
|
-
"websocket",
|
|
695
|
-
"unix"
|
|
696
|
-
]);
|
|
697
|
-
const codexAppServerHomeScopeSchema = z.enum(["agent", "user"]);
|
|
698
|
-
const SecretInputSchema = buildSecretInputSchema();
|
|
699
|
-
const codexAppServerPolicyModeSchema = z.enum(["yolo", "guardian"]);
|
|
700
|
-
const codexAppServerApprovalPolicySchema = z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
|
|
701
|
-
"never",
|
|
702
|
-
"on-request",
|
|
703
|
-
"untrusted"
|
|
704
|
-
]));
|
|
705
|
-
const codexAppServerSandboxSchema = z.enum([
|
|
706
|
-
"read-only",
|
|
707
|
-
"workspace-write",
|
|
708
|
-
"danger-full-access"
|
|
709
|
-
]);
|
|
710
|
-
const codexAppServerApprovalsReviewerSchema = z.enum([
|
|
711
|
-
"user",
|
|
712
|
-
"auto_review",
|
|
713
|
-
"guardian_subagent"
|
|
714
|
-
]);
|
|
715
|
-
const codexDynamicToolsLoadingSchema = z.enum(["searchable", "direct"]);
|
|
716
|
-
const codexComputerUseHealthIntervalSchema = z.union([
|
|
717
|
-
z.literal(30),
|
|
718
|
-
z.literal(60),
|
|
719
|
-
z.literal(120),
|
|
720
|
-
z.literal(240)
|
|
721
|
-
]);
|
|
722
|
-
const codexComputerUsePluginCacheModeSchema = z.enum(["shared", "independent"]);
|
|
723
|
-
const codexPluginDestructivePolicySchema = z.union([
|
|
724
|
-
z.boolean(),
|
|
725
|
-
z.literal("auto"),
|
|
726
|
-
z.literal("ask")
|
|
727
|
-
]);
|
|
728
|
-
const codexAppServerServiceTierSchema = z.preprocess((value) => value === null ? null : normalizeCodexServiceTier(value), z.string().trim().min(1).nullable().optional()).optional();
|
|
729
|
-
const codexAppServerExperimentalSchema = z.object({ sandboxExecServer: z.boolean().optional() }).strict();
|
|
730
|
-
const codexAppServerRemoteWorkspaceRootSchema = z.string().trim().min(1);
|
|
731
|
-
const codexAppServerNetworkProxyDomainPermissionSchema = z.enum(["allow", "deny"]);
|
|
732
|
-
const codexAppServerNetworkProxyUnixSocketPermissionSchema = z.enum(["allow", "none"]);
|
|
733
|
-
const codexAppServerNetworkProxySchema = z.object({
|
|
734
|
-
enabled: z.boolean().optional(),
|
|
735
|
-
profileName: z.string().trim().min(1).optional(),
|
|
736
|
-
baseProfile: z.enum(["read-only", "workspace"]).optional(),
|
|
737
|
-
mode: z.enum(["limited", "full"]).optional(),
|
|
738
|
-
domains: z.record(z.string(), codexAppServerNetworkProxyDomainPermissionSchema).optional(),
|
|
739
|
-
unixSockets: z.record(z.string(), codexAppServerNetworkProxyUnixSocketPermissionSchema).optional(),
|
|
740
|
-
proxyUrl: z.string().trim().min(1).optional(),
|
|
741
|
-
socksUrl: z.string().trim().min(1).optional(),
|
|
742
|
-
enableSocks5: z.boolean().optional(),
|
|
743
|
-
enableSocks5Udp: z.boolean().optional(),
|
|
744
|
-
allowUpstreamProxy: z.boolean().optional(),
|
|
745
|
-
allowLocalBinding: z.boolean().optional(),
|
|
746
|
-
dangerouslyAllowNonLoopbackProxy: z.boolean().optional(),
|
|
747
|
-
dangerouslyAllowAllUnixSockets: z.boolean().optional()
|
|
748
|
-
}).strict();
|
|
749
|
-
const codexPluginEntryConfigSchema = z.object({
|
|
750
|
-
enabled: z.boolean().optional(),
|
|
751
|
-
marketplaceName: z.string().regex(CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN).optional(),
|
|
752
|
-
pluginName: z.string().trim().min(1).optional(),
|
|
753
|
-
allow_destructive_actions: codexPluginDestructivePolicySchema.optional()
|
|
754
|
-
}).strict();
|
|
755
|
-
const codexPluginsConfigSchema = z.object({
|
|
756
|
-
enabled: z.boolean().optional(),
|
|
757
|
-
allow_all_plugins: z.boolean().optional(),
|
|
758
|
-
allow_destructive_actions: codexPluginDestructivePolicySchema.optional(),
|
|
759
|
-
plugins: z.record(z.string(), codexPluginEntryConfigSchema).optional()
|
|
760
|
-
}).strict();
|
|
761
|
-
const codexSupervisionEndpointSchema = z.union([z.object({
|
|
762
|
-
id: z.string().optional(),
|
|
763
|
-
label: z.string().optional(),
|
|
764
|
-
transport: z.literal("stdio-proxy").optional(),
|
|
765
|
-
command: z.string().optional(),
|
|
766
|
-
args: z.array(z.string()).optional(),
|
|
767
|
-
cwd: z.string().optional()
|
|
768
|
-
}).strict(), z.object({
|
|
769
|
-
id: z.string().optional(),
|
|
770
|
-
label: z.string().optional(),
|
|
771
|
-
transport: z.literal("websocket"),
|
|
772
|
-
url: z.string(),
|
|
773
|
-
authTokenEnv: z.string().optional()
|
|
774
|
-
}).strict()]);
|
|
775
|
-
const codexSupervisionConfigSchema = z.object({
|
|
776
|
-
enabled: z.boolean().optional(),
|
|
777
|
-
endpoints: z.array(codexSupervisionEndpointSchema).optional(),
|
|
778
|
-
allowRawTranscripts: z.boolean().optional(),
|
|
779
|
-
allowWriteControls: z.boolean().optional()
|
|
780
|
-
}).strict();
|
|
781
|
-
const codexPluginConfigSchema = z.object({
|
|
782
|
-
codexDynamicToolsLoading: codexDynamicToolsLoadingSchema.optional(),
|
|
783
|
-
codexDynamicToolsExclude: z.array(z.string()).optional(),
|
|
784
|
-
sessionCatalog: codexSessionCatalogConfigSchema.optional(),
|
|
785
|
-
discovery: codexDiscoveryConfigSchema.optional(),
|
|
786
|
-
computerUse: z.object({
|
|
787
|
-
enabled: z.boolean().optional(),
|
|
788
|
-
autoInstall: z.boolean().optional(),
|
|
789
|
-
marketplaceDiscoveryTimeoutMs: z.number().positive().optional(),
|
|
790
|
-
liveTestTimeoutMs: z.number().positive().optional(),
|
|
791
|
-
toolCallTimeoutMs: z.number().positive().optional(),
|
|
792
|
-
healthCheckEnabled: z.boolean().optional(),
|
|
793
|
-
healthCheckIntervalMinutes: codexComputerUseHealthIntervalSchema.optional(),
|
|
794
|
-
pluginCacheMode: codexComputerUsePluginCacheModeSchema.optional(),
|
|
795
|
-
strictReadiness: z.boolean().optional(),
|
|
796
|
-
autoRepair: z.boolean().optional(),
|
|
797
|
-
marketplaceSource: z.string().optional(),
|
|
798
|
-
marketplacePath: z.string().optional(),
|
|
799
|
-
marketplaceName: z.string().optional(),
|
|
800
|
-
pluginName: z.string().optional(),
|
|
801
|
-
mcpServerName: z.string().optional()
|
|
802
|
-
}).strict().optional(),
|
|
803
|
-
codexPlugins: z.unknown().optional(),
|
|
804
|
-
supervision: codexSupervisionConfigSchema.optional(),
|
|
805
|
-
appServer: z.object({
|
|
806
|
-
mode: codexAppServerPolicyModeSchema.optional(),
|
|
807
|
-
transport: codexAppServerTransportSchema.optional(),
|
|
808
|
-
homeScope: codexAppServerHomeScopeSchema.optional(),
|
|
809
|
-
command: z.string().optional(),
|
|
810
|
-
args: z.union([z.array(z.string()), z.string()]).optional(),
|
|
811
|
-
url: z.string().optional(),
|
|
812
|
-
authToken: SecretInputSchema.optional(),
|
|
813
|
-
headers: z.record(z.string(), SecretInputSchema).optional(),
|
|
814
|
-
clearEnv: z.array(z.string()).optional(),
|
|
815
|
-
remoteWorkspaceRoot: codexAppServerRemoteWorkspaceRootSchema.optional(),
|
|
816
|
-
codeModeOnly: z.boolean().optional(),
|
|
817
|
-
loopDetectionPreToolUseRelay: z.boolean().optional(),
|
|
818
|
-
requestTimeoutMs: z.number().positive().optional(),
|
|
819
|
-
turnCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
820
|
-
turnAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
821
|
-
postToolRawAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
822
|
-
approvalPolicy: codexAppServerApprovalPolicySchema.optional(),
|
|
823
|
-
sandbox: codexAppServerSandboxSchema.optional(),
|
|
824
|
-
approvalsReviewer: codexAppServerApprovalsReviewerSchema.optional(),
|
|
825
|
-
serviceTier: codexAppServerServiceTierSchema,
|
|
826
|
-
networkProxy: codexAppServerNetworkProxySchema.optional(),
|
|
827
|
-
defaultWorkspaceDir: z.string().optional(),
|
|
828
|
-
experimental: codexAppServerExperimentalSchema.optional()
|
|
829
|
-
}).strict().optional()
|
|
830
|
-
}).strict();
|
|
831
|
-
function readCodexPluginConfig(value) {
|
|
832
|
-
const parsed = codexPluginConfigSchema.safeParse(value);
|
|
833
|
-
if (!parsed.success) return {};
|
|
834
|
-
const { codexPlugins: rawCodexPlugins, ...config } = parsed.data;
|
|
835
|
-
const plugins = codexPluginsConfigSchema.safeParse(rawCodexPlugins);
|
|
836
|
-
if (!plugins.success) return config;
|
|
837
|
-
return {
|
|
838
|
-
...config,
|
|
839
|
-
...plugins.data ? { codexPlugins: plugins.data } : {}
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
function isCodexSandboxExecServerEnabled(pluginConfig, sandbox) {
|
|
843
|
-
return isCodexRemoteExecPlacementSandbox(sandbox) || readCodexPluginConfig(pluginConfig).appServer?.experimental?.sandboxExecServer === true;
|
|
844
|
-
}
|
|
845
|
-
function isCodexRemoteExecPlacementSandbox(sandbox) {
|
|
846
|
-
return typeof sandbox === "object" && sandbox !== null && "placementExecutionMode" in sandbox && sandbox.placementExecutionMode === "remote-exec";
|
|
847
|
-
}
|
|
848
|
-
function assertCodexAppServerCommandHasNoInlineArgs(params) {
|
|
849
|
-
const inlineArgs = detectWindowsSpawnCommandInlineArgs(params.command);
|
|
850
|
-
if (!inlineArgs) return;
|
|
851
|
-
const sourceLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_BIN" : "plugins.entries.codex.config.appServer.command";
|
|
852
|
-
const argsLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_ARGS" : "plugins.entries.codex.config.appServer.args";
|
|
853
|
-
throw new Error(`${sourceLabel} must be only the Codex app-server executable path; "${inlineArgs.executable}" was configured with inline arguments "${inlineArgs.arguments}". Move those arguments to ${argsLabel}, or remove the override to use the managed Codex startup path.`);
|
|
854
|
-
}
|
|
855
|
-
function resolveCodexPluginsPolicy(pluginConfig) {
|
|
856
|
-
const config = readCodexPluginConfig(pluginConfig).codexPlugins;
|
|
857
|
-
const configured = config !== void 0;
|
|
858
|
-
const enabled = config?.enabled === true;
|
|
859
|
-
const destructivePolicy = resolveCodexPluginDestructivePolicy(config?.allow_destructive_actions ?? true);
|
|
860
|
-
const pluginPolicies = Object.entries(config?.plugins ?? {}).flatMap(([configKey, entry]) => {
|
|
861
|
-
if (!isCodexPluginMarketplaceName(entry.marketplaceName) || !entry.pluginName) return [];
|
|
862
|
-
const entryDestructivePolicy = resolveCodexPluginDestructivePolicy(entry.allow_destructive_actions ?? config?.allow_destructive_actions ?? true);
|
|
863
|
-
return [{
|
|
864
|
-
configKey,
|
|
865
|
-
marketplaceName: entry.marketplaceName,
|
|
866
|
-
pluginName: entry.pluginName,
|
|
867
|
-
enabled: enabled && entry.enabled !== false,
|
|
868
|
-
allowDestructiveActions: entryDestructivePolicy.allowDestructiveActions,
|
|
869
|
-
destructiveApprovalMode: entryDestructivePolicy.destructiveApprovalMode
|
|
870
|
-
}];
|
|
871
|
-
}).toSorted((left, right) => left.configKey.localeCompare(right.configKey));
|
|
872
|
-
return {
|
|
873
|
-
configured,
|
|
874
|
-
enabled,
|
|
875
|
-
allowAllPlugins: enabled && config?.allow_all_plugins === true,
|
|
876
|
-
allowDestructiveActions: destructivePolicy.allowDestructiveActions,
|
|
877
|
-
destructiveApprovalMode: destructivePolicy.destructiveApprovalMode,
|
|
878
|
-
pluginPolicies
|
|
879
|
-
};
|
|
880
|
-
}
|
|
881
|
-
function isCodexPluginMarketplaceName(value) {
|
|
882
|
-
return typeof value === "string" && CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN.test(value);
|
|
883
|
-
}
|
|
884
|
-
function resolveCodexPluginDestructivePolicy(policy) {
|
|
885
|
-
if (policy === "auto" || policy === "ask") return {
|
|
886
|
-
allowDestructiveActions: true,
|
|
887
|
-
destructiveApprovalMode: policy
|
|
888
|
-
};
|
|
889
|
-
return {
|
|
890
|
-
allowDestructiveActions: policy,
|
|
891
|
-
destructiveApprovalMode: policy ? "allow" : "deny"
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
//#endregion
|
|
895
935
|
//#region extensions/codex/src/app-server/config-security.ts
|
|
896
936
|
function shouldAutoApproveCodexAppServerApprovals(appServer) {
|
|
897
937
|
return appServer.networkProxy === void 0 && appServer.approvalPolicy === "never" && appServer.sandbox === "danger-full-access";
|
|
@@ -956,6 +996,7 @@ function stableStringifyJson(value) {
|
|
|
956
996
|
return JSON.stringify(value);
|
|
957
997
|
}
|
|
958
998
|
function withMcpElicitationsApprovalPolicy(policy) {
|
|
999
|
+
if (policy === "untrusted") return policy;
|
|
959
1000
|
if (typeof policy !== "string") return { granular: {
|
|
960
1001
|
...policy.granular,
|
|
961
1002
|
mcp_elicitations: true
|
|
@@ -1039,7 +1080,7 @@ function resolveDefaultCodexAppServerPolicy(params) {
|
|
|
1039
1080
|
const allowedApprovalPolicies = parseAllowedApprovalPoliciesFromCodexRequirements(content);
|
|
1040
1081
|
const allowedApprovalsReviewers = parseAllowedApprovalsReviewersFromCodexRequirements(content);
|
|
1041
1082
|
const yoloSandboxAllowed = allowedSandboxModes === void 0 || allowedSandboxModes.has("danger-full-access");
|
|
1042
|
-
const yoloApprovalAllowed = allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has("never");
|
|
1083
|
+
const yoloApprovalAllowed = allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has("never") && !allowedApprovalPolicies.has("untrusted");
|
|
1043
1084
|
const yoloReviewerAllowed = allowedApprovalsReviewers === void 0 || allowedApprovalsReviewers.has("user");
|
|
1044
1085
|
if (!params.forceGuardian && yoloSandboxAllowed && yoloApprovalAllowed && yoloReviewerAllowed) return {
|
|
1045
1086
|
mode: "yolo",
|
|
@@ -1069,9 +1110,11 @@ function resolveCodexAppServerHomeScope(params) {
|
|
|
1069
1110
|
}
|
|
1070
1111
|
function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
1071
1112
|
const env = params.env ?? process.env;
|
|
1072
|
-
const
|
|
1113
|
+
const pluginConfig = readCodexPluginConfig(params.pluginConfig);
|
|
1114
|
+
const config = pluginConfig.appServer ?? {};
|
|
1073
1115
|
const transport = resolveTransport(config.transport);
|
|
1074
1116
|
const homeScope = resolveCodexAppServerHomeScope({ appServer: config });
|
|
1117
|
+
if (transport !== "stdio" && pluginConfig.sessionCatalog?.homes?.length) throw new Error("plugins.entries.codex.config.sessionCatalog.homes requires appServer.transport=stdio");
|
|
1075
1118
|
const configCommand = readNonEmptyString(config.command);
|
|
1076
1119
|
const envCommand = readNonEmptyString(env.OPENCLAW_CODEX_APP_SERVER_BIN);
|
|
1077
1120
|
const command = configCommand ?? envCommand ?? "codex";
|
|
@@ -1098,7 +1141,7 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
|
1098
1141
|
execMode: params.execMode,
|
|
1099
1142
|
execPolicy: params.execPolicy
|
|
1100
1143
|
});
|
|
1101
|
-
assertCodexAppServerAllowedForOpenClawExecMode(execMode);
|
|
1144
|
+
if (!params.sessionPermissionMode) assertCodexAppServerAllowedForOpenClawExecMode(execMode);
|
|
1102
1145
|
const explicitPolicyMode = resolvePolicyMode(config.mode) ?? resolvePolicyMode(env.OPENCLAW_CODEX_APP_SERVER_MODE);
|
|
1103
1146
|
const configuredSandbox = resolveSandbox(config.sandbox) ?? resolveSandbox(env.OPENCLAW_CODEX_APP_SERVER_SANDBOX);
|
|
1104
1147
|
const explicitApprovalsReviewer = resolveApprovalsReviewer(config.approvalsReviewer);
|
|
@@ -1117,6 +1160,15 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
|
1117
1160
|
const forceGuardianReviewer = execMode === "auto" && canUseModelBackedReviewer;
|
|
1118
1161
|
const execModeRequiringPromptingApprovals = execMode === "auto" || execMode === "ask" ? execMode : forceUserReviewer ? "ask" : void 0;
|
|
1119
1162
|
const forceDangerFullAccessSandbox = params.execPolicy?.touched === true && params.execPolicy.security === "full" && params.execPolicy.ask === "always";
|
|
1163
|
+
const forcePerCommandApprovals = params.execPolicy?.ask === "always";
|
|
1164
|
+
const requirementsToml = forcePerCommandApprovals ? readCodexRequirementsToml({
|
|
1165
|
+
env,
|
|
1166
|
+
requirementsToml: params.requirementsToml,
|
|
1167
|
+
requirementsPath: params.requirementsPath,
|
|
1168
|
+
readRequirementsFile: params.readRequirementsFile,
|
|
1169
|
+
platform: params.platform
|
|
1170
|
+
}) ?? null : params.requirementsToml;
|
|
1171
|
+
if (forcePerCommandApprovals && requirementsToml && parseAllowedApprovalPoliciesFromCodexRequirements(requirementsToml)?.has("untrusted") === false) throw new Error("tools.exec.ask=always requires Codex app-server per-command approvals");
|
|
1120
1172
|
const forceRuntimePolicy = forceUserReviewer || forceGuardianReviewer || forceDangerFullAccessSandbox;
|
|
1121
1173
|
const defaultPolicy = explicitPolicyMode && !forceRuntimePolicy && !ignoreLegacyYoloPolicyMode ? void 0 : resolveDefaultCodexAppServerPolicy({
|
|
1122
1174
|
transport,
|
|
@@ -1124,7 +1176,7 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
|
1124
1176
|
forceGuardian: normalizedPolicyMode === "guardian",
|
|
1125
1177
|
forceUserReviewer: forceUserReviewer || !canUseModelBackedReviewer,
|
|
1126
1178
|
execModeRequiringPromptingApprovals,
|
|
1127
|
-
requirementsToml
|
|
1179
|
+
requirementsToml,
|
|
1128
1180
|
requirementsPath: params.requirementsPath,
|
|
1129
1181
|
readRequirementsFile: params.readRequirementsFile,
|
|
1130
1182
|
platform: params.platform,
|
|
@@ -1133,7 +1185,7 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
|
1133
1185
|
});
|
|
1134
1186
|
const preserveExplicitAutoSandbox = forceGuardianReviewer && configuredSandbox === "read-only";
|
|
1135
1187
|
const forcedPolicy = forceRuntimePolicy ? {
|
|
1136
|
-
approvalPolicy: defaultPolicy?.approvalPolicy ?? "on-request",
|
|
1188
|
+
approvalPolicy: forcePerCommandApprovals ? "untrusted" : defaultPolicy?.approvalPolicy ?? "on-request",
|
|
1137
1189
|
sandbox: preserveExplicitAutoSandbox ? void 0 : forceDangerFullAccessSandbox ? selectForcedDangerFullAccessSandbox({
|
|
1138
1190
|
configuredSandbox,
|
|
1139
1191
|
defaultPolicy,
|
|
@@ -1295,17 +1347,22 @@ function codexSandboxPolicyForTurn(mode, cwd, nativeArgs = []) {
|
|
|
1295
1347
|
};
|
|
1296
1348
|
let excludeTmpdirEnvVar = false;
|
|
1297
1349
|
let excludeSlashTmp = false;
|
|
1298
|
-
for (
|
|
1299
|
-
|
|
1300
|
-
const override = arg === "-c" || arg === "--config" ? nativeArgs[++index] : arg?.startsWith("--config=") ? arg.slice(9) : void 0;
|
|
1301
|
-
if (!override) continue;
|
|
1350
|
+
for (const { name, value: override } of readCodexAppServerConfigOptions(nativeArgs)) {
|
|
1351
|
+
if (name !== "-c" && name !== "--config" || !override) continue;
|
|
1302
1352
|
const separator = override.indexOf("=");
|
|
1303
1353
|
if (separator < 0) continue;
|
|
1304
1354
|
const key = override.slice(0, separator).trim();
|
|
1305
|
-
const
|
|
1306
|
-
if (
|
|
1307
|
-
|
|
1308
|
-
|
|
1355
|
+
const isTmpdirExclusion = key === "sandbox_workspace_write.exclude_tmpdir_env_var";
|
|
1356
|
+
if (!isTmpdirExclusion && key !== "sandbox_workspace_write.exclude_slash_tmp") continue;
|
|
1357
|
+
let value;
|
|
1358
|
+
try {
|
|
1359
|
+
value = parse(`_x_ = ${override.slice(separator + 1).trim()}`)["_x_"];
|
|
1360
|
+
} catch {
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
if (typeof value !== "boolean") continue;
|
|
1364
|
+
if (isTmpdirExclusion) excludeTmpdirEnvVar = value;
|
|
1365
|
+
else excludeSlashTmp = value;
|
|
1309
1366
|
}
|
|
1310
1367
|
return {
|
|
1311
1368
|
type: "workspaceWrite",
|
|
@@ -1335,861 +1392,4 @@ function resolveCodexSupervisionAppServerRuntimeOptions(params = {}) {
|
|
|
1335
1392
|
});
|
|
1336
1393
|
}
|
|
1337
1394
|
//#endregion
|
|
1338
|
-
|
|
1339
|
-
/** SQLite-backed Codex app-server thread bindings. */
|
|
1340
|
-
var session_binding_exports = /* @__PURE__ */ __exportAll({
|
|
1341
|
-
CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS: () => CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS,
|
|
1342
|
-
CODEX_APP_SERVER_BINDING_MAX_ENTRIES: () => CODEX_APP_SERVER_BINDING_MAX_ENTRIES,
|
|
1343
|
-
CODEX_APP_SERVER_BINDING_NAMESPACE: () => CODEX_APP_SERVER_BINDING_NAMESPACE,
|
|
1344
|
-
CodexSupervisionBindingReplacementError: () => CodexSupervisionBindingReplacementError,
|
|
1345
|
-
assertCodexBindingMayBeReplaced: () => assertCodexBindingMayBeReplaced,
|
|
1346
|
-
bindingStoreKey: () => bindingStoreKey,
|
|
1347
|
-
createCodexAppServerBindingStore: () => createCodexAppServerBindingStore,
|
|
1348
|
-
createCodexSessionGenerationSupersededError: () => createCodexSessionGenerationSupersededError,
|
|
1349
|
-
createStoredCodexAppServerBinding: () => createStoredCodexAppServerBinding,
|
|
1350
|
-
hashCodexAppServerBindingFingerprint: () => hashCodexAppServerBindingFingerprint,
|
|
1351
|
-
isCodexAppServerNativeAuthProfile: () => isCodexAppServerNativeAuthProfile,
|
|
1352
|
-
normalizeCodexAppServerBindingModelProvider: () => normalizeCodexAppServerBindingModelProvider,
|
|
1353
|
-
normalizeStoredCodexAppServerBindingFingerprints: () => normalizeStoredCodexAppServerBindingFingerprints,
|
|
1354
|
-
readCodexAppServerThreadBinding: () => readCodexAppServerThreadBinding,
|
|
1355
|
-
readStoredCodexAppServerBinding: () => readStoredCodexAppServerBinding,
|
|
1356
|
-
reclaimCurrentCodexSessionGeneration: () => reclaimCurrentCodexSessionGeneration,
|
|
1357
|
-
resolveCodexRunSessionBindingAuthority: () => resolveCodexRunSessionBindingAuthority,
|
|
1358
|
-
scopeCodexRunBindingStore: () => scopeCodexRunBindingStore,
|
|
1359
|
-
sessionBindingIdentity: () => sessionBindingIdentity
|
|
1360
|
-
});
|
|
1361
|
-
const CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER = "openai";
|
|
1362
|
-
const PUBLIC_OPENAI_MODEL_PROVIDER = "openai";
|
|
1363
|
-
const BINDING_LEASE_RETRY_INTERVAL_MS = 1e3;
|
|
1364
|
-
const BOUNDED_BINDING_FINGERPRINT_PATTERN = /^sha256:[a-f0-9]{64}$/i;
|
|
1365
|
-
const CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS = 6e4;
|
|
1366
|
-
const BINDING_LEASE_STALE_MS = 65e3;
|
|
1367
|
-
const BINDING_LEASE_WAIT_MS = 7e4;
|
|
1368
|
-
const BINDING_LEASE_RENEW_INTERVAL_MS = Math.floor(BINDING_LEASE_STALE_MS / 3);
|
|
1369
|
-
const PHYSICAL_SESSION_RETIRE_TTL_MS = BINDING_LEASE_WAIT_MS;
|
|
1370
|
-
/** Resolves the same agent scope OpenClaw uses for transcript/session ownership. */
|
|
1371
|
-
function sessionBindingIdentity(params) {
|
|
1372
|
-
const { sessionAgentId } = resolveSessionAgentIds$1(params);
|
|
1373
|
-
const sessionKey = params.sessionKey?.trim();
|
|
1374
|
-
return {
|
|
1375
|
-
kind: "session",
|
|
1376
|
-
agentId: sessionAgentId,
|
|
1377
|
-
sessionId: params.sessionId,
|
|
1378
|
-
...sessionKey ? { sessionKey } : {}
|
|
1379
|
-
};
|
|
1380
|
-
}
|
|
1381
|
-
/** Decides whether a run may share the durable stable-key binding owner. */
|
|
1382
|
-
function resolveCodexRunSessionBindingAuthority(params) {
|
|
1383
|
-
const sessionKey = params.identity.sessionKey?.trim();
|
|
1384
|
-
if (!sessionKey) return "ephemeral";
|
|
1385
|
-
try {
|
|
1386
|
-
const storePath = params.storePath?.trim() || resolveStorePath(params.config?.session?.store, { agentId: params.identity.agentId });
|
|
1387
|
-
const entry = getSessionEntry({
|
|
1388
|
-
agentId: params.identity.agentId,
|
|
1389
|
-
hydrateSkillPromptRefs: false,
|
|
1390
|
-
readConsistency: "latest",
|
|
1391
|
-
sessionKey,
|
|
1392
|
-
storePath
|
|
1393
|
-
});
|
|
1394
|
-
if (!entry) return "ephemeral";
|
|
1395
|
-
return entry.sessionId === params.identity.sessionId ? "current" : "superseded";
|
|
1396
|
-
} catch {
|
|
1397
|
-
return "superseded";
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
/** Builds the terminal coordination error used when a newer OpenClaw session owns the binding. */
|
|
1401
|
-
function createCodexSessionGenerationSupersededError(sessionId) {
|
|
1402
|
-
return new AgentHarnessSessionSupersededError(`Codex session generation is no longer current: ${sessionId}`);
|
|
1403
|
-
}
|
|
1404
|
-
const optionalStringSchema = z.string().optional().catch(void 0);
|
|
1405
|
-
const optionalBooleanSchema = z.boolean().optional().catch(void 0);
|
|
1406
|
-
const optionalNonBlankStringSchema = z.string().refine((value) => Boolean(value.trim())).optional().catch(void 0);
|
|
1407
|
-
const optionalTimestampSchema = z.string().refine((value) => Number.isFinite(Date.parse(value))).optional().catch(void 0);
|
|
1408
|
-
const pendingSupervisionBranchSchema = z.object({
|
|
1409
|
-
sourceThreadId: z.string().trim().min(1),
|
|
1410
|
-
connectionFingerprint: z.string().trim().min(1).optional(),
|
|
1411
|
-
lastTurnId: z.string().trim().min(1).optional(),
|
|
1412
|
-
cleanupThreadIds: z.array(z.string().trim().min(1)).max(2).optional()
|
|
1413
|
-
}).strict().superRefine((pending, context) => {
|
|
1414
|
-
const cleanupThreadIds = pending.cleanupThreadIds ?? [];
|
|
1415
|
-
if (new Set(cleanupThreadIds).size !== cleanupThreadIds.length) context.addIssue({
|
|
1416
|
-
code: "custom",
|
|
1417
|
-
message: "pending supervision cleanup thread ids must be unique"
|
|
1418
|
-
});
|
|
1419
|
-
if (cleanupThreadIds.includes(pending.sourceThreadId)) context.addIssue({
|
|
1420
|
-
code: "custom",
|
|
1421
|
-
message: "pending supervision cleanup cannot target its source"
|
|
1422
|
-
});
|
|
1423
|
-
});
|
|
1424
|
-
const contextEngineProjectionSchema = z.object({
|
|
1425
|
-
schemaVersion: z.literal(1),
|
|
1426
|
-
mode: z.literal("thread_bootstrap"),
|
|
1427
|
-
epoch: z.string().refine((value) => Boolean(value.trim())),
|
|
1428
|
-
fingerprint: optionalStringSchema
|
|
1429
|
-
}).strict();
|
|
1430
|
-
const contextEngineSchema = z.object({
|
|
1431
|
-
schemaVersion: z.literal(1),
|
|
1432
|
-
engineId: z.string(),
|
|
1433
|
-
policyFingerprint: z.string(),
|
|
1434
|
-
projection: contextEngineProjectionSchema.optional().catch(void 0)
|
|
1435
|
-
}).strict();
|
|
1436
|
-
const destructiveApprovalModeSchema = z.enum([
|
|
1437
|
-
"allow",
|
|
1438
|
-
"deny",
|
|
1439
|
-
"auto",
|
|
1440
|
-
"ask"
|
|
1441
|
-
]).optional().catch(void 0);
|
|
1442
|
-
const accountAppPolicyEntrySchema = z.object({
|
|
1443
|
-
source: z.literal("account"),
|
|
1444
|
-
appName: z.string(),
|
|
1445
|
-
allowDestructiveActions: z.boolean(),
|
|
1446
|
-
allowOpenWorld: z.boolean().optional(),
|
|
1447
|
-
destructiveApprovalMode: destructiveApprovalModeSchema,
|
|
1448
|
-
mcpServerNames: z.array(z.string())
|
|
1449
|
-
}).strict();
|
|
1450
|
-
const pluginAppPolicyEntrySchema = z.object({
|
|
1451
|
-
source: z.literal("plugin").optional(),
|
|
1452
|
-
configKey: z.string(),
|
|
1453
|
-
marketplaceName: z.string().regex(CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN),
|
|
1454
|
-
pluginName: z.string(),
|
|
1455
|
-
allowDestructiveActions: z.boolean(),
|
|
1456
|
-
allowOpenWorld: z.boolean().optional(),
|
|
1457
|
-
destructiveApprovalMode: destructiveApprovalModeSchema,
|
|
1458
|
-
mcpServerNames: z.array(z.string())
|
|
1459
|
-
}).strict();
|
|
1460
|
-
const pluginAppPolicyContextSchema = z.object({
|
|
1461
|
-
fingerprint: z.string(),
|
|
1462
|
-
apps: z.record(z.string(), z.union([accountAppPolicyEntrySchema, pluginAppPolicyEntrySchema])),
|
|
1463
|
-
pluginAppIds: z.record(z.string(), z.array(z.string())).default({})
|
|
1464
|
-
}).strict();
|
|
1465
|
-
const threadBindingSchema = z.object({
|
|
1466
|
-
threadId: z.string().refine((value) => Boolean(value.trim())),
|
|
1467
|
-
clientId: optionalStringSchema,
|
|
1468
|
-
cwd: z.string(),
|
|
1469
|
-
rolloutPath: optionalNonBlankStringSchema,
|
|
1470
|
-
connectionScope: z.literal("supervision").optional(),
|
|
1471
|
-
supervisionSourceThreadId: z.string().trim().min(1).optional(),
|
|
1472
|
-
authProfileId: optionalStringSchema,
|
|
1473
|
-
model: optionalStringSchema,
|
|
1474
|
-
preserveNativeModel: z.literal(true).optional().catch(void 0),
|
|
1475
|
-
pendingSupervisionBranch: pendingSupervisionBranchSchema.optional(),
|
|
1476
|
-
modelProvider: z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0),
|
|
1477
|
-
approvalPolicy: z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
|
|
1478
|
-
"never",
|
|
1479
|
-
"on-request",
|
|
1480
|
-
"untrusted"
|
|
1481
|
-
]).optional()).catch(void 0),
|
|
1482
|
-
sandbox: z.enum([
|
|
1483
|
-
"read-only",
|
|
1484
|
-
"workspace-write",
|
|
1485
|
-
"danger-full-access"
|
|
1486
|
-
]).optional().catch(void 0),
|
|
1487
|
-
serviceTier: z.preprocess(normalizeCodexServiceTier, z.custom((value) => typeof value === "string").optional()).optional().catch(void 0),
|
|
1488
|
-
networkProxyProfileName: optionalStringSchema,
|
|
1489
|
-
networkProxyConfigFingerprint: optionalStringSchema,
|
|
1490
|
-
dynamicToolsFingerprint: optionalStringSchema,
|
|
1491
|
-
dynamicToolsContainDeferred: optionalBooleanSchema,
|
|
1492
|
-
webSearchThreadConfigFingerprint: optionalStringSchema,
|
|
1493
|
-
nativeSkillIsolationFingerprint: optionalStringSchema,
|
|
1494
|
-
userMcpServersFingerprint: optionalStringSchema,
|
|
1495
|
-
mcpServersFingerprint: optionalStringSchema,
|
|
1496
|
-
configuredMcpOwnershipVersion: z.literal(1).optional().catch(void 0),
|
|
1497
|
-
ringZeroConfigFingerprint: optionalStringSchema,
|
|
1498
|
-
ringZeroClientInstanceId: optionalStringSchema,
|
|
1499
|
-
/** Durable fact preventing a later unrestricted turn from widening this thread. */
|
|
1500
|
-
nativeToolPolicyRestricted: z.literal(true).optional().catch(void 0),
|
|
1501
|
-
nativeHookRelayGeneration: optionalNonBlankStringSchema,
|
|
1502
|
-
appServerRuntimeFingerprint: optionalStringSchema,
|
|
1503
|
-
pluginAppsFingerprint: optionalStringSchema,
|
|
1504
|
-
pluginAppsInputFingerprint: optionalStringSchema,
|
|
1505
|
-
pluginAppPolicyContext: pluginAppPolicyContextSchema.optional().catch(void 0),
|
|
1506
|
-
contextEngine: contextEngineSchema.optional().catch(void 0),
|
|
1507
|
-
environmentSelectionFingerprint: optionalStringSchema,
|
|
1508
|
-
conversationStartId: optionalStringSchema,
|
|
1509
|
-
conversationSourceTransferComplete: z.literal(true).optional().catch(void 0),
|
|
1510
|
-
historyCoveredThrough: optionalTimestampSchema
|
|
1511
|
-
}).superRefine((binding, context) => {
|
|
1512
|
-
if (binding.connectionScope === "supervision") {
|
|
1513
|
-
if (!binding.supervisionSourceThreadId) context.addIssue({
|
|
1514
|
-
code: "custom",
|
|
1515
|
-
message: "supervision connection ownership requires its native source thread id"
|
|
1516
|
-
});
|
|
1517
|
-
if (binding.preserveNativeModel !== true) context.addIssue({
|
|
1518
|
-
code: "custom",
|
|
1519
|
-
message: "supervision connection ownership requires native model ownership"
|
|
1520
|
-
});
|
|
1521
|
-
if (binding.conversationSourceTransferComplete !== true) context.addIssue({
|
|
1522
|
-
code: "custom",
|
|
1523
|
-
message: "supervision connection ownership requires a completed source transfer"
|
|
1524
|
-
});
|
|
1525
|
-
if (!binding.pendingSupervisionBranch && (!binding.model?.trim() || !binding.modelProvider)) context.addIssue({
|
|
1526
|
-
code: "custom",
|
|
1527
|
-
message: "materialized supervision bindings require a native model and provider"
|
|
1528
|
-
});
|
|
1529
|
-
}
|
|
1530
|
-
if (binding.supervisionSourceThreadId && binding.connectionScope !== "supervision") context.addIssue({
|
|
1531
|
-
code: "custom",
|
|
1532
|
-
message: "a supervision source thread id requires supervision connection ownership"
|
|
1533
|
-
});
|
|
1534
|
-
if (!binding.pendingSupervisionBranch) return;
|
|
1535
|
-
if (binding.threadId !== binding.pendingSupervisionBranch.sourceThreadId) context.addIssue({
|
|
1536
|
-
code: "custom",
|
|
1537
|
-
message: "pending supervision source must match the provisional thread binding"
|
|
1538
|
-
});
|
|
1539
|
-
if (binding.supervisionSourceThreadId !== binding.pendingSupervisionBranch.sourceThreadId) context.addIssue({
|
|
1540
|
-
code: "custom",
|
|
1541
|
-
message: "pending supervision source must match its durable source identity"
|
|
1542
|
-
});
|
|
1543
|
-
if (binding.preserveNativeModel !== true) context.addIssue({
|
|
1544
|
-
code: "custom",
|
|
1545
|
-
message: "pending supervision bindings must defer model selection to Codex App Server"
|
|
1546
|
-
});
|
|
1547
|
-
if (binding.connectionScope !== "supervision") context.addIssue({
|
|
1548
|
-
code: "custom",
|
|
1549
|
-
message: "pending supervision bindings require supervision connection ownership"
|
|
1550
|
-
});
|
|
1551
|
-
});
|
|
1552
|
-
var CodexSupervisionBindingReplacementError = class extends Error {
|
|
1553
|
-
constructor(threadId, operation) {
|
|
1554
|
-
super(`Refusing to replace supervised Codex thread ${threadId} while ${operation}; its native user-home connection and model ownership must be preserved`);
|
|
1555
|
-
this.name = "CodexSupervisionBindingReplacementError";
|
|
1556
|
-
}
|
|
1557
|
-
};
|
|
1558
|
-
function assertCodexBindingMayBeReplaced(binding, operation) {
|
|
1559
|
-
if (binding?.connectionScope === "supervision") throw new CodexSupervisionBindingReplacementError(binding.threadId, operation);
|
|
1560
|
-
}
|
|
1561
|
-
const bindingLeaseSchema = z.object({
|
|
1562
|
-
token: z.string().refine((value) => Boolean(value.trim())),
|
|
1563
|
-
expiresAt: z.number().finite()
|
|
1564
|
-
});
|
|
1565
|
-
const storedSessionIdSchema = z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0);
|
|
1566
|
-
const storedBindingSchema = z.discriminatedUnion("state", [z.object({
|
|
1567
|
-
version: z.literal(1),
|
|
1568
|
-
state: z.literal("active"),
|
|
1569
|
-
binding: threadBindingSchema,
|
|
1570
|
-
sessionId: storedSessionIdSchema,
|
|
1571
|
-
lease: bindingLeaseSchema.optional().catch(void 0)
|
|
1572
|
-
}), z.object({
|
|
1573
|
-
version: z.literal(1),
|
|
1574
|
-
state: z.literal("cleared"),
|
|
1575
|
-
sessionId: storedSessionIdSchema,
|
|
1576
|
-
lease: bindingLeaseSchema.optional().catch(void 0),
|
|
1577
|
-
retired: z.literal(true).optional().catch(void 0)
|
|
1578
|
-
})]);
|
|
1579
|
-
function hashCodexAppServerBindingFingerprint(canonical) {
|
|
1580
|
-
return `sha256:${createHash("sha256").update(canonical).digest("hex")}`;
|
|
1581
|
-
}
|
|
1582
|
-
function normalizeLegacyBindingFingerprint(value) {
|
|
1583
|
-
if (typeof value !== "string" || value === "" || value === "[]" || BOUNDED_BINDING_FINGERPRINT_PATTERN.test(value)) return value;
|
|
1584
|
-
return hashCodexAppServerBindingFingerprint(value);
|
|
1585
|
-
}
|
|
1586
|
-
function normalizeLegacyBindingFingerprints(record) {
|
|
1587
|
-
let normalized = record;
|
|
1588
|
-
for (const key of ["dynamicToolsFingerprint", "userMcpServersFingerprint"]) {
|
|
1589
|
-
const value = record[key];
|
|
1590
|
-
const next = normalizeLegacyBindingFingerprint(value);
|
|
1591
|
-
if (next === value) continue;
|
|
1592
|
-
if (normalized === record) normalized = { ...record };
|
|
1593
|
-
normalized[key] = next;
|
|
1594
|
-
}
|
|
1595
|
-
return normalized;
|
|
1596
|
-
}
|
|
1597
|
-
function normalizeStoredCodexAppServerBindingFingerprints(value) {
|
|
1598
|
-
const stored = readStoredCodexAppServerBinding(value);
|
|
1599
|
-
if (!stored || stored.state !== "active") return stored;
|
|
1600
|
-
const binding = normalizeLegacyBindingFingerprints(stored.binding);
|
|
1601
|
-
return binding === stored.binding ? stored : readStoredCodexAppServerBinding({
|
|
1602
|
-
...stored,
|
|
1603
|
-
binding
|
|
1604
|
-
});
|
|
1605
|
-
}
|
|
1606
|
-
/** Encodes a migrated sidecar binding as one canonical plugin-state row. */
|
|
1607
|
-
function createStoredCodexAppServerBinding(value, options = {}) {
|
|
1608
|
-
const rawRecord = asOptionalRecord(value);
|
|
1609
|
-
if (!rawRecord) return;
|
|
1610
|
-
const record = normalizeLegacyBindingFingerprints(rawRecord);
|
|
1611
|
-
if (record.schemaVersion !== 1 && record.schemaVersion !== 2) return;
|
|
1612
|
-
const pluginAppPolicyContext = readPluginAppPolicyContext(record.pluginAppPolicyContext, record.schemaVersion);
|
|
1613
|
-
const historyCoveredThrough = readTimestamp(record.historyCoveredThrough) ?? readTimestamp(record.updatedAt) ?? readTimestamp(record.createdAt) ?? readTimestamp(options.now) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1614
|
-
const authProfileId = typeof record.authProfileId === "string" ? record.authProfileId : void 0;
|
|
1615
|
-
const binding = readCodexAppServerThreadBinding({
|
|
1616
|
-
...record,
|
|
1617
|
-
modelProvider: normalizeCodexAppServerBindingModelProvider({
|
|
1618
|
-
...options.lookup,
|
|
1619
|
-
authProfileId,
|
|
1620
|
-
modelProvider: typeof record.modelProvider === "string" ? record.modelProvider : void 0
|
|
1621
|
-
}),
|
|
1622
|
-
cwd: typeof record.cwd === "string" ? record.cwd : "",
|
|
1623
|
-
pluginAppPolicyContext,
|
|
1624
|
-
historyCoveredThrough
|
|
1625
|
-
});
|
|
1626
|
-
return binding ? {
|
|
1627
|
-
version: 1,
|
|
1628
|
-
state: "active",
|
|
1629
|
-
binding: stripUndefinedBinding(binding)
|
|
1630
|
-
} : void 0;
|
|
1631
|
-
}
|
|
1632
|
-
function bindingLeaseLostError(key, cause) {
|
|
1633
|
-
return new Error(`Lost Codex binding lease: ${key}`, cause === void 0 ? void 0 : { cause });
|
|
1634
|
-
}
|
|
1635
|
-
/** Carries one prepared run identity through callers that rederive it from public params. */
|
|
1636
|
-
function scopeCodexRunBindingStore(params) {
|
|
1637
|
-
const mapSessionIdentity = (identity) => identity.agentId === params.logicalIdentity.agentId && identity.sessionId === params.logicalIdentity.sessionId && identity.sessionKey?.trim() === params.logicalIdentity.sessionKey?.trim() ? params.physicalIdentity : identity;
|
|
1638
|
-
const mapIdentity = (identity) => identity.kind === "session" ? mapSessionIdentity(identity) : identity;
|
|
1639
|
-
return {
|
|
1640
|
-
read: (identity) => params.bindingStore.read(mapIdentity(identity)),
|
|
1641
|
-
hasOtherThreadOwner: (threadId, identity) => params.bindingStore.hasOtherThreadOwner(threadId, identity ? mapIdentity(identity) : void 0),
|
|
1642
|
-
mutate: (identity, mutation) => params.bindingStore.mutate(mapIdentity(identity), mutation),
|
|
1643
|
-
prepareSessionGenerationReclaim: (identity) => params.bindingStore.prepareSessionGenerationReclaim(mapSessionIdentity(identity)),
|
|
1644
|
-
adoptSessionGeneration: (identity, expectedPreviousSessionId) => params.bindingStore.adoptSessionGeneration(mapSessionIdentity(identity), expectedPreviousSessionId),
|
|
1645
|
-
resetSessionGeneration: (identity) => params.bindingStore.resetSessionGeneration(mapSessionIdentity(identity)),
|
|
1646
|
-
retireSessionGeneration: (identity) => params.bindingStore.retireSessionGeneration(mapSessionIdentity(identity)),
|
|
1647
|
-
withThreadArchiveFence: (run) => params.bindingStore.withThreadArchiveFence(run),
|
|
1648
|
-
withLease: (identity, run) => params.bindingStore.withLease(mapIdentity(identity), run)
|
|
1649
|
-
};
|
|
1650
|
-
}
|
|
1651
|
-
/** Lets the authoritative OpenClaw session generation claim a stale stable binding row. */
|
|
1652
|
-
async function reclaimCurrentCodexSessionGeneration(params) {
|
|
1653
|
-
const sessionKey = params.identity.sessionKey?.trim();
|
|
1654
|
-
if (!sessionKey) return true;
|
|
1655
|
-
const plan = await params.bindingStore.prepareSessionGenerationReclaim(params.identity);
|
|
1656
|
-
if (plan.kind === "resolved") return plan.result;
|
|
1657
|
-
try {
|
|
1658
|
-
const storePath = params.storePath?.trim() || resolveStorePath(params.config?.session?.store, { agentId: params.identity.agentId });
|
|
1659
|
-
if (getSessionEntry({
|
|
1660
|
-
agentId: params.identity.agentId,
|
|
1661
|
-
hydrateSkillPromptRefs: false,
|
|
1662
|
-
readConsistency: "latest",
|
|
1663
|
-
sessionKey,
|
|
1664
|
-
storePath
|
|
1665
|
-
})?.sessionId !== params.identity.sessionId) return false;
|
|
1666
|
-
} catch {
|
|
1667
|
-
return false;
|
|
1668
|
-
}
|
|
1669
|
-
return await params.bindingStore.mutate(params.identity, {
|
|
1670
|
-
kind: "reclaim-generation",
|
|
1671
|
-
expectedPreviousSessionId: plan.expectedPreviousSessionId
|
|
1672
|
-
});
|
|
1673
|
-
}
|
|
1674
|
-
/** Creates the single binding facade owned by the Codex plugin runtime. */
|
|
1675
|
-
function createCodexAppServerBindingStore(state) {
|
|
1676
|
-
const update = state.update?.bind(state);
|
|
1677
|
-
if (!update) throw new Error("Codex app-server bindings require atomic plugin-state updates");
|
|
1678
|
-
const leaseContext = new AsyncLocalStorage();
|
|
1679
|
-
const archiveContext = new AsyncLocalStorage();
|
|
1680
|
-
let activeBindingMutations = 0;
|
|
1681
|
-
let pendingArchives = 0;
|
|
1682
|
-
let archiveTail = Promise.resolve();
|
|
1683
|
-
let bindingMutationsDrained = [];
|
|
1684
|
-
const waitForBindingMutations = async () => {
|
|
1685
|
-
if (activeBindingMutations === 0) return;
|
|
1686
|
-
await new Promise((resolve) => {
|
|
1687
|
-
bindingMutationsDrained.push(resolve);
|
|
1688
|
-
});
|
|
1689
|
-
};
|
|
1690
|
-
const runBindingMutation = async (run) => {
|
|
1691
|
-
if (archiveContext.getStore() === true) return await run();
|
|
1692
|
-
if (pendingArchives > 0) throw new Error("Codex binding mutation blocked while a native archive is in progress; retry");
|
|
1693
|
-
activeBindingMutations += 1;
|
|
1694
|
-
try {
|
|
1695
|
-
return await run();
|
|
1696
|
-
} finally {
|
|
1697
|
-
activeBindingMutations -= 1;
|
|
1698
|
-
if (activeBindingMutations === 0) {
|
|
1699
|
-
const drained = bindingMutationsDrained;
|
|
1700
|
-
bindingMutationsDrained = [];
|
|
1701
|
-
for (const resolve of drained) resolve();
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
};
|
|
1705
|
-
const renewLease = (key, owner) => {
|
|
1706
|
-
if (owner.failure) return;
|
|
1707
|
-
try {
|
|
1708
|
-
let renewed = false;
|
|
1709
|
-
const stored = update(key, (raw) => {
|
|
1710
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
1711
|
-
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1712
|
-
const lease = current?.lease;
|
|
1713
|
-
const now = Date.now();
|
|
1714
|
-
if (!lease || lease.token !== owner.token || lease.expiresAt <= now) return;
|
|
1715
|
-
renewed = true;
|
|
1716
|
-
return {
|
|
1717
|
-
...current,
|
|
1718
|
-
lease: {
|
|
1719
|
-
token: owner.token,
|
|
1720
|
-
expiresAt: now + BINDING_LEASE_STALE_MS
|
|
1721
|
-
}
|
|
1722
|
-
};
|
|
1723
|
-
});
|
|
1724
|
-
if (!renewed || !stored) owner.failure = bindingLeaseLostError(key);
|
|
1725
|
-
} catch (error) {
|
|
1726
|
-
owner.failure = bindingLeaseLostError(key, error);
|
|
1727
|
-
}
|
|
1728
|
-
};
|
|
1729
|
-
const transactKey = async (key, apply, ttlMs) => {
|
|
1730
|
-
const deadline = Date.now() + BINDING_LEASE_WAIT_MS;
|
|
1731
|
-
while (true) {
|
|
1732
|
-
let busy = false;
|
|
1733
|
-
let leaseLost = false;
|
|
1734
|
-
let result;
|
|
1735
|
-
const ownedLease = leaseContext.getStore()?.get(key);
|
|
1736
|
-
if (ownedLease?.failure) throw ownedLease.failure;
|
|
1737
|
-
const ownedToken = ownedLease?.token;
|
|
1738
|
-
update(key, (raw) => {
|
|
1739
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
1740
|
-
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1741
|
-
const activeLease = current?.lease;
|
|
1742
|
-
const now = Date.now();
|
|
1743
|
-
if (ownedToken && (!activeLease || activeLease.token !== ownedToken || activeLease.expiresAt <= now)) {
|
|
1744
|
-
leaseLost = true;
|
|
1745
|
-
return;
|
|
1746
|
-
}
|
|
1747
|
-
if (activeLease && activeLease.token !== ownedToken && activeLease.expiresAt > now) {
|
|
1748
|
-
busy = true;
|
|
1749
|
-
return;
|
|
1750
|
-
}
|
|
1751
|
-
const applied = apply(current, ownedToken);
|
|
1752
|
-
result = applied.result;
|
|
1753
|
-
return applied.next;
|
|
1754
|
-
}, ttlMs == null ? void 0 : { ttlMs });
|
|
1755
|
-
if (leaseLost) {
|
|
1756
|
-
const failure = bindingLeaseLostError(key);
|
|
1757
|
-
if (ownedLease) ownedLease.failure = failure;
|
|
1758
|
-
throw failure;
|
|
1759
|
-
}
|
|
1760
|
-
if (!busy) return result;
|
|
1761
|
-
if (Date.now() >= deadline) throw new Error(`Timed out waiting for Codex binding lease: ${key}`);
|
|
1762
|
-
await sleep(BINDING_LEASE_RETRY_INTERVAL_MS);
|
|
1763
|
-
}
|
|
1764
|
-
};
|
|
1765
|
-
return {
|
|
1766
|
-
async read(identity) {
|
|
1767
|
-
const key = bindingStoreKey(identity);
|
|
1768
|
-
const raw = state.lookup(key);
|
|
1769
|
-
const stored = readStoredCodexAppServerBinding(raw);
|
|
1770
|
-
if (raw !== void 0 && !stored) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1771
|
-
return stored?.state === "active" && ownsStoredSessionGeneration(identity, stored) ? stored.binding : void 0;
|
|
1772
|
-
},
|
|
1773
|
-
async hasOtherThreadOwner(threadId, currentIdentity) {
|
|
1774
|
-
const currentKey = currentIdentity ? bindingStoreKey(currentIdentity) : void 0;
|
|
1775
|
-
return state.entries().some(({ key, value }) => {
|
|
1776
|
-
const stored = readStoredCodexAppServerBinding(value);
|
|
1777
|
-
if (!stored) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1778
|
-
const isCurrentOwner = currentIdentity !== void 0 && key === currentKey && (currentIdentity.kind === "conversation" || stored.sessionId === currentIdentity.sessionId.trim());
|
|
1779
|
-
if (stored.state !== "active" || stored.binding.threadId !== threadId || isCurrentOwner) return false;
|
|
1780
|
-
return true;
|
|
1781
|
-
});
|
|
1782
|
-
},
|
|
1783
|
-
async prepareSessionGenerationReclaim(identity) {
|
|
1784
|
-
const key = bindingStoreKey(identity);
|
|
1785
|
-
const raw = state.lookup(key);
|
|
1786
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
1787
|
-
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1788
|
-
if (!current) return {
|
|
1789
|
-
kind: "resolved",
|
|
1790
|
-
result: true
|
|
1791
|
-
};
|
|
1792
|
-
const currentSessionId = current.sessionId;
|
|
1793
|
-
if (!currentSessionId) return {
|
|
1794
|
-
kind: "resolved",
|
|
1795
|
-
result: current.state !== "cleared" || current.retired !== true
|
|
1796
|
-
};
|
|
1797
|
-
if (currentSessionId === identity.sessionId) return current.state === "cleared" && current.retired === true ? {
|
|
1798
|
-
kind: "verify",
|
|
1799
|
-
expectedPreviousSessionId: currentSessionId
|
|
1800
|
-
} : {
|
|
1801
|
-
kind: "resolved",
|
|
1802
|
-
result: true
|
|
1803
|
-
};
|
|
1804
|
-
return {
|
|
1805
|
-
kind: "verify",
|
|
1806
|
-
expectedPreviousSessionId: currentSessionId
|
|
1807
|
-
};
|
|
1808
|
-
},
|
|
1809
|
-
async mutate(identity, mutation) {
|
|
1810
|
-
return await runBindingMutation(async () => {
|
|
1811
|
-
const key = bindingStoreKey(identity);
|
|
1812
|
-
const retainLegacyClear = mutation.kind === "clear" && key.startsWith("conversation:legacy-");
|
|
1813
|
-
return await transactKey(key, (current, leaseToken) => {
|
|
1814
|
-
const ownsGeneration = ownsStoredSessionGeneration(identity, current);
|
|
1815
|
-
const ownedLease = current?.lease && current.lease.token === leaseToken ? { lease: current.lease } : {};
|
|
1816
|
-
if (mutation.kind === "reclaim-generation") {
|
|
1817
|
-
if (identity.kind !== "session" || !identity.sessionKey?.trim()) return { result: false };
|
|
1818
|
-
if (!current) return { result: true };
|
|
1819
|
-
if (ownsGeneration) {
|
|
1820
|
-
if (current.state === "cleared" && current.retired === true && current.sessionId === mutation.expectedPreviousSessionId) return {
|
|
1821
|
-
result: true,
|
|
1822
|
-
next: {
|
|
1823
|
-
version: 1,
|
|
1824
|
-
state: "cleared",
|
|
1825
|
-
sessionId: identity.sessionId,
|
|
1826
|
-
...ownedLease
|
|
1827
|
-
}
|
|
1828
|
-
};
|
|
1829
|
-
return { result: current.state !== "cleared" || current.retired !== true };
|
|
1830
|
-
}
|
|
1831
|
-
if (current.sessionId !== mutation.expectedPreviousSessionId) return { result: false };
|
|
1832
|
-
if (current.state === "active" && current.binding.connectionScope === "supervision") return { result: false };
|
|
1833
|
-
return {
|
|
1834
|
-
result: true,
|
|
1835
|
-
next: {
|
|
1836
|
-
version: 1,
|
|
1837
|
-
state: "cleared",
|
|
1838
|
-
sessionId: identity.sessionId,
|
|
1839
|
-
...ownedLease
|
|
1840
|
-
}
|
|
1841
|
-
};
|
|
1842
|
-
}
|
|
1843
|
-
const storedActive = current?.state === "active" ? current : void 0;
|
|
1844
|
-
const active = ownsGeneration ? storedActive : void 0;
|
|
1845
|
-
const retiredGeneration = current?.state === "cleared" && current.retired === true && ownsGeneration;
|
|
1846
|
-
const preservesSupervisionOwner = mutation.kind === "set" && active?.binding.connectionScope === "supervision" && isSameSupervisionOwner(active.binding, mutation.binding);
|
|
1847
|
-
const clearsPendingSupervisionOwner = mutation.kind === "clear" && active?.binding.connectionScope === "supervision" && matchesPendingSupervisionClear(active.binding, mutation.threadId, mutation.expectedPendingSupervisionBranch);
|
|
1848
|
-
const replacesExpectedOrdinaryOwner = mutation.kind === "replace-thread" && active?.binding.threadId === mutation.expectedThreadId && active.binding.connectionScope !== "supervision" && mutation.binding.connectionScope !== "supervision" && mutation.binding.threadId !== mutation.expectedThreadId;
|
|
1849
|
-
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 === "replace-thread" && !replacesExpectedOrdinaryOwner || (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 };
|
|
1850
|
-
if (mutation.kind === "clear" && retiredGeneration) return { result: true };
|
|
1851
|
-
if (mutation.kind === "clear") return {
|
|
1852
|
-
result: true,
|
|
1853
|
-
next: {
|
|
1854
|
-
version: 1,
|
|
1855
|
-
state: "cleared",
|
|
1856
|
-
...storedSessionGeneration(identity, current),
|
|
1857
|
-
...ownedLease
|
|
1858
|
-
}
|
|
1859
|
-
};
|
|
1860
|
-
let binding;
|
|
1861
|
-
if (mutation.kind === "set" || mutation.kind === "replace-thread") binding = validateBindingForWrite(mutation.binding);
|
|
1862
|
-
else if (mutation.kind === "patch-pending-supervision-branch") binding = validateBindingForWrite({
|
|
1863
|
-
...active.binding,
|
|
1864
|
-
pendingSupervisionBranch: mutation.pending
|
|
1865
|
-
});
|
|
1866
|
-
else if (mutation.kind === "commit-pending-supervision-branch") binding = validateBindingForWrite({
|
|
1867
|
-
...active.binding,
|
|
1868
|
-
...mutation.patch,
|
|
1869
|
-
threadId: mutation.threadId,
|
|
1870
|
-
pendingSupervisionBranch: void 0
|
|
1871
|
-
});
|
|
1872
|
-
else binding = validateBindingForWrite({
|
|
1873
|
-
...active.binding,
|
|
1874
|
-
...mutation.patch,
|
|
1875
|
-
threadId: mutation.threadId
|
|
1876
|
-
});
|
|
1877
|
-
return {
|
|
1878
|
-
result: true,
|
|
1879
|
-
next: {
|
|
1880
|
-
version: 1,
|
|
1881
|
-
state: "active",
|
|
1882
|
-
binding,
|
|
1883
|
-
...storedSessionGeneration(identity, current),
|
|
1884
|
-
...ownedLease
|
|
1885
|
-
}
|
|
1886
|
-
};
|
|
1887
|
-
}, mutation.kind === "clear" && !retainLegacyClear && !leaseContext.getStore()?.has(key) ? 1 : void 0);
|
|
1888
|
-
});
|
|
1889
|
-
},
|
|
1890
|
-
async adoptSessionGeneration(identity, expectedPreviousSessionId) {
|
|
1891
|
-
return await runBindingMutation(async () => {
|
|
1892
|
-
const key = bindingStoreKey(identity);
|
|
1893
|
-
const expectedSessionId = expectedPreviousSessionId.trim();
|
|
1894
|
-
const targetSessionId = identity.sessionId.trim();
|
|
1895
|
-
if (!expectedSessionId) throw new Error("Codex session generation adoption requires the previous session id");
|
|
1896
|
-
return await transactKey(key, (current) => {
|
|
1897
|
-
if (current?.state !== "active") return { result: "absent" };
|
|
1898
|
-
if (current.sessionId === targetSessionId) return { result: "current" };
|
|
1899
|
-
if (current.sessionId !== expectedSessionId) return { result: "conflict" };
|
|
1900
|
-
return {
|
|
1901
|
-
result: "adopted",
|
|
1902
|
-
next: {
|
|
1903
|
-
...current,
|
|
1904
|
-
sessionId: targetSessionId
|
|
1905
|
-
}
|
|
1906
|
-
};
|
|
1907
|
-
});
|
|
1908
|
-
});
|
|
1909
|
-
},
|
|
1910
|
-
async resetSessionGeneration(identity) {
|
|
1911
|
-
return await runBindingMutation(async () => {
|
|
1912
|
-
const key = bindingStoreKey(identity);
|
|
1913
|
-
return await transactKey(key, (current, leaseToken) => {
|
|
1914
|
-
if (!current) return { result: "absent" };
|
|
1915
|
-
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
1916
|
-
if (current.state === "cleared" && current.retired === true) return { result: "conflict" };
|
|
1917
|
-
return {
|
|
1918
|
-
result: "applied",
|
|
1919
|
-
next: {
|
|
1920
|
-
version: 1,
|
|
1921
|
-
state: "cleared",
|
|
1922
|
-
...storedSessionGeneration(identity, current),
|
|
1923
|
-
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
1924
|
-
}
|
|
1925
|
-
};
|
|
1926
|
-
}, leaseContext.getStore()?.has(key) ? void 0 : 1);
|
|
1927
|
-
});
|
|
1928
|
-
},
|
|
1929
|
-
async retireSessionGeneration(identity) {
|
|
1930
|
-
return await runBindingMutation(async () => {
|
|
1931
|
-
const key = bindingStoreKey(identity);
|
|
1932
|
-
return await transactKey(key, (current, leaseToken) => {
|
|
1933
|
-
if (!current) return { result: "absent" };
|
|
1934
|
-
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
1935
|
-
if (current.state === "cleared" && current.retired === true) return { result: "applied" };
|
|
1936
|
-
return {
|
|
1937
|
-
result: "applied",
|
|
1938
|
-
next: {
|
|
1939
|
-
version: 1,
|
|
1940
|
-
state: "cleared",
|
|
1941
|
-
retired: true,
|
|
1942
|
-
...storedSessionGeneration(identity, current),
|
|
1943
|
-
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
1944
|
-
}
|
|
1945
|
-
};
|
|
1946
|
-
}, identity.sessionKey?.trim() ? void 0 : PHYSICAL_SESSION_RETIRE_TTL_MS);
|
|
1947
|
-
});
|
|
1948
|
-
},
|
|
1949
|
-
async withThreadArchiveFence(run) {
|
|
1950
|
-
pendingArchives += 1;
|
|
1951
|
-
const operation = archiveTail.then(async () => {
|
|
1952
|
-
await waitForBindingMutations();
|
|
1953
|
-
return await archiveContext.run(true, run);
|
|
1954
|
-
});
|
|
1955
|
-
archiveTail = operation.then(() => void 0, () => void 0);
|
|
1956
|
-
try {
|
|
1957
|
-
return await operation;
|
|
1958
|
-
} finally {
|
|
1959
|
-
pendingArchives -= 1;
|
|
1960
|
-
}
|
|
1961
|
-
},
|
|
1962
|
-
async withLease(identity, run) {
|
|
1963
|
-
const key = bindingStoreKey(identity);
|
|
1964
|
-
const owned = leaseContext.getStore();
|
|
1965
|
-
const existingOwner = owned?.get(key);
|
|
1966
|
-
if (existingOwner) {
|
|
1967
|
-
const failureBeforeRun = existingOwner.failure;
|
|
1968
|
-
if (failureBeforeRun) throw failureBeforeRun;
|
|
1969
|
-
const result = await run();
|
|
1970
|
-
const failureAfterRun = existingOwner.failure;
|
|
1971
|
-
if (failureAfterRun) throw failureAfterRun;
|
|
1972
|
-
return result;
|
|
1973
|
-
}
|
|
1974
|
-
const token = randomUUID();
|
|
1975
|
-
if (!await transactKey(key, (current) => {
|
|
1976
|
-
if (current?.state === "cleared" && current.retired === true && ownsStoredSessionGeneration(identity, current)) return { result: false };
|
|
1977
|
-
const lease = {
|
|
1978
|
-
token,
|
|
1979
|
-
expiresAt: Date.now() + BINDING_LEASE_STALE_MS
|
|
1980
|
-
};
|
|
1981
|
-
if (current?.state === "active") return {
|
|
1982
|
-
result: true,
|
|
1983
|
-
next: {
|
|
1984
|
-
...current,
|
|
1985
|
-
...preservedSessionGeneration(identity, current),
|
|
1986
|
-
lease
|
|
1987
|
-
}
|
|
1988
|
-
};
|
|
1989
|
-
if (current?.state === "cleared" && current.retired === true) return {
|
|
1990
|
-
result: true,
|
|
1991
|
-
next: {
|
|
1992
|
-
...current,
|
|
1993
|
-
lease
|
|
1994
|
-
}
|
|
1995
|
-
};
|
|
1996
|
-
return {
|
|
1997
|
-
result: true,
|
|
1998
|
-
next: {
|
|
1999
|
-
version: 1,
|
|
2000
|
-
state: "cleared",
|
|
2001
|
-
...preservedSessionGeneration(identity, current),
|
|
2002
|
-
lease
|
|
2003
|
-
}
|
|
2004
|
-
};
|
|
2005
|
-
})) throw new Error(`Codex binding generation was retired: ${key}`);
|
|
2006
|
-
const owner = { token };
|
|
2007
|
-
const nested = new Map(owned);
|
|
2008
|
-
nested.set(key, owner);
|
|
2009
|
-
const heartbeat = setInterval(() => renewLease(key, owner), BINDING_LEASE_RENEW_INTERVAL_MS);
|
|
2010
|
-
heartbeat.unref();
|
|
2011
|
-
try {
|
|
2012
|
-
const result = await leaseContext.run(nested, run);
|
|
2013
|
-
if (owner.failure) throw owner.failure;
|
|
2014
|
-
return result;
|
|
2015
|
-
} finally {
|
|
2016
|
-
clearInterval(heartbeat);
|
|
2017
|
-
try {
|
|
2018
|
-
const removeOwnedLease = (raw, matches) => {
|
|
2019
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
2020
|
-
if (!current || !matches(current) || current.lease?.token !== token) return;
|
|
2021
|
-
const { lease: _lease, ...released } = current;
|
|
2022
|
-
return released;
|
|
2023
|
-
};
|
|
2024
|
-
if (!update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "active"))) {
|
|
2025
|
-
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 });
|
|
2026
|
-
}
|
|
2027
|
-
} catch (error) {
|
|
2028
|
-
embeddedAgentLog.warn("failed to release codex app-server binding lease", {
|
|
2029
|
-
key,
|
|
2030
|
-
error
|
|
2031
|
-
});
|
|
2032
|
-
}
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
};
|
|
2036
|
-
}
|
|
2037
|
-
function matchesPendingSupervisionBranch(binding, expected) {
|
|
2038
|
-
const pending = binding?.pendingSupervisionBranch;
|
|
2039
|
-
if (!pending || binding?.threadId !== expected.sourceThreadId) return false;
|
|
2040
|
-
if (pending.sourceThreadId !== expected.sourceThreadId || pending.connectionFingerprint !== expected.connectionFingerprint || pending.lastTurnId !== expected.lastTurnId) return false;
|
|
2041
|
-
const currentCleanup = pending.cleanupThreadIds ?? [];
|
|
2042
|
-
const expectedCleanup = expected.cleanupThreadIds ?? [];
|
|
2043
|
-
return currentCleanup.length === expectedCleanup.length && currentCleanup.every((threadId, index) => threadId === expectedCleanup[index]);
|
|
2044
|
-
}
|
|
2045
|
-
function isSameSupervisionOwner(current, replacement) {
|
|
2046
|
-
return replacement.connectionScope === "supervision" && replacement.threadId === current.threadId && replacement.supervisionSourceThreadId === current.supervisionSourceThreadId;
|
|
2047
|
-
}
|
|
2048
|
-
function matchesPendingSupervisionClear(binding, threadId, expected) {
|
|
2049
|
-
if (!expected) return false;
|
|
2050
|
-
const sourceThreadId = expected.sourceThreadId;
|
|
2051
|
-
return threadId === sourceThreadId && binding.supervisionSourceThreadId === sourceThreadId && matchesPendingSupervisionBranch(binding, expected);
|
|
2052
|
-
}
|
|
2053
|
-
/** Stable plugin-state key for one current binding owner. */
|
|
2054
|
-
function bindingStoreKey(identity) {
|
|
2055
|
-
if (identity.kind === "session") {
|
|
2056
|
-
const rawAgentId = identity.agentId.trim();
|
|
2057
|
-
const sessionId = identity.sessionId.trim();
|
|
2058
|
-
if (!rawAgentId) throw new Error("Codex app-server binding requires an agent id");
|
|
2059
|
-
if (!sessionId) throw new Error("Codex app-server binding requires a session id");
|
|
2060
|
-
const agentId = resolveSessionAgentIds$1({ agentId: rawAgentId }).sessionAgentId;
|
|
2061
|
-
const sessionKey = identity.sessionKey?.trim();
|
|
2062
|
-
if (sessionKey) return `session-key:${agentId}:${createHash("sha256").update(sessionKey).digest("base64url")}`;
|
|
2063
|
-
return `session:${agentId}:${sessionId}`;
|
|
2064
|
-
}
|
|
2065
|
-
const bindingId = identity.bindingId.trim();
|
|
2066
|
-
if (!bindingId) throw new Error("Codex app-server conversation binding requires a binding id");
|
|
2067
|
-
return `conversation:${bindingId}`;
|
|
2068
|
-
}
|
|
2069
|
-
function readStoredCodexAppServerBinding(value) {
|
|
2070
|
-
const result = storedBindingSchema.safeParse(value);
|
|
2071
|
-
return result.success ? stripUndefinedValue(result.data) : void 0;
|
|
2072
|
-
}
|
|
2073
|
-
function storedSessionGeneration(identity, current) {
|
|
2074
|
-
if (identity.kind === "session") return { sessionId: identity.sessionId };
|
|
2075
|
-
return current?.sessionId ? { sessionId: current.sessionId } : {};
|
|
2076
|
-
}
|
|
2077
|
-
function preservedSessionGeneration(identity, current) {
|
|
2078
|
-
if (current?.sessionId) return { sessionId: current.sessionId };
|
|
2079
|
-
return storedSessionGeneration(identity, current);
|
|
2080
|
-
}
|
|
2081
|
-
function ownsStoredSessionGeneration(identity, current) {
|
|
2082
|
-
return identity.kind !== "session" || !current?.sessionId || current.sessionId === identity.sessionId;
|
|
2083
|
-
}
|
|
2084
|
-
function validateBindingForWrite(binding) {
|
|
2085
|
-
const validated = readCodexAppServerThreadBinding(binding);
|
|
2086
|
-
if (!validated) throw new Error("Invalid Codex app-server thread binding");
|
|
2087
|
-
return stripUndefinedBinding(validated);
|
|
2088
|
-
}
|
|
2089
|
-
/** Parses stored or shipped sidecar data into the current domain value. */
|
|
2090
|
-
function readCodexAppServerThreadBinding(value) {
|
|
2091
|
-
const result = threadBindingSchema.safeParse(value);
|
|
2092
|
-
if (!result.success) return;
|
|
2093
|
-
return result.data;
|
|
2094
|
-
}
|
|
2095
|
-
function stripUndefinedBinding(binding) {
|
|
2096
|
-
return stripUndefinedValue(binding);
|
|
2097
|
-
}
|
|
2098
|
-
function stripUndefinedValue(value) {
|
|
2099
|
-
if (Array.isArray(value)) return value.map(stripUndefinedValue);
|
|
2100
|
-
if (!value || typeof value !== "object") return value;
|
|
2101
|
-
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, stripUndefinedValue(entry)]));
|
|
2102
|
-
}
|
|
2103
|
-
function readTimestamp(value) {
|
|
2104
|
-
return optionalTimestampSchema.parse(value);
|
|
2105
|
-
}
|
|
2106
|
-
function readPluginAppPolicyContext(value, bindingSchemaVersion) {
|
|
2107
|
-
const record = asOptionalRecord(value);
|
|
2108
|
-
if (!record || typeof record.fingerprint !== "string") return;
|
|
2109
|
-
const apps = asOptionalRecord(record.apps);
|
|
2110
|
-
if (!apps) return;
|
|
2111
|
-
const parsedApps = {};
|
|
2112
|
-
for (const [appId, rawEntry] of Object.entries(apps)) {
|
|
2113
|
-
const entry = asOptionalRecord(rawEntry);
|
|
2114
|
-
if (!entry) return;
|
|
2115
|
-
const destructiveApprovalMode = readDestructiveApprovalMode(entry.destructiveApprovalMode, bindingSchemaVersion);
|
|
2116
|
-
const mcpServerNamesValid = Array.isArray(entry.mcpServerNames) && entry.mcpServerNames.every((serverName) => typeof serverName === "string");
|
|
2117
|
-
if (entry.source === "account") {
|
|
2118
|
-
if ("appId" in entry || typeof entry.appName !== "string" || typeof entry.allowDestructiveActions !== "boolean" || entry.allowOpenWorld !== void 0 && typeof entry.allowOpenWorld !== "boolean" || destructiveApprovalMode === "invalid" || !mcpServerNamesValid) return;
|
|
2119
|
-
parsedApps[appId] = {
|
|
2120
|
-
source: "account",
|
|
2121
|
-
appName: entry.appName,
|
|
2122
|
-
allowDestructiveActions: entry.allowDestructiveActions,
|
|
2123
|
-
...typeof entry.allowOpenWorld === "boolean" ? { allowOpenWorld: entry.allowOpenWorld } : {},
|
|
2124
|
-
...destructiveApprovalMode ? { destructiveApprovalMode } : {},
|
|
2125
|
-
mcpServerNames: entry.mcpServerNames
|
|
2126
|
-
};
|
|
2127
|
-
continue;
|
|
2128
|
-
}
|
|
2129
|
-
if ("appId" in entry || entry.source !== void 0 && entry.source !== "plugin" || typeof entry.configKey !== "string" || typeof entry.marketplaceName !== "string" || !CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN.test(entry.marketplaceName) || typeof entry.pluginName !== "string" || typeof entry.allowDestructiveActions !== "boolean" || entry.allowOpenWorld !== void 0 && typeof entry.allowOpenWorld !== "boolean" || destructiveApprovalMode === "invalid" || !mcpServerNamesValid) return;
|
|
2130
|
-
parsedApps[appId] = {
|
|
2131
|
-
configKey: entry.configKey,
|
|
2132
|
-
marketplaceName: entry.marketplaceName,
|
|
2133
|
-
pluginName: entry.pluginName,
|
|
2134
|
-
allowDestructiveActions: entry.allowDestructiveActions,
|
|
2135
|
-
...typeof entry.allowOpenWorld === "boolean" ? { allowOpenWorld: entry.allowOpenWorld } : {},
|
|
2136
|
-
...destructiveApprovalMode ? { destructiveApprovalMode } : {},
|
|
2137
|
-
mcpServerNames: entry.mcpServerNames
|
|
2138
|
-
};
|
|
2139
|
-
}
|
|
2140
|
-
const parsedPluginAppIds = {};
|
|
2141
|
-
if (record.pluginAppIds !== void 0 && (!record.pluginAppIds || typeof record.pluginAppIds !== "object" || Array.isArray(record.pluginAppIds))) return;
|
|
2142
|
-
if (record.pluginAppIds && typeof record.pluginAppIds === "object") for (const [configKey, appIds] of Object.entries(record.pluginAppIds)) {
|
|
2143
|
-
if (!Array.isArray(appIds) || appIds.some((appId) => typeof appId !== "string")) return;
|
|
2144
|
-
parsedPluginAppIds[configKey] = appIds;
|
|
2145
|
-
}
|
|
2146
|
-
return {
|
|
2147
|
-
fingerprint: record.fingerprint,
|
|
2148
|
-
apps: parsedApps,
|
|
2149
|
-
pluginAppIds: parsedPluginAppIds
|
|
2150
|
-
};
|
|
2151
|
-
}
|
|
2152
|
-
function readDestructiveApprovalMode(value, bindingSchemaVersion) {
|
|
2153
|
-
if (value === void 0) return;
|
|
2154
|
-
if (value === "allow" || value === "deny") return value;
|
|
2155
|
-
if (value === "auto") return bindingSchemaVersion === 1 ? "allow" : "auto";
|
|
2156
|
-
if (value === "ask" && bindingSchemaVersion === 2) return "ask";
|
|
2157
|
-
if (value === "on-request" && bindingSchemaVersion === 1) return "auto";
|
|
2158
|
-
return "invalid";
|
|
2159
|
-
}
|
|
2160
|
-
function sleep(ms) {
|
|
2161
|
-
return new Promise((resolve) => {
|
|
2162
|
-
setTimeout(resolve, ms);
|
|
2163
|
-
});
|
|
2164
|
-
}
|
|
2165
|
-
/** Returns true when an auth profile uses native Codex/OpenAI app-server auth. */
|
|
2166
|
-
function isCodexAppServerNativeAuthProfile(lookup) {
|
|
2167
|
-
const authProfileId = lookup.authProfileId?.trim();
|
|
2168
|
-
if (!authProfileId) return false;
|
|
2169
|
-
try {
|
|
2170
|
-
const credential = (lookup.authProfileStore ?? ensureAuthProfileStore(lookup.agentDir?.trim() || resolveDefaultAgentDir(lookup.config ?? {}), {
|
|
2171
|
-
allowKeychainPrompt: false,
|
|
2172
|
-
config: lookup.config,
|
|
2173
|
-
externalCliProviderIds: [CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER],
|
|
2174
|
-
externalCliProfileIds: [authProfileId]
|
|
2175
|
-
})).profiles[authProfileId];
|
|
2176
|
-
if (!credential || credential.type === "api_key") return false;
|
|
2177
|
-
const provider = credential.provider?.trim();
|
|
2178
|
-
return Boolean(provider && resolveProviderIdForAuth(provider, { config: lookup.config }) === CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER);
|
|
2179
|
-
} catch (error) {
|
|
2180
|
-
embeddedAgentLog.debug("failed to resolve codex app-server auth profile provider", {
|
|
2181
|
-
authProfileId,
|
|
2182
|
-
error
|
|
2183
|
-
});
|
|
2184
|
-
return false;
|
|
2185
|
-
}
|
|
2186
|
-
}
|
|
2187
|
-
/** Hides redundant OpenAI provider attribution for native Codex auth bindings. */
|
|
2188
|
-
function normalizeCodexAppServerBindingModelProvider(params) {
|
|
2189
|
-
const modelProvider = params.modelProvider?.trim();
|
|
2190
|
-
if (!modelProvider) return;
|
|
2191
|
-
if (isCodexAppServerNativeAuthProfile(params) && modelProvider.toLowerCase() === PUBLIC_OPENAI_MODEL_PROVIDER) return;
|
|
2192
|
-
return modelProvider;
|
|
2193
|
-
}
|
|
2194
|
-
//#endregion
|
|
2195
|
-
export { resolveCodexAppServerUserHomeDir as A, isCodexRemoteExecPlacementSandbox as C, CODEX_PLUGINS_MARKETPLACE_NAME as D, resolveCodexPluginsPolicy as E, isCodexAppServerApprovalPolicyAllowedByRequirements as M, resolveOpenClawExecPolicyForCodexAppServer as N, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME as O, isCodexFastServiceTier as P, withMcpElicitationsApprovalPolicy as S, readCodexPluginConfig as T, resolveCodexAppServerStartOptionsForAgent as _, hashCodexAppServerBindingFingerprint as a, assertCodexAppServerConnectionSecurity as b, reclaimCurrentCodexSessionGeneration as c, sessionBindingIdentity as d, session_binding_exports as f, resolveCodexAppServerRuntimeOptions as g, resolveCodexAppServerHomeScope as h, createCodexSessionGenerationSupersededError as i, resolveCodexModelBackedReviewerPolicyContext as j, canUseCodexModelBackedApprovalsReviewerForModel as k, resolveCodexRunSessionBindingAuthority as l, codexSandboxPolicyForTurn as m, assertCodexBindingMayBeReplaced as n, isCodexAppServerNativeAuthProfile as o, codexAppServerStartOptionsKey as p, bindingStoreKey as r, normalizeCodexAppServerBindingModelProvider as s, CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS as t, scopeCodexRunBindingStore as u, resolveCodexComputerUseConfig as v, isCodexSandboxExecServerEnabled as w, shouldAutoApproveCodexAppServerApprovals as x, resolveCodexSupervisionAppServerRuntimeOptions as y };
|
|
1395
|
+
export { normalizeCodexServiceTier as A, isCodexRemoteExecPlacementSandbox as C, resolveOpenClawExecPolicyForCodexAppServer as D, resolveCodexPluginsPolicy as E, resolveCodexAppServerLocalHomeDir as F, resolveCodexAppServerUserHomeDir as I, withEphemeralCodexAuthStore as L, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME as M, CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN as N, selectGuardianSandbox as O, resolveCodexAppServerHomeDir as P, isCodexPairedNodeRemoteExecPlacementSandbox as S, readCodexPluginConfig as T, parseAllowedSandboxModesFromCodexRequirements as _, resolveCodexAppServerStartOptionsForAgent as a, selectGuardianApprovalsReviewer as b, assertCodexAppServerConnectionSecurity as c, withMcpElicitationsApprovalPolicy as d, assertCodexModelBackedReviewerEffectiveConfig as f, parseAllowedApprovalsReviewersFromCodexRequirements as g, parseAllowedApprovalPoliciesFromCodexRequirements as h, resolveCodexAppServerRuntimeOptions as i, CODEX_PLUGINS_MARKETPLACE_NAME as j, isCodexFastServiceTier as k, resolveCodexAppServerNetworkProxy as l, resolveCodexModelBackedReviewerPolicyContext as m, codexSandboxPolicyForTurn as n, resolveCodexComputerUseConfig as o, canUseCodexModelBackedApprovalsReviewerForModel as p, resolveCodexAppServerHomeScope as r, resolveCodexSupervisionAppServerRuntimeOptions as s, codexAppServerStartOptionsKey as t, shouldAutoApproveCodexAppServerApprovals as u, readCodexRequirementsToml as v, isCodexSandboxExecServerEnabled as w, selectUserApprovalsReviewer as x, selectGuardianApprovalPolicy as y };
|