@openclaw/codex 2026.7.2-beta.7 → 2026.7.34
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/README.md +3 -27
- package/dist/{command-formatters-C336eRVS.js → .setup/app-server-policy-C_qTMEMy.mjs} +51 -9
- package/dist/{attempt-notifications-AP-a-Q5k.js → .setup/attempt-notifications-F8krwWL4.mjs} +6 -3
- package/dist/{command-handlers-DAHUSry9.js → .setup/command-handlers-DSRFfor4.mjs} +1156 -1319
- package/dist/.setup/command-rpc-BvYsfQ7G.mjs +786 -0
- package/dist/{compact-D_uvHurS.js → .setup/compact-BNgh7I4t.mjs} +10 -40
- package/dist/.setup/computer-use-C3QkmSO3.mjs +377 -0
- package/dist/.setup/config-CYEDnLJ2.mjs +1138 -0
- package/dist/{conversation-binding-data-BHRpYbX3.js → .setup/conversation-binding-data-CrRxtDBu.mjs} +1 -1
- package/dist/{bounded-turn-D2ZAgZVz.js → .setup/media-understanding-provider-EbJCyDqe.mjs} +203 -109
- package/dist/{models-BBMKU4jA.js → .setup/models-C_aZk03A.mjs} +11 -6
- package/dist/.setup/notification-correlation-iYs4WieS.mjs +35 -0
- package/dist/.setup/plugin-app-cache-key-DR8jV9oS.mjs +99 -0
- package/dist/.setup/protocol-2POPqAY4.mjs +13 -0
- package/dist/{transcript-mirror-DzsdNCf5.js → .setup/protocol-validators-dZQ-UTOa.mjs} +112 -922
- package/dist/{rate-limits-CU-gVCCS.js → .setup/provider-DGxDs6g8.mjs} +269 -13
- package/dist/{dynamic-tools-D2gYkSBO.js → .setup/provider-capabilities-DS2N_zc1.mjs} +5632 -3953
- package/dist/.setup/request-DFR0JyoV.mjs +36 -0
- package/dist/.setup/run-attempt-C7xEKFVB.mjs +8180 -0
- package/dist/{sandbox-guard-NuhpXmPB.js → .setup/sandbox-guard-DA2TQfZW.mjs} +1 -14
- package/dist/.setup/session-binding-DuihlMJc.mjs +628 -0
- package/dist/.setup/shared-client-B2KmLPRw.mjs +1854 -0
- package/dist/{side-question-_ulBk1AL.js → .setup/side-question-Cv6JXWCS.mjs} +84 -159
- package/dist/.setup/thread-lifecycle-u6CZdOOH.mjs +2593 -0
- package/dist/{web-search-provider.runtime-CCFhg2z5.js → .setup/web-search-provider.runtime-Ce2zOHxW.mjs} +3 -3
- package/dist/doctor-contract-api.js +122 -88
- package/dist/harness.js +20 -89
- package/dist/index.js +436 -1615
- package/dist/media-understanding-provider.js +1 -173
- package/dist/prompt-overlay.js +15 -0
- package/dist/provider-catalog.js +79 -0
- package/dist/provider-discovery.js +34 -0
- package/dist/provider.js +2 -0
- package/dist/web-search-contract-api.js +1 -1
- package/openclaw.plugin.json +178 -221
- package/package.json +8 -9
- package/dist/app-server-policy-BSaO2JIT.js +0 -49
- package/dist/auth-binding-B4FfbcCg.js +0 -62
- package/dist/capabilities-BFDTVYr4.js +0 -36
- package/dist/cli-metadata.js +0 -20
- package/dist/computer-use-CYEc8U3w.js +0 -693
- package/dist/conversation-control-xsIeXbo4.js +0 -287
- package/dist/effective-mcp-catalog-Bbd98Inw.js +0 -114
- package/dist/event-projector-assistant-message-DTgnPPVF.js +0 -101
- package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/notification-correlation-CU6_AnOb.js +0 -67
- package/dist/plugin-app-cache-key-DztPafOA.js +0 -408
- package/dist/request-qKh331yu.js +0 -157
- package/dist/run-attempt-CY9WlDLc.js +0 -12413
- package/dist/runtime-artifact-CmtG_t1L.js +0 -554
- package/dist/session-binding-BXpo9ymA.js +0 -2214
- package/dist/session-catalog-DyOgR4WH.js +0 -2668
- package/dist/session-cli-2PZaFLRh.js +0 -175
- package/dist/session-upstream-marker-B6U7tLw5.js +0 -82
- package/dist/settled-turn-finalizer-CXY2Z9dT.js +0 -316
- package/dist/shared-client-DTbvH-XV.js +0 -3069
- package/dist/thread-lifecycle-DF53ogiA.js +0 -3987
- package/dist/transport-stdio-DXgGZ7Ib.js +0 -88
- package/dist/upstream-session-fork-Dy4Xvuoj.js +0 -320
- package/dist/usage-CQ6GhD5-.js +0 -25
- /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
- /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
- /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
|
@@ -1,2214 +0,0 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
-
import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
5
|
-
import { AgentHarnessSessionSupersededError, embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
6
|
-
import { createHash, createHmac, randomBytes, randomUUID } from "node:crypto";
|
|
7
|
-
import { ensureAuthProfileStore, resolveDefaultAgentDir, resolveProviderIdForAuth, resolveSessionAgentIds as resolveSessionAgentIds$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
8
|
-
import { readFileSync } from "node:fs";
|
|
9
|
-
import { homedir, hostname } from "node:os";
|
|
10
|
-
import { resolveExecApprovalsFromFile } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
11
|
-
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
12
|
-
import { buildSecretInputSchema, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
13
|
-
import { normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
14
|
-
import { detectWindowsSpawnCommandInlineArgs } from "openclaw/plugin-sdk/windows-spawn";
|
|
15
|
-
import { z } from "zod";
|
|
16
|
-
import { parse } from "smol-toml";
|
|
17
|
-
import { isLoopbackHost } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
18
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
19
|
-
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
20
|
-
//#region extensions/codex/src/app-server/config-contracts.ts
|
|
21
|
-
const CODEX_PLUGINS_MARKETPLACE_NAME = "openai-curated";
|
|
22
|
-
const CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME = "workspace-directory";
|
|
23
|
-
//#endregion
|
|
24
|
-
//#region extensions/codex/src/app-server/config-utils.ts
|
|
25
|
-
const START_OPTIONS_KEY_SECRET_SYMBOL = Symbol.for("openclaw.codexAppServerStartOptionsKeySecret");
|
|
26
|
-
const START_OPTIONS_KEY_SECRET = getStartOptionsKeySecret();
|
|
27
|
-
const PLAIN_DECIMAL_NUMBER_RE = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))$/;
|
|
28
|
-
function readRecord(value) {
|
|
29
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
30
|
-
}
|
|
31
|
-
function normalizeCodexServiceTier(value) {
|
|
32
|
-
if (typeof value !== "string") return;
|
|
33
|
-
const trimmed = value.trim();
|
|
34
|
-
if (!trimmed) return;
|
|
35
|
-
const normalized = trimmed.toLowerCase();
|
|
36
|
-
if (normalized === "fast" || normalized === "priority") return "priority";
|
|
37
|
-
if (normalized === "flex") return "flex";
|
|
38
|
-
return trimmed;
|
|
39
|
-
}
|
|
40
|
-
function isCodexFastServiceTier(value) {
|
|
41
|
-
return normalizeCodexServiceTier(value) === "priority";
|
|
42
|
-
}
|
|
43
|
-
function normalizePositiveNumber(value, fallback) {
|
|
44
|
-
return resolvePositiveTimerTimeoutMs(value, fallback);
|
|
45
|
-
}
|
|
46
|
-
function normalizeHeaders(value) {
|
|
47
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
48
|
-
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key.trim(), normalizeCodexAppServerSecretInput({
|
|
49
|
-
value: child,
|
|
50
|
-
path: `plugins.entries.codex.config.appServer.headers.${key}`
|
|
51
|
-
})]).filter((entry) => Boolean(entry[0] && entry[1])));
|
|
52
|
-
}
|
|
53
|
-
function normalizeCodexAppServerSecretInput(params) {
|
|
54
|
-
return normalizeResolvedSecretInputString(params);
|
|
55
|
-
}
|
|
56
|
-
function normalizeStringList(value) {
|
|
57
|
-
return normalizeTrimmedStringList(value);
|
|
58
|
-
}
|
|
59
|
-
function readBooleanEnv(value) {
|
|
60
|
-
if (value === void 0) return;
|
|
61
|
-
const normalized = value.trim().toLowerCase();
|
|
62
|
-
if ([
|
|
63
|
-
"1",
|
|
64
|
-
"true",
|
|
65
|
-
"yes",
|
|
66
|
-
"on"
|
|
67
|
-
].includes(normalized)) return true;
|
|
68
|
-
if ([
|
|
69
|
-
"0",
|
|
70
|
-
"false",
|
|
71
|
-
"no",
|
|
72
|
-
"off"
|
|
73
|
-
].includes(normalized)) return false;
|
|
74
|
-
}
|
|
75
|
-
function readExecSecurity(value) {
|
|
76
|
-
return value === "deny" || value === "allowlist" || value === "full" ? value : void 0;
|
|
77
|
-
}
|
|
78
|
-
function readExecAsk(value) {
|
|
79
|
-
return value === "off" || value === "on-miss" || value === "always" ? value : void 0;
|
|
80
|
-
}
|
|
81
|
-
function readNumberEnv(value) {
|
|
82
|
-
const trimmed = value?.trim();
|
|
83
|
-
if (!trimmed || !PLAIN_DECIMAL_NUMBER_RE.test(trimmed)) return;
|
|
84
|
-
const parsed = Number(trimmed);
|
|
85
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
86
|
-
}
|
|
87
|
-
function resolveArgs(configArgs, envArgs) {
|
|
88
|
-
if (Array.isArray(configArgs)) return configArgs.map((entry) => readNonEmptyString(entry)).filter((entry) => entry !== void 0);
|
|
89
|
-
if (typeof configArgs === "string") return splitShellWords(configArgs);
|
|
90
|
-
return splitShellWords(envArgs ?? "");
|
|
91
|
-
}
|
|
92
|
-
function readNonEmptyString(value) {
|
|
93
|
-
if (typeof value !== "string") return;
|
|
94
|
-
return value.trim() || void 0;
|
|
95
|
-
}
|
|
96
|
-
function hashSecretForKey(value, label) {
|
|
97
|
-
if (!value) return null;
|
|
98
|
-
return createHmac("sha256", START_OPTIONS_KEY_SECRET).update(label).update("\0").update(value).digest("hex");
|
|
99
|
-
}
|
|
100
|
-
function getStartOptionsKeySecret() {
|
|
101
|
-
const globalState = globalThis;
|
|
102
|
-
globalState[START_OPTIONS_KEY_SECRET_SYMBOL] ??= randomBytes(32);
|
|
103
|
-
return globalState[START_OPTIONS_KEY_SECRET_SYMBOL];
|
|
104
|
-
}
|
|
105
|
-
function splitShellWords(value) {
|
|
106
|
-
const words = [];
|
|
107
|
-
let current = "";
|
|
108
|
-
let quote = null;
|
|
109
|
-
for (const char of value) {
|
|
110
|
-
if (quote) {
|
|
111
|
-
if (char === quote) quote = null;
|
|
112
|
-
else current += char;
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
if (char === "\"" || char === "'") {
|
|
116
|
-
quote = char;
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
if (/\s/.test(char)) {
|
|
120
|
-
if (current) {
|
|
121
|
-
words.push(current);
|
|
122
|
-
current = "";
|
|
123
|
-
}
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
current += char;
|
|
127
|
-
}
|
|
128
|
-
if (current) words.push(current);
|
|
129
|
-
return words;
|
|
130
|
-
}
|
|
131
|
-
//#endregion
|
|
132
|
-
//#region extensions/codex/src/app-server/config-exec-policy.ts
|
|
133
|
-
function selectForcedPromptingSandbox(params) {
|
|
134
|
-
if (params.configuredSandbox === "read-only" || params.defaultSandbox === "read-only") return "read-only";
|
|
135
|
-
return params.defaultSandbox ?? "workspace-write";
|
|
136
|
-
}
|
|
137
|
-
function selectForcedDangerFullAccessSandbox(params) {
|
|
138
|
-
if (params.configuredSandbox === "read-only") return "read-only";
|
|
139
|
-
if (params.defaultPolicy?.dangerFullAccessAllowed === false) {
|
|
140
|
-
if (params.openClawSandboxActive) return params.defaultPolicy.sandbox ?? "workspace-write";
|
|
141
|
-
throw new Error("legacy full exec security with ask requires Codex app-server danger-full-access");
|
|
142
|
-
}
|
|
143
|
-
return "danger-full-access";
|
|
144
|
-
}
|
|
145
|
-
function selectGuardianSandbox(allowedSandboxModes) {
|
|
146
|
-
if (allowedSandboxModes === void 0 || allowedSandboxModes.has("workspace-write")) return "workspace-write";
|
|
147
|
-
if (allowedSandboxModes.has("read-only")) return "read-only";
|
|
148
|
-
if (allowedSandboxModes.has("danger-full-access")) return "danger-full-access";
|
|
149
|
-
return "workspace-write";
|
|
150
|
-
}
|
|
151
|
-
function resolveApprovalPolicy(value) {
|
|
152
|
-
if (value === "on-failure") return "on-request";
|
|
153
|
-
return value === "on-request" || value === "untrusted" || value === "never" ? value : void 0;
|
|
154
|
-
}
|
|
155
|
-
function resolveSandbox(value) {
|
|
156
|
-
return value === "read-only" || value === "workspace-write" || value === "danger-full-access" ? value : void 0;
|
|
157
|
-
}
|
|
158
|
-
function resolveApprovalsReviewer(value) {
|
|
159
|
-
return value === "auto_review" || value === "guardian_subagent" || value === "user" ? value : void 0;
|
|
160
|
-
}
|
|
161
|
-
function resolveOpenClawExecPolicyFromConfig(params) {
|
|
162
|
-
const root = readRecord(params.config);
|
|
163
|
-
const globalExec = readRecord(readRecord(root?.tools)?.exec);
|
|
164
|
-
const globalPolicy = applyOpenClawExecPolicyLayer(createDefaultOpenClawExecPolicy(), globalExec);
|
|
165
|
-
const agentId = params.agentId?.trim();
|
|
166
|
-
if (!agentId) return globalPolicy;
|
|
167
|
-
const agents = readRecord(root?.agents);
|
|
168
|
-
const agentList = Array.isArray(agents?.list) ? agents.list : [];
|
|
169
|
-
const normalizedAgentId = normalizeAgentId(agentId);
|
|
170
|
-
return applyOpenClawExecPolicyLayer(globalPolicy, readRecord(readRecord(readRecord(agentList.find((entry) => {
|
|
171
|
-
const id = readRecord(entry)?.id;
|
|
172
|
-
return typeof id === "string" && normalizeAgentId(id) === normalizedAgentId;
|
|
173
|
-
}))?.tools)?.exec));
|
|
174
|
-
}
|
|
175
|
-
function resolveOpenClawExecPolicyForCodexAppServer(params) {
|
|
176
|
-
const overridePolicy = applyOpenClawExecPolicyLayer(resolveOpenClawExecPolicyFromConfig({
|
|
177
|
-
config: params.config,
|
|
178
|
-
agentId: params.agentId
|
|
179
|
-
}), params.execOverrides);
|
|
180
|
-
return applyOpenClawExecApprovalFloors(overridePolicy, resolveOpenClawExecApprovalFloorsForCodexAppServer({
|
|
181
|
-
approvals: params.approvals,
|
|
182
|
-
agentId: params.agentId,
|
|
183
|
-
policy: overridePolicy
|
|
184
|
-
}));
|
|
185
|
-
}
|
|
186
|
-
function resolveEffectiveOpenClawExecModeForCodexAppServer(params) {
|
|
187
|
-
if (params.execPolicy?.touched === true) return params.execPolicy.mode;
|
|
188
|
-
return params.execMode;
|
|
189
|
-
}
|
|
190
|
-
function resolveCodexPolicyModeForOpenClawExecMode(mode) {
|
|
191
|
-
if (!mode || mode === "full") return;
|
|
192
|
-
return "guardian";
|
|
193
|
-
}
|
|
194
|
-
function assertCodexAppServerAllowedForOpenClawExecMode(mode) {
|
|
195
|
-
if (mode === "deny" || mode === "allowlist") throw new Error(`Codex app-server local execution is not available when tools.exec.mode=${mode}`);
|
|
196
|
-
}
|
|
197
|
-
function createDefaultOpenClawExecPolicy() {
|
|
198
|
-
return {
|
|
199
|
-
security: "full",
|
|
200
|
-
ask: "off",
|
|
201
|
-
touched: false
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
function applyOpenClawExecPolicyLayer(base, exec) {
|
|
205
|
-
if (!exec) return base;
|
|
206
|
-
const mode = readExecMode(exec.mode);
|
|
207
|
-
if (mode !== void 0) return {
|
|
208
|
-
...resolveOpenClawExecPolicyForMode(mode),
|
|
209
|
-
touched: true
|
|
210
|
-
};
|
|
211
|
-
const security = readExecSecurity(exec.security);
|
|
212
|
-
const ask = readExecAsk(exec.ask);
|
|
213
|
-
if (security === void 0 && ask === void 0) return base;
|
|
214
|
-
const nextSecurity = security ?? base.security;
|
|
215
|
-
const nextAsk = ask ?? base.ask;
|
|
216
|
-
return {
|
|
217
|
-
mode: resolveOpenClawExecModeFromPolicy({
|
|
218
|
-
security: nextSecurity,
|
|
219
|
-
ask: nextAsk
|
|
220
|
-
}),
|
|
221
|
-
security: nextSecurity,
|
|
222
|
-
ask: nextAsk,
|
|
223
|
-
touched: true
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
function resolveOpenClawExecApprovalFloorsForCodexAppServer(params) {
|
|
227
|
-
if (!params.approvals) return;
|
|
228
|
-
return resolveExecApprovalsFromFile({
|
|
229
|
-
file: params.approvals,
|
|
230
|
-
agentId: params.agentId,
|
|
231
|
-
overrides: {
|
|
232
|
-
security: params.policy.security,
|
|
233
|
-
ask: params.policy.ask
|
|
234
|
-
}
|
|
235
|
-
}).agent;
|
|
236
|
-
}
|
|
237
|
-
function applyOpenClawExecApprovalFloors(base, approvalFloors) {
|
|
238
|
-
if (!approvalFloors) return base;
|
|
239
|
-
const nextSecurity = approvalFloors.security ? minOpenClawExecSecurity(base.security, approvalFloors.security) : base.security;
|
|
240
|
-
const nextAsk = approvalFloors.ask ? maxOpenClawExecAsk(base.ask, approvalFloors.ask) : base.ask;
|
|
241
|
-
if (nextSecurity === base.security && nextAsk === base.ask) return base;
|
|
242
|
-
return {
|
|
243
|
-
mode: resolveOpenClawExecModeFromPolicy({
|
|
244
|
-
security: nextSecurity,
|
|
245
|
-
ask: nextAsk
|
|
246
|
-
}),
|
|
247
|
-
security: nextSecurity,
|
|
248
|
-
ask: nextAsk,
|
|
249
|
-
touched: true
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
function resolveOpenClawExecPolicyForMode(mode) {
|
|
253
|
-
switch (mode) {
|
|
254
|
-
case "deny": return {
|
|
255
|
-
mode,
|
|
256
|
-
security: "deny",
|
|
257
|
-
ask: "off"
|
|
258
|
-
};
|
|
259
|
-
case "allowlist": return {
|
|
260
|
-
mode,
|
|
261
|
-
security: "allowlist",
|
|
262
|
-
ask: "off"
|
|
263
|
-
};
|
|
264
|
-
case "ask":
|
|
265
|
-
case "auto": return {
|
|
266
|
-
mode,
|
|
267
|
-
security: "allowlist",
|
|
268
|
-
ask: "on-miss"
|
|
269
|
-
};
|
|
270
|
-
case "full": return {
|
|
271
|
-
mode,
|
|
272
|
-
security: "full",
|
|
273
|
-
ask: "off"
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
return mode;
|
|
277
|
-
}
|
|
278
|
-
function resolveOpenClawExecModeFromPolicy(params) {
|
|
279
|
-
if (params.security === "deny") return "deny";
|
|
280
|
-
if (params.security === "allowlist" && params.ask === "off") return "allowlist";
|
|
281
|
-
if (params.security === "full" && params.ask !== "always") return "full";
|
|
282
|
-
return "ask";
|
|
283
|
-
}
|
|
284
|
-
function minOpenClawExecSecurity(left, right) {
|
|
285
|
-
const order = {
|
|
286
|
-
deny: 0,
|
|
287
|
-
allowlist: 1,
|
|
288
|
-
full: 2
|
|
289
|
-
};
|
|
290
|
-
return order[left] <= order[right] ? left : right;
|
|
291
|
-
}
|
|
292
|
-
function maxOpenClawExecAsk(left, right) {
|
|
293
|
-
const order = {
|
|
294
|
-
off: 0,
|
|
295
|
-
"on-miss": 1,
|
|
296
|
-
always: 2
|
|
297
|
-
};
|
|
298
|
-
return order[left] >= order[right] ? left : right;
|
|
299
|
-
}
|
|
300
|
-
function readExecMode(value) {
|
|
301
|
-
return value === "deny" || value === "allowlist" || value === "ask" || value === "auto" || value === "full" ? value : void 0;
|
|
302
|
-
}
|
|
303
|
-
//#endregion
|
|
304
|
-
//#region extensions/codex/src/app-server/session-discovery-config.ts
|
|
305
|
-
const codexSessionCatalogConfigSchema = z.object({ enabled: z.boolean().optional() }).strict();
|
|
306
|
-
const codexDiscoveryConfigSchema = z.object({
|
|
307
|
-
enabled: z.boolean().optional(),
|
|
308
|
-
timeoutMs: z.number().positive().optional()
|
|
309
|
-
}).strict();
|
|
310
|
-
//#endregion
|
|
311
|
-
//#region extensions/codex/src/app-server/config-parsing.ts
|
|
312
|
-
const DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME = "computer-use";
|
|
313
|
-
const DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS = 6e4;
|
|
314
|
-
const DEFAULT_CODEX_COMPUTER_USE_LIVE_TEST_TIMEOUT_MS = 6e4;
|
|
315
|
-
const DEFAULT_CODEX_COMPUTER_USE_TOOL_CALL_TIMEOUT_MS = 6e4;
|
|
316
|
-
const DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX = "openclaw-network";
|
|
317
|
-
const codexAppServerTransportSchema = z.enum([
|
|
318
|
-
"stdio",
|
|
319
|
-
"websocket",
|
|
320
|
-
"unix"
|
|
321
|
-
]);
|
|
322
|
-
const codexAppServerHomeScopeSchema = z.enum(["agent", "user"]);
|
|
323
|
-
const SecretInputSchema = buildSecretInputSchema();
|
|
324
|
-
const codexAppServerPolicyModeSchema = z.enum(["yolo", "guardian"]);
|
|
325
|
-
const codexAppServerApprovalPolicySchema = z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
|
|
326
|
-
"never",
|
|
327
|
-
"on-request",
|
|
328
|
-
"untrusted"
|
|
329
|
-
]));
|
|
330
|
-
const codexAppServerSandboxSchema = z.enum([
|
|
331
|
-
"read-only",
|
|
332
|
-
"workspace-write",
|
|
333
|
-
"danger-full-access"
|
|
334
|
-
]);
|
|
335
|
-
const codexAppServerApprovalsReviewerSchema = z.enum([
|
|
336
|
-
"user",
|
|
337
|
-
"auto_review",
|
|
338
|
-
"guardian_subagent"
|
|
339
|
-
]);
|
|
340
|
-
const codexDynamicToolsLoadingSchema = z.enum(["searchable", "direct"]);
|
|
341
|
-
const codexComputerUseHealthIntervalSchema = z.union([
|
|
342
|
-
z.literal(30),
|
|
343
|
-
z.literal(60),
|
|
344
|
-
z.literal(120),
|
|
345
|
-
z.literal(240)
|
|
346
|
-
]);
|
|
347
|
-
const codexComputerUsePluginCacheModeSchema = z.enum(["shared", "independent"]);
|
|
348
|
-
const codexPluginDestructivePolicySchema = z.union([
|
|
349
|
-
z.boolean(),
|
|
350
|
-
z.literal("auto"),
|
|
351
|
-
z.literal("ask")
|
|
352
|
-
]);
|
|
353
|
-
const codexAppServerServiceTierSchema = z.preprocess((value) => value === null ? null : normalizeCodexServiceTier(value), z.string().trim().min(1).nullable().optional()).optional();
|
|
354
|
-
const codexAppServerExperimentalSchema = z.object({ sandboxExecServer: z.boolean().optional() }).strict();
|
|
355
|
-
const codexAppServerRemoteWorkspaceRootSchema = z.string().trim().min(1);
|
|
356
|
-
const codexAppServerNetworkProxyDomainPermissionSchema = z.enum(["allow", "deny"]);
|
|
357
|
-
const codexAppServerNetworkProxyUnixSocketPermissionSchema = z.enum(["allow", "none"]);
|
|
358
|
-
const codexAppServerNetworkProxySchema = z.object({
|
|
359
|
-
enabled: z.boolean().optional(),
|
|
360
|
-
profileName: z.string().trim().min(1).optional(),
|
|
361
|
-
baseProfile: z.enum(["read-only", "workspace"]).optional(),
|
|
362
|
-
mode: z.enum(["limited", "full"]).optional(),
|
|
363
|
-
domains: z.record(z.string(), codexAppServerNetworkProxyDomainPermissionSchema).optional(),
|
|
364
|
-
unixSockets: z.record(z.string(), codexAppServerNetworkProxyUnixSocketPermissionSchema).optional(),
|
|
365
|
-
proxyUrl: z.string().trim().min(1).optional(),
|
|
366
|
-
socksUrl: z.string().trim().min(1).optional(),
|
|
367
|
-
enableSocks5: z.boolean().optional(),
|
|
368
|
-
enableSocks5Udp: z.boolean().optional(),
|
|
369
|
-
allowUpstreamProxy: z.boolean().optional(),
|
|
370
|
-
allowLocalBinding: z.boolean().optional(),
|
|
371
|
-
dangerouslyAllowNonLoopbackProxy: z.boolean().optional(),
|
|
372
|
-
dangerouslyAllowAllUnixSockets: z.boolean().optional()
|
|
373
|
-
}).strict();
|
|
374
|
-
const codexPluginEntryConfigSchema = z.object({
|
|
375
|
-
enabled: z.boolean().optional(),
|
|
376
|
-
marketplaceName: z.enum([CODEX_PLUGINS_MARKETPLACE_NAME, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME]).optional(),
|
|
377
|
-
pluginName: z.string().trim().min(1).optional(),
|
|
378
|
-
allow_destructive_actions: codexPluginDestructivePolicySchema.optional()
|
|
379
|
-
}).strict();
|
|
380
|
-
const codexPluginsConfigSchema = z.object({
|
|
381
|
-
enabled: z.boolean().optional(),
|
|
382
|
-
allow_all_plugins: z.boolean().optional(),
|
|
383
|
-
allow_destructive_actions: codexPluginDestructivePolicySchema.optional(),
|
|
384
|
-
plugins: z.record(z.string(), codexPluginEntryConfigSchema).optional()
|
|
385
|
-
}).strict();
|
|
386
|
-
const codexSupervisionEndpointSchema = z.union([z.object({
|
|
387
|
-
id: z.string().optional(),
|
|
388
|
-
label: z.string().optional(),
|
|
389
|
-
transport: z.literal("stdio-proxy").optional(),
|
|
390
|
-
command: z.string().optional(),
|
|
391
|
-
args: z.array(z.string()).optional(),
|
|
392
|
-
cwd: z.string().optional()
|
|
393
|
-
}).strict(), z.object({
|
|
394
|
-
id: z.string().optional(),
|
|
395
|
-
label: z.string().optional(),
|
|
396
|
-
transport: z.literal("websocket"),
|
|
397
|
-
url: z.string(),
|
|
398
|
-
authTokenEnv: z.string().optional()
|
|
399
|
-
}).strict()]);
|
|
400
|
-
const codexSupervisionConfigSchema = z.object({
|
|
401
|
-
enabled: z.boolean().optional(),
|
|
402
|
-
endpoints: z.array(codexSupervisionEndpointSchema).optional(),
|
|
403
|
-
allowRawTranscripts: z.boolean().optional(),
|
|
404
|
-
allowWriteControls: z.boolean().optional()
|
|
405
|
-
}).strict();
|
|
406
|
-
const codexPluginConfigSchema = z.object({
|
|
407
|
-
codexDynamicToolsLoading: codexDynamicToolsLoadingSchema.optional(),
|
|
408
|
-
codexDynamicToolsExclude: z.array(z.string()).optional(),
|
|
409
|
-
sessionCatalog: codexSessionCatalogConfigSchema.optional(),
|
|
410
|
-
discovery: codexDiscoveryConfigSchema.optional(),
|
|
411
|
-
computerUse: z.object({
|
|
412
|
-
enabled: z.boolean().optional(),
|
|
413
|
-
autoInstall: z.boolean().optional(),
|
|
414
|
-
marketplaceDiscoveryTimeoutMs: z.number().positive().optional(),
|
|
415
|
-
liveTestTimeoutMs: z.number().positive().optional(),
|
|
416
|
-
toolCallTimeoutMs: z.number().positive().optional(),
|
|
417
|
-
healthCheckEnabled: z.boolean().optional(),
|
|
418
|
-
healthCheckIntervalMinutes: codexComputerUseHealthIntervalSchema.optional(),
|
|
419
|
-
pluginCacheMode: codexComputerUsePluginCacheModeSchema.optional(),
|
|
420
|
-
strictReadiness: z.boolean().optional(),
|
|
421
|
-
autoRepair: z.boolean().optional(),
|
|
422
|
-
marketplaceSource: z.string().optional(),
|
|
423
|
-
marketplacePath: z.string().optional(),
|
|
424
|
-
marketplaceName: z.string().optional(),
|
|
425
|
-
pluginName: z.string().optional(),
|
|
426
|
-
mcpServerName: z.string().optional()
|
|
427
|
-
}).strict().optional(),
|
|
428
|
-
codexPlugins: z.unknown().optional(),
|
|
429
|
-
supervision: codexSupervisionConfigSchema.optional(),
|
|
430
|
-
appServer: z.object({
|
|
431
|
-
mode: codexAppServerPolicyModeSchema.optional(),
|
|
432
|
-
transport: codexAppServerTransportSchema.optional(),
|
|
433
|
-
homeScope: codexAppServerHomeScopeSchema.optional(),
|
|
434
|
-
command: z.string().optional(),
|
|
435
|
-
args: z.union([z.array(z.string()), z.string()]).optional(),
|
|
436
|
-
url: z.string().optional(),
|
|
437
|
-
authToken: SecretInputSchema.optional(),
|
|
438
|
-
headers: z.record(z.string(), SecretInputSchema).optional(),
|
|
439
|
-
clearEnv: z.array(z.string()).optional(),
|
|
440
|
-
remoteWorkspaceRoot: codexAppServerRemoteWorkspaceRootSchema.optional(),
|
|
441
|
-
codeModeOnly: z.boolean().optional(),
|
|
442
|
-
loopDetectionPreToolUseRelay: z.boolean().optional(),
|
|
443
|
-
requestTimeoutMs: z.number().positive().optional(),
|
|
444
|
-
turnCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
445
|
-
turnAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
446
|
-
postToolRawAssistantCompletionIdleTimeoutMs: z.number().positive().optional(),
|
|
447
|
-
approvalPolicy: codexAppServerApprovalPolicySchema.optional(),
|
|
448
|
-
sandbox: codexAppServerSandboxSchema.optional(),
|
|
449
|
-
approvalsReviewer: codexAppServerApprovalsReviewerSchema.optional(),
|
|
450
|
-
serviceTier: codexAppServerServiceTierSchema,
|
|
451
|
-
networkProxy: codexAppServerNetworkProxySchema.optional(),
|
|
452
|
-
defaultWorkspaceDir: z.string().optional(),
|
|
453
|
-
experimental: codexAppServerExperimentalSchema.optional()
|
|
454
|
-
}).strict().optional()
|
|
455
|
-
}).strict();
|
|
456
|
-
function readCodexPluginConfig(value) {
|
|
457
|
-
const parsed = codexPluginConfigSchema.safeParse(value);
|
|
458
|
-
if (!parsed.success) return {};
|
|
459
|
-
const { codexPlugins: rawCodexPlugins, ...config } = parsed.data;
|
|
460
|
-
const plugins = codexPluginsConfigSchema.safeParse(rawCodexPlugins);
|
|
461
|
-
if (!plugins.success) return config;
|
|
462
|
-
return {
|
|
463
|
-
...config,
|
|
464
|
-
...plugins.data ? { codexPlugins: plugins.data } : {}
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
function isCodexSandboxExecServerEnabled(pluginConfig) {
|
|
468
|
-
return readCodexPluginConfig(pluginConfig).appServer?.experimental?.sandboxExecServer === true;
|
|
469
|
-
}
|
|
470
|
-
function assertCodexAppServerCommandHasNoInlineArgs(params) {
|
|
471
|
-
const inlineArgs = detectWindowsSpawnCommandInlineArgs(params.command);
|
|
472
|
-
if (!inlineArgs) return;
|
|
473
|
-
const sourceLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_BIN" : "plugins.entries.codex.config.appServer.command";
|
|
474
|
-
const argsLabel = params.source === "env" ? "OPENCLAW_CODEX_APP_SERVER_ARGS" : "plugins.entries.codex.config.appServer.args";
|
|
475
|
-
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.`);
|
|
476
|
-
}
|
|
477
|
-
function resolveCodexPluginsPolicy(pluginConfig) {
|
|
478
|
-
const config = readCodexPluginConfig(pluginConfig).codexPlugins;
|
|
479
|
-
const configured = config !== void 0;
|
|
480
|
-
const enabled = config?.enabled === true;
|
|
481
|
-
const destructivePolicy = resolveCodexPluginDestructivePolicy(config?.allow_destructive_actions ?? true);
|
|
482
|
-
const pluginPolicies = Object.entries(config?.plugins ?? {}).flatMap(([configKey, entry]) => {
|
|
483
|
-
if (!isCodexPluginMarketplaceName(entry.marketplaceName) || !entry.pluginName) return [];
|
|
484
|
-
const entryDestructivePolicy = resolveCodexPluginDestructivePolicy(entry.allow_destructive_actions ?? config?.allow_destructive_actions ?? true);
|
|
485
|
-
return [{
|
|
486
|
-
configKey,
|
|
487
|
-
marketplaceName: entry.marketplaceName,
|
|
488
|
-
pluginName: entry.pluginName,
|
|
489
|
-
enabled: enabled && entry.enabled !== false,
|
|
490
|
-
allowDestructiveActions: entryDestructivePolicy.allowDestructiveActions,
|
|
491
|
-
destructiveApprovalMode: entryDestructivePolicy.destructiveApprovalMode
|
|
492
|
-
}];
|
|
493
|
-
}).toSorted((left, right) => left.configKey.localeCompare(right.configKey));
|
|
494
|
-
return {
|
|
495
|
-
configured,
|
|
496
|
-
enabled,
|
|
497
|
-
allowAllPlugins: enabled && config?.allow_all_plugins === true,
|
|
498
|
-
allowDestructiveActions: destructivePolicy.allowDestructiveActions,
|
|
499
|
-
destructiveApprovalMode: destructivePolicy.destructiveApprovalMode,
|
|
500
|
-
pluginPolicies
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
function isCodexPluginMarketplaceName(value) {
|
|
504
|
-
return value === "openai-curated" || value === "workspace-directory";
|
|
505
|
-
}
|
|
506
|
-
function resolveCodexPluginDestructivePolicy(policy) {
|
|
507
|
-
if (policy === "auto" || policy === "ask") return {
|
|
508
|
-
allowDestructiveActions: true,
|
|
509
|
-
destructiveApprovalMode: policy
|
|
510
|
-
};
|
|
511
|
-
return {
|
|
512
|
-
allowDestructiveActions: policy,
|
|
513
|
-
destructiveApprovalMode: policy ? "allow" : "deny"
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
//#endregion
|
|
517
|
-
//#region extensions/codex/src/app-server/config-requirements.ts
|
|
518
|
-
const UNIX_CODEX_REQUIREMENTS_PATH = "/etc/codex/requirements.toml";
|
|
519
|
-
const WINDOWS_CODEX_REQUIREMENTS_SUFFIX = "\\OpenAI\\Codex\\requirements.toml";
|
|
520
|
-
function isCodexAppServerApprovalPolicyAllowedByRequirements(policy, params = {}) {
|
|
521
|
-
const content = readCodexRequirementsToml(params);
|
|
522
|
-
if (content === void 0) return true;
|
|
523
|
-
const allowedApprovalPolicies = parseAllowedApprovalPoliciesFromCodexRequirements(content);
|
|
524
|
-
return allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has(policy);
|
|
525
|
-
}
|
|
526
|
-
function readCodexRequirementsToml(params) {
|
|
527
|
-
if (params.requirementsToml !== void 0) return params.requirementsToml ?? void 0;
|
|
528
|
-
const requirementsPath = readNonEmptyString(params.requirementsPath) ?? resolveCodexRequirementsPath(params.env ?? process.env, params.platform ?? process.platform);
|
|
529
|
-
try {
|
|
530
|
-
if (params.readRequirementsFile) return params.readRequirementsFile(requirementsPath);
|
|
531
|
-
return readFileSync(requirementsPath, "utf8");
|
|
532
|
-
} catch {
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
function resolveCodexRequirementsPath(env, platform) {
|
|
537
|
-
if (platform === "win32") return `${(readNonEmptyString(env.ProgramData) ?? "C:\\ProgramData").replace(/[\\/]+$/, "")}${WINDOWS_CODEX_REQUIREMENTS_SUFFIX}`;
|
|
538
|
-
return UNIX_CODEX_REQUIREMENTS_PATH;
|
|
539
|
-
}
|
|
540
|
-
function parseAllowedSandboxModesFromCodexRequirements(content, hostName) {
|
|
541
|
-
const remoteSandboxModes = parseMatchingRemoteSandboxModesFromCodexRequirements(content, hostName);
|
|
542
|
-
if (remoteSandboxModes !== void 0) return remoteSandboxModes;
|
|
543
|
-
return parseRequirementsSandboxModes(parseTopLevelRequirementsStringArray(content, "allowed_sandbox_modes"));
|
|
544
|
-
}
|
|
545
|
-
function parseAllowedApprovalPoliciesFromCodexRequirements(content) {
|
|
546
|
-
const values = parseTopLevelRequirementsStringArray(content, "allowed_approval_policies");
|
|
547
|
-
if (values === void 0) return;
|
|
548
|
-
const normalizedPolicies = values.map((entry) => normalizeRequirementsApprovalPolicy(entry)).filter((entry) => entry !== void 0);
|
|
549
|
-
return normalizedPolicies.length > 0 ? new Set(normalizedPolicies) : void 0;
|
|
550
|
-
}
|
|
551
|
-
function parseAllowedApprovalsReviewersFromCodexRequirements(content) {
|
|
552
|
-
const values = parseTopLevelRequirementsStringArray(content, "allowed_approvals_reviewers");
|
|
553
|
-
if (values === void 0) return;
|
|
554
|
-
const normalizedReviewers = values.map((entry) => normalizeRequirementsApprovalsReviewer(entry)).filter((entry) => entry !== void 0);
|
|
555
|
-
return normalizedReviewers.length > 0 ? new Set(normalizedReviewers) : void 0;
|
|
556
|
-
}
|
|
557
|
-
function parseMatchingRemoteSandboxModesFromCodexRequirements(content, hostName) {
|
|
558
|
-
const normalizedHostName = normalizeRequirementsHostName(hostName);
|
|
559
|
-
if (normalizedHostName === void 0) return;
|
|
560
|
-
for (const section of parseTomlArrayTableSections(content, "remote_sandbox_config")) {
|
|
561
|
-
const patterns = parseRequirementsStringArray(section, "hostname_patterns");
|
|
562
|
-
if (!patterns || !requirementsHostNameMatchesAnyPattern(normalizedHostName, patterns)) continue;
|
|
563
|
-
return parseRequirementsSandboxModes(parseRequirementsStringArray(section, "allowed_sandbox_modes"));
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
function parseRequirementsSandboxModes(values) {
|
|
567
|
-
if (values === void 0) return;
|
|
568
|
-
const normalizedModes = values.map((entry) => normalizeRequirementsSandboxMode(entry)).filter((entry) => entry !== void 0);
|
|
569
|
-
return normalizedModes.length > 0 ? new Set(normalizedModes) : void 0;
|
|
570
|
-
}
|
|
571
|
-
function parseTopLevelRequirementsStringArray(content, key) {
|
|
572
|
-
return parseRequirementsStringArray(stripTomlLineComments(content).slice(0, firstTomlTableOffset(content)), key);
|
|
573
|
-
}
|
|
574
|
-
function parseTomlStringValue(content, key) {
|
|
575
|
-
return parseTomlStringAssignmentValue(content, tomlDottedKeyPattern(key));
|
|
576
|
-
}
|
|
577
|
-
function parseInlineOpenAIModelProviderBaseUrl(content) {
|
|
578
|
-
return parseTomlStringAssignmentValue(content, `${tomlKeyPattern("model_providers")}\\s*=\\s*\\{[\\s\\S]*?${tomlKeyPattern("openai")}\\s*=\\s*\\{[\\s\\S]*?${tomlKeyPattern("base_url")}`);
|
|
579
|
-
}
|
|
580
|
-
function parseTomlStringAssignmentValue(content, keyPattern) {
|
|
581
|
-
const assignment = content.match(new RegExp(`(?:^|\\n)\\s*${keyPattern}\\s*=\\s*([^\\r\\n]*)`));
|
|
582
|
-
if (!assignment) return;
|
|
583
|
-
const rawValue = assignment[1]?.trimStart() ?? "";
|
|
584
|
-
if (rawValue.startsWith("\"\"\"") || rawValue.startsWith("'''")) return false;
|
|
585
|
-
const match = parseTomlStringAssignment(content, keyPattern);
|
|
586
|
-
return match ? match[1] ?? match[2] ?? "" : false;
|
|
587
|
-
}
|
|
588
|
-
function parseTomlStringAssignment(content, keyPattern) {
|
|
589
|
-
return content.match(new RegExp(`(?:^|\\n)\\s*${keyPattern}\\s*=\\s*(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|'([^']*)')`));
|
|
590
|
-
}
|
|
591
|
-
function tomlDottedKeyPattern(key) {
|
|
592
|
-
return key.split(".").map(tomlKeyPattern).join("\\s*\\.\\s*");
|
|
593
|
-
}
|
|
594
|
-
function tomlKeyPattern(key) {
|
|
595
|
-
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
596
|
-
return `(?:"${escaped}"|'${escaped}'|${escaped})`;
|
|
597
|
-
}
|
|
598
|
-
function parseRequirementsStringArray(content, key) {
|
|
599
|
-
const match = content.match(new RegExp(`(?:^|\\n)\\s*${key}\\s*=\\s*\\[([\\s\\S]*?)\\]`));
|
|
600
|
-
if (!match) return;
|
|
601
|
-
const arrayBody = match[1] ?? "";
|
|
602
|
-
const stringMatches = [...arrayBody.matchAll(/"([^"\\]*(?:\\.[^"\\]*)*)"|'([^']*)'/g)];
|
|
603
|
-
if (stringMatches.length === 0 && arrayBody.trim().length > 0) return;
|
|
604
|
-
return stringMatches.map((entry) => entry[1] ?? entry[2] ?? "");
|
|
605
|
-
}
|
|
606
|
-
function parseTomlTableSection(content, table) {
|
|
607
|
-
const strippedContent = stripTomlLineComments(content);
|
|
608
|
-
const tablePattern = tomlDottedKeyPattern(table);
|
|
609
|
-
const match = new RegExp(`^\\s*\\[\\s*${tablePattern}\\s*\\]\\s*$`, "m").exec(strippedContent);
|
|
610
|
-
if (!match) return;
|
|
611
|
-
const sectionStart = match.index + match[0].length;
|
|
612
|
-
const rest = strippedContent.slice(sectionStart);
|
|
613
|
-
const nextTableOffset = rest.search(/^\s*\[/m);
|
|
614
|
-
return nextTableOffset === -1 ? rest : rest.slice(0, nextTableOffset);
|
|
615
|
-
}
|
|
616
|
-
function parseTomlArrayTableSections(content, table) {
|
|
617
|
-
const strippedContent = stripTomlLineComments(content);
|
|
618
|
-
const escapedTable = table.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
619
|
-
const headerPattern = new RegExp(`^\\s*\\[\\[\\s*${escapedTable}\\s*\\]\\]\\s*$`, "gm");
|
|
620
|
-
const sections = [];
|
|
621
|
-
for (let match = headerPattern.exec(strippedContent); match; match = headerPattern.exec(strippedContent)) {
|
|
622
|
-
const sectionStart = headerPattern.lastIndex;
|
|
623
|
-
const rest = strippedContent.slice(sectionStart);
|
|
624
|
-
const nextTableOffset = rest.search(/^\s*\[/m);
|
|
625
|
-
sections.push(nextTableOffset === -1 ? rest : rest.slice(0, nextTableOffset));
|
|
626
|
-
}
|
|
627
|
-
return sections;
|
|
628
|
-
}
|
|
629
|
-
function firstTomlTableOffset(content) {
|
|
630
|
-
return content.match(/^\s*\[[^\]\n]/m)?.index ?? content.length;
|
|
631
|
-
}
|
|
632
|
-
function stripTomlLineComments(value) {
|
|
633
|
-
let output = "";
|
|
634
|
-
let quote;
|
|
635
|
-
let escaped = false;
|
|
636
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
637
|
-
const char = value[index] ?? "";
|
|
638
|
-
if (quote) {
|
|
639
|
-
output += char;
|
|
640
|
-
if (quote === "\"" && escaped) {
|
|
641
|
-
escaped = false;
|
|
642
|
-
continue;
|
|
643
|
-
}
|
|
644
|
-
if (quote === "\"" && char === "\\") {
|
|
645
|
-
escaped = true;
|
|
646
|
-
continue;
|
|
647
|
-
}
|
|
648
|
-
if (char === quote) quote = void 0;
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
|
-
if (char === "\"" || char === "'") {
|
|
652
|
-
quote = char;
|
|
653
|
-
output += char;
|
|
654
|
-
continue;
|
|
655
|
-
}
|
|
656
|
-
if (char === "#") {
|
|
657
|
-
while (index < value.length && value[index] !== "\n") index += 1;
|
|
658
|
-
if (value[index] === "\n") output += "\n";
|
|
659
|
-
continue;
|
|
660
|
-
}
|
|
661
|
-
output += char;
|
|
662
|
-
}
|
|
663
|
-
return output;
|
|
664
|
-
}
|
|
665
|
-
function normalizeRequirementsSandboxMode(value) {
|
|
666
|
-
const compact = value.replace(/[\s_-]/g, "").toLowerCase();
|
|
667
|
-
if (compact === "readonly") return "read-only";
|
|
668
|
-
if (compact === "workspacewrite") return "workspace-write";
|
|
669
|
-
if (compact === "dangerfullaccess") return "danger-full-access";
|
|
670
|
-
}
|
|
671
|
-
function normalizeRequirementsHostName(value) {
|
|
672
|
-
const normalized = value.trim().replace(/\.+$/g, "").toLowerCase();
|
|
673
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
674
|
-
}
|
|
675
|
-
function requirementsHostNameMatchesAnyPattern(hostName, patterns) {
|
|
676
|
-
return patterns.some((pattern) => {
|
|
677
|
-
const normalizedPattern = normalizeRequirementsHostName(pattern);
|
|
678
|
-
return normalizedPattern !== void 0 && globPatternMatches(hostName, normalizedPattern);
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
|
-
function globPatternMatches(value, pattern) {
|
|
682
|
-
let regex = "^";
|
|
683
|
-
for (const char of pattern) if (char === "*") regex += ".*";
|
|
684
|
-
else if (char === "?") regex += ".";
|
|
685
|
-
else regex += char.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
686
|
-
regex += "$";
|
|
687
|
-
return new RegExp(regex).test(value);
|
|
688
|
-
}
|
|
689
|
-
function normalizeRequirementsApprovalPolicy(value) {
|
|
690
|
-
const normalized = value.trim().toLowerCase();
|
|
691
|
-
if (normalized === "on-failure") return "on-request";
|
|
692
|
-
return resolveApprovalPolicy(normalized);
|
|
693
|
-
}
|
|
694
|
-
function normalizeRequirementsApprovalsReviewer(value) {
|
|
695
|
-
return resolveApprovalsReviewer(value.trim().toLowerCase());
|
|
696
|
-
}
|
|
697
|
-
function selectGuardianApprovalPolicy(allowedApprovalPolicies, execModeRequiringPromptingApprovals) {
|
|
698
|
-
if (allowedApprovalPolicies === void 0 || allowedApprovalPolicies.has("on-request")) return "on-request";
|
|
699
|
-
if (execModeRequiringPromptingApprovals) throw new Error(`tools.exec.mode=${execModeRequiringPromptingApprovals} requires Codex app-server prompting approvals`);
|
|
700
|
-
if (allowedApprovalPolicies.has("untrusted")) return "untrusted";
|
|
701
|
-
if (allowedApprovalPolicies.has("never")) return "never";
|
|
702
|
-
return "on-request";
|
|
703
|
-
}
|
|
704
|
-
function selectGuardianApprovalsReviewer(allowedApprovalsReviewers, execModeRequiringAutoReviewer) {
|
|
705
|
-
if (allowedApprovalsReviewers === void 0 || allowedApprovalsReviewers.has("auto_review")) return "auto_review";
|
|
706
|
-
if (allowedApprovalsReviewers.has("guardian_subagent")) return "guardian_subagent";
|
|
707
|
-
if (execModeRequiringAutoReviewer) throw new Error(`tools.exec.mode=${execModeRequiringAutoReviewer} requires Codex app-server auto approvals`);
|
|
708
|
-
if (allowedApprovalsReviewers.has("user")) return "user";
|
|
709
|
-
return "auto_review";
|
|
710
|
-
}
|
|
711
|
-
function selectUserApprovalsReviewer(allowedApprovalsReviewers, execModeRequiringUserReviewer) {
|
|
712
|
-
if (allowedApprovalsReviewers === void 0 || allowedApprovalsReviewers.has("user")) return "user";
|
|
713
|
-
throw new Error(`tools.exec.mode=${execModeRequiringUserReviewer ?? "ask"} requires Codex app-server user approvals`);
|
|
714
|
-
}
|
|
715
|
-
//#endregion
|
|
716
|
-
//#region extensions/codex/src/app-server/config-reviewer.ts
|
|
717
|
-
const CODEX_APP_SERVER_HOME_DIRNAME = "codex-home";
|
|
718
|
-
const CODEX_CONFIG_TOML_FILENAME = "config.toml";
|
|
719
|
-
function canUseCodexModelBackedApprovalsReviewerForModel(params) {
|
|
720
|
-
const explicitProvider = params.modelProvider?.trim().toLowerCase();
|
|
721
|
-
const inferredProvider = inferProviderFromModelRef(params.model);
|
|
722
|
-
if (explicitProvider && explicitProvider !== "codex") return isTrustedCodexModelBackedApprovalsReviewerProvider(explicitProvider, params) && (inferredProvider === void 0 || isTrustedCodexModelBackedApprovalsReviewerProvider(inferredProvider, params));
|
|
723
|
-
if (inferredProvider !== void 0) return isTrustedCodexModelBackedApprovalsReviewerProvider(inferredProvider, params);
|
|
724
|
-
return isTrustedCodexModelBackedApprovalsReviewerProvider(explicitProvider, params);
|
|
725
|
-
}
|
|
726
|
-
function isTrustedCodexModelBackedOpenAIProvider(params) {
|
|
727
|
-
if (!openAIBaseUrlEnvOverridesAreTrustedForModelBackedReview(params.env)) return false;
|
|
728
|
-
const codexBaseUrlOverrides = readCodexBaseUrlOverridesForModelBackedReview(params);
|
|
729
|
-
if (codexBaseUrlOverrides === false || !codexBaseUrlOverrides.openAI.every(isNativeOpenAIBaseUrl) || !codexBaseUrlOverrides.chatGPT.every(isNativeChatGPTBaseUrl)) return false;
|
|
730
|
-
const openAIProviders = readConfiguredOpenAIProvidersForModelBackedReview(params.config);
|
|
731
|
-
if (openAIProviders.length === 0) return true;
|
|
732
|
-
return openAIProviders.every((openAIProvider) => configuredOpenAIProviderIsTrustedForModelBackedReview(openAIProvider, params.model));
|
|
733
|
-
}
|
|
734
|
-
function resolveCodexModelBackedReviewerPolicyContext(params) {
|
|
735
|
-
const provider = params.provider?.trim();
|
|
736
|
-
if (provider && provider.toLowerCase() !== "codex") return {
|
|
737
|
-
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(provider),
|
|
738
|
-
model: params.model
|
|
739
|
-
};
|
|
740
|
-
const bindingModelProvider = params.bindingModelProvider?.trim();
|
|
741
|
-
const currentModel = params.model?.trim();
|
|
742
|
-
const bindingModel = params.bindingModel?.trim();
|
|
743
|
-
if (bindingModelProvider && currentModel && bindingModel && currentModel === bindingModel) return {
|
|
744
|
-
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(bindingModelProvider),
|
|
745
|
-
model: params.model ?? params.bindingModel
|
|
746
|
-
};
|
|
747
|
-
const currentModelProvider = inferProviderFromModelRef(params.model);
|
|
748
|
-
if (currentModelProvider) return {
|
|
749
|
-
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(currentModelProvider),
|
|
750
|
-
model: params.model
|
|
751
|
-
};
|
|
752
|
-
if (bindingModelProvider) return {
|
|
753
|
-
modelProvider: normalizeCodexModelBackedReviewerPolicyProvider(bindingModelProvider),
|
|
754
|
-
model: params.model ?? params.bindingModel
|
|
755
|
-
};
|
|
756
|
-
return {
|
|
757
|
-
modelProvider: params.nativeAuthProfile === true ? "openai" : void 0,
|
|
758
|
-
model: params.model ?? params.bindingModel
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
function isCodexModelBackedApprovalsReviewerProvider(provider) {
|
|
762
|
-
return provider?.trim().toLowerCase() === "openai";
|
|
763
|
-
}
|
|
764
|
-
function isTrustedCodexModelBackedApprovalsReviewerProvider(provider, params) {
|
|
765
|
-
return isCodexModelBackedApprovalsReviewerProvider(provider) && isTrustedCodexModelBackedOpenAIProvider({
|
|
766
|
-
config: params.config,
|
|
767
|
-
env: params.env,
|
|
768
|
-
model: params.model,
|
|
769
|
-
agentDir: params.agentDir,
|
|
770
|
-
codexConfigToml: params.codexConfigToml,
|
|
771
|
-
homeScope: params.homeScope
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
function readCodexBaseUrlOverridesForModelBackedReview(params) {
|
|
775
|
-
const configToml = readCodexAppServerConfigToml(params);
|
|
776
|
-
if (configToml === false) return false;
|
|
777
|
-
if (configToml === void 0) return {
|
|
778
|
-
openAI: [],
|
|
779
|
-
chatGPT: []
|
|
780
|
-
};
|
|
781
|
-
const topLevelContent = stripTomlLineComments(configToml).slice(0, firstTomlTableOffset(configToml));
|
|
782
|
-
const modelProviderOpenAISection = parseTomlTableSection(configToml, "model_providers.openai");
|
|
783
|
-
const openAIBaseUrl = parseTomlStringValue(topLevelContent, "openai_base_url");
|
|
784
|
-
const chatGPTBaseUrl = parseTomlStringValue(topLevelContent, "chatgpt_base_url");
|
|
785
|
-
const openAI = [
|
|
786
|
-
openAIBaseUrl,
|
|
787
|
-
parseTomlStringValue(topLevelContent, "model_providers.openai.base_url"),
|
|
788
|
-
parseInlineOpenAIModelProviderBaseUrl(topLevelContent),
|
|
789
|
-
modelProviderOpenAISection ? parseTomlStringValue(modelProviderOpenAISection, "base_url") : void 0
|
|
790
|
-
];
|
|
791
|
-
const chatGPT = [chatGPTBaseUrl];
|
|
792
|
-
if ([...openAI, ...chatGPT].includes(false)) return false;
|
|
793
|
-
return {
|
|
794
|
-
openAI: openAI.filter((entry) => typeof entry === "string"),
|
|
795
|
-
chatGPT: chatGPT.filter((entry) => typeof entry === "string")
|
|
796
|
-
};
|
|
797
|
-
}
|
|
798
|
-
function readCodexAppServerConfigToml(params) {
|
|
799
|
-
if (params.codexConfigToml !== void 0) return params.codexConfigToml ?? void 0;
|
|
800
|
-
const configPath = resolveCodexAppServerConfigPath(params);
|
|
801
|
-
if (!configPath) return;
|
|
802
|
-
try {
|
|
803
|
-
return readFileSync(configPath, "utf8");
|
|
804
|
-
} catch (error) {
|
|
805
|
-
return readErrorCode(error) === "ENOENT" ? void 0 : false;
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
function codexConfigEnablesNativeComputerUse(params) {
|
|
809
|
-
const configToml = readCodexAppServerConfigToml(params);
|
|
810
|
-
if (configToml === false) return true;
|
|
811
|
-
if (configToml === void 0) return false;
|
|
812
|
-
let parsedConfig;
|
|
813
|
-
try {
|
|
814
|
-
parsedConfig = parse(configToml, { integersAsBigInt: true });
|
|
815
|
-
} catch {
|
|
816
|
-
return true;
|
|
817
|
-
}
|
|
818
|
-
const rawPlugins = parsedConfig.plugins;
|
|
819
|
-
if (rawPlugins === void 0) return false;
|
|
820
|
-
const plugins = readRecord(rawPlugins);
|
|
821
|
-
if (!plugins) return true;
|
|
822
|
-
for (const [pluginId, rawPluginConfig] of Object.entries(plugins)) {
|
|
823
|
-
if (!params.pluginNames.some((pluginName) => pluginId === pluginName || pluginId.startsWith(`${pluginName}@`))) continue;
|
|
824
|
-
const pluginConfig = readRecord(rawPluginConfig);
|
|
825
|
-
if (!pluginConfig) return true;
|
|
826
|
-
if (pluginConfig.enabled === false) continue;
|
|
827
|
-
return true;
|
|
828
|
-
}
|
|
829
|
-
return false;
|
|
830
|
-
}
|
|
831
|
-
function resolveCodexAppServerConfigPath(params) {
|
|
832
|
-
if (params.homeScope === "user") return path.join(resolveCodexAppServerUserHomeDir(params.env), CODEX_CONFIG_TOML_FILENAME);
|
|
833
|
-
const agentDir = readNonEmptyString(params.agentDir);
|
|
834
|
-
const codexHome = agentDir ? path.join(path.resolve(agentDir), CODEX_APP_SERVER_HOME_DIRNAME) : void 0;
|
|
835
|
-
return codexHome ? path.join(codexHome, CODEX_CONFIG_TOML_FILENAME) : void 0;
|
|
836
|
-
}
|
|
837
|
-
/** Resolves the native user Codex home used by Desktop and the CLI. */
|
|
838
|
-
function resolveCodexAppServerUserHomeDir(env = process.env, homedir$1 = homedir) {
|
|
839
|
-
const configured = readNonEmptyString(env.CODEX_HOME);
|
|
840
|
-
return path.resolve(configured ?? path.join(homedir$1(), ".codex"));
|
|
841
|
-
}
|
|
842
|
-
function readErrorCode(error) {
|
|
843
|
-
return error && typeof error === "object" && "code" in error ? String(error.code) : void 0;
|
|
844
|
-
}
|
|
845
|
-
function readConfiguredOpenAIProvidersForModelBackedReview(config) {
|
|
846
|
-
const providerRecords = readRecord(readRecord(readRecord(config)?.models)?.providers);
|
|
847
|
-
if (!providerRecords) return [];
|
|
848
|
-
const openAIProviders = [];
|
|
849
|
-
for (const [providerId, providerConfig] of Object.entries(providerRecords)) {
|
|
850
|
-
if (resolveProviderIdForAuth(providerId, { config }) !== "openai") continue;
|
|
851
|
-
const record = readRecord(providerConfig);
|
|
852
|
-
if (record) openAIProviders.push(record);
|
|
853
|
-
}
|
|
854
|
-
return openAIProviders;
|
|
855
|
-
}
|
|
856
|
-
function configuredOpenAIProviderIsTrustedForModelBackedReview(openAIProvider, modelInput) {
|
|
857
|
-
if (readRecord(openAIProvider.localService) || hasNonEmptyRecord(openAIProvider.headers) || hasNonEmptyRecord(openAIProvider.request) || typeof openAIProvider.authHeader === "boolean" || !isNativeOpenAIBaseUrl(openAIProvider.baseUrl)) return false;
|
|
858
|
-
const models = openAIProvider.models;
|
|
859
|
-
if (!Array.isArray(models)) return true;
|
|
860
|
-
const modelId = normalizeOpenAIModelBackedReviewerModelId(modelInput);
|
|
861
|
-
if (!modelId) return false;
|
|
862
|
-
for (const entry of models) {
|
|
863
|
-
const model = readRecord(entry);
|
|
864
|
-
if (typeof model?.id !== "string" || !matchesConfiguredOpenAIModelId(modelId, model.id)) continue;
|
|
865
|
-
if (hasNonEmptyRecord(model.headers) || hasNonEmptyRecord(model.request) || !isNativeOpenAIBaseUrl(model.baseUrl)) return false;
|
|
866
|
-
}
|
|
867
|
-
return true;
|
|
868
|
-
}
|
|
869
|
-
function normalizeOpenAIModelBackedReviewerModelId(modelInput) {
|
|
870
|
-
const normalized = modelInput?.trim() ?? "";
|
|
871
|
-
const authProfileIndex = normalized.indexOf("@");
|
|
872
|
-
const withoutAuthProfile = authProfileIndex > 0 ? normalized.slice(0, authProfileIndex) : normalized;
|
|
873
|
-
const slashIndex = withoutAuthProfile.indexOf("/");
|
|
874
|
-
return slashIndex > 0 ? withoutAuthProfile.slice(slashIndex + 1).trim() : withoutAuthProfile;
|
|
875
|
-
}
|
|
876
|
-
function matchesConfiguredOpenAIModelId(modelId, configuredModelId) {
|
|
877
|
-
const configured = normalizeOpenAIModelBackedReviewerModelId(configuredModelId);
|
|
878
|
-
return Boolean(configured) && (modelId === configured || modelId.startsWith(`${configured}@`));
|
|
879
|
-
}
|
|
880
|
-
function hasNonEmptyRecord(value) {
|
|
881
|
-
const record = readRecord(value);
|
|
882
|
-
return record !== void 0 && Object.keys(record).length > 0;
|
|
883
|
-
}
|
|
884
|
-
function isNativeOpenAIBaseUrl(value) {
|
|
885
|
-
if (typeof value !== "string" || !value.trim()) return true;
|
|
886
|
-
try {
|
|
887
|
-
const url = new URL(value);
|
|
888
|
-
return url.protocol === "https:" && url.hostname.toLowerCase() === "api.openai.com";
|
|
889
|
-
} catch {
|
|
890
|
-
return false;
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
function openAIBaseUrlEnvOverridesAreTrustedForModelBackedReview(env) {
|
|
894
|
-
return [env?.OPENAI_BASE_URL, env?.OPENAI_API_BASE].every(isNativeOpenAIBaseUrl);
|
|
895
|
-
}
|
|
896
|
-
function isNativeChatGPTBaseUrl(value) {
|
|
897
|
-
if (typeof value !== "string" || !value.trim()) return true;
|
|
898
|
-
try {
|
|
899
|
-
const url = new URL(value);
|
|
900
|
-
return url.protocol === "https:" && url.hostname.toLowerCase() === "chatgpt.com";
|
|
901
|
-
} catch {
|
|
902
|
-
return false;
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
function normalizeCodexModelBackedReviewerPolicyProvider(provider) {
|
|
906
|
-
return provider.toLowerCase() === "openai" ? "openai" : provider;
|
|
907
|
-
}
|
|
908
|
-
function inferProviderFromModelRef(model) {
|
|
909
|
-
const normalized = model?.trim().toLowerCase();
|
|
910
|
-
const slashIndex = normalized?.indexOf("/") ?? -1;
|
|
911
|
-
return slashIndex > 0 ? normalized?.slice(0, slashIndex) : void 0;
|
|
912
|
-
}
|
|
913
|
-
//#endregion
|
|
914
|
-
//#region extensions/codex/src/app-server/config-security.ts
|
|
915
|
-
function shouldAutoApproveCodexAppServerApprovals(appServer) {
|
|
916
|
-
return appServer.networkProxy === void 0 && appServer.approvalPolicy === "never" && appServer.sandbox === "danger-full-access";
|
|
917
|
-
}
|
|
918
|
-
function resolveCodexAppServerNetworkProxy(config, sandbox) {
|
|
919
|
-
if (config?.enabled !== true) return {};
|
|
920
|
-
const fileSystemMode = config.baseProfile === "read-only" || !config.baseProfile && sandbox === "read-only" ? "read" : "write";
|
|
921
|
-
const networkConfig = removeUndefinedJsonFields({
|
|
922
|
-
enabled: true,
|
|
923
|
-
mode: config.mode,
|
|
924
|
-
domains: normalizeNetworkProxyPermissionMap(config.domains),
|
|
925
|
-
unix_sockets: normalizeNetworkProxyPermissionMap(config.unixSockets),
|
|
926
|
-
proxy_url: readNonEmptyString(config.proxyUrl),
|
|
927
|
-
socks_url: readNonEmptyString(config.socksUrl),
|
|
928
|
-
enable_socks5: config.enableSocks5,
|
|
929
|
-
enable_socks5_udp: config.enableSocks5Udp,
|
|
930
|
-
allow_upstream_proxy: config.allowUpstreamProxy,
|
|
931
|
-
allow_local_binding: config.allowLocalBinding,
|
|
932
|
-
dangerously_allow_non_loopback_proxy: config.dangerouslyAllowNonLoopbackProxy,
|
|
933
|
-
dangerously_allow_all_unix_sockets: config.dangerouslyAllowAllUnixSockets
|
|
934
|
-
});
|
|
935
|
-
const profile = {
|
|
936
|
-
filesystem: {
|
|
937
|
-
":minimal": "read",
|
|
938
|
-
":project_roots": { ".": fileSystemMode }
|
|
939
|
-
},
|
|
940
|
-
network: networkConfig
|
|
941
|
-
};
|
|
942
|
-
const profileName = resolveNetworkProxyPermissionProfileName(config, profile);
|
|
943
|
-
const configPatch = {
|
|
944
|
-
"features.network_proxy.enabled": true,
|
|
945
|
-
default_permissions: profileName,
|
|
946
|
-
permissions: { [profileName]: profile }
|
|
947
|
-
};
|
|
948
|
-
return { networkProxy: {
|
|
949
|
-
profileName,
|
|
950
|
-
configFingerprint: fingerprintCodexAppServerNetworkProxyConfigPatch(configPatch),
|
|
951
|
-
configPatch
|
|
952
|
-
} };
|
|
953
|
-
}
|
|
954
|
-
function resolveNetworkProxyPermissionProfileName(config, profile) {
|
|
955
|
-
const explicitProfileName = readNonEmptyString(config.profileName);
|
|
956
|
-
if (explicitProfileName) return explicitProfileName;
|
|
957
|
-
return `${DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX}-${createHash("sha256").update(stableStringifyJson({
|
|
958
|
-
version: 1,
|
|
959
|
-
profile
|
|
960
|
-
})).digest("hex").slice(0, 16)}`;
|
|
961
|
-
}
|
|
962
|
-
function fingerprintCodexAppServerNetworkProxyConfigPatch(configPatch) {
|
|
963
|
-
return createHash("sha256").update(stableStringifyJson(configPatch)).digest("hex");
|
|
964
|
-
}
|
|
965
|
-
function normalizeNetworkProxyPermissionMap(value) {
|
|
966
|
-
const entries = Object.entries(value ?? {}).map(([key, permission]) => [key.trim(), permission]).filter(([key]) => key.length > 0);
|
|
967
|
-
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
968
|
-
}
|
|
969
|
-
function removeUndefinedJsonFields(value) {
|
|
970
|
-
return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
|
|
971
|
-
}
|
|
972
|
-
function stableStringifyJson(value) {
|
|
973
|
-
if (Array.isArray(value)) return `[${value.map((item) => stableStringifyJson(item)).join(",")}]`;
|
|
974
|
-
if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringifyJson(item)}`).join(",")}}`;
|
|
975
|
-
return JSON.stringify(value);
|
|
976
|
-
}
|
|
977
|
-
function withMcpElicitationsApprovalPolicy(policy) {
|
|
978
|
-
if (typeof policy !== "string") return { granular: {
|
|
979
|
-
...policy.granular,
|
|
980
|
-
mcp_elicitations: true
|
|
981
|
-
} };
|
|
982
|
-
if (policy === "never") return { granular: {
|
|
983
|
-
mcp_elicitations: true,
|
|
984
|
-
rules: false,
|
|
985
|
-
sandbox_approval: false,
|
|
986
|
-
request_permissions: false,
|
|
987
|
-
skill_approval: false
|
|
988
|
-
} };
|
|
989
|
-
return { granular: {
|
|
990
|
-
mcp_elicitations: true,
|
|
991
|
-
rules: true,
|
|
992
|
-
sandbox_approval: true,
|
|
993
|
-
request_permissions: true,
|
|
994
|
-
skill_approval: true
|
|
995
|
-
} };
|
|
996
|
-
}
|
|
997
|
-
function resolveTransport(value) {
|
|
998
|
-
return value === "websocket" || value === "unix" ? value : "stdio";
|
|
999
|
-
}
|
|
1000
|
-
function normalizeRemoteWorkspaceRoot(value) {
|
|
1001
|
-
return readNonEmptyString(value);
|
|
1002
|
-
}
|
|
1003
|
-
function inferCodexAppServerConnectionClass(params) {
|
|
1004
|
-
if (params.transport !== "websocket") return "local-loopback";
|
|
1005
|
-
return params.url && isLoopbackWebSocketUrl(params.url) ? "local-loopback" : "remote";
|
|
1006
|
-
}
|
|
1007
|
-
function assertCodexAppServerConnectionClassConfig(params) {
|
|
1008
|
-
if (params.connectionClass === "remote" && !hasIdentityBearingWebSocketAuth({
|
|
1009
|
-
authToken: params.authToken,
|
|
1010
|
-
headers: params.headers
|
|
1011
|
-
})) throw new Error("remote Codex app-server WebSocket URLs require appServer.authToken or an Authorization header");
|
|
1012
|
-
}
|
|
1013
|
-
/** Applies the canonical remote-auth boundary to any Codex AppServer transport. */
|
|
1014
|
-
function assertCodexAppServerConnectionSecurity(params) {
|
|
1015
|
-
assertCodexAppServerConnectionClassConfig({
|
|
1016
|
-
connectionClass: inferCodexAppServerConnectionClass(params),
|
|
1017
|
-
authToken: params.authToken,
|
|
1018
|
-
headers: params.headers
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
function isLoopbackWebSocketUrl(value) {
|
|
1022
|
-
let parsed;
|
|
1023
|
-
try {
|
|
1024
|
-
parsed = new URL(value);
|
|
1025
|
-
} catch {
|
|
1026
|
-
return false;
|
|
1027
|
-
}
|
|
1028
|
-
if (parsed.protocol !== "ws:" && parsed.protocol !== "wss:") return false;
|
|
1029
|
-
return isLoopbackHost(parsed.hostname);
|
|
1030
|
-
}
|
|
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)));
|
|
1034
|
-
}
|
|
1035
|
-
function resolvePolicyMode(value) {
|
|
1036
|
-
return value === "guardian" || value === "yolo" ? value : void 0;
|
|
1037
|
-
}
|
|
1038
|
-
function resolveDefaultCodexAppServerPolicy(params) {
|
|
1039
|
-
if (params.transport !== "stdio") return {
|
|
1040
|
-
mode: "yolo",
|
|
1041
|
-
dangerFullAccessAllowed: true
|
|
1042
|
-
};
|
|
1043
|
-
const content = readCodexRequirementsToml(params);
|
|
1044
|
-
if (content === void 0) {
|
|
1045
|
-
if (!params.forceGuardian) return {
|
|
1046
|
-
mode: "yolo",
|
|
1047
|
-
dangerFullAccessAllowed: true
|
|
1048
|
-
};
|
|
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)
|
|
1055
|
-
};
|
|
1056
|
-
}
|
|
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
|
-
};
|
|
1074
|
-
}
|
|
1075
|
-
//#endregion
|
|
1076
|
-
//#region extensions/codex/src/app-server/config-runtime.ts
|
|
1077
|
-
/**
|
|
1078
|
-
* Sole owner of the app-server home-scope decision. Ordinary harness connections
|
|
1079
|
-
* default to the isolated agent home; the supervision connection owns the operator's
|
|
1080
|
-
* native Codex home on local transports. Auth handoffs must read the scope from here
|
|
1081
|
-
* (or from resolved start options) because a prepared login on a native home rewrites
|
|
1082
|
-
* the account Codex CLI and Desktop share.
|
|
1083
|
-
*/
|
|
1084
|
-
function resolveCodexAppServerHomeScope(params) {
|
|
1085
|
-
const configured = params.appServer?.homeScope;
|
|
1086
|
-
if (configured) return configured;
|
|
1087
|
-
return params.connectionScope === "supervision" && resolveTransport(params.appServer?.transport) !== "websocket" ? "user" : "agent";
|
|
1088
|
-
}
|
|
1089
|
-
function resolveCodexAppServerRuntimeOptions(params = {}) {
|
|
1090
|
-
const env = params.env ?? process.env;
|
|
1091
|
-
const config = readCodexPluginConfig(params.pluginConfig).appServer ?? {};
|
|
1092
|
-
const transport = resolveTransport(config.transport);
|
|
1093
|
-
const homeScope = resolveCodexAppServerHomeScope({ appServer: config });
|
|
1094
|
-
const configCommand = readNonEmptyString(config.command);
|
|
1095
|
-
const envCommand = readNonEmptyString(env.OPENCLAW_CODEX_APP_SERVER_BIN);
|
|
1096
|
-
const command = configCommand ?? envCommand ?? "codex";
|
|
1097
|
-
const commandSource = configCommand ? "config" : envCommand ? "env" : "managed";
|
|
1098
|
-
if (commandSource === "config" || commandSource === "env") assertCodexAppServerCommandHasNoInlineArgs({
|
|
1099
|
-
command,
|
|
1100
|
-
source: commandSource
|
|
1101
|
-
});
|
|
1102
|
-
const args = resolveArgs(config.args, env.OPENCLAW_CODEX_APP_SERVER_ARGS);
|
|
1103
|
-
const headers = normalizeHeaders(config.headers);
|
|
1104
|
-
const clearEnv = normalizeStringList(config.clearEnv);
|
|
1105
|
-
const authToken = normalizeCodexAppServerSecretInput({
|
|
1106
|
-
value: config.authToken,
|
|
1107
|
-
path: "plugins.entries.codex.config.appServer.authToken"
|
|
1108
|
-
});
|
|
1109
|
-
const url = readNonEmptyString(config.url) ?? (transport === "unix" ? "unix://" : void 0);
|
|
1110
|
-
const connectionClass = inferCodexAppServerConnectionClass({
|
|
1111
|
-
transport,
|
|
1112
|
-
url
|
|
1113
|
-
});
|
|
1114
|
-
const remoteAppsSubstrate = "preconfigured";
|
|
1115
|
-
const remoteWorkspaceRoot = normalizeRemoteWorkspaceRoot(config.remoteWorkspaceRoot);
|
|
1116
|
-
const execMode = resolveEffectiveOpenClawExecModeForCodexAppServer({
|
|
1117
|
-
execMode: params.execMode,
|
|
1118
|
-
execPolicy: params.execPolicy
|
|
1119
|
-
});
|
|
1120
|
-
assertCodexAppServerAllowedForOpenClawExecMode(execMode);
|
|
1121
|
-
const explicitPolicyMode = resolvePolicyMode(config.mode) ?? resolvePolicyMode(env.OPENCLAW_CODEX_APP_SERVER_MODE);
|
|
1122
|
-
const configuredSandbox = resolveSandbox(config.sandbox) ?? resolveSandbox(env.OPENCLAW_CODEX_APP_SERVER_SANDBOX);
|
|
1123
|
-
const explicitApprovalsReviewer = resolveApprovalsReviewer(config.approvalsReviewer);
|
|
1124
|
-
const normalizedPolicyMode = resolveCodexPolicyModeForOpenClawExecMode(execMode);
|
|
1125
|
-
const ignoreLegacyYoloPolicyMode = normalizedPolicyMode === "guardian" && explicitPolicyMode === "yolo";
|
|
1126
|
-
const canUseModelBackedReviewer = canUseCodexModelBackedApprovalsReviewerForModel({
|
|
1127
|
-
modelProvider: params.modelProvider,
|
|
1128
|
-
model: params.model,
|
|
1129
|
-
config: params.config,
|
|
1130
|
-
env,
|
|
1131
|
-
agentDir: params.agentDir,
|
|
1132
|
-
codexConfigToml: params.codexConfigToml,
|
|
1133
|
-
homeScope
|
|
1134
|
-
});
|
|
1135
|
-
const forceUserReviewer = !canUseModelBackedReviewer && (explicitApprovalsReviewer === "auto_review" || explicitApprovalsReviewer === "guardian_subagent" || explicitPolicyMode === "guardian" && explicitApprovalsReviewer !== "user") || execMode !== void 0 && execMode !== "full" && (execMode !== "auto" || !canUseModelBackedReviewer);
|
|
1136
|
-
const forceGuardianReviewer = execMode === "auto" && canUseModelBackedReviewer;
|
|
1137
|
-
const execModeRequiringPromptingApprovals = execMode === "auto" || execMode === "ask" ? execMode : forceUserReviewer ? "ask" : void 0;
|
|
1138
|
-
const forceDangerFullAccessSandbox = params.execPolicy?.touched === true && params.execPolicy.security === "full" && params.execPolicy.ask === "always";
|
|
1139
|
-
const forceRuntimePolicy = forceUserReviewer || forceGuardianReviewer || forceDangerFullAccessSandbox;
|
|
1140
|
-
const defaultPolicy = explicitPolicyMode && !forceRuntimePolicy && !ignoreLegacyYoloPolicyMode ? void 0 : resolveDefaultCodexAppServerPolicy({
|
|
1141
|
-
transport,
|
|
1142
|
-
env,
|
|
1143
|
-
forceGuardian: normalizedPolicyMode === "guardian",
|
|
1144
|
-
forceUserReviewer: forceUserReviewer || !canUseModelBackedReviewer,
|
|
1145
|
-
execModeRequiringPromptingApprovals,
|
|
1146
|
-
requirementsToml: params.requirementsToml,
|
|
1147
|
-
requirementsPath: params.requirementsPath,
|
|
1148
|
-
readRequirementsFile: params.readRequirementsFile,
|
|
1149
|
-
platform: params.platform,
|
|
1150
|
-
hostName: params.hostName,
|
|
1151
|
-
execModeRequiringUserReviewer: forceUserReviewer ? execMode : void 0
|
|
1152
|
-
});
|
|
1153
|
-
const preserveExplicitAutoSandbox = forceGuardianReviewer && configuredSandbox === "read-only";
|
|
1154
|
-
const forcedPolicy = forceRuntimePolicy ? {
|
|
1155
|
-
approvalPolicy: defaultPolicy?.approvalPolicy ?? "on-request",
|
|
1156
|
-
sandbox: preserveExplicitAutoSandbox ? void 0 : forceDangerFullAccessSandbox ? selectForcedDangerFullAccessSandbox({
|
|
1157
|
-
configuredSandbox,
|
|
1158
|
-
defaultPolicy,
|
|
1159
|
-
openClawSandboxActive: Boolean(params.openClawSandboxActive)
|
|
1160
|
-
}) : selectForcedPromptingSandbox({
|
|
1161
|
-
configuredSandbox,
|
|
1162
|
-
defaultSandbox: defaultPolicy?.sandbox
|
|
1163
|
-
}),
|
|
1164
|
-
approvalsReviewer: defaultPolicy?.approvalsReviewer ?? (forceUserReviewer ? "user" : "auto_review")
|
|
1165
|
-
} : void 0;
|
|
1166
|
-
const policyMode = ignoreLegacyYoloPolicyMode ? normalizedPolicyMode : explicitPolicyMode ?? normalizedPolicyMode ?? defaultPolicy?.mode ?? "yolo";
|
|
1167
|
-
const serviceTier = normalizeCodexServiceTier(config.serviceTier);
|
|
1168
|
-
const resolvedSandbox = forcedPolicy?.sandbox ?? configuredSandbox ?? defaultPolicy?.sandbox ?? (policyMode === "guardian" ? "workspace-write" : "danger-full-access");
|
|
1169
|
-
if (transport === "websocket" && !url) throw new Error("plugins.entries.codex.config.appServer.url is required when appServer.transport is websocket");
|
|
1170
|
-
if (transport === "websocket" && homeScope === "user") throw new Error("plugins.entries.codex.config.appServer.homeScope=user requires appServer.transport=stdio or unix");
|
|
1171
|
-
if (transport === "unix" && homeScope !== "user") throw new Error("plugins.entries.codex.config.appServer.transport=unix requires appServer.homeScope=user");
|
|
1172
|
-
if (transport === "unix" && !url?.startsWith("unix://")) throw new Error("plugins.entries.codex.config.appServer.url must use unix:// when appServer.transport is unix");
|
|
1173
|
-
assertCodexAppServerConnectionSecurity({
|
|
1174
|
-
transport,
|
|
1175
|
-
url,
|
|
1176
|
-
authToken,
|
|
1177
|
-
headers
|
|
1178
|
-
});
|
|
1179
|
-
const configApprovalPolicy = resolveApprovalPolicy(config.approvalPolicy);
|
|
1180
|
-
const envApprovalPolicy = resolveApprovalPolicy(env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY);
|
|
1181
|
-
const approvalPolicy = configApprovalPolicy ?? envApprovalPolicy ?? defaultPolicy?.approvalPolicy ?? (policyMode === "guardian" ? "on-request" : "never");
|
|
1182
|
-
const approvalPolicySource = configApprovalPolicy ? "config" : envApprovalPolicy ? "env" : defaultPolicy?.approvalPolicy ? "requirements" : "implicit";
|
|
1183
|
-
const computerUseConfig = resolveCodexComputerUseConfig({
|
|
1184
|
-
pluginConfig: params.pluginConfig,
|
|
1185
|
-
env
|
|
1186
|
-
});
|
|
1187
|
-
const managedCommandOrder = params.managedCommandOrder ?? (homeScope === "user" || computerUseConfig.enabled ? "desktop-first" : "package-first");
|
|
1188
|
-
const includeManagedCommandOrder = commandSource === "managed" && (managedCommandOrder === "desktop-first" || params.managedCommandOrder === "package-first");
|
|
1189
|
-
const managedComputerUsePluginNames = [.../* @__PURE__ */ new Set([DEFAULT_CODEX_COMPUTER_USE_PLUGIN_NAME, computerUseConfig.pluginName])];
|
|
1190
|
-
return {
|
|
1191
|
-
start: {
|
|
1192
|
-
transport,
|
|
1193
|
-
homeScope,
|
|
1194
|
-
command,
|
|
1195
|
-
commandSource,
|
|
1196
|
-
...includeManagedCommandOrder ? { managedCommandOrder } : {},
|
|
1197
|
-
...commandSource === "managed" ? { managedComputerUsePluginNames } : {},
|
|
1198
|
-
args: args.length > 0 ? args : [
|
|
1199
|
-
"app-server",
|
|
1200
|
-
"--listen",
|
|
1201
|
-
"stdio://"
|
|
1202
|
-
],
|
|
1203
|
-
...url ? { url } : {},
|
|
1204
|
-
...authToken ? { authToken } : {},
|
|
1205
|
-
headers,
|
|
1206
|
-
...transport === "stdio" && clearEnv.length > 0 ? { clearEnv } : {}
|
|
1207
|
-
},
|
|
1208
|
-
connectionClass,
|
|
1209
|
-
remoteAppsSubstrate,
|
|
1210
|
-
...remoteWorkspaceRoot ? { remoteWorkspaceRoot } : {},
|
|
1211
|
-
codeModeOnly: config.codeModeOnly === true,
|
|
1212
|
-
loopDetectionPreToolUseRelay: config.loopDetectionPreToolUseRelay !== false,
|
|
1213
|
-
requestTimeoutMs: normalizePositiveNumber(config.requestTimeoutMs, 6e4),
|
|
1214
|
-
turnCompletionIdleTimeoutMs: normalizePositiveNumber(config.turnCompletionIdleTimeoutMs, 6e4),
|
|
1215
|
-
turnAssistantCompletionIdleTimeoutMs: normalizePositiveNumber(config.turnAssistantCompletionIdleTimeoutMs, 1e4),
|
|
1216
|
-
...config.postToolRawAssistantCompletionIdleTimeoutMs !== void 0 ? { postToolRawAssistantCompletionIdleTimeoutMs: normalizePositiveNumber(config.postToolRawAssistantCompletionIdleTimeoutMs, 6e4) } : {},
|
|
1217
|
-
approvalPolicy: forcedPolicy?.approvalPolicy ?? approvalPolicy,
|
|
1218
|
-
approvalPolicySource,
|
|
1219
|
-
sandbox: resolvedSandbox,
|
|
1220
|
-
approvalsReviewer: forcedPolicy?.approvalsReviewer ?? explicitApprovalsReviewer ?? defaultPolicy?.approvalsReviewer ?? (policyMode === "guardian" ? "auto_review" : "user"),
|
|
1221
|
-
...serviceTier ? { serviceTier } : {},
|
|
1222
|
-
...resolveCodexAppServerNetworkProxy(config.networkProxy, resolvedSandbox)
|
|
1223
|
-
};
|
|
1224
|
-
}
|
|
1225
|
-
/**
|
|
1226
|
-
* Rechecks Codex-owned plugin state at the final spawn boundary, where the
|
|
1227
|
-
* effective agent home is known, so Computer Use keeps the desktop app's TCC ownership.
|
|
1228
|
-
*/
|
|
1229
|
-
function resolveCodexAppServerStartOptionsForAgent(params) {
|
|
1230
|
-
const startOptions = params.startOptions;
|
|
1231
|
-
if (startOptions.transport !== "stdio" || startOptions.commandSource !== "managed" || startOptions.managedCommandOrder !== void 0) return startOptions;
|
|
1232
|
-
if (startOptions.homeScope === "user") return {
|
|
1233
|
-
...startOptions,
|
|
1234
|
-
managedCommandOrder: "desktop-first"
|
|
1235
|
-
};
|
|
1236
|
-
return codexConfigEnablesNativeComputerUse({
|
|
1237
|
-
agentDir: params.agentDir,
|
|
1238
|
-
codexConfigToml: params.codexConfigToml,
|
|
1239
|
-
env: params.env,
|
|
1240
|
-
homeScope: "agent",
|
|
1241
|
-
pluginNames: startOptions.managedComputerUsePluginNames ?? ["computer-use"]
|
|
1242
|
-
}) ? {
|
|
1243
|
-
...startOptions,
|
|
1244
|
-
managedCommandOrder: "desktop-first"
|
|
1245
|
-
} : startOptions;
|
|
1246
|
-
}
|
|
1247
|
-
function resolveCodexComputerUseConfig(params = {}) {
|
|
1248
|
-
const env = params.env ?? process.env;
|
|
1249
|
-
const config = readCodexPluginConfig(params.pluginConfig).computerUse ?? {};
|
|
1250
|
-
const marketplaceSource = readNonEmptyString(params.overrides?.marketplaceSource) ?? readNonEmptyString(config.marketplaceSource) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_SOURCE);
|
|
1251
|
-
const marketplacePath = readNonEmptyString(params.overrides?.marketplacePath) ?? readNonEmptyString(config.marketplacePath) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_PATH);
|
|
1252
|
-
const marketplaceName = readNonEmptyString(params.overrides?.marketplaceName) ?? readNonEmptyString(config.marketplaceName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MARKETPLACE_NAME);
|
|
1253
|
-
const configuredPluginName = readNonEmptyString(params.overrides?.pluginName) ?? readNonEmptyString(config.pluginName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_NAME);
|
|
1254
|
-
const configuredMcpServerName = readNonEmptyString(params.overrides?.mcpServerName) ?? readNonEmptyString(config.mcpServerName) ?? readNonEmptyString(env.OPENCLAW_CODEX_COMPUTER_USE_MCP_SERVER_NAME);
|
|
1255
|
-
const autoInstall = params.overrides?.autoInstall ?? config.autoInstall ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_AUTO_INSTALL) ?? false;
|
|
1256
|
-
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);
|
|
1257
|
-
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);
|
|
1258
|
-
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);
|
|
1259
|
-
const healthCheckIntervalMinutes = normalizeComputerUseHealthCheckIntervalMinutes(params.overrides?.healthCheckIntervalMinutes ?? config.healthCheckIntervalMinutes ?? readNumberEnv(env.OPENCLAW_CODEX_COMPUTER_USE_HEALTH_CHECK_INTERVAL_MINUTES));
|
|
1260
|
-
const healthCheckEnabled = params.overrides?.healthCheckEnabled ?? config.healthCheckEnabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_HEALTH_CHECK_ENABLED) ?? false;
|
|
1261
|
-
const pluginCacheMode = normalizeComputerUsePluginCacheMode(params.overrides?.pluginCacheMode) ?? normalizeComputerUsePluginCacheMode(config.pluginCacheMode) ?? normalizeComputerUsePluginCacheMode(env.OPENCLAW_CODEX_COMPUTER_USE_PLUGIN_CACHE_MODE) ?? "independent";
|
|
1262
|
-
const strictReadiness = params.overrides?.strictReadiness ?? config.strictReadiness ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_STRICT_READINESS) ?? false;
|
|
1263
|
-
const autoRepair = params.overrides?.autoRepair ?? config.autoRepair ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE_AUTO_REPAIR) ?? false;
|
|
1264
|
-
return {
|
|
1265
|
-
enabled: params.overrides?.enabled ?? config.enabled ?? readBooleanEnv(env.OPENCLAW_CODEX_COMPUTER_USE) ?? Boolean(autoInstall || marketplaceSource || marketplacePath || marketplaceName || configuredPluginName || configuredMcpServerName),
|
|
1266
|
-
autoInstall,
|
|
1267
|
-
marketplaceDiscoveryTimeoutMs,
|
|
1268
|
-
liveTestTimeoutMs,
|
|
1269
|
-
toolCallTimeoutMs,
|
|
1270
|
-
healthCheckEnabled,
|
|
1271
|
-
healthCheckIntervalMinutes,
|
|
1272
|
-
pluginCacheMode,
|
|
1273
|
-
strictReadiness,
|
|
1274
|
-
autoRepair,
|
|
1275
|
-
pluginName: configuredPluginName ?? "computer-use",
|
|
1276
|
-
mcpServerName: configuredMcpServerName ?? "computer-use",
|
|
1277
|
-
...marketplaceSource ? { marketplaceSource } : {},
|
|
1278
|
-
...marketplacePath ? { marketplacePath } : {},
|
|
1279
|
-
...marketplaceName ? { marketplaceName } : {}
|
|
1280
|
-
};
|
|
1281
|
-
}
|
|
1282
|
-
function normalizeComputerUseHealthCheckIntervalMinutes(value) {
|
|
1283
|
-
return value === 30 || value === 60 || value === 120 || value === 240 ? value : 60;
|
|
1284
|
-
}
|
|
1285
|
-
function normalizeComputerUsePluginCacheMode(value) {
|
|
1286
|
-
return value === "shared" || value === "independent" ? value : null;
|
|
1287
|
-
}
|
|
1288
|
-
function codexAppServerStartOptionsKey(options, params = {}) {
|
|
1289
|
-
return JSON.stringify({
|
|
1290
|
-
transport: options.transport,
|
|
1291
|
-
command: options.command,
|
|
1292
|
-
commandSource: options.commandSource ?? null,
|
|
1293
|
-
managedCommandOrder: options.managedCommandOrder ?? "package-first",
|
|
1294
|
-
managedComputerUsePluginNames: [...options.managedComputerUsePluginNames ?? []].toSorted(),
|
|
1295
|
-
managedFallbackCommandPaths: [...options.managedFallbackCommandPaths ?? []],
|
|
1296
|
-
args: options.args,
|
|
1297
|
-
cwd: options.cwd ?? null,
|
|
1298
|
-
url: options.url ?? null,
|
|
1299
|
-
authToken: hashSecretForKey(options.authToken, "authToken"),
|
|
1300
|
-
headers: Object.entries(options.headers).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `header:${key}`)]),
|
|
1301
|
-
env: Object.entries(options.env ?? {}).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, hashSecretForKey(value, `env:${key}`)]),
|
|
1302
|
-
clearEnv: [...options.clearEnv ?? []].toSorted(),
|
|
1303
|
-
authProfileId: params.authProfileId ?? null,
|
|
1304
|
-
authBindingFingerprint: params.authBindingFingerprint ?? null,
|
|
1305
|
-
agentDir: params.agentDir ?? null,
|
|
1306
|
-
fallbackApiKeyCacheKey: params.fallbackApiKeyCacheKey ?? null
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
function codexSandboxPolicyForTurn(mode, cwd, nativeArgs = []) {
|
|
1310
|
-
if (mode === "danger-full-access") return { type: "dangerFullAccess" };
|
|
1311
|
-
if (mode === "read-only") return {
|
|
1312
|
-
type: "readOnly",
|
|
1313
|
-
networkAccess: false
|
|
1314
|
-
};
|
|
1315
|
-
let excludeTmpdirEnvVar = false;
|
|
1316
|
-
let excludeSlashTmp = false;
|
|
1317
|
-
for (let index = 0; index < nativeArgs.length; index += 1) {
|
|
1318
|
-
const arg = nativeArgs[index];
|
|
1319
|
-
const override = arg === "-c" || arg === "--config" ? nativeArgs[++index] : arg?.startsWith("--config=") ? arg.slice(9) : void 0;
|
|
1320
|
-
if (!override) continue;
|
|
1321
|
-
const separator = override.indexOf("=");
|
|
1322
|
-
if (separator < 0) continue;
|
|
1323
|
-
const key = override.slice(0, separator).trim();
|
|
1324
|
-
const value = override.slice(separator + 1).trim();
|
|
1325
|
-
if (value !== "true" && value !== "false") continue;
|
|
1326
|
-
if (key === "sandbox_workspace_write.exclude_tmpdir_env_var") excludeTmpdirEnvVar = value === "true";
|
|
1327
|
-
else if (key === "sandbox_workspace_write.exclude_slash_tmp") excludeSlashTmp = value === "true";
|
|
1328
|
-
}
|
|
1329
|
-
return {
|
|
1330
|
-
type: "workspaceWrite",
|
|
1331
|
-
writableRoots: [cwd],
|
|
1332
|
-
networkAccess: false,
|
|
1333
|
-
excludeTmpdirEnvVar,
|
|
1334
|
-
excludeSlashTmp
|
|
1335
|
-
};
|
|
1336
|
-
}
|
|
1337
|
-
/** Resolves the passive supervision control connection without changing harness defaults. */
|
|
1338
|
-
function resolveCodexSupervisionAppServerRuntimeOptions(params = {}) {
|
|
1339
|
-
const pluginConfig = readCodexPluginConfig(params.pluginConfig);
|
|
1340
|
-
const appServer = pluginConfig.appServer ?? {};
|
|
1341
|
-
const homeScope = resolveCodexAppServerHomeScope({
|
|
1342
|
-
appServer,
|
|
1343
|
-
connectionScope: "supervision"
|
|
1344
|
-
});
|
|
1345
|
-
return resolveCodexAppServerRuntimeOptions({
|
|
1346
|
-
...params,
|
|
1347
|
-
pluginConfig: {
|
|
1348
|
-
...pluginConfig,
|
|
1349
|
-
appServer: {
|
|
1350
|
-
...appServer,
|
|
1351
|
-
homeScope
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
});
|
|
1355
|
-
}
|
|
1356
|
-
//#endregion
|
|
1357
|
-
//#region extensions/codex/src/app-server/session-binding.ts
|
|
1358
|
-
/** SQLite-backed Codex app-server thread bindings. */
|
|
1359
|
-
var session_binding_exports = /* @__PURE__ */ __exportAll({
|
|
1360
|
-
CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS: () => CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS,
|
|
1361
|
-
CODEX_APP_SERVER_BINDING_MAX_ENTRIES: () => CODEX_APP_SERVER_BINDING_MAX_ENTRIES,
|
|
1362
|
-
CODEX_APP_SERVER_BINDING_NAMESPACE: () => CODEX_APP_SERVER_BINDING_NAMESPACE,
|
|
1363
|
-
CodexSupervisionBindingReplacementError: () => CodexSupervisionBindingReplacementError,
|
|
1364
|
-
assertCodexBindingMayBeReplaced: () => assertCodexBindingMayBeReplaced,
|
|
1365
|
-
bindingStoreKey: () => bindingStoreKey,
|
|
1366
|
-
createCodexAppServerBindingStore: () => createCodexAppServerBindingStore,
|
|
1367
|
-
createCodexSessionGenerationSupersededError: () => createCodexSessionGenerationSupersededError,
|
|
1368
|
-
createStoredCodexAppServerBinding: () => createStoredCodexAppServerBinding,
|
|
1369
|
-
hashCodexAppServerBindingFingerprint: () => hashCodexAppServerBindingFingerprint,
|
|
1370
|
-
isCodexAppServerNativeAuthProfile: () => isCodexAppServerNativeAuthProfile,
|
|
1371
|
-
normalizeCodexAppServerBindingModelProvider: () => normalizeCodexAppServerBindingModelProvider,
|
|
1372
|
-
normalizeStoredCodexAppServerBindingFingerprints: () => normalizeStoredCodexAppServerBindingFingerprints,
|
|
1373
|
-
readCodexAppServerThreadBinding: () => readCodexAppServerThreadBinding,
|
|
1374
|
-
readStoredCodexAppServerBinding: () => readStoredCodexAppServerBinding,
|
|
1375
|
-
reclaimCurrentCodexSessionGeneration: () => reclaimCurrentCodexSessionGeneration,
|
|
1376
|
-
resolveCodexAppServerBindingModelProvider: () => resolveCodexAppServerBindingModelProvider,
|
|
1377
|
-
resolveCodexRunSessionBindingAuthority: () => resolveCodexRunSessionBindingAuthority,
|
|
1378
|
-
scopeCodexRunBindingStore: () => scopeCodexRunBindingStore,
|
|
1379
|
-
sessionBindingIdentity: () => sessionBindingIdentity
|
|
1380
|
-
});
|
|
1381
|
-
const CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER = "openai";
|
|
1382
|
-
const PUBLIC_OPENAI_MODEL_PROVIDER = "openai";
|
|
1383
|
-
const BINDING_LEASE_RETRY_INTERVAL_MS = 1e3;
|
|
1384
|
-
const BOUNDED_BINDING_FINGERPRINT_PATTERN = /^sha256:[a-f0-9]{64}$/i;
|
|
1385
|
-
const CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS = 6e4;
|
|
1386
|
-
const BINDING_LEASE_STALE_MS = 65e3;
|
|
1387
|
-
const BINDING_LEASE_WAIT_MS = 7e4;
|
|
1388
|
-
const BINDING_LEASE_RENEW_INTERVAL_MS = Math.floor(BINDING_LEASE_STALE_MS / 3);
|
|
1389
|
-
const PHYSICAL_SESSION_RETIRE_TTL_MS = BINDING_LEASE_WAIT_MS;
|
|
1390
|
-
/** Resolves the same agent scope OpenClaw uses for transcript/session ownership. */
|
|
1391
|
-
function sessionBindingIdentity(params) {
|
|
1392
|
-
const { sessionAgentId } = resolveSessionAgentIds$1(params);
|
|
1393
|
-
const sessionKey = params.sessionKey?.trim();
|
|
1394
|
-
return {
|
|
1395
|
-
kind: "session",
|
|
1396
|
-
agentId: sessionAgentId,
|
|
1397
|
-
sessionId: params.sessionId,
|
|
1398
|
-
...sessionKey ? { sessionKey } : {}
|
|
1399
|
-
};
|
|
1400
|
-
}
|
|
1401
|
-
/** Decides whether a run may share the durable stable-key binding owner. */
|
|
1402
|
-
function resolveCodexRunSessionBindingAuthority(params) {
|
|
1403
|
-
const sessionKey = params.identity.sessionKey?.trim();
|
|
1404
|
-
if (!sessionKey) return "ephemeral";
|
|
1405
|
-
try {
|
|
1406
|
-
const storePath = params.storePath?.trim() || resolveStorePath(params.config?.session?.store, { agentId: params.identity.agentId });
|
|
1407
|
-
const entry = getSessionEntry({
|
|
1408
|
-
agentId: params.identity.agentId,
|
|
1409
|
-
hydrateSkillPromptRefs: false,
|
|
1410
|
-
readConsistency: "latest",
|
|
1411
|
-
sessionKey,
|
|
1412
|
-
storePath
|
|
1413
|
-
});
|
|
1414
|
-
if (!entry) return "ephemeral";
|
|
1415
|
-
return entry.sessionId === params.identity.sessionId ? "current" : "superseded";
|
|
1416
|
-
} catch {
|
|
1417
|
-
return "superseded";
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
/** Builds the terminal coordination error used when a newer OpenClaw session owns the binding. */
|
|
1421
|
-
function createCodexSessionGenerationSupersededError(sessionId) {
|
|
1422
|
-
return new AgentHarnessSessionSupersededError(`Codex session generation is no longer current: ${sessionId}`);
|
|
1423
|
-
}
|
|
1424
|
-
const optionalStringSchema = z.string().optional().catch(void 0);
|
|
1425
|
-
const optionalBooleanSchema = z.boolean().optional().catch(void 0);
|
|
1426
|
-
const optionalNonBlankStringSchema = z.string().refine((value) => Boolean(value.trim())).optional().catch(void 0);
|
|
1427
|
-
const optionalTimestampSchema = z.string().refine((value) => Number.isFinite(Date.parse(value))).optional().catch(void 0);
|
|
1428
|
-
const pendingSupervisionBranchSchema = z.object({
|
|
1429
|
-
sourceThreadId: z.string().trim().min(1),
|
|
1430
|
-
connectionFingerprint: z.string().trim().min(1).optional(),
|
|
1431
|
-
lastTurnId: z.string().trim().min(1).optional(),
|
|
1432
|
-
cleanupThreadIds: z.array(z.string().trim().min(1)).max(2).optional()
|
|
1433
|
-
}).strict().superRefine((pending, context) => {
|
|
1434
|
-
const cleanupThreadIds = pending.cleanupThreadIds ?? [];
|
|
1435
|
-
if (new Set(cleanupThreadIds).size !== cleanupThreadIds.length) context.addIssue({
|
|
1436
|
-
code: "custom",
|
|
1437
|
-
message: "pending supervision cleanup thread ids must be unique"
|
|
1438
|
-
});
|
|
1439
|
-
if (cleanupThreadIds.includes(pending.sourceThreadId)) context.addIssue({
|
|
1440
|
-
code: "custom",
|
|
1441
|
-
message: "pending supervision cleanup cannot target its source"
|
|
1442
|
-
});
|
|
1443
|
-
});
|
|
1444
|
-
const contextEngineProjectionSchema = z.object({
|
|
1445
|
-
schemaVersion: z.literal(1),
|
|
1446
|
-
mode: z.literal("thread_bootstrap"),
|
|
1447
|
-
epoch: z.string().refine((value) => Boolean(value.trim())),
|
|
1448
|
-
fingerprint: optionalStringSchema
|
|
1449
|
-
}).strict();
|
|
1450
|
-
const contextEngineSchema = z.object({
|
|
1451
|
-
schemaVersion: z.literal(1),
|
|
1452
|
-
engineId: z.string(),
|
|
1453
|
-
policyFingerprint: z.string(),
|
|
1454
|
-
projection: contextEngineProjectionSchema.optional().catch(void 0)
|
|
1455
|
-
}).strict();
|
|
1456
|
-
const destructiveApprovalModeSchema = z.enum([
|
|
1457
|
-
"allow",
|
|
1458
|
-
"deny",
|
|
1459
|
-
"auto",
|
|
1460
|
-
"ask"
|
|
1461
|
-
]).optional().catch(void 0);
|
|
1462
|
-
const accountAppPolicyEntrySchema = z.object({
|
|
1463
|
-
source: z.literal("account"),
|
|
1464
|
-
appName: z.string(),
|
|
1465
|
-
allowDestructiveActions: z.boolean(),
|
|
1466
|
-
destructiveApprovalMode: destructiveApprovalModeSchema,
|
|
1467
|
-
mcpServerNames: z.array(z.string())
|
|
1468
|
-
}).strict();
|
|
1469
|
-
const pluginAppPolicyEntrySchema = z.object({
|
|
1470
|
-
source: z.literal("plugin").optional(),
|
|
1471
|
-
configKey: z.string(),
|
|
1472
|
-
marketplaceName: z.enum([CODEX_PLUGINS_MARKETPLACE_NAME, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME]),
|
|
1473
|
-
pluginName: z.string(),
|
|
1474
|
-
allowDestructiveActions: z.boolean(),
|
|
1475
|
-
destructiveApprovalMode: destructiveApprovalModeSchema,
|
|
1476
|
-
mcpServerNames: z.array(z.string())
|
|
1477
|
-
}).strict();
|
|
1478
|
-
const pluginAppPolicyContextSchema = z.object({
|
|
1479
|
-
fingerprint: z.string(),
|
|
1480
|
-
apps: z.record(z.string(), z.union([accountAppPolicyEntrySchema, pluginAppPolicyEntrySchema])),
|
|
1481
|
-
pluginAppIds: z.record(z.string(), z.array(z.string())).default({})
|
|
1482
|
-
}).strict();
|
|
1483
|
-
const threadBindingSchema = z.object({
|
|
1484
|
-
threadId: z.string().refine((value) => Boolean(value.trim())),
|
|
1485
|
-
clientId: optionalStringSchema,
|
|
1486
|
-
cwd: z.string(),
|
|
1487
|
-
rolloutPath: optionalNonBlankStringSchema,
|
|
1488
|
-
connectionScope: z.literal("supervision").optional(),
|
|
1489
|
-
supervisionSourceThreadId: z.string().trim().min(1).optional(),
|
|
1490
|
-
authProfileId: optionalStringSchema,
|
|
1491
|
-
model: optionalStringSchema,
|
|
1492
|
-
preserveNativeModel: z.literal(true).optional().catch(void 0),
|
|
1493
|
-
pendingSupervisionBranch: pendingSupervisionBranchSchema.optional(),
|
|
1494
|
-
modelProvider: z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0),
|
|
1495
|
-
approvalPolicy: z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
|
|
1496
|
-
"never",
|
|
1497
|
-
"on-request",
|
|
1498
|
-
"untrusted"
|
|
1499
|
-
]).optional()).catch(void 0),
|
|
1500
|
-
sandbox: z.enum([
|
|
1501
|
-
"read-only",
|
|
1502
|
-
"workspace-write",
|
|
1503
|
-
"danger-full-access"
|
|
1504
|
-
]).optional().catch(void 0),
|
|
1505
|
-
serviceTier: z.preprocess(normalizeCodexServiceTier, z.custom((value) => typeof value === "string").optional()).optional().catch(void 0),
|
|
1506
|
-
networkProxyProfileName: optionalStringSchema,
|
|
1507
|
-
networkProxyConfigFingerprint: optionalStringSchema,
|
|
1508
|
-
dynamicToolsFingerprint: optionalStringSchema,
|
|
1509
|
-
dynamicToolsContainDeferred: optionalBooleanSchema,
|
|
1510
|
-
webSearchThreadConfigFingerprint: optionalStringSchema,
|
|
1511
|
-
nativeSkillIsolationFingerprint: optionalStringSchema,
|
|
1512
|
-
userMcpServersFingerprint: optionalStringSchema,
|
|
1513
|
-
mcpServersFingerprint: optionalStringSchema,
|
|
1514
|
-
ringZeroConfigFingerprint: optionalStringSchema,
|
|
1515
|
-
ringZeroClientInstanceId: optionalStringSchema,
|
|
1516
|
-
nativeHookRelayGeneration: optionalNonBlankStringSchema,
|
|
1517
|
-
appServerRuntimeFingerprint: optionalStringSchema,
|
|
1518
|
-
pluginAppsFingerprint: optionalStringSchema,
|
|
1519
|
-
pluginAppsInputFingerprint: optionalStringSchema,
|
|
1520
|
-
pluginAppPolicyContext: pluginAppPolicyContextSchema.optional().catch(void 0),
|
|
1521
|
-
contextEngine: contextEngineSchema.optional().catch(void 0),
|
|
1522
|
-
environmentSelectionFingerprint: optionalStringSchema,
|
|
1523
|
-
conversationStartId: optionalStringSchema,
|
|
1524
|
-
conversationSourceTransferComplete: z.literal(true).optional().catch(void 0),
|
|
1525
|
-
historyCoveredThrough: optionalTimestampSchema
|
|
1526
|
-
}).superRefine((binding, context) => {
|
|
1527
|
-
if (binding.connectionScope === "supervision") {
|
|
1528
|
-
if (!binding.supervisionSourceThreadId) context.addIssue({
|
|
1529
|
-
code: "custom",
|
|
1530
|
-
message: "supervision connection ownership requires its native source thread id"
|
|
1531
|
-
});
|
|
1532
|
-
if (binding.preserveNativeModel !== true) context.addIssue({
|
|
1533
|
-
code: "custom",
|
|
1534
|
-
message: "supervision connection ownership requires native model ownership"
|
|
1535
|
-
});
|
|
1536
|
-
if (binding.conversationSourceTransferComplete !== true) context.addIssue({
|
|
1537
|
-
code: "custom",
|
|
1538
|
-
message: "supervision connection ownership requires a completed source transfer"
|
|
1539
|
-
});
|
|
1540
|
-
if (!binding.pendingSupervisionBranch && (!binding.model?.trim() || !binding.modelProvider)) context.addIssue({
|
|
1541
|
-
code: "custom",
|
|
1542
|
-
message: "materialized supervision bindings require a native model and provider"
|
|
1543
|
-
});
|
|
1544
|
-
}
|
|
1545
|
-
if (binding.supervisionSourceThreadId && binding.connectionScope !== "supervision") context.addIssue({
|
|
1546
|
-
code: "custom",
|
|
1547
|
-
message: "a supervision source thread id requires supervision connection ownership"
|
|
1548
|
-
});
|
|
1549
|
-
if (!binding.pendingSupervisionBranch) return;
|
|
1550
|
-
if (binding.threadId !== binding.pendingSupervisionBranch.sourceThreadId) context.addIssue({
|
|
1551
|
-
code: "custom",
|
|
1552
|
-
message: "pending supervision source must match the provisional thread binding"
|
|
1553
|
-
});
|
|
1554
|
-
if (binding.supervisionSourceThreadId !== binding.pendingSupervisionBranch.sourceThreadId) context.addIssue({
|
|
1555
|
-
code: "custom",
|
|
1556
|
-
message: "pending supervision source must match its durable source identity"
|
|
1557
|
-
});
|
|
1558
|
-
if (binding.preserveNativeModel !== true) context.addIssue({
|
|
1559
|
-
code: "custom",
|
|
1560
|
-
message: "pending supervision bindings must defer model selection to Codex App Server"
|
|
1561
|
-
});
|
|
1562
|
-
if (binding.connectionScope !== "supervision") context.addIssue({
|
|
1563
|
-
code: "custom",
|
|
1564
|
-
message: "pending supervision bindings require supervision connection ownership"
|
|
1565
|
-
});
|
|
1566
|
-
});
|
|
1567
|
-
var CodexSupervisionBindingReplacementError = class extends Error {
|
|
1568
|
-
constructor(threadId, operation) {
|
|
1569
|
-
super(`Refusing to replace supervised Codex thread ${threadId} while ${operation}; its native user-home connection and model ownership must be preserved`);
|
|
1570
|
-
this.name = "CodexSupervisionBindingReplacementError";
|
|
1571
|
-
}
|
|
1572
|
-
};
|
|
1573
|
-
function assertCodexBindingMayBeReplaced(binding, operation) {
|
|
1574
|
-
if (binding?.connectionScope === "supervision") throw new CodexSupervisionBindingReplacementError(binding.threadId, operation);
|
|
1575
|
-
}
|
|
1576
|
-
const bindingLeaseSchema = z.object({
|
|
1577
|
-
token: z.string().refine((value) => Boolean(value.trim())),
|
|
1578
|
-
expiresAt: z.number().finite()
|
|
1579
|
-
});
|
|
1580
|
-
const storedSessionIdSchema = z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0);
|
|
1581
|
-
const storedBindingSchema = z.discriminatedUnion("state", [z.object({
|
|
1582
|
-
version: z.literal(1),
|
|
1583
|
-
state: z.literal("active"),
|
|
1584
|
-
binding: threadBindingSchema,
|
|
1585
|
-
sessionId: storedSessionIdSchema,
|
|
1586
|
-
lease: bindingLeaseSchema.optional().catch(void 0)
|
|
1587
|
-
}), z.object({
|
|
1588
|
-
version: z.literal(1),
|
|
1589
|
-
state: z.literal("cleared"),
|
|
1590
|
-
sessionId: storedSessionIdSchema,
|
|
1591
|
-
lease: bindingLeaseSchema.optional().catch(void 0),
|
|
1592
|
-
retired: z.literal(true).optional().catch(void 0)
|
|
1593
|
-
})]);
|
|
1594
|
-
function hashCodexAppServerBindingFingerprint(canonical) {
|
|
1595
|
-
return `sha256:${createHash("sha256").update(canonical).digest("hex")}`;
|
|
1596
|
-
}
|
|
1597
|
-
function normalizeLegacyBindingFingerprint(value) {
|
|
1598
|
-
if (typeof value !== "string" || value === "" || value === "[]" || BOUNDED_BINDING_FINGERPRINT_PATTERN.test(value)) return value;
|
|
1599
|
-
return hashCodexAppServerBindingFingerprint(value);
|
|
1600
|
-
}
|
|
1601
|
-
function normalizeLegacyBindingFingerprints(record) {
|
|
1602
|
-
let normalized = record;
|
|
1603
|
-
for (const key of ["dynamicToolsFingerprint", "userMcpServersFingerprint"]) {
|
|
1604
|
-
const value = record[key];
|
|
1605
|
-
const next = normalizeLegacyBindingFingerprint(value);
|
|
1606
|
-
if (next === value) continue;
|
|
1607
|
-
if (normalized === record) normalized = { ...record };
|
|
1608
|
-
normalized[key] = next;
|
|
1609
|
-
}
|
|
1610
|
-
return normalized;
|
|
1611
|
-
}
|
|
1612
|
-
function normalizeStoredCodexAppServerBindingFingerprints(value) {
|
|
1613
|
-
const stored = readStoredCodexAppServerBinding(value);
|
|
1614
|
-
if (!stored || stored.state !== "active") return stored;
|
|
1615
|
-
const binding = normalizeLegacyBindingFingerprints(stored.binding);
|
|
1616
|
-
return binding === stored.binding ? stored : readStoredCodexAppServerBinding({
|
|
1617
|
-
...stored,
|
|
1618
|
-
binding
|
|
1619
|
-
});
|
|
1620
|
-
}
|
|
1621
|
-
/** Encodes a migrated sidecar binding as one canonical plugin-state row. */
|
|
1622
|
-
function createStoredCodexAppServerBinding(value, options = {}) {
|
|
1623
|
-
const rawRecord = asRecord(value);
|
|
1624
|
-
if (!rawRecord) return;
|
|
1625
|
-
const record = normalizeLegacyBindingFingerprints(rawRecord);
|
|
1626
|
-
if (record.schemaVersion !== 1 && record.schemaVersion !== 2) return;
|
|
1627
|
-
const pluginAppPolicyContext = readPluginAppPolicyContext(record.pluginAppPolicyContext, record.schemaVersion);
|
|
1628
|
-
const historyCoveredThrough = readTimestamp(record.historyCoveredThrough) ?? readTimestamp(record.updatedAt) ?? readTimestamp(record.createdAt) ?? readTimestamp(options.now) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1629
|
-
const authProfileId = typeof record.authProfileId === "string" ? record.authProfileId : void 0;
|
|
1630
|
-
const binding = readCodexAppServerThreadBinding({
|
|
1631
|
-
...record,
|
|
1632
|
-
modelProvider: normalizeCodexAppServerBindingModelProvider({
|
|
1633
|
-
...options.lookup,
|
|
1634
|
-
authProfileId,
|
|
1635
|
-
modelProvider: typeof record.modelProvider === "string" ? record.modelProvider : void 0
|
|
1636
|
-
}),
|
|
1637
|
-
cwd: typeof record.cwd === "string" ? record.cwd : "",
|
|
1638
|
-
pluginAppPolicyContext,
|
|
1639
|
-
historyCoveredThrough
|
|
1640
|
-
});
|
|
1641
|
-
return binding ? {
|
|
1642
|
-
version: 1,
|
|
1643
|
-
state: "active",
|
|
1644
|
-
binding: stripUndefinedBinding(binding)
|
|
1645
|
-
} : void 0;
|
|
1646
|
-
}
|
|
1647
|
-
function bindingLeaseLostError(key, cause) {
|
|
1648
|
-
return new Error(`Lost Codex binding lease: ${key}`, cause === void 0 ? void 0 : { cause });
|
|
1649
|
-
}
|
|
1650
|
-
/** Carries one prepared run identity through callers that rederive it from public params. */
|
|
1651
|
-
function scopeCodexRunBindingStore(params) {
|
|
1652
|
-
const mapSessionIdentity = (identity) => identity.agentId === params.logicalIdentity.agentId && identity.sessionId === params.logicalIdentity.sessionId && identity.sessionKey?.trim() === params.logicalIdentity.sessionKey?.trim() ? params.physicalIdentity : identity;
|
|
1653
|
-
const mapIdentity = (identity) => identity.kind === "session" ? mapSessionIdentity(identity) : identity;
|
|
1654
|
-
return {
|
|
1655
|
-
read: (identity) => params.bindingStore.read(mapIdentity(identity)),
|
|
1656
|
-
hasOtherThreadOwner: (threadId, identity) => params.bindingStore.hasOtherThreadOwner(threadId, identity ? mapIdentity(identity) : void 0),
|
|
1657
|
-
mutate: (identity, mutation) => params.bindingStore.mutate(mapIdentity(identity), mutation),
|
|
1658
|
-
prepareSessionGenerationReclaim: (identity) => params.bindingStore.prepareSessionGenerationReclaim(mapSessionIdentity(identity)),
|
|
1659
|
-
adoptSessionGeneration: (identity, expectedPreviousSessionId) => params.bindingStore.adoptSessionGeneration(mapSessionIdentity(identity), expectedPreviousSessionId),
|
|
1660
|
-
resetSessionGeneration: (identity) => params.bindingStore.resetSessionGeneration(mapSessionIdentity(identity)),
|
|
1661
|
-
retireSessionGeneration: (identity) => params.bindingStore.retireSessionGeneration(mapSessionIdentity(identity)),
|
|
1662
|
-
withThreadArchiveFence: (run) => params.bindingStore.withThreadArchiveFence(run),
|
|
1663
|
-
withLease: (identity, run) => params.bindingStore.withLease(mapIdentity(identity), run)
|
|
1664
|
-
};
|
|
1665
|
-
}
|
|
1666
|
-
/** Lets the authoritative OpenClaw session generation claim a stale stable binding row. */
|
|
1667
|
-
async function reclaimCurrentCodexSessionGeneration(params) {
|
|
1668
|
-
const sessionKey = params.identity.sessionKey?.trim();
|
|
1669
|
-
if (!sessionKey) return true;
|
|
1670
|
-
const plan = await params.bindingStore.prepareSessionGenerationReclaim(params.identity);
|
|
1671
|
-
if (plan.kind === "resolved") return plan.result;
|
|
1672
|
-
try {
|
|
1673
|
-
const storePath = params.storePath?.trim() || resolveStorePath(params.config?.session?.store, { agentId: params.identity.agentId });
|
|
1674
|
-
if (getSessionEntry({
|
|
1675
|
-
agentId: params.identity.agentId,
|
|
1676
|
-
hydrateSkillPromptRefs: false,
|
|
1677
|
-
readConsistency: "latest",
|
|
1678
|
-
sessionKey,
|
|
1679
|
-
storePath
|
|
1680
|
-
})?.sessionId !== params.identity.sessionId) return false;
|
|
1681
|
-
} catch {
|
|
1682
|
-
return false;
|
|
1683
|
-
}
|
|
1684
|
-
return await params.bindingStore.mutate(params.identity, {
|
|
1685
|
-
kind: "reclaim-generation",
|
|
1686
|
-
expectedPreviousSessionId: plan.expectedPreviousSessionId
|
|
1687
|
-
});
|
|
1688
|
-
}
|
|
1689
|
-
/** Creates the single binding facade owned by the Codex plugin runtime. */
|
|
1690
|
-
function createCodexAppServerBindingStore(state) {
|
|
1691
|
-
const update = state.update?.bind(state);
|
|
1692
|
-
if (!update) throw new Error("Codex app-server bindings require atomic plugin-state updates");
|
|
1693
|
-
const leaseContext = new AsyncLocalStorage();
|
|
1694
|
-
const archiveContext = new AsyncLocalStorage();
|
|
1695
|
-
let activeBindingMutations = 0;
|
|
1696
|
-
let pendingArchives = 0;
|
|
1697
|
-
let archiveTail = Promise.resolve();
|
|
1698
|
-
let bindingMutationsDrained = [];
|
|
1699
|
-
const waitForBindingMutations = async () => {
|
|
1700
|
-
if (activeBindingMutations === 0) return;
|
|
1701
|
-
await new Promise((resolve) => {
|
|
1702
|
-
bindingMutationsDrained.push(resolve);
|
|
1703
|
-
});
|
|
1704
|
-
};
|
|
1705
|
-
const runBindingMutation = async (run) => {
|
|
1706
|
-
if (archiveContext.getStore() === true) return await run();
|
|
1707
|
-
if (pendingArchives > 0) throw new Error("Codex binding mutation blocked while a native archive is in progress; retry");
|
|
1708
|
-
activeBindingMutations += 1;
|
|
1709
|
-
try {
|
|
1710
|
-
return await run();
|
|
1711
|
-
} finally {
|
|
1712
|
-
activeBindingMutations -= 1;
|
|
1713
|
-
if (activeBindingMutations === 0) {
|
|
1714
|
-
const drained = bindingMutationsDrained;
|
|
1715
|
-
bindingMutationsDrained = [];
|
|
1716
|
-
for (const resolve of drained) resolve();
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
};
|
|
1720
|
-
const renewLease = (key, owner) => {
|
|
1721
|
-
if (owner.failure) return;
|
|
1722
|
-
try {
|
|
1723
|
-
let renewed = false;
|
|
1724
|
-
const stored = update(key, (raw) => {
|
|
1725
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
1726
|
-
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1727
|
-
const lease = current?.lease;
|
|
1728
|
-
const now = Date.now();
|
|
1729
|
-
if (!lease || lease.token !== owner.token || lease.expiresAt <= now) return;
|
|
1730
|
-
renewed = true;
|
|
1731
|
-
return {
|
|
1732
|
-
...current,
|
|
1733
|
-
lease: {
|
|
1734
|
-
token: owner.token,
|
|
1735
|
-
expiresAt: now + BINDING_LEASE_STALE_MS
|
|
1736
|
-
}
|
|
1737
|
-
};
|
|
1738
|
-
});
|
|
1739
|
-
if (!renewed || !stored) owner.failure = bindingLeaseLostError(key);
|
|
1740
|
-
} catch (error) {
|
|
1741
|
-
owner.failure = bindingLeaseLostError(key, error);
|
|
1742
|
-
}
|
|
1743
|
-
};
|
|
1744
|
-
const transactKey = async (key, apply, ttlMs) => {
|
|
1745
|
-
const deadline = Date.now() + BINDING_LEASE_WAIT_MS;
|
|
1746
|
-
while (true) {
|
|
1747
|
-
let busy = false;
|
|
1748
|
-
let leaseLost = false;
|
|
1749
|
-
let result;
|
|
1750
|
-
const ownedLease = leaseContext.getStore()?.get(key);
|
|
1751
|
-
if (ownedLease?.failure) throw ownedLease.failure;
|
|
1752
|
-
const ownedToken = ownedLease?.token;
|
|
1753
|
-
update(key, (raw) => {
|
|
1754
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
1755
|
-
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1756
|
-
const activeLease = current?.lease;
|
|
1757
|
-
const now = Date.now();
|
|
1758
|
-
if (ownedToken && (!activeLease || activeLease.token !== ownedToken || activeLease.expiresAt <= now)) {
|
|
1759
|
-
leaseLost = true;
|
|
1760
|
-
return;
|
|
1761
|
-
}
|
|
1762
|
-
if (activeLease && activeLease.token !== ownedToken && activeLease.expiresAt > now) {
|
|
1763
|
-
busy = true;
|
|
1764
|
-
return;
|
|
1765
|
-
}
|
|
1766
|
-
const applied = apply(current, ownedToken);
|
|
1767
|
-
result = applied.result;
|
|
1768
|
-
return applied.next;
|
|
1769
|
-
}, ttlMs == null ? void 0 : { ttlMs });
|
|
1770
|
-
if (leaseLost) {
|
|
1771
|
-
const failure = bindingLeaseLostError(key);
|
|
1772
|
-
if (ownedLease) ownedLease.failure = failure;
|
|
1773
|
-
throw failure;
|
|
1774
|
-
}
|
|
1775
|
-
if (!busy) return result;
|
|
1776
|
-
if (Date.now() >= deadline) throw new Error(`Timed out waiting for Codex binding lease: ${key}`);
|
|
1777
|
-
await sleep(BINDING_LEASE_RETRY_INTERVAL_MS);
|
|
1778
|
-
}
|
|
1779
|
-
};
|
|
1780
|
-
return {
|
|
1781
|
-
async read(identity) {
|
|
1782
|
-
const key = bindingStoreKey(identity);
|
|
1783
|
-
const raw = state.lookup(key);
|
|
1784
|
-
const stored = readStoredCodexAppServerBinding(raw);
|
|
1785
|
-
if (raw !== void 0 && !stored) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1786
|
-
return stored?.state === "active" && ownsStoredSessionGeneration(identity, stored) ? stored.binding : void 0;
|
|
1787
|
-
},
|
|
1788
|
-
async hasOtherThreadOwner(threadId, currentIdentity) {
|
|
1789
|
-
const currentKey = currentIdentity ? bindingStoreKey(currentIdentity) : void 0;
|
|
1790
|
-
return state.entries().some(({ key, value }) => {
|
|
1791
|
-
const stored = readStoredCodexAppServerBinding(value);
|
|
1792
|
-
if (!stored) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1793
|
-
const isCurrentOwner = currentIdentity !== void 0 && key === currentKey && (currentIdentity.kind === "conversation" || stored.sessionId === currentIdentity.sessionId.trim());
|
|
1794
|
-
if (stored.state !== "active" || stored.binding.threadId !== threadId || isCurrentOwner) return false;
|
|
1795
|
-
return true;
|
|
1796
|
-
});
|
|
1797
|
-
},
|
|
1798
|
-
async prepareSessionGenerationReclaim(identity) {
|
|
1799
|
-
const key = bindingStoreKey(identity);
|
|
1800
|
-
const raw = state.lookup(key);
|
|
1801
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
1802
|
-
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
1803
|
-
if (!current) return {
|
|
1804
|
-
kind: "resolved",
|
|
1805
|
-
result: true
|
|
1806
|
-
};
|
|
1807
|
-
const currentSessionId = current.sessionId;
|
|
1808
|
-
if (!currentSessionId) return {
|
|
1809
|
-
kind: "resolved",
|
|
1810
|
-
result: current.state !== "cleared" || current.retired !== true
|
|
1811
|
-
};
|
|
1812
|
-
if (currentSessionId === identity.sessionId) return current.state === "cleared" && current.retired === true ? {
|
|
1813
|
-
kind: "verify",
|
|
1814
|
-
expectedPreviousSessionId: currentSessionId
|
|
1815
|
-
} : {
|
|
1816
|
-
kind: "resolved",
|
|
1817
|
-
result: true
|
|
1818
|
-
};
|
|
1819
|
-
return {
|
|
1820
|
-
kind: "verify",
|
|
1821
|
-
expectedPreviousSessionId: currentSessionId
|
|
1822
|
-
};
|
|
1823
|
-
},
|
|
1824
|
-
async mutate(identity, mutation) {
|
|
1825
|
-
return await runBindingMutation(async () => {
|
|
1826
|
-
const key = bindingStoreKey(identity);
|
|
1827
|
-
const retainLegacyClear = mutation.kind === "clear" && key.startsWith("conversation:legacy-");
|
|
1828
|
-
return await transactKey(key, (current, leaseToken) => {
|
|
1829
|
-
const ownsGeneration = ownsStoredSessionGeneration(identity, current);
|
|
1830
|
-
const ownedLease = current?.lease && current.lease.token === leaseToken ? { lease: current.lease } : {};
|
|
1831
|
-
if (mutation.kind === "reclaim-generation") {
|
|
1832
|
-
if (identity.kind !== "session" || !identity.sessionKey?.trim()) return { result: false };
|
|
1833
|
-
if (!current) return { result: true };
|
|
1834
|
-
if (ownsGeneration) {
|
|
1835
|
-
if (current.state === "cleared" && current.retired === true && current.sessionId === mutation.expectedPreviousSessionId) return {
|
|
1836
|
-
result: true,
|
|
1837
|
-
next: {
|
|
1838
|
-
version: 1,
|
|
1839
|
-
state: "cleared",
|
|
1840
|
-
sessionId: identity.sessionId,
|
|
1841
|
-
...ownedLease
|
|
1842
|
-
}
|
|
1843
|
-
};
|
|
1844
|
-
return { result: current.state !== "cleared" || current.retired !== true };
|
|
1845
|
-
}
|
|
1846
|
-
if (current.sessionId !== mutation.expectedPreviousSessionId) return { result: false };
|
|
1847
|
-
if (current.state === "active" && current.binding.connectionScope === "supervision") return { result: false };
|
|
1848
|
-
return {
|
|
1849
|
-
result: true,
|
|
1850
|
-
next: {
|
|
1851
|
-
version: 1,
|
|
1852
|
-
state: "cleared",
|
|
1853
|
-
sessionId: identity.sessionId,
|
|
1854
|
-
...ownedLease
|
|
1855
|
-
}
|
|
1856
|
-
};
|
|
1857
|
-
}
|
|
1858
|
-
const storedActive = current?.state === "active" ? current : void 0;
|
|
1859
|
-
const active = ownsGeneration ? storedActive : void 0;
|
|
1860
|
-
const retiredGeneration = current?.state === "cleared" && current.retired === true && ownsGeneration;
|
|
1861
|
-
const preservesSupervisionOwner = mutation.kind === "set" && active?.binding.connectionScope === "supervision" && isSameSupervisionOwner(active.binding, mutation.binding);
|
|
1862
|
-
const clearsPendingSupervisionOwner = mutation.kind === "clear" && active?.binding.connectionScope === "supervision" && matchesPendingSupervisionClear(active.binding, mutation.threadId, mutation.expectedPendingSupervisionBranch);
|
|
1863
|
-
if (mutation.kind === "set" && (mutation.if?.kind === "absent" && storedActive || current !== void 0 && !ownsGeneration || retiredGeneration || active?.binding.connectionScope === "supervision" && !preservesSupervisionOwner) || mutation.kind === "patch" && active?.binding.threadId !== mutation.threadId || (mutation.kind === "patch-pending-supervision-branch" || mutation.kind === "commit-pending-supervision-branch") && !matchesPendingSupervisionBranch(active?.binding, mutation.expected) || mutation.kind === "clear" && (mutation.threadId !== void 0 && active?.binding.threadId !== mutation.threadId || !ownsGeneration || active?.binding.connectionScope === "supervision" && !clearsPendingSupervisionOwner)) return { result: false };
|
|
1864
|
-
if (mutation.kind === "clear" && retiredGeneration) return { result: true };
|
|
1865
|
-
if (mutation.kind === "clear") return {
|
|
1866
|
-
result: true,
|
|
1867
|
-
next: {
|
|
1868
|
-
version: 1,
|
|
1869
|
-
state: "cleared",
|
|
1870
|
-
...storedSessionGeneration(identity, current),
|
|
1871
|
-
...ownedLease
|
|
1872
|
-
}
|
|
1873
|
-
};
|
|
1874
|
-
let binding;
|
|
1875
|
-
if (mutation.kind === "set") binding = validateBindingForWrite(mutation.binding);
|
|
1876
|
-
else if (mutation.kind === "patch-pending-supervision-branch") binding = validateBindingForWrite({
|
|
1877
|
-
...active.binding,
|
|
1878
|
-
pendingSupervisionBranch: mutation.pending
|
|
1879
|
-
});
|
|
1880
|
-
else if (mutation.kind === "commit-pending-supervision-branch") binding = validateBindingForWrite({
|
|
1881
|
-
...active.binding,
|
|
1882
|
-
...mutation.patch,
|
|
1883
|
-
threadId: mutation.threadId,
|
|
1884
|
-
pendingSupervisionBranch: void 0
|
|
1885
|
-
});
|
|
1886
|
-
else binding = validateBindingForWrite({
|
|
1887
|
-
...active.binding,
|
|
1888
|
-
...mutation.patch,
|
|
1889
|
-
threadId: mutation.threadId
|
|
1890
|
-
});
|
|
1891
|
-
return {
|
|
1892
|
-
result: true,
|
|
1893
|
-
next: {
|
|
1894
|
-
version: 1,
|
|
1895
|
-
state: "active",
|
|
1896
|
-
binding,
|
|
1897
|
-
...storedSessionGeneration(identity, current),
|
|
1898
|
-
...ownedLease
|
|
1899
|
-
}
|
|
1900
|
-
};
|
|
1901
|
-
}, mutation.kind === "clear" && !retainLegacyClear && !leaseContext.getStore()?.has(key) ? 1 : void 0);
|
|
1902
|
-
});
|
|
1903
|
-
},
|
|
1904
|
-
async adoptSessionGeneration(identity, expectedPreviousSessionId) {
|
|
1905
|
-
return await runBindingMutation(async () => {
|
|
1906
|
-
const key = bindingStoreKey(identity);
|
|
1907
|
-
const expectedSessionId = expectedPreviousSessionId.trim();
|
|
1908
|
-
const targetSessionId = identity.sessionId.trim();
|
|
1909
|
-
if (!expectedSessionId) throw new Error("Codex session generation adoption requires the previous session id");
|
|
1910
|
-
return await transactKey(key, (current) => {
|
|
1911
|
-
if (current?.state !== "active") return { result: "absent" };
|
|
1912
|
-
if (current.sessionId === targetSessionId) return { result: "current" };
|
|
1913
|
-
if (current.sessionId !== expectedSessionId) return { result: "conflict" };
|
|
1914
|
-
return {
|
|
1915
|
-
result: "adopted",
|
|
1916
|
-
next: {
|
|
1917
|
-
...current,
|
|
1918
|
-
sessionId: targetSessionId
|
|
1919
|
-
}
|
|
1920
|
-
};
|
|
1921
|
-
});
|
|
1922
|
-
});
|
|
1923
|
-
},
|
|
1924
|
-
async resetSessionGeneration(identity) {
|
|
1925
|
-
return await runBindingMutation(async () => {
|
|
1926
|
-
const key = bindingStoreKey(identity);
|
|
1927
|
-
return await transactKey(key, (current, leaseToken) => {
|
|
1928
|
-
if (!current) return { result: "absent" };
|
|
1929
|
-
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
1930
|
-
if (current.state === "cleared" && current.retired === true) return { result: "conflict" };
|
|
1931
|
-
return {
|
|
1932
|
-
result: "applied",
|
|
1933
|
-
next: {
|
|
1934
|
-
version: 1,
|
|
1935
|
-
state: "cleared",
|
|
1936
|
-
...storedSessionGeneration(identity, current),
|
|
1937
|
-
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
1938
|
-
}
|
|
1939
|
-
};
|
|
1940
|
-
}, leaseContext.getStore()?.has(key) ? void 0 : 1);
|
|
1941
|
-
});
|
|
1942
|
-
},
|
|
1943
|
-
async retireSessionGeneration(identity) {
|
|
1944
|
-
return await runBindingMutation(async () => {
|
|
1945
|
-
const key = bindingStoreKey(identity);
|
|
1946
|
-
return await transactKey(key, (current, leaseToken) => {
|
|
1947
|
-
if (!current) return { result: "absent" };
|
|
1948
|
-
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
1949
|
-
if (current.state === "cleared" && current.retired === true) return { result: "applied" };
|
|
1950
|
-
return {
|
|
1951
|
-
result: "applied",
|
|
1952
|
-
next: {
|
|
1953
|
-
version: 1,
|
|
1954
|
-
state: "cleared",
|
|
1955
|
-
retired: true,
|
|
1956
|
-
...storedSessionGeneration(identity, current),
|
|
1957
|
-
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
1958
|
-
}
|
|
1959
|
-
};
|
|
1960
|
-
}, identity.sessionKey?.trim() ? void 0 : PHYSICAL_SESSION_RETIRE_TTL_MS);
|
|
1961
|
-
});
|
|
1962
|
-
},
|
|
1963
|
-
async withThreadArchiveFence(run) {
|
|
1964
|
-
pendingArchives += 1;
|
|
1965
|
-
const operation = archiveTail.then(async () => {
|
|
1966
|
-
await waitForBindingMutations();
|
|
1967
|
-
return await archiveContext.run(true, run);
|
|
1968
|
-
});
|
|
1969
|
-
archiveTail = operation.then(() => void 0, () => void 0);
|
|
1970
|
-
try {
|
|
1971
|
-
return await operation;
|
|
1972
|
-
} finally {
|
|
1973
|
-
pendingArchives -= 1;
|
|
1974
|
-
}
|
|
1975
|
-
},
|
|
1976
|
-
async withLease(identity, run) {
|
|
1977
|
-
const key = bindingStoreKey(identity);
|
|
1978
|
-
const owned = leaseContext.getStore();
|
|
1979
|
-
const existingOwner = owned?.get(key);
|
|
1980
|
-
if (existingOwner) {
|
|
1981
|
-
const failureBeforeRun = existingOwner.failure;
|
|
1982
|
-
if (failureBeforeRun) throw failureBeforeRun;
|
|
1983
|
-
const result = await run();
|
|
1984
|
-
const failureAfterRun = existingOwner.failure;
|
|
1985
|
-
if (failureAfterRun) throw failureAfterRun;
|
|
1986
|
-
return result;
|
|
1987
|
-
}
|
|
1988
|
-
const token = randomUUID();
|
|
1989
|
-
if (!await transactKey(key, (current) => {
|
|
1990
|
-
if (current?.state === "cleared" && current.retired === true && ownsStoredSessionGeneration(identity, current)) return { result: false };
|
|
1991
|
-
const lease = {
|
|
1992
|
-
token,
|
|
1993
|
-
expiresAt: Date.now() + BINDING_LEASE_STALE_MS
|
|
1994
|
-
};
|
|
1995
|
-
if (current?.state === "active") return {
|
|
1996
|
-
result: true,
|
|
1997
|
-
next: {
|
|
1998
|
-
...current,
|
|
1999
|
-
...preservedSessionGeneration(identity, current),
|
|
2000
|
-
lease
|
|
2001
|
-
}
|
|
2002
|
-
};
|
|
2003
|
-
if (current?.state === "cleared" && current.retired === true) return {
|
|
2004
|
-
result: true,
|
|
2005
|
-
next: {
|
|
2006
|
-
...current,
|
|
2007
|
-
lease
|
|
2008
|
-
}
|
|
2009
|
-
};
|
|
2010
|
-
return {
|
|
2011
|
-
result: true,
|
|
2012
|
-
next: {
|
|
2013
|
-
version: 1,
|
|
2014
|
-
state: "cleared",
|
|
2015
|
-
...preservedSessionGeneration(identity, current),
|
|
2016
|
-
lease
|
|
2017
|
-
}
|
|
2018
|
-
};
|
|
2019
|
-
})) throw new Error(`Codex binding generation was retired: ${key}`);
|
|
2020
|
-
const owner = { token };
|
|
2021
|
-
const nested = new Map(owned);
|
|
2022
|
-
nested.set(key, owner);
|
|
2023
|
-
const heartbeat = setInterval(() => renewLease(key, owner), BINDING_LEASE_RENEW_INTERVAL_MS);
|
|
2024
|
-
heartbeat.unref();
|
|
2025
|
-
try {
|
|
2026
|
-
const result = await leaseContext.run(nested, run);
|
|
2027
|
-
if (owner.failure) throw owner.failure;
|
|
2028
|
-
return result;
|
|
2029
|
-
} finally {
|
|
2030
|
-
clearInterval(heartbeat);
|
|
2031
|
-
try {
|
|
2032
|
-
const removeOwnedLease = (raw, matches) => {
|
|
2033
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
2034
|
-
if (!current || !matches(current) || current.lease?.token !== token) return;
|
|
2035
|
-
const { lease: _lease, ...released } = current;
|
|
2036
|
-
return released;
|
|
2037
|
-
};
|
|
2038
|
-
if (!update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "active"))) {
|
|
2039
|
-
if (!update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "cleared" && current.retired === true), key.startsWith("session:") ? { ttlMs: PHYSICAL_SESSION_RETIRE_TTL_MS } : void 0)) update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "cleared"), { ttlMs: 1 });
|
|
2040
|
-
}
|
|
2041
|
-
} catch (error) {
|
|
2042
|
-
embeddedAgentLog.warn("failed to release codex app-server binding lease", {
|
|
2043
|
-
key,
|
|
2044
|
-
error
|
|
2045
|
-
});
|
|
2046
|
-
}
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
};
|
|
2050
|
-
}
|
|
2051
|
-
function matchesPendingSupervisionBranch(binding, expected) {
|
|
2052
|
-
const pending = binding?.pendingSupervisionBranch;
|
|
2053
|
-
if (!pending || binding?.threadId !== expected.sourceThreadId) return false;
|
|
2054
|
-
if (pending.sourceThreadId !== expected.sourceThreadId || pending.connectionFingerprint !== expected.connectionFingerprint || pending.lastTurnId !== expected.lastTurnId) return false;
|
|
2055
|
-
const currentCleanup = pending.cleanupThreadIds ?? [];
|
|
2056
|
-
const expectedCleanup = expected.cleanupThreadIds ?? [];
|
|
2057
|
-
return currentCleanup.length === expectedCleanup.length && currentCleanup.every((threadId, index) => threadId === expectedCleanup[index]);
|
|
2058
|
-
}
|
|
2059
|
-
function isSameSupervisionOwner(current, replacement) {
|
|
2060
|
-
return replacement.connectionScope === "supervision" && replacement.threadId === current.threadId && replacement.supervisionSourceThreadId === current.supervisionSourceThreadId;
|
|
2061
|
-
}
|
|
2062
|
-
function matchesPendingSupervisionClear(binding, threadId, expected) {
|
|
2063
|
-
if (!expected) return false;
|
|
2064
|
-
const sourceThreadId = expected.sourceThreadId;
|
|
2065
|
-
return threadId === sourceThreadId && binding.supervisionSourceThreadId === sourceThreadId && matchesPendingSupervisionBranch(binding, expected);
|
|
2066
|
-
}
|
|
2067
|
-
/** Stable plugin-state key for one current binding owner. */
|
|
2068
|
-
function bindingStoreKey(identity) {
|
|
2069
|
-
if (identity.kind === "session") {
|
|
2070
|
-
const rawAgentId = identity.agentId.trim();
|
|
2071
|
-
const sessionId = identity.sessionId.trim();
|
|
2072
|
-
if (!rawAgentId) throw new Error("Codex app-server binding requires an agent id");
|
|
2073
|
-
if (!sessionId) throw new Error("Codex app-server binding requires a session id");
|
|
2074
|
-
const agentId = resolveSessionAgentIds$1({ agentId: rawAgentId }).sessionAgentId;
|
|
2075
|
-
const sessionKey = identity.sessionKey?.trim();
|
|
2076
|
-
if (sessionKey) return `session-key:${agentId}:${createHash("sha256").update(sessionKey).digest("base64url")}`;
|
|
2077
|
-
return `session:${agentId}:${sessionId}`;
|
|
2078
|
-
}
|
|
2079
|
-
const bindingId = identity.bindingId.trim();
|
|
2080
|
-
if (!bindingId) throw new Error("Codex app-server conversation binding requires a binding id");
|
|
2081
|
-
return `conversation:${bindingId}`;
|
|
2082
|
-
}
|
|
2083
|
-
function readStoredCodexAppServerBinding(value) {
|
|
2084
|
-
const result = storedBindingSchema.safeParse(value);
|
|
2085
|
-
return result.success ? stripUndefinedValue(result.data) : void 0;
|
|
2086
|
-
}
|
|
2087
|
-
function storedSessionGeneration(identity, current) {
|
|
2088
|
-
if (identity.kind === "session") return { sessionId: identity.sessionId };
|
|
2089
|
-
return current?.sessionId ? { sessionId: current.sessionId } : {};
|
|
2090
|
-
}
|
|
2091
|
-
function preservedSessionGeneration(identity, current) {
|
|
2092
|
-
if (current?.sessionId) return { sessionId: current.sessionId };
|
|
2093
|
-
return storedSessionGeneration(identity, current);
|
|
2094
|
-
}
|
|
2095
|
-
function ownsStoredSessionGeneration(identity, current) {
|
|
2096
|
-
return identity.kind !== "session" || !current?.sessionId || current.sessionId === identity.sessionId;
|
|
2097
|
-
}
|
|
2098
|
-
function validateBindingForWrite(binding) {
|
|
2099
|
-
const validated = readCodexAppServerThreadBinding(binding);
|
|
2100
|
-
if (!validated) throw new Error("Invalid Codex app-server thread binding");
|
|
2101
|
-
return stripUndefinedBinding(validated);
|
|
2102
|
-
}
|
|
2103
|
-
/** Parses stored or shipped sidecar data into the current domain value. */
|
|
2104
|
-
function readCodexAppServerThreadBinding(value) {
|
|
2105
|
-
const result = threadBindingSchema.safeParse(value);
|
|
2106
|
-
if (!result.success) return;
|
|
2107
|
-
return result.data;
|
|
2108
|
-
}
|
|
2109
|
-
function stripUndefinedBinding(binding) {
|
|
2110
|
-
return stripUndefinedValue(binding);
|
|
2111
|
-
}
|
|
2112
|
-
function stripUndefinedValue(value) {
|
|
2113
|
-
if (Array.isArray(value)) return value.map(stripUndefinedValue);
|
|
2114
|
-
if (!value || typeof value !== "object") return value;
|
|
2115
|
-
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, stripUndefinedValue(entry)]));
|
|
2116
|
-
}
|
|
2117
|
-
function asRecord(value) {
|
|
2118
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
2119
|
-
}
|
|
2120
|
-
function readTimestamp(value) {
|
|
2121
|
-
return optionalTimestampSchema.parse(value);
|
|
2122
|
-
}
|
|
2123
|
-
function readPluginAppPolicyContext(value, bindingSchemaVersion) {
|
|
2124
|
-
const record = asRecord(value);
|
|
2125
|
-
if (!record || typeof record.fingerprint !== "string") return;
|
|
2126
|
-
const apps = asRecord(record.apps);
|
|
2127
|
-
if (!apps) return;
|
|
2128
|
-
const parsedApps = {};
|
|
2129
|
-
for (const [appId, rawEntry] of Object.entries(apps)) {
|
|
2130
|
-
const entry = asRecord(rawEntry);
|
|
2131
|
-
if (!entry) return;
|
|
2132
|
-
const destructiveApprovalMode = readDestructiveApprovalMode(entry.destructiveApprovalMode, bindingSchemaVersion);
|
|
2133
|
-
const mcpServerNamesValid = Array.isArray(entry.mcpServerNames) && entry.mcpServerNames.every((serverName) => typeof serverName === "string");
|
|
2134
|
-
if (entry.source === "account") {
|
|
2135
|
-
if ("appId" in entry || typeof entry.appName !== "string" || typeof entry.allowDestructiveActions !== "boolean" || destructiveApprovalMode === "invalid" || !mcpServerNamesValid) return;
|
|
2136
|
-
parsedApps[appId] = {
|
|
2137
|
-
source: "account",
|
|
2138
|
-
appName: entry.appName,
|
|
2139
|
-
allowDestructiveActions: entry.allowDestructiveActions,
|
|
2140
|
-
...destructiveApprovalMode ? { destructiveApprovalMode } : {},
|
|
2141
|
-
mcpServerNames: entry.mcpServerNames
|
|
2142
|
-
};
|
|
2143
|
-
continue;
|
|
2144
|
-
}
|
|
2145
|
-
if ("appId" in entry || entry.source !== void 0 && entry.source !== "plugin" || typeof entry.configKey !== "string" || entry.marketplaceName !== "openai-curated" && entry.marketplaceName !== "workspace-directory" || typeof entry.pluginName !== "string" || typeof entry.allowDestructiveActions !== "boolean" || destructiveApprovalMode === "invalid" || !mcpServerNamesValid) return;
|
|
2146
|
-
parsedApps[appId] = {
|
|
2147
|
-
configKey: entry.configKey,
|
|
2148
|
-
marketplaceName: entry.marketplaceName,
|
|
2149
|
-
pluginName: entry.pluginName,
|
|
2150
|
-
allowDestructiveActions: entry.allowDestructiveActions,
|
|
2151
|
-
...destructiveApprovalMode ? { destructiveApprovalMode } : {},
|
|
2152
|
-
mcpServerNames: entry.mcpServerNames
|
|
2153
|
-
};
|
|
2154
|
-
}
|
|
2155
|
-
const parsedPluginAppIds = {};
|
|
2156
|
-
if (record.pluginAppIds !== void 0 && (!record.pluginAppIds || typeof record.pluginAppIds !== "object" || Array.isArray(record.pluginAppIds))) return;
|
|
2157
|
-
if (record.pluginAppIds && typeof record.pluginAppIds === "object") for (const [configKey, appIds] of Object.entries(record.pluginAppIds)) {
|
|
2158
|
-
if (!Array.isArray(appIds) || appIds.some((appId) => typeof appId !== "string")) return;
|
|
2159
|
-
parsedPluginAppIds[configKey] = appIds;
|
|
2160
|
-
}
|
|
2161
|
-
return {
|
|
2162
|
-
fingerprint: record.fingerprint,
|
|
2163
|
-
apps: parsedApps,
|
|
2164
|
-
pluginAppIds: parsedPluginAppIds
|
|
2165
|
-
};
|
|
2166
|
-
}
|
|
2167
|
-
function readDestructiveApprovalMode(value, bindingSchemaVersion) {
|
|
2168
|
-
if (value === void 0) return;
|
|
2169
|
-
if (value === "allow" || value === "deny") return value;
|
|
2170
|
-
if (value === "auto") return bindingSchemaVersion === 1 ? "allow" : "auto";
|
|
2171
|
-
if (value === "ask" && bindingSchemaVersion === 2) return "ask";
|
|
2172
|
-
if (value === "on-request" && bindingSchemaVersion === 1) return "auto";
|
|
2173
|
-
return "invalid";
|
|
2174
|
-
}
|
|
2175
|
-
function sleep(ms) {
|
|
2176
|
-
return new Promise((resolve) => {
|
|
2177
|
-
setTimeout(resolve, ms);
|
|
2178
|
-
});
|
|
2179
|
-
}
|
|
2180
|
-
/** Returns true when an auth profile uses native Codex/OpenAI app-server auth. */
|
|
2181
|
-
function isCodexAppServerNativeAuthProfile(lookup) {
|
|
2182
|
-
const authProfileId = lookup.authProfileId?.trim();
|
|
2183
|
-
if (!authProfileId) return false;
|
|
2184
|
-
try {
|
|
2185
|
-
const credential = (lookup.authProfileStore ?? ensureAuthProfileStore(lookup.agentDir?.trim() || resolveDefaultAgentDir(lookup.config ?? {}), {
|
|
2186
|
-
allowKeychainPrompt: false,
|
|
2187
|
-
config: lookup.config,
|
|
2188
|
-
externalCliProviderIds: [CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER],
|
|
2189
|
-
externalCliProfileIds: [authProfileId]
|
|
2190
|
-
})).profiles[authProfileId];
|
|
2191
|
-
if (!credential || credential.type === "api_key") return false;
|
|
2192
|
-
const provider = credential.provider?.trim();
|
|
2193
|
-
return Boolean(provider && resolveProviderIdForAuth(provider, { config: lookup.config }) === CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER);
|
|
2194
|
-
} catch (error) {
|
|
2195
|
-
embeddedAgentLog.debug("failed to resolve codex app-server auth profile provider", {
|
|
2196
|
-
authProfileId,
|
|
2197
|
-
error
|
|
2198
|
-
});
|
|
2199
|
-
return false;
|
|
2200
|
-
}
|
|
2201
|
-
}
|
|
2202
|
-
/** Hides redundant OpenAI provider attribution for native Codex auth bindings. */
|
|
2203
|
-
function normalizeCodexAppServerBindingModelProvider(params) {
|
|
2204
|
-
const modelProvider = params.modelProvider?.trim();
|
|
2205
|
-
if (!modelProvider) return;
|
|
2206
|
-
if (isCodexAppServerNativeAuthProfile(params) && modelProvider.toLowerCase() === PUBLIC_OPENAI_MODEL_PROVIDER) return;
|
|
2207
|
-
return modelProvider;
|
|
2208
|
-
}
|
|
2209
|
-
/** Restores the sole provider intentionally omitted from canonical binding rows. */
|
|
2210
|
-
function resolveCodexAppServerBindingModelProvider(params) {
|
|
2211
|
-
return params.modelProvider?.trim() || (isCodexAppServerNativeAuthProfile(params) ? PUBLIC_OPENAI_MODEL_PROVIDER : void 0);
|
|
2212
|
-
}
|
|
2213
|
-
//#endregion
|
|
2214
|
-
export { resolveOpenClawExecPolicyForCodexAppServer as A, canUseCodexModelBackedApprovalsReviewerForModel as C, isCodexSandboxExecServerEnabled as D, isCodexAppServerApprovalPolicyAllowedByRequirements as E, CODEX_PLUGINS_MARKETPLACE_NAME as M, CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME as N, readCodexPluginConfig as O, withMcpElicitationsApprovalPolicy as S, resolveCodexModelBackedReviewerPolicyContext as T, resolveCodexAppServerStartOptionsForAgent as _, hashCodexAppServerBindingFingerprint as a, assertCodexAppServerConnectionSecurity as b, reclaimCurrentCodexSessionGeneration as c, sessionBindingIdentity as d, session_binding_exports as f, resolveCodexAppServerRuntimeOptions as g, resolveCodexAppServerHomeScope as h, createCodexSessionGenerationSupersededError as i, isCodexFastServiceTier as j, resolveCodexPluginsPolicy as k, resolveCodexRunSessionBindingAuthority as l, codexSandboxPolicyForTurn as m, assertCodexBindingMayBeReplaced as n, isCodexAppServerNativeAuthProfile as o, codexAppServerStartOptionsKey as p, bindingStoreKey as r, normalizeCodexAppServerBindingModelProvider as s, CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS as t, scopeCodexRunBindingStore as u, resolveCodexComputerUseConfig as v, resolveCodexAppServerUserHomeDir as w, shouldAutoApproveCodexAppServerApprovals as x, resolveCodexSupervisionAppServerRuntimeOptions as y };
|