@openclaw/codex 2026.7.2-beta.7 → 2026.8.1-beta.3
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 +2 -0
- package/dist/api.js +147 -0
- package/dist/app-server-policy-bg5QPSVP.js +25 -0
- package/dist/attempt-client-cleanup-URjUlCHg.js +735 -0
- package/dist/binding-connection-DAvZwp96.js +45 -0
- package/dist/{bounded-turn-D2ZAgZVz.js → bounded-turn-4BjrZEwW.js} +63 -56
- package/dist/{capabilities-BFDTVYr4.js → capabilities-CH3K57v4.js} +8 -2
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-C336eRVS.js → command-formatters-D0nZ3qtd.js} +18 -18
- package/dist/{command-handlers-DAHUSry9.js → command-handlers-DC86lgT4.js} +507 -101
- package/dist/command-rpc-xUIIonsO.js +90 -0
- package/dist/{compact-D_uvHurS.js → compact-COqgBRny.js} +234 -214
- package/dist/{session-binding-BXpo9ymA.js → config-CpNeo5AE.js} +284 -1163
- package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
- package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
- package/dist/doctor-contract-api.js +48 -50
- package/dist/{dynamic-tools-D2gYkSBO.js → dynamic-tools-fJZhl4CE.js} +3442 -1433
- package/dist/{effective-mcp-catalog-Bbd98Inw.js → effective-mcp-catalog-4YKn51aG.js} +20 -15
- package/dist/elicitation-input-DMkeki8d.js +71 -0
- package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
- package/dist/{attempt-notifications-AP-a-Q5k.js → event-projector-usage-CLwNEJqW.js} +113 -29
- package/dist/harness-DoKQcF8n.js +258 -0
- package/dist/harness.js +2 -160
- package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
- package/dist/index.js +730 -256
- package/dist/isolated-completion-DPMtlH9r.js +75 -0
- package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
- package/dist/managed-binary-By4FZC6i.js +212 -0
- package/dist/media-understanding-provider.js +5 -5
- package/dist/model-catalog-CmGoqVKB.js +48 -0
- package/dist/{models-BBMKU4jA.js → models-CZw1wClT.js} +12 -17
- package/dist/native-subagent-monitor-GGq3RnOo.js +3225 -0
- package/dist/node-exec-server.runtime-Bsu1LdFZ.js +192 -0
- package/dist/{plugin-app-cache-key-DztPafOA.js → plugin-app-cache-key-DMNQ8Zi8.js} +18 -6
- package/dist/plugin-approval-roundtrip-C75Yiiwc.js +95 -0
- package/dist/plugin-marketplace-discovery-CSWDkMrP.js +399 -0
- package/dist/{computer-use-CYEc8U3w.js → plugin-metadata-cache-BXH5NF-4.js} +109 -6
- package/dist/protocol-validators-VAVyEnDp.js +2399 -0
- package/dist/{rate-limits-CU-gVCCS.js → rate-limits-BI1dMHDG.js} +17 -35
- package/dist/{request-qKh331yu.js → request-DSK0W6YI.js} +3 -3
- package/dist/{run-attempt-CY9WlDLc.js → run-attempt-BV3HzuCf.js} +3416 -7194
- package/dist/{runtime-artifact-CmtG_t1L.js → runtime-artifact-BvyT1uyd.js} +11 -29
- package/dist/{sandbox-guard-NuhpXmPB.js → sandbox-guard-C1qEeZ5C.js} +29 -30
- package/dist/session-binding-BTrLf9Qm.js +874 -0
- package/dist/{session-catalog-DyOgR4WH.js → session-catalog-ezP_UcRM.js} +1584 -1289
- package/dist/session-catalog-home-id-BNwAJ9D7.js +18 -0
- package/dist/{session-cli-2PZaFLRh.js → session-cli-B1hKvfkI.js} +20 -7
- package/dist/session-retirement-CE4iMiLh.js +36 -0
- package/dist/{session-upstream-marker-B6U7tLw5.js → session-upstream-marker-D_2npHlA.js} +1 -1
- package/dist/{settled-turn-finalizer-CXY2Z9dT.js → settled-turn-finalizer-Dx1onIqg.js} +40 -28
- package/dist/{shared-client-DTbvH-XV.js → shared-client-Dw-rzii0.js} +1315 -469
- package/dist/{side-question-_ulBk1AL.js → side-question-DbXkJZzg.js} +140 -69
- package/dist/{thread-lifecycle-DF53ogiA.js → thread-lifecycle-DKdrnTMX.js} +927 -768
- package/dist/thread-ownership-i2NBwDUL.js +92 -0
- package/dist/thread-resume-CdJk2Ehf.js +30 -0
- package/dist/transcript-mirror-BU0_LKAL.js +588 -0
- package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DhoGy33Z.js} +13 -2
- package/dist/upstream-prompt-provenance-CFmsKwr9.js +39 -0
- package/dist/{upstream-session-fork-Dy4Xvuoj.js → upstream-session-fork-BDVJCLAD.js} +14 -8
- package/dist/{usage-CQ6GhD5-.js → usage-9dKJCgcy.js} +3 -3
- package/dist/{web-search-provider.runtime-CCFhg2z5.js → web-search-provider.runtime-DCdx4DGu.js} +8 -9
- package/openclaw.plugin.json +49 -4
- package/package.json +6 -5
- package/dist/app-server-policy-BSaO2JIT.js +0 -49
- package/dist/conversation-control-xsIeXbo4.js +0 -287
- package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
- package/dist/notification-correlation-CU6_AnOb.js +0 -67
- package/dist/transcript-mirror-DzsdNCf5.js +0 -6924
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { z as closeCodexAppServerTransportAndWait } from "./shared-client-Dw-rzii0.js";
|
|
2
|
+
import { t as createStdioTransport } from "./transport-stdio-DhoGy33Z.js";
|
|
3
|
+
import { n as resolveManagedCodexAppServerStartOptions, r as resolveManagedCodexNativeCommand, t as isManagedCodexDesktopCommand } from "./managed-binary-By4FZC6i.js";
|
|
4
|
+
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import { mkdir } from "node:fs/promises";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
|
8
|
+
import { killProcessTree } from "openclaw/plugin-sdk/process-runtime";
|
|
9
|
+
import { once } from "node:events";
|
|
10
|
+
import { sanitizeEnvVars } from "openclaw/plugin-sdk/sandbox";
|
|
11
|
+
//#region extensions/codex/src/node-exec-server.runtime.ts
|
|
12
|
+
const MAX_CODEX_EXEC_SERVER_MESSAGE_BYTES = 64 * 1024 * 1024;
|
|
13
|
+
const CODEX_EXEC_SERVER_TERMINATION_GRACE_MS = 1e3;
|
|
14
|
+
const CODEX_EXEC_SERVER_REAP_TIMEOUT_MS = 5e3;
|
|
15
|
+
const NODE_EXEC_SERVER_PLATFORM_ENVIRONMENT = /^(?:SYSTEMROOT|WINDIR|COMSPEC|PATHEXT|TEMP|TMP|TMPDIR)$/iu;
|
|
16
|
+
function validateNodeExecServerMessage(message) {
|
|
17
|
+
if (message.byteLength === 0 || message.byteLength > MAX_CODEX_EXEC_SERVER_MESSAGE_BYTES) throw new Error("Codex exec-server JSON-RPC message exceeds its 64 MiB limit.");
|
|
18
|
+
const encoded = Buffer.from(message.buffer, message.byteOffset, message.byteLength);
|
|
19
|
+
if (encoded.includes(10) || encoded.includes(13)) throw new Error("Codex exec-server JSON-RPC frames must contain exactly one message.");
|
|
20
|
+
let decoded;
|
|
21
|
+
try {
|
|
22
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(encoded);
|
|
23
|
+
decoded = JSON.parse(text);
|
|
24
|
+
} catch {
|
|
25
|
+
throw new Error("Codex exec-server received malformed UTF-8 or JSON-RPC.");
|
|
26
|
+
}
|
|
27
|
+
if (!isRecord(decoded) || decoded.jsonrpc !== void 0 && decoded.jsonrpc !== "2.0" || typeof decoded.method !== "string" && !("id" in decoded && ("result" in decoded || "error" in decoded))) throw new Error("Codex exec-server received an invalid JSON-RPC message.");
|
|
28
|
+
return encoded;
|
|
29
|
+
}
|
|
30
|
+
function nodeExecServerAbortError(signal) {
|
|
31
|
+
return signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("Codex node exec-server connection closed.");
|
|
32
|
+
}
|
|
33
|
+
function writeNodeExecServerMessage(child, message, signal) {
|
|
34
|
+
if (signal.aborted) throw nodeExecServerAbortError(signal);
|
|
35
|
+
const payload = Buffer.concat([message, Buffer.from("\n")]);
|
|
36
|
+
if (!child.stdin.write(payload)) return once(child.stdin, "drain", { signal }).then(() => void 0);
|
|
37
|
+
}
|
|
38
|
+
async function relayNodeExecServerOutput(child, send) {
|
|
39
|
+
let fragments = [];
|
|
40
|
+
let pendingBytes = 0;
|
|
41
|
+
for await (const rawChunk of child.stdout) {
|
|
42
|
+
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
|
|
43
|
+
let offset = 0;
|
|
44
|
+
while (offset < chunk.byteLength) {
|
|
45
|
+
const newline = chunk.indexOf(10, offset);
|
|
46
|
+
const fragment = chunk.subarray(offset, newline === -1 ? chunk.byteLength : newline);
|
|
47
|
+
const nextLength = pendingBytes + fragment.byteLength;
|
|
48
|
+
if (nextLength > 67108865) throw new Error("Codex exec-server stdout message exceeds its 64 MiB limit.");
|
|
49
|
+
if (fragment.byteLength > 0) fragments.push(fragment);
|
|
50
|
+
pendingBytes = nextLength;
|
|
51
|
+
if (newline === -1) {
|
|
52
|
+
if (pendingBytes > MAX_CODEX_EXEC_SERVER_MESSAGE_BYTES && fragment[fragment.byteLength - 1] !== 13) throw new Error("Codex exec-server stdout message exceeds its 64 MiB limit.");
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
const trailing = fragments.at(-1);
|
|
56
|
+
if (trailing?.[trailing.byteLength - 1] === 13) {
|
|
57
|
+
pendingBytes -= 1;
|
|
58
|
+
if (trailing.byteLength === 1) fragments.pop();
|
|
59
|
+
else fragments[fragments.length - 1] = trailing.subarray(0, trailing.byteLength - 1);
|
|
60
|
+
}
|
|
61
|
+
const message = validateNodeExecServerMessage(fragments.length === 1 ? fragments[0] : Buffer.concat(fragments, pendingBytes));
|
|
62
|
+
fragments = [];
|
|
63
|
+
pendingBytes = 0;
|
|
64
|
+
await send(message);
|
|
65
|
+
offset = newline + 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (pendingBytes > 0) throw new Error("Codex exec-server stdout ended with an unterminated JSON-RPC message.");
|
|
69
|
+
}
|
|
70
|
+
function createNodeExecServerProcessOwner(child, closed) {
|
|
71
|
+
let termination;
|
|
72
|
+
return { terminate: () => termination ??= (async () => {
|
|
73
|
+
if (process.platform === "win32" && child.pid) killProcessTree(child.pid, { graceMs: CODEX_EXEC_SERVER_TERMINATION_GRACE_MS });
|
|
74
|
+
if (!await closeCodexAppServerTransportAndWait(child, {
|
|
75
|
+
forceKillDelayMs: CODEX_EXEC_SERVER_TERMINATION_GRACE_MS,
|
|
76
|
+
exitTimeoutMs: CODEX_EXEC_SERVER_REAP_TIMEOUT_MS
|
|
77
|
+
})) throw new Error("Codex node exec-server process tree did not terminate.");
|
|
78
|
+
await closed;
|
|
79
|
+
})() };
|
|
80
|
+
}
|
|
81
|
+
/** Runs the one-connection paired-node exec-server after lightweight command admission. */
|
|
82
|
+
async function runCodexNodeExecServer(params) {
|
|
83
|
+
const { io } = params;
|
|
84
|
+
const frames = io.frames;
|
|
85
|
+
if (!frames) throw new Error("Codex node exec-server requires duplex frames.");
|
|
86
|
+
const cwd = params.workspaceDir;
|
|
87
|
+
let writes;
|
|
88
|
+
let rejectDisconnected;
|
|
89
|
+
const disconnected = new Promise((_resolve, reject) => {
|
|
90
|
+
rejectDisconnected = reject;
|
|
91
|
+
});
|
|
92
|
+
disconnected.catch(() => {});
|
|
93
|
+
const onAbort = () => {
|
|
94
|
+
const error = nodeExecServerAbortError(io.signal);
|
|
95
|
+
rejectDisconnected(error);
|
|
96
|
+
};
|
|
97
|
+
io.signal.addEventListener("abort", onAbort, { once: true });
|
|
98
|
+
try {
|
|
99
|
+
if (io.signal.aborted) throw nodeExecServerAbortError(io.signal);
|
|
100
|
+
return await withTempWorkspace({
|
|
101
|
+
rootDir: resolvePreferredOpenClawTmpDir(),
|
|
102
|
+
prefix: "codex-node-exec-server-"
|
|
103
|
+
}, async ({ dir }) => {
|
|
104
|
+
const codexHome = path.join(dir, ".codex");
|
|
105
|
+
await mkdir(codexHome, {
|
|
106
|
+
recursive: true,
|
|
107
|
+
mode: 448
|
|
108
|
+
});
|
|
109
|
+
const resolved = await resolveManagedCodexAppServerStartOptions({
|
|
110
|
+
transport: "stdio",
|
|
111
|
+
command: "codex",
|
|
112
|
+
commandSource: "managed",
|
|
113
|
+
managedCommandOrder: "package-first",
|
|
114
|
+
args: [
|
|
115
|
+
"exec-server",
|
|
116
|
+
"--listen",
|
|
117
|
+
"stdio"
|
|
118
|
+
],
|
|
119
|
+
headers: {}
|
|
120
|
+
});
|
|
121
|
+
const native = resolveManagedCodexNativeCommand(resolved.command);
|
|
122
|
+
if (!native || isManagedCodexDesktopCommand(resolved.command)) throw new Error("Codex node exec-server requires the pinned managed package binary.");
|
|
123
|
+
const baseEnv = sanitizeEnvVars(process.env, {
|
|
124
|
+
strictMode: true,
|
|
125
|
+
customAllowedPatterns: [NODE_EXEC_SERVER_PLATFORM_ENVIRONMENT]
|
|
126
|
+
}).allowed;
|
|
127
|
+
if (io.signal.aborted) throw nodeExecServerAbortError(io.signal);
|
|
128
|
+
const child = createStdioTransport({
|
|
129
|
+
transport: "stdio",
|
|
130
|
+
command: native,
|
|
131
|
+
commandSource: "resolved-managed",
|
|
132
|
+
args: resolved.args,
|
|
133
|
+
headers: {},
|
|
134
|
+
cwd,
|
|
135
|
+
env: {
|
|
136
|
+
HOME: dir,
|
|
137
|
+
CODEX_HOME: codexHome,
|
|
138
|
+
...process.platform === "win32" ? { USERPROFILE: dir } : {}
|
|
139
|
+
},
|
|
140
|
+
clearEnv: ["NODE_OPTIONS"]
|
|
141
|
+
}, baseEnv);
|
|
142
|
+
child.stdin.on("error", (error) => {
|
|
143
|
+
rejectDisconnected(error);
|
|
144
|
+
});
|
|
145
|
+
let stderr = Buffer.alloc(0);
|
|
146
|
+
child.stderr.on("data", (chunk) => {
|
|
147
|
+
const bounded = (Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)).subarray(-4096);
|
|
148
|
+
stderr = Buffer.concat([stderr, bounded]).subarray(-4096);
|
|
149
|
+
});
|
|
150
|
+
const closed = new Promise((resolve) => {
|
|
151
|
+
child.once("close", (code, signal) => resolve({
|
|
152
|
+
code,
|
|
153
|
+
signal
|
|
154
|
+
}));
|
|
155
|
+
});
|
|
156
|
+
child.once("error", (error) => {
|
|
157
|
+
rejectDisconnected(error);
|
|
158
|
+
});
|
|
159
|
+
const owner = createNodeExecServerProcessOwner(child, closed);
|
|
160
|
+
params.activeProcesses.add(owner.terminate);
|
|
161
|
+
const output = relayNodeExecServerOutput(child, frames.send.bind(frames));
|
|
162
|
+
output.catch((error) => {
|
|
163
|
+
rejectDisconnected(error instanceof Error ? error : new Error(String(error)));
|
|
164
|
+
});
|
|
165
|
+
try {
|
|
166
|
+
if (io.signal.aborted) throw nodeExecServerAbortError(io.signal);
|
|
167
|
+
params.onFrameReceiver((message) => {
|
|
168
|
+
const encoded = validateNodeExecServerMessage(message);
|
|
169
|
+
const operation = writes ? writes.then(() => writeNodeExecServerMessage(child, encoded, io.signal)) : writeNodeExecServerMessage(child, encoded, io.signal);
|
|
170
|
+
if (!operation) return;
|
|
171
|
+
const observed = operation.catch(() => {});
|
|
172
|
+
writes = observed;
|
|
173
|
+
observed.then(() => {
|
|
174
|
+
if (writes === observed) writes = void 0;
|
|
175
|
+
});
|
|
176
|
+
return operation;
|
|
177
|
+
});
|
|
178
|
+
const outcome = await Promise.race([closed, disconnected]);
|
|
179
|
+
const diagnostic = stderr.toString("utf8").trim();
|
|
180
|
+
throw new Error(`Codex node exec-server exited (code ${outcome.code ?? "none"}, signal ${outcome.signal ?? "none"})${diagnostic ? `: ${diagnostic}` : "."}`);
|
|
181
|
+
} finally {
|
|
182
|
+
await owner.terminate();
|
|
183
|
+
params.activeProcesses.delete(owner.terminate);
|
|
184
|
+
await Promise.allSettled([output, ...writes ? [writes] : []]);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
} finally {
|
|
188
|
+
io.signal.removeEventListener("abort", onAbort);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
192
|
+
export { runCodexNodeExecServer };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { x as resolveCodexAppServerUserHomeDir } from "./config-CpNeo5AE.js";
|
|
2
|
+
import { ft as resolveCodexAppServerHomeDir, pt as resolveCodexAppServerLocalHomeDir } from "./shared-client-Dw-rzii0.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
+
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import { readPluginPackageVersion } from "openclaw/plugin-sdk/extension-shared";
|
|
4
6
|
import { isFutureDateTimestampMs, resolveDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
5
7
|
import { OPENCLAW_VERSION, embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
6
8
|
import { createHash } from "node:crypto";
|
|
7
|
-
import { readPluginPackageVersion } from "openclaw/plugin-sdk/extension-shared";
|
|
8
|
-
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
9
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
10
10
|
//#region extensions/codex/src/app-server/app-inventory-cache.ts
|
|
11
11
|
/**
|
|
@@ -331,6 +331,14 @@ function isSensitiveErrorDataKey(key) {
|
|
|
331
331
|
* auth, account, and version inputs without storing secret material.
|
|
332
332
|
*/
|
|
333
333
|
const CODEX_PLUGIN_VERSION = readPluginPackageVersion({ require: createRequire(import.meta.url) });
|
|
334
|
+
let catalogConnectionHomes = /* @__PURE__ */ new Map();
|
|
335
|
+
function catalogConnectionHomeKey(fingerprint, agentDir) {
|
|
336
|
+
return `${agentDir ?? ""}\0${fingerprint}`;
|
|
337
|
+
}
|
|
338
|
+
/** Replaces the lifecycle-owned catalog connection snapshot used by supervised bindings. */
|
|
339
|
+
function replaceCodexCatalogConnectionHomes(homes) {
|
|
340
|
+
catalogConnectionHomes = new Map(homes.map((home) => [catalogConnectionHomeKey(home.fingerprint, home.agentDir), home.codexHome]));
|
|
341
|
+
}
|
|
334
342
|
/** Builds the full app inventory cache key for Codex plugin/app discovery. */
|
|
335
343
|
function buildCodexPluginAppCacheKey(params) {
|
|
336
344
|
return buildCodexAppInventoryCacheKey({
|
|
@@ -364,13 +372,17 @@ function buildCodexAppServerConnectionFingerprint(appServer, agentDir) {
|
|
|
364
372
|
cwd: appServer.start.cwd ?? null
|
|
365
373
|
});
|
|
366
374
|
}
|
|
375
|
+
/** Looks up a snapshotted catalog store without repeating filesystem discovery on a run. */
|
|
376
|
+
function resolveCodexCatalogConnectionHome(fingerprint, agentDir) {
|
|
377
|
+
return catalogConnectionHomes.get(catalogConnectionHomeKey(fingerprint, agentDir));
|
|
378
|
+
}
|
|
367
379
|
function resolveCodexAppServerConnectionHome(start, agentDir) {
|
|
368
380
|
const configured = start.env?.CODEX_HOME?.trim();
|
|
369
381
|
if (configured) return configured;
|
|
370
382
|
if (start.transport === "unix" && (!start.url || start.url === "unix://")) return resolveCodexAppServerUserHomeDir(start.env ?? process.env);
|
|
371
383
|
if (start.transport !== "stdio") return null;
|
|
372
384
|
if (start.homeScope === "user") return resolveCodexAppServerUserHomeDir(process.env);
|
|
373
|
-
return agentDir ?
|
|
385
|
+
return agentDir ? resolveCodexAppServerLocalHomeDir(start, agentDir) : null;
|
|
374
386
|
}
|
|
375
387
|
/** Serializes app-server endpoint identity, including credential fingerprints. */
|
|
376
388
|
function resolveCodexPluginAppCacheEndpoint(appServer) {
|
|
@@ -405,4 +417,4 @@ function fingerprintCodexPluginAppCacheCredentials(startOptions) {
|
|
|
405
417
|
return `sha256:${hash.digest("hex")}`;
|
|
406
418
|
}
|
|
407
419
|
//#endregion
|
|
408
|
-
export {
|
|
420
|
+
export { resolveCodexCatalogConnectionHome as a, replaceCodexCatalogConnectionHomes as i, buildCodexAppServerRuntimeFingerprint as n, defaultCodexAppInventoryCache as o, buildCodexPluginAppCacheKey as r, serializeCodexAppInventoryError as s, buildCodexAppServerConnectionFingerprint as t };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { S as resolveCodexGatewayTimeoutWithGraceMs } from "./shared-client-Dw-rzii0.js";
|
|
2
|
+
import { isApprovalNotFoundError, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
|
3
|
+
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
4
|
+
//#region extensions/codex/src/app-server/plugin-approval-roundtrip.ts
|
|
5
|
+
const DEFAULT_CODEX_APPROVAL_TIMEOUT_MS = 12e4;
|
|
6
|
+
const MAX_PLUGIN_APPROVAL_TITLE_LENGTH = 80;
|
|
7
|
+
const MAX_PLUGIN_APPROVAL_DESCRIPTION_LENGTH = 256;
|
|
8
|
+
const ANSI_OSC_SEQUENCE_RE = new RegExp(String.raw`(?:\u001b]|\u009d)[^\u001b\u009c\u0007]*(?:\u0007|\u001b\\|\u009c)`, "g");
|
|
9
|
+
const ANSI_CONTROL_SEQUENCE_RE = new RegExp(String.raw`(?:\u001b\[[0-?]*[ -/]*[@-~]|\u009b[0-?]*[ -/]*[@-~]|\u001b[@-Z\\-_])`, "g");
|
|
10
|
+
const CONTROL_CHARACTER_RE = new RegExp(String.raw`[\u0000-\u001f\u007f-\u009f]+`, "g");
|
|
11
|
+
const INVISIBLE_FORMATTING_CONTROL_RE = new RegExp(String.raw`[\u00ad\u034f\u061c\u200b-\u200f\u202a-\u202e\u2060-\u206f\ufeff\ufe00-\ufe0f\u{e0100}-\u{e01ef}]`, "gu");
|
|
12
|
+
const DANGLING_TERMINAL_SEQUENCE_SUFFIX_RE = new RegExp(String.raw`(?:\u001b\][^\u001b\u009c\u0007]*|\u009d[^\u001b\u009c\u0007]*|\u001b\[[0-?]*[ -/]*|\u009b[0-?]*[ -/]*|\u001b)$`);
|
|
13
|
+
const CODEX_APPROVAL_TIMEOUT_SUBJECTS = {
|
|
14
|
+
command: "Command approval",
|
|
15
|
+
"file-change": "File change approval",
|
|
16
|
+
permissions: "Permission approval",
|
|
17
|
+
other: "Approval"
|
|
18
|
+
};
|
|
19
|
+
function codexApprovalTimeoutText(kind) {
|
|
20
|
+
return `${CODEX_APPROVAL_TIMEOUT_SUBJECTS[kind]} timed out before an operator responded.`;
|
|
21
|
+
}
|
|
22
|
+
/** Starts a two-phase plugin approval request through the OpenClaw gateway. */
|
|
23
|
+
async function requestPluginApproval(params) {
|
|
24
|
+
const timeoutMs = DEFAULT_CODEX_APPROVAL_TIMEOUT_MS;
|
|
25
|
+
return params.hostCapabilities.requestApproval({
|
|
26
|
+
title: truncateCodexApprovalDisplayText(params.title, MAX_PLUGIN_APPROVAL_TITLE_LENGTH),
|
|
27
|
+
description: truncateCodexApprovalDisplayText(params.description, MAX_PLUGIN_APPROVAL_DESCRIPTION_LENGTH),
|
|
28
|
+
severity: params.severity,
|
|
29
|
+
toolName: params.toolName,
|
|
30
|
+
toolCallId: params.toolCallId,
|
|
31
|
+
timeoutMs,
|
|
32
|
+
transportTimeoutMs: resolveCodexGatewayTimeoutWithGraceMs(timeoutMs),
|
|
33
|
+
...params.allowedDecisions ? { allowedDecisions: params.allowedDecisions } : {}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/** Detects the gateway's explicit null-decision marker for unavailable approvals. */
|
|
37
|
+
function approvalRequestExplicitlyUnavailable(result) {
|
|
38
|
+
if (result === null || result === void 0 || typeof result !== "object") return false;
|
|
39
|
+
let descriptor;
|
|
40
|
+
try {
|
|
41
|
+
descriptor = Object.getOwnPropertyDescriptor(result, "decision");
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return descriptor !== void 0 && "value" in descriptor && descriptor.value === null;
|
|
46
|
+
}
|
|
47
|
+
/** Waits for the gateway's final approval decision, respecting turn aborts. */
|
|
48
|
+
async function waitForPluginApprovalDecision(params) {
|
|
49
|
+
const timeoutMs = DEFAULT_CODEX_APPROVAL_TIMEOUT_MS;
|
|
50
|
+
const waitPromise = params.hostCapabilities.waitForApproval({
|
|
51
|
+
approvalId: params.approvalId,
|
|
52
|
+
timeoutMs,
|
|
53
|
+
transportTimeoutMs: resolveCodexGatewayTimeoutWithGraceMs(timeoutMs),
|
|
54
|
+
signal: params.signal
|
|
55
|
+
}).catch((error) => {
|
|
56
|
+
if (isApprovalNotFoundError(error)) return;
|
|
57
|
+
throw error;
|
|
58
|
+
});
|
|
59
|
+
if (!params.signal) return await waitPromise;
|
|
60
|
+
let onAbort;
|
|
61
|
+
const abortPromise = new Promise((_, reject) => {
|
|
62
|
+
if (params.signal.aborted) {
|
|
63
|
+
reject(toErrorObject(params.signal.reason, "Non-Error rejection"));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
onAbort = () => reject(toErrorObject(params.signal.reason, "Non-Error rejection"));
|
|
67
|
+
params.signal.addEventListener("abort", onAbort, { once: true });
|
|
68
|
+
});
|
|
69
|
+
try {
|
|
70
|
+
return await Promise.race([waitPromise, abortPromise]);
|
|
71
|
+
} finally {
|
|
72
|
+
if (onAbort) params.signal.removeEventListener("abort", onAbort);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Converts a gateway exec approval decision into the app-server approval outcome enum. */
|
|
76
|
+
function mapExecDecisionToOutcome(decision) {
|
|
77
|
+
switch (decision) {
|
|
78
|
+
case "allow-once": return "approved-once";
|
|
79
|
+
case "allow-always": return "approved-session";
|
|
80
|
+
case "deny": return "denied";
|
|
81
|
+
default: return "unavailable";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function truncateCodexApprovalDisplayText(value, maxLength) {
|
|
85
|
+
return value.length <= maxLength ? value : `${truncateUtf16Safe(value, maxLength - 3)}...`;
|
|
86
|
+
}
|
|
87
|
+
function stripDanglingCodexApprovalTerminalSequence(value) {
|
|
88
|
+
return value.replace(DANGLING_TERMINAL_SEQUENCE_SUFFIX_RE, "");
|
|
89
|
+
}
|
|
90
|
+
function sanitizeCodexApprovalVisibleText(value, options = {}) {
|
|
91
|
+
const terminalSafe = value.replace(ANSI_OSC_SEQUENCE_RE, "").replace(ANSI_CONTROL_SEQUENCE_RE, "");
|
|
92
|
+
return (options.stripDanglingTerminalSequence ? stripDanglingCodexApprovalTerminalSequence(terminalSafe) : terminalSafe).replace(INVISIBLE_FORMATTING_CONTROL_RE, " ").replace(CONTROL_CHARACTER_RE, " ").replace(/\s+/g, " ").trim();
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { sanitizeCodexApprovalVisibleText as a, waitForPluginApprovalDecision as c, requestPluginApproval as i, codexApprovalTimeoutText as n, stripDanglingCodexApprovalTerminalSequence as o, mapExecDecisionToOutcome as r, truncateCodexApprovalDisplayText as s, approvalRequestExplicitlyUnavailable as t };
|