@openclaw/codex 2026.7.2-beta.4 → 2026.7.2-beta.5
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/{app-server-policy-BO3jYBkv.js → app-server-policy-BmDgseo_.js} +1 -1
- package/dist/attempt-client-cleanup-Ia52yRWc.js +127 -0
- package/dist/{attempt-notifications-DdmnBMUp.js → attempt-notifications-CMR2_fmR.js} +1 -1
- package/dist/{bounded-turn-CaQL96kg.js → bounded-turn-FEbUXoYT.js} +36 -13
- package/dist/{capabilities-CLICvTxf.js → capabilities-BHRSI6Cn.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-DgADqnHa.js → command-formatters-ico4ZFnk.js} +2 -2
- package/dist/{command-handlers-l_lVPNlB.js → command-handlers-CRmnwI2N.js} +1232 -1221
- package/dist/{compact-CC5KhBzX.js → compact-dEN49UH6.js} +7 -7
- package/dist/{computer-use-Ip1-QGa-.js → computer-use-BjGylO-E.js} +16 -6
- package/dist/{conversation-control-sNPsbTCP.js → conversation-control-DE7d9DOj.js} +6 -6
- package/dist/doctor-contract-api.js +24 -86
- package/dist/{dynamic-tools-CQI3UwqY.js → dynamic-tools-LIt9ojep.js} +50 -46
- package/dist/{event-projector-usage-D6tE7_qD.js → event-projector-usage-tvgb1NCX.js} +2 -2
- package/dist/harness.js +14 -13
- package/dist/index.js +208 -267
- package/dist/media-understanding-provider.js +6 -1
- package/dist/{models-BNeMlHgg.js → models-BA01NEez.js} +2 -2
- package/dist/{notification-correlation-BGLixv5_.js → notification-correlation-Bj_Ak_jI.js} +3 -3
- package/dist/{plugin-app-cache-key-CvzvmBRz.js → plugin-app-cache-key-DSXX-rXO.js} +5 -5
- package/dist/{transcript-mirror-2p7kl6e4.js → protocol-validators-Dm4eXZmt.js} +2 -550
- package/dist/{rate-limits-D0IJT-a6.js → rate-limits-S_PXs0ul.js} +1 -1
- package/dist/realtime-voice-api-BPcA1uN9.js +494 -0
- package/dist/realtime-voice-api.js +2 -0
- package/dist/{request-BTccUTD3.js → request-CXpPennK.js} +1 -1
- package/dist/{run-attempt--858NXDl.js → run-attempt-C5GTPJOE.js} +417 -237
- package/dist/{session-binding-ZSMX1omP.js → session-binding-DlVQ-Pxs.js} +952 -890
- package/dist/{session-catalog-DsKaezgR.js → session-catalog-CP2oCcEb.js} +32 -23
- package/dist/{session-cli-CYJTfRLG.js → session-cli-CqZ0Fp2a.js} +2 -2
- package/dist/{session-upstream-marker-D7XlI9us.js → session-upstream-marker-QE-m5QFG.js} +1 -1
- package/dist/{settled-turn-finalizer-DHltNgtF.js → settled-turn-finalizer-CA_2QXIE.js} +2 -2
- package/dist/{shared-client-wmgNFNYp.js → shared-client-BVKE40c-.js} +1863 -1707
- package/dist/{side-question-BfFZCsJ-.js → side-question-CO12sHxo.js} +11 -9
- package/dist/{thread-lifecycle-cqrOlJkq.js → thread-lifecycle-DRg_FdzC.js} +12 -132
- package/dist/transcript-mirror-uKA-A4tB.js +550 -0
- package/dist/{upstream-session-fork-vPjwkT1i.js → upstream-session-fork-_Vrz4WJr.js} +3 -3
- package/dist/{usage-DM_I3mPT.js → usage-UpVbdX5G.js} +3 -3
- package/dist/{web-search-provider.runtime-Bx6HAc_k.js → web-search-provider.runtime-CaQMYDbp.js} +3 -3
- package/package.json +4 -5
- package/npm-shrinkwrap.json +0 -202
- package/dist/{auth-binding-C1czuHPA.js → auth-binding-B4FfbcCg.js} +1 -1
|
@@ -2,704 +2,526 @@ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
|
2
2
|
import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
5
|
+
import { AgentHarnessSessionSupersededError, embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
5
6
|
import { createHash, createHmac, randomBytes, randomUUID } from "node:crypto";
|
|
7
|
+
import { ensureAuthProfileStore, resolveDefaultAgentDir, resolveProviderIdForAuth, resolveSessionAgentIds as resolveSessionAgentIds$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
6
8
|
import { readFileSync } from "node:fs";
|
|
7
9
|
import { homedir, hostname } from "node:os";
|
|
8
|
-
import { ensureAuthProfileStore, resolveDefaultAgentDir, resolveProviderIdForAuth, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
|
|
9
10
|
import { resolveExecApprovalsFromFile } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
10
11
|
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
11
12
|
import { buildSecretInputSchema, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
12
13
|
import { normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
13
14
|
import { detectWindowsSpawnCommandInlineArgs } from "openclaw/plugin-sdk/windows-spawn";
|
|
14
|
-
import { parse } from "smol-toml";
|
|
15
15
|
import { z } from "zod";
|
|
16
|
-
import {
|
|
16
|
+
import { parse } from "smol-toml";
|
|
17
17
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18
18
|
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
19
|
-
//#region extensions/codex/src/app-server/
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
enabled: z.boolean().optional(),
|
|
23
|
-
timeoutMs: z.number().positive().optional()
|
|
24
|
-
}).strict();
|
|
19
|
+
//#region extensions/codex/src/app-server/config-contracts.ts
|
|
20
|
+
const CODEX_PLUGINS_MARKETPLACE_NAME = "openai-curated";
|
|
21
|
+
const CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME = "workspace-directory";
|
|
25
22
|
//#endregion
|
|
26
|
-
//#region extensions/codex/src/app-server/config.ts
|
|
23
|
+
//#region extensions/codex/src/app-server/config-utils.ts
|
|
27
24
|
const START_OPTIONS_KEY_SECRET_SYMBOL = Symbol.for("openclaw.codexAppServerStartOptionsKeySecret");
|
|
28
25
|
const START_OPTIONS_KEY_SECRET = getStartOptionsKeySecret();
|
|
29
|
-
const UNIX_CODEX_REQUIREMENTS_PATH = "/etc/codex/requirements.toml";
|
|
30
|
-
const WINDOWS_CODEX_REQUIREMENTS_SUFFIX = "\\OpenAI\\Codex\\requirements.toml";
|
|
31
|
-
const CODEX_APP_SERVER_HOME_DIRNAME = "codex-home";
|
|
32
|
-
const CODEX_CONFIG_TOML_FILENAME = "config.toml";
|
|
33
26
|
const PLAIN_DECIMAL_NUMBER_RE = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))$/;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
function shouldAutoApproveCodexAppServerApprovals(appServer) {
|
|
37
|
-
return appServer.networkProxy === void 0 && appServer.approvalPolicy === "never" && appServer.sandbox === "danger-full-access";
|
|
27
|
+
function readRecord(value) {
|
|
28
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
38
29
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"stdio",
|
|
48
|
-
"websocket",
|
|
49
|
-
"unix"
|
|
50
|
-
]);
|
|
51
|
-
const codexAppServerHomeScopeSchema = z.enum(["agent", "user"]);
|
|
52
|
-
const SecretInputSchema = buildSecretInputSchema();
|
|
53
|
-
const codexAppServerPolicyModeSchema = z.enum(["yolo", "guardian"]);
|
|
54
|
-
const codexAppServerApprovalPolicySchema = z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
|
|
55
|
-
"never",
|
|
56
|
-
"on-request",
|
|
57
|
-
"untrusted"
|
|
58
|
-
]));
|
|
59
|
-
const codexAppServerSandboxSchema = z.enum([
|
|
60
|
-
"read-only",
|
|
61
|
-
"workspace-write",
|
|
62
|
-
"danger-full-access"
|
|
63
|
-
]);
|
|
64
|
-
const codexAppServerApprovalsReviewerSchema = z.enum([
|
|
65
|
-
"user",
|
|
66
|
-
"auto_review",
|
|
67
|
-
"guardian_subagent"
|
|
68
|
-
]);
|
|
69
|
-
const codexDynamicToolsLoadingSchema = z.enum(["searchable", "direct"]);
|
|
70
|
-
const codexComputerUseHealthIntervalSchema = z.union([
|
|
71
|
-
z.literal(30),
|
|
72
|
-
z.literal(60),
|
|
73
|
-
z.literal(120),
|
|
74
|
-
z.literal(240)
|
|
75
|
-
]);
|
|
76
|
-
const codexComputerUsePluginCacheModeSchema = z.enum(["shared", "independent"]);
|
|
77
|
-
const codexPluginDestructivePolicySchema = z.union([
|
|
78
|
-
z.boolean(),
|
|
79
|
-
z.literal("auto"),
|
|
80
|
-
z.literal("ask")
|
|
81
|
-
]);
|
|
82
|
-
const codexAppServerServiceTierSchema = z.preprocess((value) => value === null ? null : normalizeCodexServiceTier(value), z.string().trim().min(1).nullable().optional()).optional();
|
|
83
|
-
const codexAppServerExperimentalSchema = z.object({ sandboxExecServer: z.boolean().optional() }).strict();
|
|
84
|
-
const codexAppServerRemoteWorkspaceRootSchema = z.string().trim().min(1);
|
|
85
|
-
const codexAppServerNetworkProxyDomainPermissionSchema = z.enum(["allow", "deny"]);
|
|
86
|
-
const codexAppServerNetworkProxyUnixSocketPermissionSchema = z.enum(["allow", "none"]);
|
|
87
|
-
const codexAppServerNetworkProxySchema = z.object({
|
|
88
|
-
enabled: z.boolean().optional(),
|
|
89
|
-
profileName: z.string().trim().min(1).optional(),
|
|
90
|
-
baseProfile: z.enum(["read-only", "workspace"]).optional(),
|
|
91
|
-
mode: z.enum(["limited", "full"]).optional(),
|
|
92
|
-
domains: z.record(z.string(), codexAppServerNetworkProxyDomainPermissionSchema).optional(),
|
|
93
|
-
unixSockets: z.record(z.string(), codexAppServerNetworkProxyUnixSocketPermissionSchema).optional(),
|
|
94
|
-
proxyUrl: z.string().trim().min(1).optional(),
|
|
95
|
-
socksUrl: z.string().trim().min(1).optional(),
|
|
96
|
-
enableSocks5: z.boolean().optional(),
|
|
97
|
-
enableSocks5Udp: z.boolean().optional(),
|
|
98
|
-
allowUpstreamProxy: z.boolean().optional(),
|
|
99
|
-
allowLocalBinding: z.boolean().optional(),
|
|
100
|
-
dangerouslyAllowNonLoopbackProxy: z.boolean().optional(),
|
|
101
|
-
dangerouslyAllowAllUnixSockets: z.boolean().optional()
|
|
102
|
-
}).strict();
|
|
103
|
-
const codexPluginEntryConfigSchema = z.object({
|
|
104
|
-
enabled: z.boolean().optional(),
|
|
105
|
-
marketplaceName: z.enum([CODEX_PLUGINS_MARKETPLACE_NAME, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME]).optional(),
|
|
106
|
-
pluginName: z.string().trim().min(1).optional(),
|
|
107
|
-
allow_destructive_actions: codexPluginDestructivePolicySchema.optional()
|
|
108
|
-
}).strict();
|
|
109
|
-
const codexPluginsConfigSchema = z.object({
|
|
110
|
-
enabled: z.boolean().optional(),
|
|
111
|
-
allow_all_plugins: z.boolean().optional(),
|
|
112
|
-
allow_destructive_actions: codexPluginDestructivePolicySchema.optional(),
|
|
113
|
-
plugins: z.record(z.string(), codexPluginEntryConfigSchema).optional()
|
|
114
|
-
}).strict();
|
|
115
|
-
const codexSupervisionEndpointSchema = z.union([z.object({
|
|
116
|
-
id: z.string().optional(),
|
|
117
|
-
label: z.string().optional(),
|
|
118
|
-
transport: z.literal("stdio-proxy").optional(),
|
|
119
|
-
command: z.string().optional(),
|
|
120
|
-
args: z.array(z.string()).optional(),
|
|
121
|
-
cwd: z.string().optional()
|
|
122
|
-
}).strict(), z.object({
|
|
123
|
-
id: z.string().optional(),
|
|
124
|
-
label: z.string().optional(),
|
|
125
|
-
transport: z.literal("websocket"),
|
|
126
|
-
url: z.string(),
|
|
127
|
-
authTokenEnv: z.string().optional()
|
|
128
|
-
}).strict()]);
|
|
129
|
-
const codexSupervisionConfigSchema = z.object({
|
|
130
|
-
enabled: z.boolean().optional(),
|
|
131
|
-
endpoints: z.array(codexSupervisionEndpointSchema).optional(),
|
|
132
|
-
allowRawTranscripts: z.boolean().optional(),
|
|
133
|
-
allowWriteControls: z.boolean().optional()
|
|
134
|
-
}).strict();
|
|
135
|
-
const codexPluginConfigSchema = z.object({
|
|
136
|
-
codexDynamicToolsLoading: codexDynamicToolsLoadingSchema.optional(),
|
|
137
|
-
codexDynamicToolsExclude: z.array(z.string()).optional(),
|
|
138
|
-
sessionCatalog: codexSessionCatalogConfigSchema.optional(),
|
|
139
|
-
discovery: codexDiscoveryConfigSchema.optional(),
|
|
140
|
-
computerUse: z.object({
|
|
141
|
-
enabled: z.boolean().optional(),
|
|
142
|
-
autoInstall: z.boolean().optional(),
|
|
143
|
-
marketplaceDiscoveryTimeoutMs: z.number().positive().optional(),
|
|
144
|
-
liveTestTimeoutMs: z.number().positive().optional(),
|
|
145
|
-
toolCallTimeoutMs: z.number().positive().optional(),
|
|
146
|
-
healthCheckEnabled: z.boolean().optional(),
|
|
147
|
-
healthCheckIntervalMinutes: codexComputerUseHealthIntervalSchema.optional(),
|
|
148
|
-
pluginCacheMode: codexComputerUsePluginCacheModeSchema.optional(),
|
|
149
|
-
strictReadiness: z.boolean().optional(),
|
|
150
|
-
autoRepair: z.boolean().optional(),
|
|
151
|
-
marketplaceSource: z.string().optional(),
|
|
152
|
-
marketplacePath: z.string().optional(),
|
|
153
|
-
marketplaceName: z.string().optional(),
|
|
154
|
-
pluginName: z.string().optional(),
|
|
155
|
-
mcpServerName: z.string().optional()
|
|
156
|
-
}).strict().optional(),
|
|
157
|
-
codexPlugins: z.unknown().optional(),
|
|
158
|
-
supervision: codexSupervisionConfigSchema.optional(),
|
|
159
|
-
appServer: z.object({
|
|
160
|
-
mode: codexAppServerPolicyModeSchema.optional(),
|
|
161
|
-
transport: codexAppServerTransportSchema.optional(),
|
|
162
|
-
homeScope: codexAppServerHomeScopeSchema.optional(),
|
|
163
|
-
command: z.string().optional(),
|
|
164
|
-
args: z.union([z.array(z.string()), z.string()]).optional(),
|
|
165
|
-
url: z.string().optional(),
|
|
166
|
-
authToken: SecretInputSchema.optional(),
|
|
167
|
-
headers: z.record(z.string(), SecretInputSchema).optional(),
|
|
168
|
-
clearEnv: z.array(z.string()).optional(),
|
|
169
|
-
remoteWorkspaceRoot: codexAppServerRemoteWorkspaceRootSchema.optional(),
|
|
170
|
-
codeModeOnly: z.boolean().optional(),
|
|
171
|
-
loopDetectionPreToolUseRelay: z.boolean().optional(),
|
|
172
|
-
requestTimeoutMs: z.number().positive().optional(),
|
|
173
|
-
turnCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
174
|
-
turnAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
175
|
-
postToolRawAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
176
|
-
approvalPolicy: codexAppServerApprovalPolicySchema.optional(),
|
|
177
|
-
sandbox: codexAppServerSandboxSchema.optional(),
|
|
178
|
-
approvalsReviewer: codexAppServerApprovalsReviewerSchema.optional(),
|
|
179
|
-
serviceTier: codexAppServerServiceTierSchema,
|
|
180
|
-
networkProxy: codexAppServerNetworkProxySchema.optional(),
|
|
181
|
-
defaultWorkspaceDir: z.string().optional(),
|
|
182
|
-
experimental: codexAppServerExperimentalSchema.optional()
|
|
183
|
-
}).strict().optional()
|
|
184
|
-
}).strict();
|
|
185
|
-
function readCodexPluginConfig(value) {
|
|
186
|
-
const parsed = codexPluginConfigSchema.safeParse(value);
|
|
187
|
-
if (!parsed.success) return {};
|
|
188
|
-
const { codexPlugins: rawCodexPlugins, ...config } = parsed.data;
|
|
189
|
-
const plugins = codexPluginsConfigSchema.safeParse(rawCodexPlugins);
|
|
190
|
-
if (!plugins.success) return config;
|
|
191
|
-
return {
|
|
192
|
-
...config,
|
|
193
|
-
...plugins.data ? { codexPlugins: plugins.data } : {}
|
|
194
|
-
};
|
|
30
|
+
function normalizeCodexServiceTier(value) {
|
|
31
|
+
if (typeof value !== "string") return;
|
|
32
|
+
const trimmed = value.trim();
|
|
33
|
+
if (!trimmed) return;
|
|
34
|
+
const normalized = trimmed.toLowerCase();
|
|
35
|
+
if (normalized === "fast" || normalized === "priority") return "priority";
|
|
36
|
+
if (normalized === "flex") return "flex";
|
|
37
|
+
return trimmed;
|
|
195
38
|
}
|
|
196
|
-
function
|
|
197
|
-
return
|
|
39
|
+
function isCodexFastServiceTier(value) {
|
|
40
|
+
return normalizeCodexServiceTier(value) === "priority";
|
|
198
41
|
}
|
|
199
|
-
function
|
|
200
|
-
|
|
201
|
-
if (!inlineArgs) return;
|
|
202
|
-
const sourceLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_BIN" : "plugins.entries.codex.config.appServer.command";
|
|
203
|
-
const argsLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_ARGS" : "plugins.entries.codex.config.appServer.args";
|
|
204
|
-
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.`);
|
|
42
|
+
function normalizePositiveNumber(value, fallback) {
|
|
43
|
+
return resolvePositiveTimerTimeoutMs(value, fallback);
|
|
205
44
|
}
|
|
206
|
-
function
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (!isCodexPluginMarketplaceName(entry.marketplaceName) || !entry.pluginName) return [];
|
|
213
|
-
const entryDestructivePolicy = resolveCodexPluginDestructivePolicy(entry.allow_destructive_actions ?? config?.allow_destructive_actions ?? true);
|
|
214
|
-
return [{
|
|
215
|
-
configKey,
|
|
216
|
-
marketplaceName: entry.marketplaceName,
|
|
217
|
-
pluginName: entry.pluginName,
|
|
218
|
-
enabled: enabled && entry.enabled !== false,
|
|
219
|
-
allowDestructiveActions: entryDestructivePolicy.allowDestructiveActions,
|
|
220
|
-
destructiveApprovalMode: entryDestructivePolicy.destructiveApprovalMode
|
|
221
|
-
}];
|
|
222
|
-
}).toSorted((left, right) => left.configKey.localeCompare(right.configKey));
|
|
223
|
-
return {
|
|
224
|
-
configured,
|
|
225
|
-
enabled,
|
|
226
|
-
allowAllPlugins: enabled && config?.allow_all_plugins === true,
|
|
227
|
-
allowDestructiveActions: destructivePolicy.allowDestructiveActions,
|
|
228
|
-
destructiveApprovalMode: destructivePolicy.destructiveApprovalMode,
|
|
229
|
-
pluginPolicies
|
|
230
|
-
};
|
|
45
|
+
function normalizeHeaders(value) {
|
|
46
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
47
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key.trim(), normalizeCodexAppServerSecretInput({
|
|
48
|
+
value: child,
|
|
49
|
+
path: `plugins.entries.codex.config.appServer.headers.${key}`
|
|
50
|
+
})]).filter((entry) => Boolean(entry[0] && entry[1])));
|
|
231
51
|
}
|
|
232
|
-
function
|
|
233
|
-
return
|
|
52
|
+
function normalizeCodexAppServerSecretInput(params) {
|
|
53
|
+
return normalizeResolvedSecretInputString(params);
|
|
234
54
|
}
|
|
235
|
-
function
|
|
236
|
-
|
|
237
|
-
allowDestructiveActions: true,
|
|
238
|
-
destructiveApprovalMode: policy
|
|
239
|
-
};
|
|
240
|
-
return {
|
|
241
|
-
allowDestructiveActions: policy,
|
|
242
|
-
destructiveApprovalMode: policy ? "allow" : "deny"
|
|
243
|
-
};
|
|
55
|
+
function normalizeStringList(value) {
|
|
56
|
+
return normalizeTrimmedStringList(value);
|
|
244
57
|
}
|
|
245
|
-
function
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const clearEnv = normalizeStringList(config.clearEnv);
|
|
261
|
-
const authToken = normalizeCodexAppServerSecretInput({
|
|
262
|
-
value: config.authToken,
|
|
263
|
-
path: "plugins.entries.codex.config.appServer.authToken"
|
|
264
|
-
});
|
|
265
|
-
const url = readNonEmptyString(config.url) ?? (transport === "unix" ? "unix://" : void 0);
|
|
266
|
-
const connectionClass = inferCodexAppServerConnectionClass({
|
|
267
|
-
transport,
|
|
268
|
-
url
|
|
269
|
-
});
|
|
270
|
-
const remoteAppsSubstrate = "preconfigured";
|
|
271
|
-
const remoteWorkspaceRoot = normalizeRemoteWorkspaceRoot(config.remoteWorkspaceRoot);
|
|
272
|
-
const execMode = resolveEffectiveOpenClawExecModeForCodexAppServer({
|
|
273
|
-
execMode: params.execMode,
|
|
274
|
-
execPolicy: params.execPolicy
|
|
275
|
-
});
|
|
276
|
-
assertCodexAppServerAllowedForOpenClawExecMode(execMode);
|
|
277
|
-
const explicitPolicyMode = resolvePolicyMode(config.mode) ?? resolvePolicyMode(env.OPENCLAW_CODEX_APP_SERVER_MODE);
|
|
278
|
-
const configuredSandbox = resolveSandbox(config.sandbox) ?? resolveSandbox(env.OPENCLAW_CODEX_APP_SERVER_SANDBOX);
|
|
279
|
-
const explicitApprovalsReviewer = resolveApprovalsReviewer(config.approvalsReviewer);
|
|
280
|
-
const normalizedPolicyMode = resolveCodexPolicyModeForOpenClawExecMode(execMode);
|
|
281
|
-
const ignoreLegacyYoloPolicyMode = normalizedPolicyMode === "guardian" && explicitPolicyMode === "yolo";
|
|
282
|
-
const canUseModelBackedReviewer = canUseCodexModelBackedApprovalsReviewerForModel({
|
|
283
|
-
modelProvider: params.modelProvider,
|
|
284
|
-
model: params.model,
|
|
285
|
-
config: params.config,
|
|
286
|
-
env,
|
|
287
|
-
agentDir: params.agentDir,
|
|
288
|
-
codexConfigToml: params.codexConfigToml,
|
|
289
|
-
homeScope
|
|
290
|
-
});
|
|
291
|
-
const forceUserReviewer = !canUseModelBackedReviewer && (explicitApprovalsReviewer === "auto_review" || explicitApprovalsReviewer === "guardian_subagent" || explicitPolicyMode === "guardian" && explicitApprovalsReviewer !== "user") || execMode !== void 0 && execMode !== "full" && (execMode !== "auto" || !canUseModelBackedReviewer);
|
|
292
|
-
const forceGuardianReviewer = execMode === "auto" && canUseModelBackedReviewer;
|
|
293
|
-
const execModeRequiringPromptingApprovals = execMode === "auto" || execMode === "ask" ? execMode : forceUserReviewer ? "ask" : void 0;
|
|
294
|
-
const forceDangerFullAccessSandbox = params.execPolicy?.touched === true && params.execPolicy.security === "full" && params.execPolicy.ask === "always";
|
|
295
|
-
const forceRuntimePolicy = forceUserReviewer || forceGuardianReviewer || forceDangerFullAccessSandbox;
|
|
296
|
-
const defaultPolicy = explicitPolicyMode && !forceRuntimePolicy && !ignoreLegacyYoloPolicyMode ? void 0 : resolveDefaultCodexAppServerPolicy({
|
|
297
|
-
transport,
|
|
298
|
-
env,
|
|
299
|
-
forceGuardian: normalizedPolicyMode === "guardian",
|
|
300
|
-
forceUserReviewer: forceUserReviewer || !canUseModelBackedReviewer,
|
|
301
|
-
execModeRequiringPromptingApprovals,
|
|
302
|
-
requirementsToml: params.requirementsToml,
|
|
303
|
-
requirementsPath: params.requirementsPath,
|
|
304
|
-
readRequirementsFile: params.readRequirementsFile,
|
|
305
|
-
platform: params.platform,
|
|
306
|
-
hostName: params.hostName,
|
|
307
|
-
execModeRequiringUserReviewer: forceUserReviewer ? execMode : void 0
|
|
308
|
-
});
|
|
309
|
-
const preserveExplicitAutoSandbox = forceGuardianReviewer && configuredSandbox === "read-only";
|
|
310
|
-
const forcedPolicy = forceRuntimePolicy ? {
|
|
311
|
-
approvalPolicy: defaultPolicy?.approvalPolicy ?? "on-request",
|
|
312
|
-
sandbox: preserveExplicitAutoSandbox ? void 0 : forceDangerFullAccessSandbox ? selectForcedDangerFullAccessSandbox({
|
|
313
|
-
configuredSandbox,
|
|
314
|
-
defaultPolicy,
|
|
315
|
-
openClawSandboxActive: Boolean(params.openClawSandboxActive)
|
|
316
|
-
}) : selectForcedPromptingSandbox({
|
|
317
|
-
configuredSandbox,
|
|
318
|
-
defaultSandbox: defaultPolicy?.sandbox
|
|
319
|
-
}),
|
|
320
|
-
approvalsReviewer: defaultPolicy?.approvalsReviewer ?? (forceUserReviewer ? "user" : "auto_review")
|
|
321
|
-
} : void 0;
|
|
322
|
-
const policyMode = ignoreLegacyYoloPolicyMode ? normalizedPolicyMode : explicitPolicyMode ?? normalizedPolicyMode ?? defaultPolicy?.mode ?? "yolo";
|
|
323
|
-
const serviceTier = normalizeCodexServiceTier(config.serviceTier);
|
|
324
|
-
const resolvedSandbox = forcedPolicy?.sandbox ?? configuredSandbox ?? defaultPolicy?.sandbox ?? (policyMode === "guardian" ? "workspace-write" : "danger-full-access");
|
|
325
|
-
if (transport === "websocket" && !url) throw new Error("plugins.entries.codex.config.appServer.url is required when appServer.transport is websocket");
|
|
326
|
-
if (transport === "websocket" && homeScope === "user") throw new Error("plugins.entries.codex.config.appServer.homeScope=user requires appServer.transport=stdio or unix");
|
|
327
|
-
if (transport === "unix" && homeScope !== "user") throw new Error("plugins.entries.codex.config.appServer.transport=unix requires appServer.homeScope=user");
|
|
328
|
-
if (transport === "unix" && !url?.startsWith("unix://")) throw new Error("plugins.entries.codex.config.appServer.url must use unix:// when appServer.transport is unix");
|
|
329
|
-
assertCodexAppServerConnectionSecurity({
|
|
330
|
-
transport,
|
|
331
|
-
url,
|
|
332
|
-
authToken,
|
|
333
|
-
headers
|
|
334
|
-
});
|
|
335
|
-
const configApprovalPolicy = resolveApprovalPolicy(config.approvalPolicy);
|
|
336
|
-
const envApprovalPolicy = resolveApprovalPolicy(env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY);
|
|
337
|
-
const approvalPolicy = configApprovalPolicy ?? envApprovalPolicy ?? defaultPolicy?.approvalPolicy ?? (policyMode === "guardian" ? "on-request" : "never");
|
|
338
|
-
const approvalPolicySource = configApprovalPolicy ? "config" : envApprovalPolicy ? "env" : defaultPolicy?.approvalPolicy ? "requirements" : "implicit";
|
|
339
|
-
const computerUseConfig = resolveCodexComputerUseConfig({
|
|
340
|
-
pluginConfig: params.pluginConfig,
|
|
341
|
-
env
|
|
342
|
-
});
|
|
343
|
-
const managedCommandOrder = params.managedCommandOrder ?? (homeScope === "user" || computerUseConfig.enabled ? "desktop-first" : "package-first");
|
|
344
|
-
const includeManagedCommandOrder = commandSource === "managed" && (managedCommandOrder === "desktop-first" || params.managedCommandOrder === "package-first");
|
|
345
|
-
const managedComputerUsePluginNames = [.../* @__PURE__ */ new Set([DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME, computerUseConfig.pluginName])];
|
|
346
|
-
return {
|
|
347
|
-
start: {
|
|
348
|
-
transport,
|
|
349
|
-
homeScope,
|
|
350
|
-
command,
|
|
351
|
-
commandSource,
|
|
352
|
-
...includeManagedCommandOrder ? { managedCommandOrder } : {},
|
|
353
|
-
...commandSource === "managed" ? { managedComputerUsePluginNames } : {},
|
|
354
|
-
args: args.length > 0 ? args : [
|
|
355
|
-
"app-server",
|
|
356
|
-
"--listen",
|
|
357
|
-
"stdio://"
|
|
358
|
-
],
|
|
359
|
-
...url ? { url } : {},
|
|
360
|
-
...authToken ? { authToken } : {},
|
|
361
|
-
headers,
|
|
362
|
-
...transport === "stdio" && clearEnv.length > 0 ? { clearEnv } : {}
|
|
363
|
-
},
|
|
364
|
-
connectionClass,
|
|
365
|
-
remoteAppsSubstrate,
|
|
366
|
-
...remoteWorkspaceRoot ? { remoteWorkspaceRoot } : {},
|
|
367
|
-
codeModeOnly: config.codeModeOnly === true,
|
|
368
|
-
loopDetectionPreToolUseRelay: config.loopDetectionPreToolUseRelay !== false,
|
|
369
|
-
requestTimeoutMs: normalizePositiveNumber(config.requestTimeoutMs, 6e4),
|
|
370
|
-
turnCompletionIdleTimeoutMs: normalizePositiveNumber(config.turnCompletionIdleTimeoutMs, 6e4),
|
|
371
|
-
turnAssistantCompletionIdleTimeoutMs: normalizePositiveNumber(config.turnAssistantCompletionIdleTimeoutMs, 1e4),
|
|
372
|
-
...config.postToolRawAssistantCompletionIdleTimeoutMs !== void 0 ? { postToolRawAssistantCompletionIdleTimeoutMs: normalizePositiveNumber(config.postToolRawAssistantCompletionIdleTimeoutMs, 6e4) } : {},
|
|
373
|
-
approvalPolicy: forcedPolicy?.approvalPolicy ?? approvalPolicy,
|
|
374
|
-
approvalPolicySource,
|
|
375
|
-
sandbox: resolvedSandbox,
|
|
376
|
-
approvalsReviewer: forcedPolicy?.approvalsReviewer ?? explicitApprovalsReviewer ?? defaultPolicy?.approvalsReviewer ?? (policyMode === "guardian" ? "auto_review" : "user"),
|
|
377
|
-
...serviceTier ? { serviceTier } : {},
|
|
378
|
-
...resolveCodexAppServerNetworkProxy(config.networkProxy, resolvedSandbox)
|
|
379
|
-
};
|
|
58
|
+
function readBooleanEnv(value) {
|
|
59
|
+
if (value === void 0) return;
|
|
60
|
+
const normalized = value.trim().toLowerCase();
|
|
61
|
+
if ([
|
|
62
|
+
"1",
|
|
63
|
+
"true",
|
|
64
|
+
"yes",
|
|
65
|
+
"on"
|
|
66
|
+
].includes(normalized)) return true;
|
|
67
|
+
if ([
|
|
68
|
+
"0",
|
|
69
|
+
"false",
|
|
70
|
+
"no",
|
|
71
|
+
"off"
|
|
72
|
+
].includes(normalized)) return false;
|
|
380
73
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
* effective agent home is known, so Computer Use keeps the desktop app's TCC ownership.
|
|
384
|
-
*/
|
|
385
|
-
function resolveCodexAppServerStartOptionsForAgent(params) {
|
|
386
|
-
const startOptions = params.startOptions;
|
|
387
|
-
if (startOptions.transport !== "stdio" || startOptions.commandSource !== "managed" || startOptions.managedCommandOrder !== void 0) return startOptions;
|
|
388
|
-
if (startOptions.homeScope === "user") return {
|
|
389
|
-
...startOptions,
|
|
390
|
-
managedCommandOrder: "desktop-first"
|
|
391
|
-
};
|
|
392
|
-
return codexConfigEnablesNativeComputerUse({
|
|
393
|
-
agentDir: params.agentDir,
|
|
394
|
-
codexConfigToml: params.codexConfigToml,
|
|
395
|
-
env: params.env,
|
|
396
|
-
homeScope: "agent",
|
|
397
|
-
pluginNames: startOptions.managedComputerUsePluginNames ?? [DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME]
|
|
398
|
-
}) ? {
|
|
399
|
-
...startOptions,
|
|
400
|
-
managedCommandOrder: "desktop-first"
|
|
401
|
-
} : startOptions;
|
|
74
|
+
function readExecSecurity(value) {
|
|
75
|
+
return value === "deny" || value === "allowlist" || value === "full" ? value : void 0;
|
|
402
76
|
}
|
|
403
|
-
function
|
|
404
|
-
|
|
405
|
-
if (content === void 0) return true;
|
|
406
|
-
const allowedApprovalPolicies = parseAllowedApprovalPoliciesFromCodexRequirements(content);
|
|
407
|
-
return allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has(policy);
|
|
77
|
+
function readExecAsk(value) {
|
|
78
|
+
return value === "off" || value === "on-miss" || value === "always" ? value : void 0;
|
|
408
79
|
}
|
|
409
|
-
function
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return isTrustedCodexModelBackedApprovalsReviewerProvider(explicitProvider, params);
|
|
80
|
+
function readNumberEnv(value) {
|
|
81
|
+
const trimmed = value?.trim();
|
|
82
|
+
if (!trimmed || !PLAIN_DECIMAL_NUMBER_RE.test(trimmed)) return;
|
|
83
|
+
const parsed = Number(trimmed);
|
|
84
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
415
85
|
}
|
|
416
|
-
function
|
|
417
|
-
if (
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const openAIProviders = readConfiguredOpenAIProvidersForModelBackedReview(params.config);
|
|
421
|
-
if (openAIProviders.length === 0) return true;
|
|
422
|
-
return openAIProviders.every((openAIProvider) => configuredOpenAIProviderIsTrustedForModelBackedReview(openAIProvider, params.model));
|
|
86
|
+
function resolveArgs(configArgs, envArgs) {
|
|
87
|
+
if (Array.isArray(configArgs)) return configArgs.map((entry) => readNonEmptyString(entry)).filter((entry) => entry !== void 0);
|
|
88
|
+
if (typeof configArgs === "string") return splitShellWords(configArgs);
|
|
89
|
+
return splitShellWords(envArgs ?? "");
|
|
423
90
|
}
|
|
424
|
-
function
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(provider),
|
|
428
|
-
model: params.model
|
|
429
|
-
};
|
|
430
|
-
const bindingModelProvider = params.bindingModelProvider?.trim();
|
|
431
|
-
const currentModel = params.model?.trim();
|
|
432
|
-
const bindingModel = params.bindingModel?.trim();
|
|
433
|
-
if (bindingModelProvider && currentModel && bindingModel && currentModel === bindingModel) return {
|
|
434
|
-
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(bindingModelProvider),
|
|
435
|
-
model: params.model ?? params.bindingModel
|
|
436
|
-
};
|
|
437
|
-
const currentModelProvider = inferProviderFromModelRef(params.model);
|
|
438
|
-
if (currentModelProvider) return {
|
|
439
|
-
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(currentModelProvider),
|
|
440
|
-
model: params.model
|
|
441
|
-
};
|
|
442
|
-
if (bindingModelProvider) return {
|
|
443
|
-
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(bindingModelProvider),
|
|
444
|
-
model: params.model ?? params.bindingModel
|
|
445
|
-
};
|
|
446
|
-
return {
|
|
447
|
-
modelProvider: params.nativeAuthProfile === true ? "openai" : void 0,
|
|
448
|
-
model: params.model ?? params.bindingModel
|
|
449
|
-
};
|
|
91
|
+
function readNonEmptyString(value) {
|
|
92
|
+
if (typeof value !== "string") return;
|
|
93
|
+
return value.trim() || void 0;
|
|
450
94
|
}
|
|
451
|
-
function
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
const marketplaceSource = readNonEmptyString(params.overrides?.marketplaceSource) ?? readNonEmptyString(config.marketplaceSource) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_SOURCE);
|
|
455
|
-
const marketplacePath = readNonEmptyString(params.overrides?.marketplacePath) ?? readNonEmptyString(config.marketplacePath) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_PATH);
|
|
456
|
-
const marketplaceName = readNonEmptyString(params.overrides?.marketplaceName) ?? readNonEmptyString(config.marketplaceName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_NAME);
|
|
457
|
-
const configuredPluginName = readNonEmptyString(params.overrides?.pluginName) ?? readNonEmptyString(config.pluginName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_NAME);
|
|
458
|
-
const configuredMcpServerName = readNonEmptyString(params.overrides?.mcpServerName) ?? readNonEmptyString(config.mcpServerName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MCP_SERVER_NAME);
|
|
459
|
-
const autoInstall = params.overrides?.autoInstall ?? config.autoInstall ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_AUTO_INSTALL) ?? false;
|
|
460
|
-
const marketplaceDiscoveryTimeoutMs = normalizePositiveNumber(params.overrides?.marketplaceDiscoveryTimeoutMs ?? config.marketplaceDiscoveryTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS);
|
|
461
|
-
const liveTestTimeoutMs = normalizePositiveNumber(params.overrides?.liveTestTimeoutMs ?? config.liveTestTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS);
|
|
462
|
-
const toolCallTimeoutMs = normalizePositiveNumber(params.overrides?.toolCallTimeoutMs ?? config.toolCallTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS);
|
|
463
|
-
const healthCheckIntervalMinutes = normalizeComputerUseHealthCheckIntervalMinutes(params.overrides?.healthCheckIntervalMinutes ?? config.healthCheckIntervalMinutes ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_HEALTH_CHECK_INTERVAL_MINUTES));
|
|
464
|
-
const healthCheckEnabled = params.overrides?.healthCheckEnabled ?? config.healthCheckEnabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_HEALTH_CHECK_ENABLED) ?? false;
|
|
465
|
-
const pluginCacheMode = normalizeComputerUsePluginCacheMode(params.overrides?.pluginCacheMode) ?? normalizeComputerUsePluginCacheMode(config.pluginCacheMode) ?? normalizeComputerUsePluginCacheMode(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_CACHE_MODE) ?? "independent";
|
|
466
|
-
const strictReadiness = params.overrides?.strictReadiness ?? config.strictReadiness ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_STRICT_READINESS) ?? false;
|
|
467
|
-
const autoRepair = params.overrides?.autoRepair ?? config.autoRepair ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_AUTO_REPAIR) ?? false;
|
|
468
|
-
return {
|
|
469
|
-
enabled: params.overrides?.enabled ?? config.enabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE) ?? Boolean(autoInstall || marketplaceSource || marketplacePath || marketplaceName || configuredPluginName || configuredMcpServerName),
|
|
470
|
-
autoInstall,
|
|
471
|
-
marketplaceDiscoveryTimeoutMs,
|
|
472
|
-
liveTestTimeoutMs,
|
|
473
|
-
toolCallTimeoutMs,
|
|
474
|
-
healthCheckEnabled,
|
|
475
|
-
healthCheckIntervalMinutes,
|
|
476
|
-
pluginCacheMode,
|
|
477
|
-
strictReadiness,
|
|
478
|
-
autoRepair,
|
|
479
|
-
pluginName: configuredPluginName ?? DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME,
|
|
480
|
-
mcpServerName: configuredMcpServerName ?? DEFAULT_CODEX_COMPUTER_USE_MCP_SERVER_NAME,
|
|
481
|
-
...marketplaceSource ? { marketplaceSource } : {},
|
|
482
|
-
...marketplacePath ? { marketplacePath } : {},
|
|
483
|
-
...marketplaceName ? { marketplaceName } : {}
|
|
484
|
-
};
|
|
95
|
+
function hashSecretForKey(value, label) {
|
|
96
|
+
if (!value) return null;
|
|
97
|
+
return createHmac("sha256", START_OPTIONS_KEY_SECRET).update(label).update("\0").update(value).digest("hex");
|
|
485
98
|
}
|
|
486
|
-
function
|
|
487
|
-
|
|
99
|
+
function getStartOptionsKeySecret() {
|
|
100
|
+
const globalState = globalThis;
|
|
101
|
+
globalState[START_OPTIONS_KEY_SECRET_SYMBOL] ??= randomBytes(32);
|
|
102
|
+
return globalState[START_OPTIONS_KEY_SECRET_SYMBOL];
|
|
488
103
|
}
|
|
489
|
-
function
|
|
490
|
-
|
|
104
|
+
function splitShellWords(value) {
|
|
105
|
+
const words = [];
|
|
106
|
+
let current = "";
|
|
107
|
+
let quote = null;
|
|
108
|
+
for (const char of value) {
|
|
109
|
+
if (quote) {
|
|
110
|
+
if (char === quote) quote = null;
|
|
111
|
+
else current += char;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (char === "\"" || char === "'") {
|
|
115
|
+
quote = char;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (/\s/.test(char)) {
|
|
119
|
+
if (current) {
|
|
120
|
+
words.push(current);
|
|
121
|
+
current = "";
|
|
122
|
+
}
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
current += char;
|
|
126
|
+
}
|
|
127
|
+
if (current) words.push(current);
|
|
128
|
+
return words;
|
|
491
129
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
managedCommandOrder: options.managedCommandOrder ?? "package-first",
|
|
498
|
-
managedComputerUsePluginNames: [...options.managedComputerUsePluginNames ?? []].toSorted(),
|
|
499
|
-
managedFallbackCommandPaths: [...options.managedFallbackCommandPaths ?? []],
|
|
500
|
-
args: options.args,
|
|
501
|
-
cwd: options.cwd ?? null,
|
|
502
|
-
url: options.url ?? null,
|
|
503
|
-
authToken: hashSecretForKey(options.authToken, "authToken"),
|
|
504
|
-
headers: Object.entries(options.headers).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `header:${key}`)]),
|
|
505
|
-
env: Object.entries(options.env ?? {}).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `env:${key}`)]),
|
|
506
|
-
clearEnv: [...options.clearEnv ?? []].toSorted(),
|
|
507
|
-
authProfileId: params.authProfileId ?? null,
|
|
508
|
-
authBindingFingerprint: params.authBindingFingerprint ?? null,
|
|
509
|
-
agentDir: params.agentDir ?? null,
|
|
510
|
-
fallbackApiKeyCacheKey: params.fallbackApiKeyCacheKey ?? null
|
|
511
|
-
});
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region extensions/codex/src/app-server/config-exec-policy.ts
|
|
132
|
+
function selectForcedPromptingSandbox(params) {
|
|
133
|
+
if (params.configuredSandbox === "read-only" || params.defaultSandbox === "read-only") return "read-only";
|
|
134
|
+
return params.defaultSandbox ?? "workspace-write";
|
|
512
135
|
}
|
|
513
|
-
function
|
|
514
|
-
if (
|
|
515
|
-
if (
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
return
|
|
520
|
-
type: "workspaceWrite",
|
|
521
|
-
writableRoots: [cwd],
|
|
522
|
-
networkAccess: false,
|
|
523
|
-
excludeTmpdirEnvVar: false,
|
|
524
|
-
excludeSlashTmp: false
|
|
525
|
-
};
|
|
136
|
+
function selectForcedDangerFullAccessSandbox(params) {
|
|
137
|
+
if (params.configuredSandbox === "read-only") return "read-only";
|
|
138
|
+
if (params.defaultPolicy?.dangerFullAccessAllowed === false) {
|
|
139
|
+
if (params.openClawSandboxActive) return params.defaultPolicy.sandbox ?? "workspace-write";
|
|
140
|
+
throw new Error("legacy full exec security with ask requires Codex app-server danger-full-access");
|
|
141
|
+
}
|
|
142
|
+
return "danger-full-access";
|
|
526
143
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
const homeScope = appServer.homeScope ?? (transport === "websocket" ? "agent" : "user");
|
|
533
|
-
return resolveCodexAppServerRuntimeOptions({
|
|
534
|
-
...params,
|
|
535
|
-
pluginConfig: {
|
|
536
|
-
...pluginConfig,
|
|
537
|
-
appServer: {
|
|
538
|
-
...appServer,
|
|
539
|
-
homeScope
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
});
|
|
144
|
+
function selectGuardianSandbox(allowedSandboxModes) {
|
|
145
|
+
if (allowedSandboxModes === void 0 || allowedSandboxModes.has("workspace-write")) return "workspace-write";
|
|
146
|
+
if (allowedSandboxModes.has("read-only")) return "read-only";
|
|
147
|
+
if (allowedSandboxModes.has("danger-full-access")) return "danger-full-access";
|
|
148
|
+
return "workspace-write";
|
|
543
149
|
}
|
|
544
|
-
function
|
|
545
|
-
if (
|
|
546
|
-
|
|
547
|
-
const networkConfig = removeUndefinedJsonFields({
|
|
548
|
-
enabled: true,
|
|
549
|
-
mode: config.mode,
|
|
550
|
-
domains: normalizeNetworkProxyPermissionMap(config.domains),
|
|
551
|
-
unix_sockets: normalizeNetworkProxyPermissionMap(config.unixSockets),
|
|
552
|
-
proxy_url: readNonEmptyString(config.proxyUrl),
|
|
553
|
-
socks_url: readNonEmptyString(config.socksUrl),
|
|
554
|
-
enable_socks5: config.enableSocks5,
|
|
555
|
-
enable_socks5_udp: config.enableSocks5Udp,
|
|
556
|
-
allow_upstream_proxy: config.allowUpstreamProxy,
|
|
557
|
-
allow_local_binding: config.allowLocalBinding,
|
|
558
|
-
dangerously_allow_non_loopback_proxy: config.dangerouslyAllowNonLoopbackProxy,
|
|
559
|
-
dangerously_allow_all_unix_sockets: config.dangerouslyAllowAllUnixSockets
|
|
560
|
-
});
|
|
561
|
-
const profile = {
|
|
562
|
-
filesystem: {
|
|
563
|
-
":minimal": "read",
|
|
564
|
-
":project_roots": { ".": fileSystemMode }
|
|
565
|
-
},
|
|
566
|
-
network: networkConfig
|
|
567
|
-
};
|
|
568
|
-
const profileName = resolveNetworkProxyPermissionProfileName(config, profile);
|
|
569
|
-
const configPatch = {
|
|
570
|
-
"features.network_proxy.enabled": true,
|
|
571
|
-
default_permissions: profileName,
|
|
572
|
-
permissions: { [profileName]: profile }
|
|
573
|
-
};
|
|
574
|
-
return { networkProxy: {
|
|
575
|
-
profileName,
|
|
576
|
-
configFingerprint: fingerprintCodexAppServerNetworkProxyConfigPatch(configPatch),
|
|
577
|
-
configPatch
|
|
578
|
-
} };
|
|
150
|
+
function resolveApprovalPolicy(value) {
|
|
151
|
+
if (value === "on-failure") return "on-request";
|
|
152
|
+
return value === "on-request" || value === "untrusted" || value === "never" ? value : void 0;
|
|
579
153
|
}
|
|
580
|
-
function
|
|
581
|
-
|
|
582
|
-
if (explicitProfileName) return explicitProfileName;
|
|
583
|
-
const suffix = createHash("sha256").update(stableStringifyJson({
|
|
584
|
-
version: 1,
|
|
585
|
-
profile
|
|
586
|
-
})).digest("hex").slice(0, 16);
|
|
587
|
-
return `${DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX}-${suffix}`;
|
|
154
|
+
function resolveSandbox(value) {
|
|
155
|
+
return value === "read-only" || value === "workspace-write" || value === "danger-full-access" ? value : void 0;
|
|
588
156
|
}
|
|
589
|
-
function
|
|
590
|
-
return
|
|
157
|
+
function resolveApprovalsReviewer(value) {
|
|
158
|
+
return value === "auto_review" || value === "guardian_subagent" || value === "user" ? value : void 0;
|
|
591
159
|
}
|
|
592
|
-
function
|
|
593
|
-
const
|
|
594
|
-
|
|
160
|
+
function resolveOpenClawExecPolicyFromConfig(params) {
|
|
161
|
+
const root = readRecord(params.config);
|
|
162
|
+
const globalExec = readRecord(readRecord(root?.tools)?.exec);
|
|
163
|
+
const globalPolicy = applyOpenClawExecPolicyLayer(createDefaultOpenClawExecPolicy(), globalExec);
|
|
164
|
+
const agentId = params.agentId?.trim();
|
|
165
|
+
if (!agentId) return globalPolicy;
|
|
166
|
+
const agents = readRecord(root?.agents);
|
|
167
|
+
const agentList = Array.isArray(agents?.list) ? agents.list : [];
|
|
168
|
+
const normalizedAgentId = normalizeAgentId(agentId);
|
|
169
|
+
return applyOpenClawExecPolicyLayer(globalPolicy, readRecord(readRecord(readRecord(agentList.find((entry) => {
|
|
170
|
+
const id = readRecord(entry)?.id;
|
|
171
|
+
return typeof id === "string" && normalizeAgentId(id) === normalizedAgentId;
|
|
172
|
+
}))?.tools)?.exec));
|
|
595
173
|
}
|
|
596
|
-
function
|
|
597
|
-
|
|
174
|
+
function resolveOpenClawExecPolicyForCodexAppServer(params) {
|
|
175
|
+
const overridePolicy = applyOpenClawExecPolicyLayer(resolveOpenClawExecPolicyFromConfig({
|
|
176
|
+
config: params.config,
|
|
177
|
+
agentId: params.agentId
|
|
178
|
+
}), params.execOverrides);
|
|
179
|
+
return applyOpenClawExecApprovalFloors(overridePolicy, resolveOpenClawExecApprovalFloorsForCodexAppServer({
|
|
180
|
+
approvals: params.approvals,
|
|
181
|
+
agentId: params.agentId,
|
|
182
|
+
policy: overridePolicy
|
|
183
|
+
}));
|
|
598
184
|
}
|
|
599
|
-
function
|
|
600
|
-
if (
|
|
601
|
-
|
|
602
|
-
return JSON.stringify(value);
|
|
185
|
+
function resolveEffectiveOpenClawExecModeForCodexAppServer(params) {
|
|
186
|
+
if (params.execPolicy?.touched === true) return params.execPolicy.mode;
|
|
187
|
+
return params.execMode;
|
|
603
188
|
}
|
|
604
|
-
function
|
|
605
|
-
if (
|
|
606
|
-
|
|
607
|
-
mcp_elicitations: true
|
|
608
|
-
} };
|
|
609
|
-
if (policy === "never") return { granular: {
|
|
610
|
-
mcp_elicitations: true,
|
|
611
|
-
rules: false,
|
|
612
|
-
sandbox_approval: false,
|
|
613
|
-
request_permissions: false,
|
|
614
|
-
skill_approval: false
|
|
615
|
-
} };
|
|
616
|
-
return { granular: {
|
|
617
|
-
mcp_elicitations: true,
|
|
618
|
-
rules: true,
|
|
619
|
-
sandbox_approval: true,
|
|
620
|
-
request_permissions: true,
|
|
621
|
-
skill_approval: true
|
|
622
|
-
} };
|
|
189
|
+
function resolveCodexPolicyModeForOpenClawExecMode(mode) {
|
|
190
|
+
if (!mode || mode === "full") return;
|
|
191
|
+
return "guardian";
|
|
623
192
|
}
|
|
624
|
-
function
|
|
625
|
-
|
|
193
|
+
function assertCodexAppServerAllowedForOpenClawExecMode(mode) {
|
|
194
|
+
if (mode === "deny" || mode === "allowlist") throw new Error(`Codex app-server local execution is not available when tools.exec.mode=${mode}`);
|
|
626
195
|
}
|
|
627
|
-
function
|
|
628
|
-
return
|
|
196
|
+
function createDefaultOpenClawExecPolicy() {
|
|
197
|
+
return {
|
|
198
|
+
security: "full",
|
|
199
|
+
ask: "off",
|
|
200
|
+
touched: false
|
|
201
|
+
};
|
|
629
202
|
}
|
|
630
|
-
function
|
|
631
|
-
if (
|
|
632
|
-
|
|
203
|
+
function applyOpenClawExecPolicyLayer(base, exec) {
|
|
204
|
+
if (!exec) return base;
|
|
205
|
+
const mode = readExecMode(exec.mode);
|
|
206
|
+
if (mode !== void 0) return {
|
|
207
|
+
...resolveOpenClawExecPolicyForMode(mode),
|
|
208
|
+
touched: true
|
|
209
|
+
};
|
|
210
|
+
const security = readExecSecurity(exec.security);
|
|
211
|
+
const ask = readExecAsk(exec.ask);
|
|
212
|
+
if (security === void 0 && ask === void 0) return base;
|
|
213
|
+
const nextSecurity = security ?? base.security;
|
|
214
|
+
const nextAsk = ask ?? base.ask;
|
|
215
|
+
return {
|
|
216
|
+
mode: resolveOpenClawExecModeFromPolicy({
|
|
217
|
+
security: nextSecurity,
|
|
218
|
+
ask: nextAsk
|
|
219
|
+
}),
|
|
220
|
+
security: nextSecurity,
|
|
221
|
+
ask: nextAsk,
|
|
222
|
+
touched: true
|
|
223
|
+
};
|
|
633
224
|
}
|
|
634
|
-
function
|
|
635
|
-
if (params.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
225
|
+
function resolveOpenClawExecApprovalFloorsForCodexAppServer(params) {
|
|
226
|
+
if (!params.approvals) return;
|
|
227
|
+
return resolveExecApprovalsFromFile({
|
|
228
|
+
file: params.approvals,
|
|
229
|
+
agentId: params.agentId,
|
|
230
|
+
overrides: {
|
|
231
|
+
security: params.policy.security,
|
|
232
|
+
ask: params.policy.ask
|
|
233
|
+
}
|
|
234
|
+
}).agent;
|
|
639
235
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
236
|
+
function applyOpenClawExecApprovalFloors(base, approvalFloors) {
|
|
237
|
+
if (!approvalFloors) return base;
|
|
238
|
+
const nextSecurity = approvalFloors.security ? minOpenClawExecSecurity(base.security, approvalFloors.security) : base.security;
|
|
239
|
+
const nextAsk = approvalFloors.ask ? maxOpenClawExecAsk(base.ask, approvalFloors.ask) : base.ask;
|
|
240
|
+
if (nextSecurity === base.security && nextAsk === base.ask) return base;
|
|
241
|
+
return {
|
|
242
|
+
mode: resolveOpenClawExecModeFromPolicy({
|
|
243
|
+
security: nextSecurity,
|
|
244
|
+
ask: nextAsk
|
|
245
|
+
}),
|
|
246
|
+
security: nextSecurity,
|
|
247
|
+
ask: nextAsk,
|
|
248
|
+
touched: true
|
|
249
|
+
};
|
|
647
250
|
}
|
|
648
|
-
function
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
251
|
+
function resolveOpenClawExecPolicyForMode(mode) {
|
|
252
|
+
switch (mode) {
|
|
253
|
+
case "deny": return {
|
|
254
|
+
mode,
|
|
255
|
+
security: "deny",
|
|
256
|
+
ask: "off"
|
|
257
|
+
};
|
|
258
|
+
case "allowlist": return {
|
|
259
|
+
mode,
|
|
260
|
+
security: "allowlist",
|
|
261
|
+
ask: "off"
|
|
262
|
+
};
|
|
263
|
+
case "ask":
|
|
264
|
+
case "auto": return {
|
|
265
|
+
mode,
|
|
266
|
+
security: "allowlist",
|
|
267
|
+
ask: "on-miss"
|
|
268
|
+
};
|
|
269
|
+
case "full": return {
|
|
270
|
+
mode,
|
|
271
|
+
security: "full",
|
|
272
|
+
ask: "off"
|
|
273
|
+
};
|
|
654
274
|
}
|
|
655
|
-
|
|
656
|
-
const host = parsed.hostname.toLowerCase();
|
|
657
|
-
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.startsWith("127.");
|
|
275
|
+
return mode;
|
|
658
276
|
}
|
|
659
|
-
function
|
|
660
|
-
if (
|
|
661
|
-
|
|
277
|
+
function resolveOpenClawExecModeFromPolicy(params) {
|
|
278
|
+
if (params.security === "deny") return "deny";
|
|
279
|
+
if (params.security === "allowlist" && params.ask === "off") return "allowlist";
|
|
280
|
+
if (params.security === "full" && params.ask !== "always") return "full";
|
|
281
|
+
return "ask";
|
|
282
|
+
}
|
|
283
|
+
function minOpenClawExecSecurity(left, right) {
|
|
284
|
+
const order = {
|
|
285
|
+
deny: 0,
|
|
286
|
+
allowlist: 1,
|
|
287
|
+
full: 2
|
|
288
|
+
};
|
|
289
|
+
return order[left] <= order[right] ? left : right;
|
|
290
|
+
}
|
|
291
|
+
function maxOpenClawExecAsk(left, right) {
|
|
292
|
+
const order = {
|
|
293
|
+
off: 0,
|
|
294
|
+
"on-miss": 1,
|
|
295
|
+
always: 2
|
|
296
|
+
};
|
|
297
|
+
return order[left] >= order[right] ? left : right;
|
|
298
|
+
}
|
|
299
|
+
function readExecMode(value) {
|
|
300
|
+
return value === "deny" || value === "allowlist" || value === "ask" || value === "auto" || value === "full" ? value : void 0;
|
|
301
|
+
}
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region extensions/codex/src/app-server/session-discovery-config.ts
|
|
304
|
+
const codexSessionCatalogConfigSchema = z.object({ enabled: z.boolean().optional() }).strict();
|
|
305
|
+
const codexDiscoveryConfigSchema = z.object({
|
|
306
|
+
enabled: z.boolean().optional(),
|
|
307
|
+
timeoutMs: z.number().positive().optional()
|
|
308
|
+
}).strict();
|
|
309
|
+
//#endregion
|
|
310
|
+
//#region extensions/codex/src/app-server/config-parsing.ts
|
|
311
|
+
const DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME = "computer-use";
|
|
312
|
+
const DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS = 6e4;
|
|
313
|
+
const DEFAULT_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS = 6e4;
|
|
314
|
+
const DEFAULT_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS = 6e4;
|
|
315
|
+
const DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX = "openclaw-network";
|
|
316
|
+
const codexAppServerTransportSchema = z.enum([
|
|
317
|
+
"stdio",
|
|
318
|
+
"websocket",
|
|
319
|
+
"unix"
|
|
320
|
+
]);
|
|
321
|
+
const codexAppServerHomeScopeSchema = z.enum(["agent", "user"]);
|
|
322
|
+
const SecretInputSchema = buildSecretInputSchema();
|
|
323
|
+
const codexAppServerPolicyModeSchema = z.enum(["yolo", "guardian"]);
|
|
324
|
+
const codexAppServerApprovalPolicySchema = z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
|
|
325
|
+
"never",
|
|
326
|
+
"on-request",
|
|
327
|
+
"untrusted"
|
|
328
|
+
]));
|
|
329
|
+
const codexAppServerSandboxSchema = z.enum([
|
|
330
|
+
"read-only",
|
|
331
|
+
"workspace-write",
|
|
332
|
+
"danger-full-access"
|
|
333
|
+
]);
|
|
334
|
+
const codexAppServerApprovalsReviewerSchema = z.enum([
|
|
335
|
+
"user",
|
|
336
|
+
"auto_review",
|
|
337
|
+
"guardian_subagent"
|
|
338
|
+
]);
|
|
339
|
+
const codexDynamicToolsLoadingSchema = z.enum(["searchable", "direct"]);
|
|
340
|
+
const codexComputerUseHealthIntervalSchema = z.union([
|
|
341
|
+
z.literal(30),
|
|
342
|
+
z.literal(60),
|
|
343
|
+
z.literal(120),
|
|
344
|
+
z.literal(240)
|
|
345
|
+
]);
|
|
346
|
+
const codexComputerUsePluginCacheModeSchema = z.enum(["shared", "independent"]);
|
|
347
|
+
const codexPluginDestructivePolicySchema = z.union([
|
|
348
|
+
z.boolean(),
|
|
349
|
+
z.literal("auto"),
|
|
350
|
+
z.literal("ask")
|
|
351
|
+
]);
|
|
352
|
+
const codexAppServerServiceTierSchema = z.preprocess((value) => value === null ? null : normalizeCodexServiceTier(value), z.string().trim().min(1).nullable().optional()).optional();
|
|
353
|
+
const codexAppServerExperimentalSchema = z.object({ sandboxExecServer: z.boolean().optional() }).strict();
|
|
354
|
+
const codexAppServerRemoteWorkspaceRootSchema = z.string().trim().min(1);
|
|
355
|
+
const codexAppServerNetworkProxyDomainPermissionSchema = z.enum(["allow", "deny"]);
|
|
356
|
+
const codexAppServerNetworkProxyUnixSocketPermissionSchema = z.enum(["allow", "none"]);
|
|
357
|
+
const codexAppServerNetworkProxySchema = z.object({
|
|
358
|
+
enabled: z.boolean().optional(),
|
|
359
|
+
profileName: z.string().trim().min(1).optional(),
|
|
360
|
+
baseProfile: z.enum(["read-only", "workspace"]).optional(),
|
|
361
|
+
mode: z.enum(["limited", "full"]).optional(),
|
|
362
|
+
domains: z.record(z.string(), codexAppServerNetworkProxyDomainPermissionSchema).optional(),
|
|
363
|
+
unixSockets: z.record(z.string(), codexAppServerNetworkProxyUnixSocketPermissionSchema).optional(),
|
|
364
|
+
proxyUrl: z.string().trim().min(1).optional(),
|
|
365
|
+
socksUrl: z.string().trim().min(1).optional(),
|
|
366
|
+
enableSocks5: z.boolean().optional(),
|
|
367
|
+
enableSocks5Udp: z.boolean().optional(),
|
|
368
|
+
allowUpstreamProxy: z.boolean().optional(),
|
|
369
|
+
allowLocalBinding: z.boolean().optional(),
|
|
370
|
+
dangerouslyAllowNonLoopbackProxy: z.boolean().optional(),
|
|
371
|
+
dangerouslyAllowAllUnixSockets: z.boolean().optional()
|
|
372
|
+
}).strict();
|
|
373
|
+
const codexPluginEntryConfigSchema = z.object({
|
|
374
|
+
enabled: z.boolean().optional(),
|
|
375
|
+
marketplaceName: z.enum([CODEX_PLUGINS_MARKETPLACE_NAME, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME]).optional(),
|
|
376
|
+
pluginName: z.string().trim().min(1).optional(),
|
|
377
|
+
allow_destructive_actions: codexPluginDestructivePolicySchema.optional()
|
|
378
|
+
}).strict();
|
|
379
|
+
const codexPluginsConfigSchema = z.object({
|
|
380
|
+
enabled: z.boolean().optional(),
|
|
381
|
+
allow_all_plugins: z.boolean().optional(),
|
|
382
|
+
allow_destructive_actions: codexPluginDestructivePolicySchema.optional(),
|
|
383
|
+
plugins: z.record(z.string(), codexPluginEntryConfigSchema).optional()
|
|
384
|
+
}).strict();
|
|
385
|
+
const codexSupervisionEndpointSchema = z.union([z.object({
|
|
386
|
+
id: z.string().optional(),
|
|
387
|
+
label: z.string().optional(),
|
|
388
|
+
transport: z.literal("stdio-proxy").optional(),
|
|
389
|
+
command: z.string().optional(),
|
|
390
|
+
args: z.array(z.string()).optional(),
|
|
391
|
+
cwd: z.string().optional()
|
|
392
|
+
}).strict(), z.object({
|
|
393
|
+
id: z.string().optional(),
|
|
394
|
+
label: z.string().optional(),
|
|
395
|
+
transport: z.literal("websocket"),
|
|
396
|
+
url: z.string(),
|
|
397
|
+
authTokenEnv: z.string().optional()
|
|
398
|
+
}).strict()]);
|
|
399
|
+
const codexSupervisionConfigSchema = z.object({
|
|
400
|
+
enabled: z.boolean().optional(),
|
|
401
|
+
endpoints: z.array(codexSupervisionEndpointSchema).optional(),
|
|
402
|
+
allowRawTranscripts: z.boolean().optional(),
|
|
403
|
+
allowWriteControls: z.boolean().optional()
|
|
404
|
+
}).strict();
|
|
405
|
+
const codexPluginConfigSchema = z.object({
|
|
406
|
+
codexDynamicToolsLoading: codexDynamicToolsLoadingSchema.optional(),
|
|
407
|
+
codexDynamicToolsExclude: z.array(z.string()).optional(),
|
|
408
|
+
sessionCatalog: codexSessionCatalogConfigSchema.optional(),
|
|
409
|
+
discovery: codexDiscoveryConfigSchema.optional(),
|
|
410
|
+
computerUse: z.object({
|
|
411
|
+
enabled: z.boolean().optional(),
|
|
412
|
+
autoInstall: z.boolean().optional(),
|
|
413
|
+
marketplaceDiscoveryTimeoutMs: z.number().positive().optional(),
|
|
414
|
+
liveTestTimeoutMs: z.number().positive().optional(),
|
|
415
|
+
toolCallTimeoutMs: z.number().positive().optional(),
|
|
416
|
+
healthCheckEnabled: z.boolean().optional(),
|
|
417
|
+
healthCheckIntervalMinutes: codexComputerUseHealthIntervalSchema.optional(),
|
|
418
|
+
pluginCacheMode: codexComputerUsePluginCacheModeSchema.optional(),
|
|
419
|
+
strictReadiness: z.boolean().optional(),
|
|
420
|
+
autoRepair: z.boolean().optional(),
|
|
421
|
+
marketplaceSource: z.string().optional(),
|
|
422
|
+
marketplacePath: z.string().optional(),
|
|
423
|
+
marketplaceName: z.string().optional(),
|
|
424
|
+
pluginName: z.string().optional(),
|
|
425
|
+
mcpServerName: z.string().optional()
|
|
426
|
+
}).strict().optional(),
|
|
427
|
+
codexPlugins: z.unknown().optional(),
|
|
428
|
+
supervision: codexSupervisionConfigSchema.optional(),
|
|
429
|
+
appServer: z.object({
|
|
430
|
+
mode: codexAppServerPolicyModeSchema.optional(),
|
|
431
|
+
transport: codexAppServerTransportSchema.optional(),
|
|
432
|
+
homeScope: codexAppServerHomeScopeSchema.optional(),
|
|
433
|
+
command: z.string().optional(),
|
|
434
|
+
args: z.union([z.array(z.string()), z.string()]).optional(),
|
|
435
|
+
url: z.string().optional(),
|
|
436
|
+
authToken: SecretInputSchema.optional(),
|
|
437
|
+
headers: z.record(z.string(), SecretInputSchema).optional(),
|
|
438
|
+
clearEnv: z.array(z.string()).optional(),
|
|
439
|
+
remoteWorkspaceRoot: codexAppServerRemoteWorkspaceRootSchema.optional(),
|
|
440
|
+
codeModeOnly: z.boolean().optional(),
|
|
441
|
+
loopDetectionPreToolUseRelay: z.boolean().optional(),
|
|
442
|
+
requestTimeoutMs: z.number().positive().optional(),
|
|
443
|
+
turnCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
444
|
+
turnAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
445
|
+
postToolRawAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
446
|
+
approvalPolicy: codexAppServerApprovalPolicySchema.optional(),
|
|
447
|
+
sandbox: codexAppServerSandboxSchema.optional(),
|
|
448
|
+
approvalsReviewer: codexAppServerApprovalsReviewerSchema.optional(),
|
|
449
|
+
serviceTier: codexAppServerServiceTierSchema,
|
|
450
|
+
networkProxy: codexAppServerNetworkProxySchema.optional(),
|
|
451
|
+
defaultWorkspaceDir: z.string().optional(),
|
|
452
|
+
experimental: codexAppServerExperimentalSchema.optional()
|
|
453
|
+
}).strict().optional()
|
|
454
|
+
}).strict();
|
|
455
|
+
function readCodexPluginConfig(value) {
|
|
456
|
+
const parsed = codexPluginConfigSchema.safeParse(value);
|
|
457
|
+
if (!parsed.success) return {};
|
|
458
|
+
const { codexPlugins: rawCodexPlugins, ...config } = parsed.data;
|
|
459
|
+
const plugins = codexPluginsConfigSchema.safeParse(rawCodexPlugins);
|
|
460
|
+
if (!plugins.success) return config;
|
|
461
|
+
return {
|
|
462
|
+
...config,
|
|
463
|
+
...plugins.data ? { codexPlugins: plugins.data } : {}
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function isCodexSandboxExecServerEnabled(pluginConfig) {
|
|
467
|
+
return readCodexPluginConfig(pluginConfig).appServer?.experimental?.sandboxExecServer === true;
|
|
662
468
|
}
|
|
663
|
-
function
|
|
664
|
-
|
|
469
|
+
function assertCodexAppServerCommandHasNoInlineArgs(params) {
|
|
470
|
+
const inlineArgs = detectWindowsSpawnCommandInlineArgs(params.command);
|
|
471
|
+
if (!inlineArgs) return;
|
|
472
|
+
const sourceLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_BIN" : "plugins.entries.codex.config.appServer.command";
|
|
473
|
+
const argsLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_ARGS" : "plugins.entries.codex.config.appServer.args";
|
|
474
|
+
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.`);
|
|
665
475
|
}
|
|
666
|
-
function
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
476
|
+
function resolveCodexPluginsPolicy(pluginConfig) {
|
|
477
|
+
const config = readCodexPluginConfig(pluginConfig).codexPlugins;
|
|
478
|
+
const configured = config !== void 0;
|
|
479
|
+
const enabled = config?.enabled === true;
|
|
480
|
+
const destructivePolicy = resolveCodexPluginDestructivePolicy(config?.allow_destructive_actions ?? true);
|
|
481
|
+
const pluginPolicies = Object.entries(config?.plugins ?? {}).flatMap(([configKey, entry]) => {
|
|
482
|
+
if (!isCodexPluginMarketplaceName(entry.marketplaceName) || !entry.pluginName) return [];
|
|
483
|
+
const entryDestructivePolicy = resolveCodexPluginDestructivePolicy(entry.allow_destructive_actions ?? config?.allow_destructive_actions ?? true);
|
|
484
|
+
return [{
|
|
485
|
+
configKey,
|
|
486
|
+
marketplaceName: entry.marketplaceName,
|
|
487
|
+
pluginName: entry.pluginName,
|
|
488
|
+
enabled: enabled && entry.enabled !== false,
|
|
489
|
+
allowDestructiveActions: entryDestructivePolicy.allowDestructiveActions,
|
|
490
|
+
destructiveApprovalMode: entryDestructivePolicy.destructiveApprovalMode
|
|
491
|
+
}];
|
|
492
|
+
}).toSorted((left, right) => left.configKey.localeCompare(right.configKey));
|
|
493
|
+
return {
|
|
494
|
+
configured,
|
|
495
|
+
enabled,
|
|
496
|
+
allowAllPlugins: enabled && config?.allow_all_plugins === true,
|
|
497
|
+
allowDestructiveActions: destructivePolicy.allowDestructiveActions,
|
|
498
|
+
destructiveApprovalMode: destructivePolicy.destructiveApprovalMode,
|
|
499
|
+
pluginPolicies
|
|
670
500
|
};
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
dangerFullAccessAllowed: true,
|
|
680
|
-
approvalPolicy: selectGuardianApprovalPolicy(void 0, params.execModeRequiringPromptingApprovals),
|
|
681
|
-
approvalsReviewer: params.forceUserReviewer ? selectUserApprovalsReviewer(void 0, params.execModeRequiringUserReviewer) : selectGuardianApprovalsReviewer(void 0, params.execModeRequiringPromptingApprovals === "auto" ? "auto" : void 0),
|
|
682
|
-
sandbox: selectGuardianSandbox(void 0)
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
const allowedSandboxModes = parseAllowedSandboxModesFromCodexRequirements(content, readNonEmptyString(params.hostName) ?? hostname());
|
|
686
|
-
const allowedApprovalPolicies = parseAllowedApprovalPoliciesFromCodexRequirements(content);
|
|
687
|
-
const allowedApprovalsReviewers = parseAllowedApprovalsReviewersFromCodexRequirements(content);
|
|
688
|
-
const yoloSandboxAllowed = allowedSandboxModes === void 0 || allowedSandboxModes.has("danger-full-access");
|
|
689
|
-
const yoloApprovalAllowed = allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has("never");
|
|
690
|
-
const yoloReviewerAllowed = allowedApprovalsReviewers === void 0 || allowedApprovalsReviewers.has("user");
|
|
691
|
-
if (!params.forceGuardian && yoloSandboxAllowed && yoloApprovalAllowed && yoloReviewerAllowed) return {
|
|
692
|
-
mode: "yolo",
|
|
693
|
-
dangerFullAccessAllowed: true
|
|
501
|
+
}
|
|
502
|
+
function isCodexPluginMarketplaceName(value) {
|
|
503
|
+
return value === "openai-curated" || value === "workspace-directory";
|
|
504
|
+
}
|
|
505
|
+
function resolveCodexPluginDestructivePolicy(policy) {
|
|
506
|
+
if (policy === "auto" || policy === "ask") return {
|
|
507
|
+
allowDestructiveActions: true,
|
|
508
|
+
destructiveApprovalMode: policy
|
|
694
509
|
};
|
|
695
510
|
return {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
approvalPolicy: selectGuardianApprovalPolicy(allowedApprovalPolicies, params.execModeRequiringPromptingApprovals),
|
|
699
|
-
approvalsReviewer: params.forceUserReviewer ? selectUserApprovalsReviewer(allowedApprovalsReviewers, params.execModeRequiringUserReviewer) : selectGuardianApprovalsReviewer(allowedApprovalsReviewers, params.execModeRequiringPromptingApprovals === "auto" ? "auto" : void 0),
|
|
700
|
-
sandbox: selectGuardianSandbox(allowedSandboxModes)
|
|
511
|
+
allowDestructiveActions: policy,
|
|
512
|
+
destructiveApprovalMode: policy ? "allow" : "deny"
|
|
701
513
|
};
|
|
702
514
|
}
|
|
515
|
+
//#endregion
|
|
516
|
+
//#region extensions/codex/src/app-server/config-requirements.ts
|
|
517
|
+
const UNIX_CODEX_REQUIREMENTS_PATH = "/etc/codex/requirements.toml";
|
|
518
|
+
const WINDOWS_CODEX_REQUIREMENTS_SUFFIX = "\\OpenAI\\Codex\\requirements.toml";
|
|
519
|
+
function isCodexAppServerApprovalPolicyAllowedByRequirements(policy, params = {}) {
|
|
520
|
+
const content = readCodexRequirementsToml(params);
|
|
521
|
+
if (content === void 0) return true;
|
|
522
|
+
const allowedApprovalPolicies = parseAllowedApprovalPoliciesFromCodexRequirements(content);
|
|
523
|
+
return allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has(policy);
|
|
524
|
+
}
|
|
703
525
|
function readCodexRequirementsToml(params) {
|
|
704
526
|
if (params.requirementsToml !== void 0) return params.requirementsToml ?? void 0;
|
|
705
527
|
const requirementsPath = readNonEmptyString(params.requirementsPath) ?? resolveCodexRequirementsPath(params.env ?? process.env, params.platform ?? process.platform);
|
|
@@ -889,6 +711,52 @@ function selectUserApprovalsReviewer(allowedApprovalsReviewers, execModeRequirin
|
|
|
889
711
|
if (allowedApprovalsReviewers === void 0 || allowedApprovalsReviewers.has("user")) return "user";
|
|
890
712
|
throw new Error(`tools.exec.mode=${execModeRequiringUserReviewer ?? "ask"} requires Codex app-server user approvals`);
|
|
891
713
|
}
|
|
714
|
+
//#endregion
|
|
715
|
+
//#region extensions/codex/src/app-server/config-reviewer.ts
|
|
716
|
+
const CODEX_APP_SERVER_HOME_DIRNAME = "codex-home";
|
|
717
|
+
const CODEX_CONFIG_TOML_FILENAME = "config.toml";
|
|
718
|
+
function canUseCodexModelBackedApprovalsReviewerForModel(params) {
|
|
719
|
+
const explicitProvider = params.modelProvider?.trim().toLowerCase();
|
|
720
|
+
const inferredProvider = inferProviderFromModelRef(params.model);
|
|
721
|
+
if (explicitProvider && explicitProvider !== "codex") return isTrustedCodexModelBackedApprovalsReviewerProvider(explicitProvider, params) && (inferredProvider === void 0 || isTrustedCodexModelBackedApprovalsReviewerProvider(inferredProvider, params));
|
|
722
|
+
if (inferredProvider !== void 0) return isTrustedCodexModelBackedApprovalsReviewerProvider(inferredProvider, params);
|
|
723
|
+
return isTrustedCodexModelBackedApprovalsReviewerProvider(explicitProvider, params);
|
|
724
|
+
}
|
|
725
|
+
function isTrustedCodexModelBackedOpenAIProvider(params) {
|
|
726
|
+
if (!openAIBaseUrlEnvOverridesAreTrustedForModelBackedReview(params.env)) return false;
|
|
727
|
+
const codexBaseUrlOverrides = readCodexBaseUrlOverridesForModelBackedReview(params);
|
|
728
|
+
if (codexBaseUrlOverrides === false || !codexBaseUrlOverrides.openAI.every(isNativeOpenAIBaseUrl) || !codexBaseUrlOverrides.chatGPT.every(isNativeChatGPTBaseUrl)) return false;
|
|
729
|
+
const openAIProviders = readConfiguredOpenAIProvidersForModelBackedReview(params.config);
|
|
730
|
+
if (openAIProviders.length === 0) return true;
|
|
731
|
+
return openAIProviders.every((openAIProvider) => configuredOpenAIProviderIsTrustedForModelBackedReview(openAIProvider, params.model));
|
|
732
|
+
}
|
|
733
|
+
function resolveCodexModelBackedReviewerPolicyContext(params) {
|
|
734
|
+
const provider = params.provider?.trim();
|
|
735
|
+
if (provider && provider.toLowerCase() !== "codex") return {
|
|
736
|
+
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(provider),
|
|
737
|
+
model: params.model
|
|
738
|
+
};
|
|
739
|
+
const bindingModelProvider = params.bindingModelProvider?.trim();
|
|
740
|
+
const currentModel = params.model?.trim();
|
|
741
|
+
const bindingModel = params.bindingModel?.trim();
|
|
742
|
+
if (bindingModelProvider && currentModel && bindingModel && currentModel === bindingModel) return {
|
|
743
|
+
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(bindingModelProvider),
|
|
744
|
+
model: params.model ?? params.bindingModel
|
|
745
|
+
};
|
|
746
|
+
const currentModelProvider = inferProviderFromModelRef(params.model);
|
|
747
|
+
if (currentModelProvider) return {
|
|
748
|
+
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(currentModelProvider),
|
|
749
|
+
model: params.model
|
|
750
|
+
};
|
|
751
|
+
if (bindingModelProvider) return {
|
|
752
|
+
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(bindingModelProvider),
|
|
753
|
+
model: params.model ?? params.bindingModel
|
|
754
|
+
};
|
|
755
|
+
return {
|
|
756
|
+
modelProvider: params.nativeAuthProfile === true ? "openai" : void 0,
|
|
757
|
+
model: params.model ?? params.bindingModel
|
|
758
|
+
};
|
|
759
|
+
}
|
|
892
760
|
function isCodexModelBackedApprovalsReviewerProvider(provider) {
|
|
893
761
|
return provider?.trim().toLowerCase() === "openai";
|
|
894
762
|
}
|
|
@@ -1041,278 +909,435 @@ function inferProviderFromModelRef(model) {
|
|
|
1041
909
|
const slashIndex = normalized?.indexOf("/") ?? -1;
|
|
1042
910
|
return slashIndex > 0 ? normalized?.slice(0, slashIndex) : void 0;
|
|
1043
911
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
912
|
+
//#endregion
|
|
913
|
+
//#region extensions/codex/src/app-server/config-security.ts
|
|
914
|
+
function shouldAutoApproveCodexAppServerApprovals(appServer) {
|
|
915
|
+
return appServer.networkProxy === void 0 && appServer.approvalPolicy === "never" && appServer.sandbox === "danger-full-access";
|
|
1047
916
|
}
|
|
1048
|
-
function
|
|
1049
|
-
if (
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
917
|
+
function resolveCodexAppServerNetworkProxy(config, sandbox) {
|
|
918
|
+
if (config?.enabled !== true) return {};
|
|
919
|
+
const fileSystemMode = config.baseProfile === "read-only" || !config.baseProfile && sandbox === "read-only" ? "read" : "write";
|
|
920
|
+
const networkConfig = removeUndefinedJsonFields({
|
|
921
|
+
enabled: true,
|
|
922
|
+
mode: config.mode,
|
|
923
|
+
domains: normalizeNetworkProxyPermissionMap(config.domains),
|
|
924
|
+
unix_sockets: normalizeNetworkProxyPermissionMap(config.unixSockets),
|
|
925
|
+
proxy_url: readNonEmptyString(config.proxyUrl),
|
|
926
|
+
socks_url: readNonEmptyString(config.socksUrl),
|
|
927
|
+
enable_socks5: config.enableSocks5,
|
|
928
|
+
enable_socks5_udp: config.enableSocks5Udp,
|
|
929
|
+
allow_upstream_proxy: config.allowUpstreamProxy,
|
|
930
|
+
allow_local_binding: config.allowLocalBinding,
|
|
931
|
+
dangerously_allow_non_loopback_proxy: config.dangerouslyAllowNonLoopbackProxy,
|
|
932
|
+
dangerously_allow_all_unix_sockets: config.dangerouslyAllowAllUnixSockets
|
|
933
|
+
});
|
|
934
|
+
const profile = {
|
|
935
|
+
filesystem: {
|
|
936
|
+
":minimal": "read",
|
|
937
|
+
":project_roots": { ".": fileSystemMode }
|
|
938
|
+
},
|
|
939
|
+
network: networkConfig
|
|
940
|
+
};
|
|
941
|
+
const profileName = resolveNetworkProxyPermissionProfileName(config, profile);
|
|
942
|
+
const configPatch = {
|
|
943
|
+
"features.network_proxy.enabled": true,
|
|
944
|
+
default_permissions: profileName,
|
|
945
|
+
permissions: { [profileName]: profile }
|
|
946
|
+
};
|
|
947
|
+
return { networkProxy: {
|
|
948
|
+
profileName,
|
|
949
|
+
configFingerprint: fingerprintCodexAppServerNetworkProxyConfigPatch(configPatch),
|
|
950
|
+
configPatch
|
|
951
|
+
} };
|
|
1055
952
|
}
|
|
1056
|
-
function
|
|
1057
|
-
|
|
1058
|
-
if (
|
|
1059
|
-
|
|
1060
|
-
|
|
953
|
+
function resolveNetworkProxyPermissionProfileName(config, profile) {
|
|
954
|
+
const explicitProfileName = readNonEmptyString(config.profileName);
|
|
955
|
+
if (explicitProfileName) return explicitProfileName;
|
|
956
|
+
return `${DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX}-${createHash("sha256").update(stableStringifyJson({
|
|
957
|
+
version: 1,
|
|
958
|
+
profile
|
|
959
|
+
})).digest("hex").slice(0, 16)}`;
|
|
1061
960
|
}
|
|
1062
|
-
function
|
|
1063
|
-
|
|
1064
|
-
return value === "on-request" || value === "untrusted" || value === "never" ? value : void 0;
|
|
961
|
+
function fingerprintCodexAppServerNetworkProxyConfigPatch(configPatch) {
|
|
962
|
+
return createHash("sha256").update(stableStringifyJson(configPatch)).digest("hex");
|
|
1065
963
|
}
|
|
1066
|
-
function
|
|
1067
|
-
|
|
964
|
+
function normalizeNetworkProxyPermissionMap(value) {
|
|
965
|
+
const entries = Object.entries(value ?? {}).map(([key, permission]) => [key.trim(), permission]).filter(([key]) => key.length > 0);
|
|
966
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
1068
967
|
}
|
|
1069
|
-
function
|
|
1070
|
-
return value
|
|
968
|
+
function removeUndefinedJsonFields(value) {
|
|
969
|
+
return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
|
|
1071
970
|
}
|
|
1072
|
-
function
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
const agentId = params.agentId?.trim();
|
|
1077
|
-
if (!agentId) return globalPolicy;
|
|
1078
|
-
const agents = readRecord(root?.agents);
|
|
1079
|
-
const agentList = Array.isArray(agents?.list) ? agents.list : [];
|
|
1080
|
-
const normalizedAgentId = normalizeAgentId(agentId);
|
|
1081
|
-
return applyOpenClawExecPolicyLayer(globalPolicy, readRecord(readRecord(readRecord(agentList.find((entry) => {
|
|
1082
|
-
const id = readRecord(entry)?.id;
|
|
1083
|
-
return typeof id === "string" && normalizeAgentId(id) === normalizedAgentId;
|
|
1084
|
-
}))?.tools)?.exec));
|
|
971
|
+
function stableStringifyJson(value) {
|
|
972
|
+
if (Array.isArray(value)) return `[${value.map((item) => stableStringifyJson(item)).join(",")}]`;
|
|
973
|
+
if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringifyJson(item)}`).join(",")}}`;
|
|
974
|
+
return JSON.stringify(value);
|
|
1085
975
|
}
|
|
1086
|
-
function
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
976
|
+
function withMcpElicitationsApprovalPolicy(policy) {
|
|
977
|
+
if (typeof policy !== "string") return { granular: {
|
|
978
|
+
...policy.granular,
|
|
979
|
+
mcp_elicitations: true
|
|
980
|
+
} };
|
|
981
|
+
if (policy === "never") return { granular: {
|
|
982
|
+
mcp_elicitations: true,
|
|
983
|
+
rules: false,
|
|
984
|
+
sandbox_approval: false,
|
|
985
|
+
request_permissions: false,
|
|
986
|
+
skill_approval: false
|
|
987
|
+
} };
|
|
988
|
+
return { granular: {
|
|
989
|
+
mcp_elicitations: true,
|
|
990
|
+
rules: true,
|
|
991
|
+
sandbox_approval: true,
|
|
992
|
+
request_permissions: true,
|
|
993
|
+
skill_approval: true
|
|
994
|
+
} };
|
|
1096
995
|
}
|
|
1097
|
-
function
|
|
1098
|
-
|
|
1099
|
-
|
|
996
|
+
function resolveTransport(value) {
|
|
997
|
+
return value === "websocket" || value === "unix" ? value : "stdio";
|
|
998
|
+
}
|
|
999
|
+
function normalizeRemoteWorkspaceRoot(value) {
|
|
1000
|
+
return readNonEmptyString(value);
|
|
1001
|
+
}
|
|
1002
|
+
function inferCodexAppServerConnectionClass(params) {
|
|
1003
|
+
if (params.transport !== "websocket") return "local-loopback";
|
|
1004
|
+
return params.url && isLoopbackWebSocketUrl(params.url) ? "local-loopback" : "remote";
|
|
1100
1005
|
}
|
|
1101
|
-
function
|
|
1102
|
-
if (
|
|
1103
|
-
|
|
1006
|
+
function assertCodexAppServerConnectionClassConfig(params) {
|
|
1007
|
+
if (params.connectionClass === "remote" && !hasIdentityBearingWebSocketAuth({
|
|
1008
|
+
authToken: params.authToken,
|
|
1009
|
+
headers: params.headers
|
|
1010
|
+
})) throw new Error("remote Codex app-server WebSocket URLs require appServer.authToken or an Authorization header");
|
|
1104
1011
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1012
|
+
/** Applies the canonical remote-auth boundary to any Codex AppServer transport. */
|
|
1013
|
+
function assertCodexAppServerConnectionSecurity(params) {
|
|
1014
|
+
assertCodexAppServerConnectionClassConfig({
|
|
1015
|
+
connectionClass: inferCodexAppServerConnectionClass(params),
|
|
1016
|
+
authToken: params.authToken,
|
|
1017
|
+
headers: params.headers
|
|
1018
|
+
});
|
|
1107
1019
|
}
|
|
1108
|
-
function
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1020
|
+
function isLoopbackWebSocketUrl(value) {
|
|
1021
|
+
let parsed;
|
|
1022
|
+
try {
|
|
1023
|
+
parsed = new URL(value);
|
|
1024
|
+
} catch {
|
|
1025
|
+
return false;
|
|
1026
|
+
}
|
|
1027
|
+
if (parsed.protocol !== "ws:" && parsed.protocol !== "wss:") return false;
|
|
1028
|
+
const host = parsed.hostname.toLowerCase();
|
|
1029
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.startsWith("127.");
|
|
1114
1030
|
}
|
|
1115
|
-
function
|
|
1116
|
-
if (
|
|
1117
|
-
|
|
1118
|
-
if (mode !== void 0) return {
|
|
1119
|
-
...resolveOpenClawExecPolicyForMode(mode),
|
|
1120
|
-
touched: true
|
|
1121
|
-
};
|
|
1122
|
-
const security = readExecSecurity(exec.security);
|
|
1123
|
-
const ask = readExecAsk(exec.ask);
|
|
1124
|
-
if (security === void 0 && ask === void 0) return base;
|
|
1125
|
-
const nextSecurity = security ?? base.security;
|
|
1126
|
-
const nextAsk = ask ?? base.ask;
|
|
1127
|
-
return {
|
|
1128
|
-
mode: resolveOpenClawExecModeFromPolicy({
|
|
1129
|
-
security: nextSecurity,
|
|
1130
|
-
ask: nextAsk
|
|
1131
|
-
}),
|
|
1132
|
-
security: nextSecurity,
|
|
1133
|
-
ask: nextAsk,
|
|
1134
|
-
touched: true
|
|
1135
|
-
};
|
|
1031
|
+
function hasIdentityBearingWebSocketAuth(params) {
|
|
1032
|
+
if (readNonEmptyString(params.authToken)) return true;
|
|
1033
|
+
return Object.entries(params.headers).some(([key, value]) => key.trim().toLowerCase() === "authorization" && Boolean(readNonEmptyString(value)));
|
|
1136
1034
|
}
|
|
1137
|
-
function
|
|
1138
|
-
|
|
1139
|
-
return resolveExecApprovalsFromFile({
|
|
1140
|
-
file: params.approvals,
|
|
1141
|
-
agentId: params.agentId,
|
|
1142
|
-
overrides: {
|
|
1143
|
-
security: params.policy.security,
|
|
1144
|
-
ask: params.policy.ask
|
|
1145
|
-
}
|
|
1146
|
-
}).agent;
|
|
1035
|
+
function resolvePolicyMode(value) {
|
|
1036
|
+
return value === "guardian" || value === "yolo" ? value : void 0;
|
|
1147
1037
|
}
|
|
1148
|
-
function
|
|
1149
|
-
if (
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
if (nextSecurity === base.security && nextAsk === base.ask) return base;
|
|
1153
|
-
return {
|
|
1154
|
-
mode: resolveOpenClawExecModeFromPolicy({
|
|
1155
|
-
security: nextSecurity,
|
|
1156
|
-
ask: nextAsk
|
|
1157
|
-
}),
|
|
1158
|
-
security: nextSecurity,
|
|
1159
|
-
ask: nextAsk,
|
|
1160
|
-
touched: true
|
|
1038
|
+
function resolveDefaultCodexAppServerPolicy(params) {
|
|
1039
|
+
if (params.transport !== "stdio") return {
|
|
1040
|
+
mode: "yolo",
|
|
1041
|
+
dangerFullAccessAllowed: true
|
|
1161
1042
|
};
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
security: "deny",
|
|
1168
|
-
ask: "off"
|
|
1169
|
-
};
|
|
1170
|
-
case "allowlist": return {
|
|
1171
|
-
mode,
|
|
1172
|
-
security: "allowlist",
|
|
1173
|
-
ask: "off"
|
|
1174
|
-
};
|
|
1175
|
-
case "ask":
|
|
1176
|
-
case "auto": return {
|
|
1177
|
-
mode,
|
|
1178
|
-
security: "allowlist",
|
|
1179
|
-
ask: "on-miss"
|
|
1043
|
+
const content = readCodexRequirementsToml(params);
|
|
1044
|
+
if (content === void 0) {
|
|
1045
|
+
if (!params.forceGuardian) return {
|
|
1046
|
+
mode: "yolo",
|
|
1047
|
+
dangerFullAccessAllowed: true
|
|
1180
1048
|
};
|
|
1181
|
-
|
|
1182
|
-
mode,
|
|
1183
|
-
|
|
1184
|
-
|
|
1049
|
+
return {
|
|
1050
|
+
mode: "guardian",
|
|
1051
|
+
dangerFullAccessAllowed: true,
|
|
1052
|
+
approvalPolicy: selectGuardianApprovalPolicy(void 0, params.execModeRequiringPromptingApprovals),
|
|
1053
|
+
approvalsReviewer: params.forceUserReviewer ? selectUserApprovalsReviewer(void 0, params.execModeRequiringUserReviewer) : selectGuardianApprovalsReviewer(void 0, params.execModeRequiringPromptingApprovals === "auto" ? "auto" : void 0),
|
|
1054
|
+
sandbox: selectGuardianSandbox(void 0)
|
|
1185
1055
|
};
|
|
1186
1056
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
return
|
|
1057
|
+
const allowedSandboxModes = parseAllowedSandboxModesFromCodexRequirements(content, readNonEmptyString(params.hostName) ?? hostname());
|
|
1058
|
+
const allowedApprovalPolicies = parseAllowedApprovalPoliciesFromCodexRequirements(content);
|
|
1059
|
+
const allowedApprovalsReviewers = parseAllowedApprovalsReviewersFromCodexRequirements(content);
|
|
1060
|
+
const yoloSandboxAllowed = allowedSandboxModes === void 0 || allowedSandboxModes.has("danger-full-access");
|
|
1061
|
+
const yoloApprovalAllowed = allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has("never");
|
|
1062
|
+
const yoloReviewerAllowed = allowedApprovalsReviewers === void 0 || allowedApprovalsReviewers.has("user");
|
|
1063
|
+
if (!params.forceGuardian && yoloSandboxAllowed && yoloApprovalAllowed && yoloReviewerAllowed) return {
|
|
1064
|
+
mode: "yolo",
|
|
1065
|
+
dangerFullAccessAllowed: true
|
|
1066
|
+
};
|
|
1067
|
+
return {
|
|
1068
|
+
mode: "guardian",
|
|
1069
|
+
dangerFullAccessAllowed: yoloSandboxAllowed,
|
|
1070
|
+
approvalPolicy: selectGuardianApprovalPolicy(allowedApprovalPolicies, params.execModeRequiringPromptingApprovals),
|
|
1071
|
+
approvalsReviewer: params.forceUserReviewer ? selectUserApprovalsReviewer(allowedApprovalsReviewers, params.execModeRequiringUserReviewer) : selectGuardianApprovalsReviewer(allowedApprovalsReviewers, params.execModeRequiringPromptingApprovals === "auto" ? "auto" : void 0),
|
|
1072
|
+
sandbox: selectGuardianSandbox(allowedSandboxModes)
|
|
1073
|
+
};
|
|
1194
1074
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1075
|
+
//#endregion
|
|
1076
|
+
//#region extensions/codex/src/app-server/config-runtime.ts
|
|
1077
|
+
function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
1078
|
+
const env = params.env ?? process.env;
|
|
1079
|
+
const config = readCodexPluginConfig(params.pluginConfig).appServer ?? {};
|
|
1080
|
+
const transport = resolveTransport(config.transport);
|
|
1081
|
+
const homeScope = config.homeScope ?? "agent";
|
|
1082
|
+
const configCommand = readNonEmptyString(config.command);
|
|
1083
|
+
const envCommand = readNonEmptyString(env.OPENCLAW_CODEX_APP_SERVER_BIN);
|
|
1084
|
+
const command = configCommand ?? envCommand ?? "codex";
|
|
1085
|
+
const commandSource = configCommand ? "config" : envCommand ? "env" : "managed";
|
|
1086
|
+
if (commandSource === "config" || commandSource === "env") assertCodexAppServerCommandHasNoInlineArgs({
|
|
1087
|
+
command,
|
|
1088
|
+
source: commandSource
|
|
1089
|
+
});
|
|
1090
|
+
const args = resolveArgs(config.args, env.OPENCLAW_CODEX_APP_SERVER_ARGS);
|
|
1091
|
+
const headers = normalizeHeaders(config.headers);
|
|
1092
|
+
const clearEnv = normalizeStringList(config.clearEnv);
|
|
1093
|
+
const authToken = normalizeCodexAppServerSecretInput({
|
|
1094
|
+
value: config.authToken,
|
|
1095
|
+
path: "plugins.entries.codex.config.appServer.authToken"
|
|
1096
|
+
});
|
|
1097
|
+
const url = readNonEmptyString(config.url) ?? (transport === "unix" ? "unix://" : void 0);
|
|
1098
|
+
const connectionClass = inferCodexAppServerConnectionClass({
|
|
1099
|
+
transport,
|
|
1100
|
+
url
|
|
1101
|
+
});
|
|
1102
|
+
const remoteAppsSubstrate = "preconfigured";
|
|
1103
|
+
const remoteWorkspaceRoot = normalizeRemoteWorkspaceRoot(config.remoteWorkspaceRoot);
|
|
1104
|
+
const execMode = resolveEffectiveOpenClawExecModeForCodexAppServer({
|
|
1105
|
+
execMode: params.execMode,
|
|
1106
|
+
execPolicy: params.execPolicy
|
|
1107
|
+
});
|
|
1108
|
+
assertCodexAppServerAllowedForOpenClawExecMode(execMode);
|
|
1109
|
+
const explicitPolicyMode = resolvePolicyMode(config.mode) ?? resolvePolicyMode(env.OPENCLAW_CODEX_APP_SERVER_MODE);
|
|
1110
|
+
const configuredSandbox = resolveSandbox(config.sandbox) ?? resolveSandbox(env.OPENCLAW_CODEX_APP_SERVER_SANDBOX);
|
|
1111
|
+
const explicitApprovalsReviewer = resolveApprovalsReviewer(config.approvalsReviewer);
|
|
1112
|
+
const normalizedPolicyMode = resolveCodexPolicyModeForOpenClawExecMode(execMode);
|
|
1113
|
+
const ignoreLegacyYoloPolicyMode = normalizedPolicyMode === "guardian" && explicitPolicyMode === "yolo";
|
|
1114
|
+
const canUseModelBackedReviewer = canUseCodexModelBackedApprovalsReviewerForModel({
|
|
1115
|
+
modelProvider: params.modelProvider,
|
|
1116
|
+
model: params.model,
|
|
1117
|
+
config: params.config,
|
|
1118
|
+
env,
|
|
1119
|
+
agentDir: params.agentDir,
|
|
1120
|
+
codexConfigToml: params.codexConfigToml,
|
|
1121
|
+
homeScope
|
|
1122
|
+
});
|
|
1123
|
+
const forceUserReviewer = !canUseModelBackedReviewer && (explicitApprovalsReviewer === "auto_review" || explicitApprovalsReviewer === "guardian_subagent" || explicitPolicyMode === "guardian" && explicitApprovalsReviewer !== "user") || execMode !== void 0 && execMode !== "full" && (execMode !== "auto" || !canUseModelBackedReviewer);
|
|
1124
|
+
const forceGuardianReviewer = execMode === "auto" && canUseModelBackedReviewer;
|
|
1125
|
+
const execModeRequiringPromptingApprovals = execMode === "auto" || execMode === "ask" ? execMode : forceUserReviewer ? "ask" : void 0;
|
|
1126
|
+
const forceDangerFullAccessSandbox = params.execPolicy?.touched === true && params.execPolicy.security === "full" && params.execPolicy.ask === "always";
|
|
1127
|
+
const forceRuntimePolicy = forceUserReviewer || forceGuardianReviewer || forceDangerFullAccessSandbox;
|
|
1128
|
+
const defaultPolicy = explicitPolicyMode && !forceRuntimePolicy && !ignoreLegacyYoloPolicyMode ? void 0 : resolveDefaultCodexAppServerPolicy({
|
|
1129
|
+
transport,
|
|
1130
|
+
env,
|
|
1131
|
+
forceGuardian: normalizedPolicyMode === "guardian",
|
|
1132
|
+
forceUserReviewer: forceUserReviewer || !canUseModelBackedReviewer,
|
|
1133
|
+
execModeRequiringPromptingApprovals,
|
|
1134
|
+
requirementsToml: params.requirementsToml,
|
|
1135
|
+
requirementsPath: params.requirementsPath,
|
|
1136
|
+
readRequirementsFile: params.readRequirementsFile,
|
|
1137
|
+
platform: params.platform,
|
|
1138
|
+
hostName: params.hostName,
|
|
1139
|
+
execModeRequiringUserReviewer: forceUserReviewer ? execMode : void 0
|
|
1140
|
+
});
|
|
1141
|
+
const preserveExplicitAutoSandbox = forceGuardianReviewer && configuredSandbox === "read-only";
|
|
1142
|
+
const forcedPolicy = forceRuntimePolicy ? {
|
|
1143
|
+
approvalPolicy: defaultPolicy?.approvalPolicy ?? "on-request",
|
|
1144
|
+
sandbox: preserveExplicitAutoSandbox ? void 0 : forceDangerFullAccessSandbox ? selectForcedDangerFullAccessSandbox({
|
|
1145
|
+
configuredSandbox,
|
|
1146
|
+
defaultPolicy,
|
|
1147
|
+
openClawSandboxActive: Boolean(params.openClawSandboxActive)
|
|
1148
|
+
}) : selectForcedPromptingSandbox({
|
|
1149
|
+
configuredSandbox,
|
|
1150
|
+
defaultSandbox: defaultPolicy?.sandbox
|
|
1151
|
+
}),
|
|
1152
|
+
approvalsReviewer: defaultPolicy?.approvalsReviewer ?? (forceUserReviewer ? "user" : "auto_review")
|
|
1153
|
+
} : void 0;
|
|
1154
|
+
const policyMode = ignoreLegacyYoloPolicyMode ? normalizedPolicyMode : explicitPolicyMode ?? normalizedPolicyMode ?? defaultPolicy?.mode ?? "yolo";
|
|
1155
|
+
const serviceTier = normalizeCodexServiceTier(config.serviceTier);
|
|
1156
|
+
const resolvedSandbox = forcedPolicy?.sandbox ?? configuredSandbox ?? defaultPolicy?.sandbox ?? (policyMode === "guardian" ? "workspace-write" : "danger-full-access");
|
|
1157
|
+
if (transport === "websocket" && !url) throw new Error("plugins.entries.codex.config.appServer.url is required when appServer.transport is websocket");
|
|
1158
|
+
if (transport === "websocket" && homeScope === "user") throw new Error("plugins.entries.codex.config.appServer.homeScope=user requires appServer.transport=stdio or unix");
|
|
1159
|
+
if (transport === "unix" && homeScope !== "user") throw new Error("plugins.entries.codex.config.appServer.transport=unix requires appServer.homeScope=user");
|
|
1160
|
+
if (transport === "unix" && !url?.startsWith("unix://")) throw new Error("plugins.entries.codex.config.appServer.url must use unix:// when appServer.transport is unix");
|
|
1161
|
+
assertCodexAppServerConnectionSecurity({
|
|
1162
|
+
transport,
|
|
1163
|
+
url,
|
|
1164
|
+
authToken,
|
|
1165
|
+
headers
|
|
1166
|
+
});
|
|
1167
|
+
const configApprovalPolicy = resolveApprovalPolicy(config.approvalPolicy);
|
|
1168
|
+
const envApprovalPolicy = resolveApprovalPolicy(env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY);
|
|
1169
|
+
const approvalPolicy = configApprovalPolicy ?? envApprovalPolicy ?? defaultPolicy?.approvalPolicy ?? (policyMode === "guardian" ? "on-request" : "never");
|
|
1170
|
+
const approvalPolicySource = configApprovalPolicy ? "config" : envApprovalPolicy ? "env" : defaultPolicy?.approvalPolicy ? "requirements" : "implicit";
|
|
1171
|
+
const computerUseConfig = resolveCodexComputerUseConfig({
|
|
1172
|
+
pluginConfig: params.pluginConfig,
|
|
1173
|
+
env
|
|
1174
|
+
});
|
|
1175
|
+
const managedCommandOrder = params.managedCommandOrder ?? (homeScope === "user" || computerUseConfig.enabled ? "desktop-first" : "package-first");
|
|
1176
|
+
const includeManagedCommandOrder = commandSource === "managed" && (managedCommandOrder === "desktop-first" || params.managedCommandOrder === "package-first");
|
|
1177
|
+
const managedComputerUsePluginNames = [.../* @__PURE__ */ new Set([DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME, computerUseConfig.pluginName])];
|
|
1178
|
+
return {
|
|
1179
|
+
start: {
|
|
1180
|
+
transport,
|
|
1181
|
+
homeScope,
|
|
1182
|
+
command,
|
|
1183
|
+
commandSource,
|
|
1184
|
+
...includeManagedCommandOrder ? { managedCommandOrder } : {},
|
|
1185
|
+
...commandSource === "managed" ? { managedComputerUsePluginNames } : {},
|
|
1186
|
+
args: args.length > 0 ? args : [
|
|
1187
|
+
"app-server",
|
|
1188
|
+
"--listen",
|
|
1189
|
+
"stdio://"
|
|
1190
|
+
],
|
|
1191
|
+
...url ? { url } : {},
|
|
1192
|
+
...authToken ? { authToken } : {},
|
|
1193
|
+
headers,
|
|
1194
|
+
...transport === "stdio" && clearEnv.length > 0 ? { clearEnv } : {}
|
|
1195
|
+
},
|
|
1196
|
+
connectionClass,
|
|
1197
|
+
remoteAppsSubstrate,
|
|
1198
|
+
...remoteWorkspaceRoot ? { remoteWorkspaceRoot } : {},
|
|
1199
|
+
codeModeOnly: config.codeModeOnly === true,
|
|
1200
|
+
loopDetectionPreToolUseRelay: config.loopDetectionPreToolUseRelay !== false,
|
|
1201
|
+
requestTimeoutMs: normalizePositiveNumber(config.requestTimeoutMs, 6e4),
|
|
1202
|
+
turnCompletionIdleTimeoutMs: normalizePositiveNumber(config.turnCompletionIdleTimeoutMs, 6e4),
|
|
1203
|
+
turnAssistantCompletionIdleTimeoutMs: normalizePositiveNumber(config.turnAssistantCompletionIdleTimeoutMs, 1e4),
|
|
1204
|
+
...config.postToolRawAssistantCompletionIdleTimeoutMs !== void 0 ? { postToolRawAssistantCompletionIdleTimeoutMs: normalizePositiveNumber(config.postToolRawAssistantCompletionIdleTimeoutMs, 6e4) } : {},
|
|
1205
|
+
approvalPolicy: forcedPolicy?.approvalPolicy ?? approvalPolicy,
|
|
1206
|
+
approvalPolicySource,
|
|
1207
|
+
sandbox: resolvedSandbox,
|
|
1208
|
+
approvalsReviewer: forcedPolicy?.approvalsReviewer ?? explicitApprovalsReviewer ?? defaultPolicy?.approvalsReviewer ?? (policyMode === "guardian" ? "auto_review" : "user"),
|
|
1209
|
+
...serviceTier ? { serviceTier } : {},
|
|
1210
|
+
...resolveCodexAppServerNetworkProxy(config.networkProxy, resolvedSandbox)
|
|
1200
1211
|
};
|
|
1201
|
-
return order[left] <= order[right] ? left : right;
|
|
1202
1212
|
}
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1213
|
+
/**
|
|
1214
|
+
* Rechecks Codex-owned plugin state at the final spawn boundary, where the
|
|
1215
|
+
* effective agent home is known, so Computer Use keeps the desktop app's TCC ownership.
|
|
1216
|
+
*/
|
|
1217
|
+
function resolveCodexAppServerStartOptionsForAgent(params) {
|
|
1218
|
+
const startOptions = params.startOptions;
|
|
1219
|
+
if (startOptions.transport !== "stdio" || startOptions.commandSource !== "managed" || startOptions.managedCommandOrder !== void 0) return startOptions;
|
|
1220
|
+
if (startOptions.homeScope === "user") return {
|
|
1221
|
+
...startOptions,
|
|
1222
|
+
managedCommandOrder: "desktop-first"
|
|
1208
1223
|
};
|
|
1209
|
-
return
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
const trimmed = value.trim();
|
|
1220
|
-
if (!trimmed) return;
|
|
1221
|
-
const normalized = trimmed.toLowerCase();
|
|
1222
|
-
if (normalized === "fast" || normalized === "priority") return "priority";
|
|
1223
|
-
if (normalized === "flex") return "flex";
|
|
1224
|
-
return trimmed;
|
|
1225
|
-
}
|
|
1226
|
-
function isCodexFastServiceTier(value) {
|
|
1227
|
-
return normalizeCodexServiceTier(value) === "priority";
|
|
1228
|
-
}
|
|
1229
|
-
function normalizePositiveNumber(value, fallback) {
|
|
1230
|
-
return resolvePositiveTimerTimeoutMs(value, fallback);
|
|
1231
|
-
}
|
|
1232
|
-
function normalizeHeaders(value) {
|
|
1233
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1234
|
-
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key.trim(), normalizeCodexAppServerSecretInput({
|
|
1235
|
-
value: child,
|
|
1236
|
-
path: `plugins.entries.codex.config.appServer.headers.${key}`
|
|
1237
|
-
})]).filter((entry) => Boolean(entry[0] && entry[1])));
|
|
1238
|
-
}
|
|
1239
|
-
function normalizeCodexAppServerSecretInput(params) {
|
|
1240
|
-
return normalizeResolvedSecretInputString(params);
|
|
1241
|
-
}
|
|
1242
|
-
function normalizeStringList(value) {
|
|
1243
|
-
return normalizeTrimmedStringList(value);
|
|
1244
|
-
}
|
|
1245
|
-
function readBooleanEnv(value) {
|
|
1246
|
-
if (value === void 0) return;
|
|
1247
|
-
const normalized = value.trim().toLowerCase();
|
|
1248
|
-
if ([
|
|
1249
|
-
"1",
|
|
1250
|
-
"true",
|
|
1251
|
-
"yes",
|
|
1252
|
-
"on"
|
|
1253
|
-
].includes(normalized)) return true;
|
|
1254
|
-
if ([
|
|
1255
|
-
"0",
|
|
1256
|
-
"false",
|
|
1257
|
-
"no",
|
|
1258
|
-
"off"
|
|
1259
|
-
].includes(normalized)) return false;
|
|
1260
|
-
}
|
|
1261
|
-
function readExecSecurity(value) {
|
|
1262
|
-
return value === "deny" || value === "allowlist" || value === "full" ? value : void 0;
|
|
1263
|
-
}
|
|
1264
|
-
function readExecAsk(value) {
|
|
1265
|
-
return value === "off" || value === "on-miss" || value === "always" ? value : void 0;
|
|
1224
|
+
return codexConfigEnablesNativeComputerUse({
|
|
1225
|
+
agentDir: params.agentDir,
|
|
1226
|
+
codexConfigToml: params.codexConfigToml,
|
|
1227
|
+
env: params.env,
|
|
1228
|
+
homeScope: "agent",
|
|
1229
|
+
pluginNames: startOptions.managedComputerUsePluginNames ?? ["computer-use"]
|
|
1230
|
+
}) ? {
|
|
1231
|
+
...startOptions,
|
|
1232
|
+
managedCommandOrder: "desktop-first"
|
|
1233
|
+
} : startOptions;
|
|
1266
1234
|
}
|
|
1267
|
-
function
|
|
1268
|
-
const
|
|
1269
|
-
|
|
1270
|
-
const
|
|
1271
|
-
|
|
1235
|
+
function resolveCodexComputerUseConfig(params = {}) {
|
|
1236
|
+
const env = params.env ?? process.env;
|
|
1237
|
+
const config = readCodexPluginConfig(params.pluginConfig).computerUse ?? {};
|
|
1238
|
+
const marketplaceSource = readNonEmptyString(params.overrides?.marketplaceSource) ?? readNonEmptyString(config.marketplaceSource) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_SOURCE);
|
|
1239
|
+
const marketplacePath = readNonEmptyString(params.overrides?.marketplacePath) ?? readNonEmptyString(config.marketplacePath) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_PATH);
|
|
1240
|
+
const marketplaceName = readNonEmptyString(params.overrides?.marketplaceName) ?? readNonEmptyString(config.marketplaceName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_NAME);
|
|
1241
|
+
const configuredPluginName = readNonEmptyString(params.overrides?.pluginName) ?? readNonEmptyString(config.pluginName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_NAME);
|
|
1242
|
+
const configuredMcpServerName = readNonEmptyString(params.overrides?.mcpServerName) ?? readNonEmptyString(config.mcpServerName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MCP_SERVER_NAME);
|
|
1243
|
+
const autoInstall = params.overrides?.autoInstall ?? config.autoInstall ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_AUTO_INSTALL) ?? false;
|
|
1244
|
+
const marketplaceDiscoveryTimeoutMs = normalizePositiveNumber(params.overrides?.marketplaceDiscoveryTimeoutMs ?? config.marketplaceDiscoveryTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS);
|
|
1245
|
+
const liveTestTimeoutMs = normalizePositiveNumber(params.overrides?.liveTestTimeoutMs ?? config.liveTestTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS);
|
|
1246
|
+
const toolCallTimeoutMs = normalizePositiveNumber(params.overrides?.toolCallTimeoutMs ?? config.toolCallTimeoutMs ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS), DEFAULT_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS);
|
|
1247
|
+
const healthCheckIntervalMinutes = normalizeComputerUseHealthCheckIntervalMinutes(params.overrides?.healthCheckIntervalMinutes ?? config.healthCheckIntervalMinutes ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_HEALTH_CHECK_INTERVAL_MINUTES));
|
|
1248
|
+
const healthCheckEnabled = params.overrides?.healthCheckEnabled ?? config.healthCheckEnabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_HEALTH_CHECK_ENABLED) ?? false;
|
|
1249
|
+
const pluginCacheMode = normalizeComputerUsePluginCacheMode(params.overrides?.pluginCacheMode) ?? normalizeComputerUsePluginCacheMode(config.pluginCacheMode) ?? normalizeComputerUsePluginCacheMode(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_CACHE_MODE) ?? "independent";
|
|
1250
|
+
const strictReadiness = params.overrides?.strictReadiness ?? config.strictReadiness ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_STRICT_READINESS) ?? false;
|
|
1251
|
+
const autoRepair = params.overrides?.autoRepair ?? config.autoRepair ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_AUTO_REPAIR) ?? false;
|
|
1252
|
+
return {
|
|
1253
|
+
enabled: params.overrides?.enabled ?? config.enabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE) ?? Boolean(autoInstall || marketplaceSource || marketplacePath || marketplaceName || configuredPluginName || configuredMcpServerName),
|
|
1254
|
+
autoInstall,
|
|
1255
|
+
marketplaceDiscoveryTimeoutMs,
|
|
1256
|
+
liveTestTimeoutMs,
|
|
1257
|
+
toolCallTimeoutMs,
|
|
1258
|
+
healthCheckEnabled,
|
|
1259
|
+
healthCheckIntervalMinutes,
|
|
1260
|
+
pluginCacheMode,
|
|
1261
|
+
strictReadiness,
|
|
1262
|
+
autoRepair,
|
|
1263
|
+
pluginName: configuredPluginName ?? "computer-use",
|
|
1264
|
+
mcpServerName: configuredMcpServerName ?? "computer-use",
|
|
1265
|
+
...marketplaceSource ? { marketplaceSource } : {},
|
|
1266
|
+
...marketplacePath ? { marketplacePath } : {},
|
|
1267
|
+
...marketplaceName ? { marketplaceName } : {}
|
|
1268
|
+
};
|
|
1272
1269
|
}
|
|
1273
|
-
function
|
|
1274
|
-
|
|
1275
|
-
if (typeof configArgs === "string") return splitShellWords(configArgs);
|
|
1276
|
-
return splitShellWords(envArgs ?? "");
|
|
1270
|
+
function normalizeComputerUseHealthCheckIntervalMinutes(value) {
|
|
1271
|
+
return value === 30 || value === 60 || value === 120 || value === 240 ? value : 60;
|
|
1277
1272
|
}
|
|
1278
|
-
function
|
|
1279
|
-
|
|
1280
|
-
return value.trim() || void 0;
|
|
1273
|
+
function normalizeComputerUsePluginCacheMode(value) {
|
|
1274
|
+
return value === "shared" || value === "independent" ? value : null;
|
|
1281
1275
|
}
|
|
1282
|
-
function
|
|
1283
|
-
|
|
1284
|
-
|
|
1276
|
+
function codexAppServerStartOptionsKey(options, params = {}) {
|
|
1277
|
+
return JSON.stringify({
|
|
1278
|
+
transport: options.transport,
|
|
1279
|
+
command: options.command,
|
|
1280
|
+
commandSource: options.commandSource ?? null,
|
|
1281
|
+
managedCommandOrder: options.managedCommandOrder ?? "package-first",
|
|
1282
|
+
managedComputerUsePluginNames: [...options.managedComputerUsePluginNames ?? []].toSorted(),
|
|
1283
|
+
managedFallbackCommandPaths: [...options.managedFallbackCommandPaths ?? []],
|
|
1284
|
+
args: options.args,
|
|
1285
|
+
cwd: options.cwd ?? null,
|
|
1286
|
+
url: options.url ?? null,
|
|
1287
|
+
authToken: hashSecretForKey(options.authToken, "authToken"),
|
|
1288
|
+
headers: Object.entries(options.headers).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `header:${key}`)]),
|
|
1289
|
+
env: Object.entries(options.env ?? {}).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `env:${key}`)]),
|
|
1290
|
+
clearEnv: [...options.clearEnv ?? []].toSorted(),
|
|
1291
|
+
authProfileId: params.authProfileId ?? null,
|
|
1292
|
+
authBindingFingerprint: params.authBindingFingerprint ?? null,
|
|
1293
|
+
agentDir: params.agentDir ?? null,
|
|
1294
|
+
fallbackApiKeyCacheKey: params.fallbackApiKeyCacheKey ?? null
|
|
1295
|
+
});
|
|
1285
1296
|
}
|
|
1286
|
-
function
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1297
|
+
function codexSandboxPolicyForTurn(mode, cwd, nativeArgs = []) {
|
|
1298
|
+
if (mode === "danger-full-access") return { type: "dangerFullAccess" };
|
|
1299
|
+
if (mode === "read-only") return {
|
|
1300
|
+
type: "readOnly",
|
|
1301
|
+
networkAccess: false
|
|
1302
|
+
};
|
|
1303
|
+
let excludeTmpdirEnvVar = false;
|
|
1304
|
+
let excludeSlashTmp = false;
|
|
1305
|
+
for (let index = 0; index < nativeArgs.length; index += 1) {
|
|
1306
|
+
const arg = nativeArgs[index];
|
|
1307
|
+
const override = arg === "-c" || arg === "--config" ? nativeArgs[++index] : arg?.startsWith("--config=") ? arg.slice(9) : void 0;
|
|
1308
|
+
if (!override) continue;
|
|
1309
|
+
const separator = override.indexOf("=");
|
|
1310
|
+
if (separator < 0) continue;
|
|
1311
|
+
const key = override.slice(0, separator).trim();
|
|
1312
|
+
const value = override.slice(separator + 1).trim();
|
|
1313
|
+
if (value !== "true" && value !== "false") continue;
|
|
1314
|
+
if (key === "sandbox_workspace_write.exclude_tmpdir_env_var") excludeTmpdirEnvVar = value === "true";
|
|
1315
|
+
else if (key === "sandbox_workspace_write.exclude_slash_tmp") excludeSlashTmp = value === "true";
|
|
1316
|
+
}
|
|
1317
|
+
return {
|
|
1318
|
+
type: "workspaceWrite",
|
|
1319
|
+
writableRoots: [cwd],
|
|
1320
|
+
networkAccess: false,
|
|
1321
|
+
excludeTmpdirEnvVar,
|
|
1322
|
+
excludeSlashTmp
|
|
1323
|
+
};
|
|
1290
1324
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
}
|
|
1305
|
-
if (/\s/.test(char)) {
|
|
1306
|
-
if (current) {
|
|
1307
|
-
words.push(current);
|
|
1308
|
-
current = "";
|
|
1325
|
+
/** Resolves the passive supervision control connection without changing harness defaults. */
|
|
1326
|
+
function resolveCodexSupervisionAppServerRuntimeOptions(params = {}) {
|
|
1327
|
+
const pluginConfig = readCodexPluginConfig(params.pluginConfig);
|
|
1328
|
+
const appServer = pluginConfig.appServer ?? {};
|
|
1329
|
+
const transport = resolveTransport(appServer.transport);
|
|
1330
|
+
const homeScope = appServer.homeScope ?? (transport === "websocket" ? "agent" : "user");
|
|
1331
|
+
return resolveCodexAppServerRuntimeOptions({
|
|
1332
|
+
...params,
|
|
1333
|
+
pluginConfig: {
|
|
1334
|
+
...pluginConfig,
|
|
1335
|
+
appServer: {
|
|
1336
|
+
...appServer,
|
|
1337
|
+
homeScope
|
|
1309
1338
|
}
|
|
1310
|
-
continue;
|
|
1311
1339
|
}
|
|
1312
|
-
|
|
1313
|
-
}
|
|
1314
|
-
if (current) words.push(current);
|
|
1315
|
-
return words;
|
|
1340
|
+
});
|
|
1316
1341
|
}
|
|
1317
1342
|
//#endregion
|
|
1318
1343
|
//#region extensions/codex/src/app-server/session-binding.ts
|
|
@@ -1348,7 +1373,7 @@ const BINDING_LEASE_RENEW_INTERVAL_MS = Math.floor(BINDING_LEASE_STALE_MS / 3);
|
|
|
1348
1373
|
const PHYSICAL_SESSION_RETIRE_TTL_MS = BINDING_LEASE_WAIT_MS;
|
|
1349
1374
|
/** Resolves the same agent scope OpenClaw uses for transcript/session ownership. */
|
|
1350
1375
|
function sessionBindingIdentity(params) {
|
|
1351
|
-
const { sessionAgentId } = resolveSessionAgentIds(params);
|
|
1376
|
+
const { sessionAgentId } = resolveSessionAgentIds$1(params);
|
|
1352
1377
|
const sessionKey = params.sessionKey?.trim();
|
|
1353
1378
|
return {
|
|
1354
1379
|
kind: "session",
|
|
@@ -1727,10 +1752,17 @@ function createCodexAppServerBindingStore(state) {
|
|
|
1727
1752
|
result: true
|
|
1728
1753
|
};
|
|
1729
1754
|
const currentSessionId = current.sessionId;
|
|
1730
|
-
if (!currentSessionId
|
|
1755
|
+
if (!currentSessionId) return {
|
|
1731
1756
|
kind: "resolved",
|
|
1732
1757
|
result: current.state !== "cleared" || current.retired !== true
|
|
1733
1758
|
};
|
|
1759
|
+
if (currentSessionId === identity.sessionId) return current.state === "cleared" && current.retired === true ? {
|
|
1760
|
+
kind: "verify",
|
|
1761
|
+
expectedPreviousSessionId: currentSessionId
|
|
1762
|
+
} : {
|
|
1763
|
+
kind: "resolved",
|
|
1764
|
+
result: true
|
|
1765
|
+
};
|
|
1734
1766
|
return {
|
|
1735
1767
|
kind: "verify",
|
|
1736
1768
|
expectedPreviousSessionId: currentSessionId
|
|
@@ -1746,7 +1778,18 @@ function createCodexAppServerBindingStore(state) {
|
|
|
1746
1778
|
if (mutation.kind === "reclaim-generation") {
|
|
1747
1779
|
if (identity.kind !== "session" || !identity.sessionKey?.trim()) return { result: false };
|
|
1748
1780
|
if (!current) return { result: true };
|
|
1749
|
-
if (ownsGeneration)
|
|
1781
|
+
if (ownsGeneration) {
|
|
1782
|
+
if (current.state === "cleared" && current.retired === true && current.sessionId === mutation.expectedPreviousSessionId) return {
|
|
1783
|
+
result: true,
|
|
1784
|
+
next: {
|
|
1785
|
+
version: 1,
|
|
1786
|
+
state: "cleared",
|
|
1787
|
+
sessionId: identity.sessionId,
|
|
1788
|
+
...ownedLease
|
|
1789
|
+
}
|
|
1790
|
+
};
|
|
1791
|
+
return { result: current.state !== "cleared" || current.retired !== true };
|
|
1792
|
+
}
|
|
1750
1793
|
if (current.sessionId !== mutation.expectedPreviousSessionId) return { result: false };
|
|
1751
1794
|
if (current.state === "active" && current.binding.connectionScope === "supervision") return { result: false };
|
|
1752
1795
|
return {
|
|
@@ -1825,6 +1868,25 @@ function createCodexAppServerBindingStore(state) {
|
|
|
1825
1868
|
});
|
|
1826
1869
|
});
|
|
1827
1870
|
},
|
|
1871
|
+
async resetSessionGeneration(identity) {
|
|
1872
|
+
return await runBindingMutation(async () => {
|
|
1873
|
+
const key = bindingStoreKey(identity);
|
|
1874
|
+
return await transactKey(key, (current, leaseToken) => {
|
|
1875
|
+
if (!current) return { result: "absent" };
|
|
1876
|
+
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
1877
|
+
if (current.state === "cleared" && current.retired === true) return { result: "conflict" };
|
|
1878
|
+
return {
|
|
1879
|
+
result: "applied",
|
|
1880
|
+
next: {
|
|
1881
|
+
version: 1,
|
|
1882
|
+
state: "cleared",
|
|
1883
|
+
...storedSessionGeneration(identity, current),
|
|
1884
|
+
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
}, leaseContext.getStore()?.has(key) ? void 0 : 1);
|
|
1888
|
+
});
|
|
1889
|
+
},
|
|
1828
1890
|
async retireSessionGeneration(identity) {
|
|
1829
1891
|
return await runBindingMutation(async () => {
|
|
1830
1892
|
const key = bindingStoreKey(identity);
|
|
@@ -1956,7 +2018,7 @@ function bindingStoreKey(identity) {
|
|
|
1956
2018
|
const sessionId = identity.sessionId.trim();
|
|
1957
2019
|
if (!rawAgentId) throw new Error("Codex app-server binding requires an agent id");
|
|
1958
2020
|
if (!sessionId) throw new Error("Codex app-server binding requires a session id");
|
|
1959
|
-
const agentId = resolveSessionAgentIds({ agentId: rawAgentId }).sessionAgentId;
|
|
2021
|
+
const agentId = resolveSessionAgentIds$1({ agentId: rawAgentId }).sessionAgentId;
|
|
1960
2022
|
const sessionKey = identity.sessionKey?.trim();
|
|
1961
2023
|
if (sessionKey) return `session-key:${agentId}:${createHash("sha256").update(sessionKey).digest("base64url")}`;
|
|
1962
2024
|
return `session:${agentId}:${sessionId}`;
|
|
@@ -2096,4 +2158,4 @@ function resolveCodexAppServerBindingModelProvider(params) {
|
|
|
2096
2158
|
return params.modelProvider?.trim() || (isCodexAppServerNativeAuthProfile(params) ? PUBLIC_OPENAI_MODEL_PROVIDER : void 0);
|
|
2097
2159
|
}
|
|
2098
2160
|
//#endregion
|
|
2099
|
-
export {
|
|
2161
|
+
export { CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME as A, isCodexAppServerApprovalPolicyAllowedByRequirements as C, resolveOpenClawExecPolicyForCodexAppServer as D, resolveCodexPluginsPolicy as E, isCodexFastServiceTier as O, resolveCodexModelBackedReviewerPolicyContext as S, readCodexPluginConfig as T, assertCodexAppServerConnectionSecurity as _, hashCodexAppServerBindingFingerprint as a, canUseCodexModelBackedApprovalsReviewerForModel as b, reclaimCurrentCodexSessionGeneration as c, codexAppServerStartOptionsKey as d, codexSandboxPolicyForTurn as f, resolveCodexSupervisionAppServerRuntimeOptions as g, resolveCodexComputerUseConfig as h, createCodexSessionGenerationSupersededError as i, CODEX_PLUGINS_MARKETPLACE_NAME as k, sessionBindingIdentity as l, resolveCodexAppServerStartOptionsForAgent as m, assertCodexBindingMayBeReplaced as n, isCodexAppServerNativeAuthProfile as o, resolveCodexAppServerRuntimeOptions as p, bindingStoreKey as r, normalizeCodexAppServerBindingModelProvider as s, CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS as t, session_binding_exports as u, shouldAutoApproveCodexAppServerApprovals as v, isCodexSandboxExecServerEnabled as w, resolveCodexAppServerUserHomeDir as x, withMcpElicitationsApprovalPolicy as y };
|