@openclaw/codex 2026.6.8 → 2026.6.9
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/{notification-correlation-BGoG0N90.js → app-server-policy-BPTiVNsW.js} +15 -74
- package/dist/attempt-notifications-7oZeRa71.js +249 -0
- package/dist/{client-DovmVtbr.js → client-CLrtWgrD.js} +24 -2
- package/dist/{client-factory-C71Xdb6z.js → client-factory-Bm6HsGob.js} +3 -2
- package/dist/{command-handlers-DHecBkuc.js → command-handlers-BaqM9s9b.js} +17 -13
- package/dist/{compact-GEKusemL.js → compact-aQJ0ZKhe.js} +5 -5
- package/dist/{computer-use-D1qxvTE_.js → computer-use-BmuwYrW6.js} +3 -3
- package/dist/{config-DJXpBkGf.js → config-CszD0vP3.js} +176 -25
- package/dist/{conversation-binding-CbnMilVW.js → conversation-binding-DbG2ZJQY.js} +166 -58
- package/dist/doctor-contract-api.js +37 -3
- package/dist/harness.js +6 -6
- package/dist/index.js +108 -27
- package/dist/media-understanding-provider-Dmfg4tH_.js +463 -0
- package/dist/media-understanding-provider.js +1 -355
- package/dist/{models-DRKnOpzF.js → models-CAmfBWRl.js} +2 -2
- package/dist/{plugin-app-cache-key-kIqpGTQj.js → plugin-app-cache-key-vaZ_8Usz.js} +17 -6
- package/dist/prompt-overlay.js +2 -6
- package/dist/{protocol-oeJQu4rs.js → protocol-dh-ETiNd.js} +4 -1
- package/dist/{protocol-validators-B48C6S9O.js → protocol-validators-B19q5BIX.js} +210 -16
- package/dist/{provider-C5P6352f.js → provider-B-OHpbD3.js} +4 -4
- package/dist/{native-hook-relay-C3i3FYtc.js → provider-capabilities-ByR82ytL.js} +803 -78
- package/dist/provider.js +1 -1
- package/dist/{request-BxZ40QKY.js → request-Dcd452Nk.js} +2 -2
- package/dist/{run-attempt-D_q-VrpR.js → run-attempt-DYt00Jxz.js} +519 -789
- package/dist/{sandbox-guard-C-Yv9uwY.js → sandbox-guard-3tnjhjFb.js} +37 -10
- package/dist/{session-binding-ElbcSq2o.js → session-binding-HOuPt-E0.js} +27 -8
- package/dist/{shared-client-jFMumCOe.js → shared-client-Dtx5i7Ez.js} +4 -4
- package/dist/{side-question-DqKLfWMB.js → side-question-h01W1aCe.js} +106 -42
- package/dist/{thread-lifecycle-cban34w3.js → thread-lifecycle-DQyii5vp.js} +948 -616
- package/dist/web-search-contract-api.js +10 -0
- package/dist/web-search-provider.runtime-BWG_oqLf.js +74 -0
- package/dist/web-search-provider.shared-BrZmlqyR.js +32 -0
- package/npm-shrinkwrap.json +2 -2
- package/openclaw.plugin.json +140 -6
- package/package.json +4 -4
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
2
|
-
import {
|
|
3
|
+
import { normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
|
+
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
3
5
|
import { readFileSync } from "node:fs";
|
|
4
6
|
import { hostname } from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
7
|
import { resolveProviderIdForAuth } from "openclaw/plugin-sdk/agent-runtime";
|
|
7
8
|
import { resolveExecApprovalsFromFile } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
8
9
|
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
9
|
-
import {
|
|
10
|
+
import { buildSecretInputSchema, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
10
11
|
import { detectWindowsSpawnCommandInlineArgs } from "openclaw/plugin-sdk/windows-spawn";
|
|
11
12
|
import { z } from "zod";
|
|
12
13
|
//#region extensions/codex/src/app-server/config.ts
|
|
@@ -19,12 +20,14 @@ const CODEX_CONFIG_TOML_FILENAME = "config.toml";
|
|
|
19
20
|
const PLAIN_DECIMAL_NUMBER_RE = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))$/;
|
|
20
21
|
const CODEX_PLUGINS_MARKETPLACE_NAME = "openai-curated";
|
|
21
22
|
function shouldAutoApproveCodexAppServerApprovals(appServer) {
|
|
22
|
-
return appServer.approvalPolicy === "never" && appServer.sandbox === "danger-full-access";
|
|
23
|
+
return appServer.networkProxy === void 0 && appServer.approvalPolicy === "never" && appServer.sandbox === "danger-full-access";
|
|
23
24
|
}
|
|
24
25
|
const DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME = "computer-use";
|
|
25
26
|
const DEFAULT_CODEX_COMPUTER_USE_MCP_SERVER_NAME = "computer-use";
|
|
26
27
|
const DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS = 6e4;
|
|
28
|
+
const DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX = "openclaw-network";
|
|
27
29
|
const codexAppServerTransportSchema = z.enum(["stdio", "websocket"]);
|
|
30
|
+
const SecretInputSchema = buildSecretInputSchema();
|
|
28
31
|
const codexAppServerPolicyModeSchema = z.enum(["yolo", "guardian"]);
|
|
29
32
|
const codexAppServerApprovalPolicySchema = z.enum([
|
|
30
33
|
"never",
|
|
@@ -43,17 +46,37 @@ const codexAppServerApprovalsReviewerSchema = z.enum([
|
|
|
43
46
|
"guardian_subagent"
|
|
44
47
|
]);
|
|
45
48
|
const codexDynamicToolsLoadingSchema = z.enum(["searchable", "direct"]);
|
|
49
|
+
const codexPluginDestructivePolicySchema = z.union([z.boolean(), z.literal("auto")]);
|
|
46
50
|
const codexAppServerServiceTierSchema = z.preprocess((value) => value === null ? null : normalizeCodexServiceTier(value), z.string().trim().min(1).nullable().optional()).optional();
|
|
47
51
|
const codexAppServerExperimentalSchema = z.object({ sandboxExecServer: z.boolean().optional() }).strict();
|
|
52
|
+
const codexAppServerRemoteWorkspaceRootSchema = z.string().trim().min(1);
|
|
53
|
+
const codexAppServerNetworkProxyDomainPermissionSchema = z.enum(["allow", "deny"]);
|
|
54
|
+
const codexAppServerNetworkProxyUnixSocketPermissionSchema = z.enum(["allow", "none"]);
|
|
55
|
+
const codexAppServerNetworkProxySchema = z.object({
|
|
56
|
+
enabled: z.boolean().optional(),
|
|
57
|
+
profileName: z.string().trim().min(1).optional(),
|
|
58
|
+
baseProfile: z.enum(["read-only", "workspace"]).optional(),
|
|
59
|
+
mode: z.enum(["limited", "full"]).optional(),
|
|
60
|
+
domains: z.record(z.string(), codexAppServerNetworkProxyDomainPermissionSchema).optional(),
|
|
61
|
+
unixSockets: z.record(z.string(), codexAppServerNetworkProxyUnixSocketPermissionSchema).optional(),
|
|
62
|
+
proxyUrl: z.string().trim().min(1).optional(),
|
|
63
|
+
socksUrl: z.string().trim().min(1).optional(),
|
|
64
|
+
enableSocks5: z.boolean().optional(),
|
|
65
|
+
enableSocks5Udp: z.boolean().optional(),
|
|
66
|
+
allowUpstreamProxy: z.boolean().optional(),
|
|
67
|
+
allowLocalBinding: z.boolean().optional(),
|
|
68
|
+
dangerouslyAllowNonLoopbackProxy: z.boolean().optional(),
|
|
69
|
+
dangerouslyAllowAllUnixSockets: z.boolean().optional()
|
|
70
|
+
}).strict();
|
|
48
71
|
const codexPluginEntryConfigSchema = z.object({
|
|
49
72
|
enabled: z.boolean().optional(),
|
|
50
73
|
marketplaceName: z.literal(CODEX_PLUGINS_MARKETPLACE_NAME).optional(),
|
|
51
74
|
pluginName: z.string().trim().min(1).optional(),
|
|
52
|
-
allow_destructive_actions:
|
|
75
|
+
allow_destructive_actions: codexPluginDestructivePolicySchema.optional()
|
|
53
76
|
}).strict();
|
|
54
77
|
const codexPluginsConfigSchema = z.object({
|
|
55
78
|
enabled: z.boolean().optional(),
|
|
56
|
-
allow_destructive_actions:
|
|
79
|
+
allow_destructive_actions: codexPluginDestructivePolicySchema.optional(),
|
|
57
80
|
plugins: z.record(z.string(), codexPluginEntryConfigSchema).optional()
|
|
58
81
|
}).strict();
|
|
59
82
|
const codexPluginConfigSchema = z.object({
|
|
@@ -80,9 +103,10 @@ const codexPluginConfigSchema = z.object({
|
|
|
80
103
|
command: z.string().optional(),
|
|
81
104
|
args: z.union([z.array(z.string()), z.string()]).optional(),
|
|
82
105
|
url: z.string().optional(),
|
|
83
|
-
authToken:
|
|
84
|
-
headers: z.record(z.string(),
|
|
106
|
+
authToken: SecretInputSchema.optional(),
|
|
107
|
+
headers: z.record(z.string(), SecretInputSchema).optional(),
|
|
85
108
|
clearEnv: z.array(z.string()).optional(),
|
|
109
|
+
remoteWorkspaceRoot: codexAppServerRemoteWorkspaceRootSchema.optional(),
|
|
86
110
|
codeModeOnly: z.boolean().optional(),
|
|
87
111
|
requestTimeoutMs: z.number().positive().optional(),
|
|
88
112
|
turnCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
@@ -91,6 +115,7 @@ const codexPluginConfigSchema = z.object({
|
|
|
91
115
|
sandbox: codexAppServerSandboxSchema.optional(),
|
|
92
116
|
approvalsReviewer: codexAppServerApprovalsReviewerSchema.optional(),
|
|
93
117
|
serviceTier: codexAppServerServiceTierSchema,
|
|
118
|
+
networkProxy: codexAppServerNetworkProxySchema.optional(),
|
|
94
119
|
defaultWorkspaceDir: z.string().optional(),
|
|
95
120
|
experimental: codexAppServerExperimentalSchema.optional()
|
|
96
121
|
}).strict().optional()
|
|
@@ -120,21 +145,35 @@ function resolveCodexPluginsPolicy(pluginConfig) {
|
|
|
120
145
|
const config = readCodexPluginConfig(pluginConfig).codexPlugins;
|
|
121
146
|
const configured = config !== void 0;
|
|
122
147
|
const enabled = config?.enabled === true;
|
|
123
|
-
const
|
|
148
|
+
const destructivePolicy = resolveCodexPluginDestructivePolicy(config?.allow_destructive_actions ?? true);
|
|
149
|
+
const pluginPolicies = Object.entries(config?.plugins ?? {}).flatMap(([configKey, entry]) => {
|
|
150
|
+
if (entry.marketplaceName !== "openai-curated" || !entry.pluginName) return [];
|
|
151
|
+
const entryDestructivePolicy = resolveCodexPluginDestructivePolicy(entry.allow_destructive_actions ?? config?.allow_destructive_actions ?? true);
|
|
152
|
+
return [{
|
|
153
|
+
configKey,
|
|
154
|
+
marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME,
|
|
155
|
+
pluginName: entry.pluginName,
|
|
156
|
+
enabled: enabled && entry.enabled !== false,
|
|
157
|
+
allowDestructiveActions: entryDestructivePolicy.allowDestructiveActions,
|
|
158
|
+
destructiveApprovalMode: entryDestructivePolicy.destructiveApprovalMode
|
|
159
|
+
}];
|
|
160
|
+
}).toSorted((left, right) => left.configKey.localeCompare(right.configKey));
|
|
124
161
|
return {
|
|
125
162
|
configured,
|
|
126
163
|
enabled,
|
|
127
|
-
allowDestructiveActions,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
164
|
+
allowDestructiveActions: destructivePolicy.allowDestructiveActions,
|
|
165
|
+
destructiveApprovalMode: destructivePolicy.destructiveApprovalMode,
|
|
166
|
+
pluginPolicies
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function resolveCodexPluginDestructivePolicy(policy) {
|
|
170
|
+
if (policy === "auto") return {
|
|
171
|
+
allowDestructiveActions: true,
|
|
172
|
+
destructiveApprovalMode: "auto"
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
allowDestructiveActions: policy,
|
|
176
|
+
destructiveApprovalMode: policy ? "allow" : "deny"
|
|
138
177
|
};
|
|
139
178
|
}
|
|
140
179
|
function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
@@ -152,8 +191,17 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
|
152
191
|
const args = resolveArgs(config.args, env.OPENCLAW_CODEX_APP_SERVER_ARGS);
|
|
153
192
|
const headers = normalizeHeaders(config.headers);
|
|
154
193
|
const clearEnv = normalizeStringList(config.clearEnv);
|
|
155
|
-
const authToken =
|
|
194
|
+
const authToken = normalizeCodexAppServerSecretInput({
|
|
195
|
+
value: config.authToken,
|
|
196
|
+
path: "plugins.entries.codex.config.appServer.authToken"
|
|
197
|
+
});
|
|
156
198
|
const url = readNonEmptyString(config.url);
|
|
199
|
+
const connectionClass = inferCodexAppServerConnectionClass({
|
|
200
|
+
transport,
|
|
201
|
+
url
|
|
202
|
+
});
|
|
203
|
+
const remoteAppsSubstrate = "preconfigured";
|
|
204
|
+
const remoteWorkspaceRoot = normalizeRemoteWorkspaceRoot(config.remoteWorkspaceRoot);
|
|
157
205
|
const execMode = resolveEffectiveOpenClawExecModeForCodexAppServer({
|
|
158
206
|
execMode: params.execMode,
|
|
159
207
|
execPolicy: params.execPolicy
|
|
@@ -205,7 +253,13 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
|
205
253
|
} : void 0;
|
|
206
254
|
const policyMode = ignoreLegacyYoloPolicyMode ? normalizedPolicyMode : explicitPolicyMode ?? normalizedPolicyMode ?? defaultPolicy?.mode ?? "yolo";
|
|
207
255
|
const serviceTier = normalizeCodexServiceTier(config.serviceTier);
|
|
256
|
+
const resolvedSandbox = forcedPolicy?.sandbox ?? configuredSandbox ?? defaultPolicy?.sandbox ?? (policyMode === "guardian" ? "workspace-write" : "danger-full-access");
|
|
208
257
|
if (transport === "websocket" && !url) throw new Error("plugins.entries.codex.config.appServer.url is required when appServer.transport is websocket");
|
|
258
|
+
assertCodexAppServerConnectionClassConfig({
|
|
259
|
+
connectionClass,
|
|
260
|
+
authToken,
|
|
261
|
+
headers
|
|
262
|
+
});
|
|
209
263
|
const configApprovalPolicy = resolveApprovalPolicy(config.approvalPolicy);
|
|
210
264
|
const envApprovalPolicy = resolveApprovalPolicy(env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY);
|
|
211
265
|
const approvalPolicy = configApprovalPolicy ?? envApprovalPolicy ?? defaultPolicy?.approvalPolicy ?? (policyMode === "guardian" ? "on-request" : "never");
|
|
@@ -225,15 +279,19 @@ function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
|
225
279
|
headers,
|
|
226
280
|
...transport === "stdio" && clearEnv.length > 0 ? { clearEnv } : {}
|
|
227
281
|
},
|
|
282
|
+
connectionClass,
|
|
283
|
+
remoteAppsSubstrate,
|
|
284
|
+
...remoteWorkspaceRoot ? { remoteWorkspaceRoot } : {},
|
|
228
285
|
codeModeOnly: config.codeModeOnly === true,
|
|
229
286
|
requestTimeoutMs: normalizePositiveNumber(config.requestTimeoutMs, 6e4),
|
|
230
287
|
turnCompletionIdleTimeoutMs: normalizePositiveNumber(config.turnCompletionIdleTimeoutMs, 6e4),
|
|
231
288
|
...config.postToolRawAssistantCompletionIdleTimeoutMs !== void 0 ? { postToolRawAssistantCompletionIdleTimeoutMs: normalizePositiveNumber(config.postToolRawAssistantCompletionIdleTimeoutMs, 6e4) } : {},
|
|
232
289
|
approvalPolicy: forcedPolicy?.approvalPolicy ?? approvalPolicy,
|
|
233
290
|
approvalPolicySource,
|
|
234
|
-
sandbox:
|
|
291
|
+
sandbox: resolvedSandbox,
|
|
235
292
|
approvalsReviewer: forcedPolicy?.approvalsReviewer ?? explicitApprovalsReviewer ?? defaultPolicy?.approvalsReviewer ?? (policyMode === "guardian" ? "auto_review" : "user"),
|
|
236
|
-
...serviceTier ? { serviceTier } : {}
|
|
293
|
+
...serviceTier ? { serviceTier } : {},
|
|
294
|
+
...resolveCodexAppServerNetworkProxy(config.networkProxy, resolvedSandbox)
|
|
237
295
|
};
|
|
238
296
|
}
|
|
239
297
|
function isCodexAppServerApprovalPolicyAllowedByRequirements(policy, params = {}) {
|
|
@@ -311,7 +369,7 @@ function codexAppServerStartOptionsKey(options, params = {}) {
|
|
|
311
369
|
args: options.args,
|
|
312
370
|
url: options.url ?? null,
|
|
313
371
|
authToken: hashSecretForKey(options.authToken, "authToken"),
|
|
314
|
-
headers: Object.entries(options.headers).toSorted(([left], [right]) => left.localeCompare(right)),
|
|
372
|
+
headers: Object.entries(options.headers).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `header:${key}`)]),
|
|
315
373
|
env: Object.entries(options.env ?? {}).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `env:${key}`)]),
|
|
316
374
|
clearEnv: [...options.clearEnv ?? []].toSorted(),
|
|
317
375
|
authProfileId: params.authProfileId ?? null,
|
|
@@ -333,6 +391,65 @@ function codexSandboxPolicyForTurn(mode, cwd) {
|
|
|
333
391
|
excludeSlashTmp: false
|
|
334
392
|
};
|
|
335
393
|
}
|
|
394
|
+
function resolveCodexAppServerNetworkProxy(config, sandbox) {
|
|
395
|
+
if (config?.enabled !== true) return {};
|
|
396
|
+
const fileSystemMode = config.baseProfile === "read-only" || !config.baseProfile && sandbox === "read-only" ? "read" : "write";
|
|
397
|
+
const networkConfig = removeUndefinedJsonFields({
|
|
398
|
+
enabled: true,
|
|
399
|
+
mode: config.mode,
|
|
400
|
+
domains: normalizeNetworkProxyPermissionMap(config.domains),
|
|
401
|
+
unix_sockets: normalizeNetworkProxyPermissionMap(config.unixSockets),
|
|
402
|
+
proxy_url: readNonEmptyString(config.proxyUrl),
|
|
403
|
+
socks_url: readNonEmptyString(config.socksUrl),
|
|
404
|
+
enable_socks5: config.enableSocks5,
|
|
405
|
+
enable_socks5_udp: config.enableSocks5Udp,
|
|
406
|
+
allow_upstream_proxy: config.allowUpstreamProxy,
|
|
407
|
+
allow_local_binding: config.allowLocalBinding,
|
|
408
|
+
dangerously_allow_non_loopback_proxy: config.dangerouslyAllowNonLoopbackProxy,
|
|
409
|
+
dangerously_allow_all_unix_sockets: config.dangerouslyAllowAllUnixSockets
|
|
410
|
+
});
|
|
411
|
+
const profile = {
|
|
412
|
+
filesystem: {
|
|
413
|
+
":minimal": "read",
|
|
414
|
+
":project_roots": { ".": fileSystemMode }
|
|
415
|
+
},
|
|
416
|
+
network: networkConfig
|
|
417
|
+
};
|
|
418
|
+
const profileName = resolveNetworkProxyPermissionProfileName(config, profile);
|
|
419
|
+
const configPatch = {
|
|
420
|
+
"features.network_proxy.enabled": true,
|
|
421
|
+
default_permissions: profileName,
|
|
422
|
+
permissions: { [profileName]: profile }
|
|
423
|
+
};
|
|
424
|
+
return { networkProxy: {
|
|
425
|
+
profileName,
|
|
426
|
+
configFingerprint: fingerprintCodexAppServerNetworkProxyConfigPatch(configPatch),
|
|
427
|
+
configPatch
|
|
428
|
+
} };
|
|
429
|
+
}
|
|
430
|
+
function resolveNetworkProxyPermissionProfileName(config, profile) {
|
|
431
|
+
const explicitProfileName = readNonEmptyString(config.profileName);
|
|
432
|
+
if (explicitProfileName) return explicitProfileName;
|
|
433
|
+
return `${DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX}-${createHash("sha256").update(stableStringifyJson({
|
|
434
|
+
version: 1,
|
|
435
|
+
profile
|
|
436
|
+
})).digest("hex").slice(0, 16)}`;
|
|
437
|
+
}
|
|
438
|
+
function fingerprintCodexAppServerNetworkProxyConfigPatch(configPatch) {
|
|
439
|
+
return createHash("sha256").update(stableStringifyJson(configPatch)).digest("hex");
|
|
440
|
+
}
|
|
441
|
+
function normalizeNetworkProxyPermissionMap(value) {
|
|
442
|
+
const entries = Object.entries(value ?? {}).map(([key, permission]) => [key.trim(), permission]).filter(([key]) => key.length > 0);
|
|
443
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
444
|
+
}
|
|
445
|
+
function removeUndefinedJsonFields(value) {
|
|
446
|
+
return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
|
|
447
|
+
}
|
|
448
|
+
function stableStringifyJson(value) {
|
|
449
|
+
if (Array.isArray(value)) return `[${value.map((item) => stableStringifyJson(item)).join(",")}]`;
|
|
450
|
+
if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringifyJson(item)}`).join(",")}}`;
|
|
451
|
+
return JSON.stringify(value);
|
|
452
|
+
}
|
|
336
453
|
function withMcpElicitationsApprovalPolicy(policy) {
|
|
337
454
|
if (typeof policy !== "string") return { granular: {
|
|
338
455
|
...policy.granular,
|
|
@@ -352,6 +469,34 @@ function withMcpElicitationsApprovalPolicy(policy) {
|
|
|
352
469
|
function resolveTransport(value) {
|
|
353
470
|
return value === "websocket" ? "websocket" : "stdio";
|
|
354
471
|
}
|
|
472
|
+
function normalizeRemoteWorkspaceRoot(value) {
|
|
473
|
+
return readNonEmptyString(value);
|
|
474
|
+
}
|
|
475
|
+
function inferCodexAppServerConnectionClass(params) {
|
|
476
|
+
if (params.transport !== "websocket") return "local-loopback";
|
|
477
|
+
return params.url && isLoopbackWebSocketUrl(params.url) ? "local-loopback" : "remote";
|
|
478
|
+
}
|
|
479
|
+
function assertCodexAppServerConnectionClassConfig(params) {
|
|
480
|
+
if (params.connectionClass === "remote" && !hasIdentityBearingWebSocketAuth({
|
|
481
|
+
authToken: params.authToken,
|
|
482
|
+
headers: params.headers
|
|
483
|
+
})) throw new Error("remote Codex app-server WebSocket URLs require appServer.authToken or an Authorization header");
|
|
484
|
+
}
|
|
485
|
+
function isLoopbackWebSocketUrl(value) {
|
|
486
|
+
let parsed;
|
|
487
|
+
try {
|
|
488
|
+
parsed = new URL(value);
|
|
489
|
+
} catch {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
if (parsed.protocol !== "ws:" && parsed.protocol !== "wss:") return false;
|
|
493
|
+
const host = parsed.hostname.toLowerCase();
|
|
494
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.startsWith("127.");
|
|
495
|
+
}
|
|
496
|
+
function hasIdentityBearingWebSocketAuth(params) {
|
|
497
|
+
if (readNonEmptyString(params.authToken)) return true;
|
|
498
|
+
return Object.entries(params.headers).some(([key, value]) => key.trim().toLowerCase() === "authorization" && Boolean(readNonEmptyString(value)));
|
|
499
|
+
}
|
|
355
500
|
function resolvePolicyMode(value) {
|
|
356
501
|
return value === "guardian" || value === "yolo" ? value : void 0;
|
|
357
502
|
}
|
|
@@ -880,7 +1025,13 @@ function normalizePositiveNumber(value, fallback) {
|
|
|
880
1025
|
}
|
|
881
1026
|
function normalizeHeaders(value) {
|
|
882
1027
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
883
|
-
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key.trim(),
|
|
1028
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key.trim(), normalizeCodexAppServerSecretInput({
|
|
1029
|
+
value: child,
|
|
1030
|
+
path: `plugins.entries.codex.config.appServer.headers.${key}`
|
|
1031
|
+
})]).filter((entry) => Boolean(entry[0] && entry[1])));
|
|
1032
|
+
}
|
|
1033
|
+
function normalizeCodexAppServerSecretInput(params) {
|
|
1034
|
+
return normalizeResolvedSecretInputString(params);
|
|
884
1035
|
}
|
|
885
1036
|
function normalizeStringList(value) {
|
|
886
1037
|
return normalizeTrimmedStringList(value);
|