@openclaw/codex 2026.7.2-beta.4 → 2026.7.2-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-server-policy-BO3jYBkv.js → app-server-policy-BSaO2JIT.js} +1 -1
- package/dist/{attempt-notifications-DdmnBMUp.js → attempt-notifications-AP-a-Q5k.js} +1 -1
- package/dist/{bounded-turn-CaQL96kg.js → bounded-turn-D2ZAgZVz.js} +54 -24
- package/dist/{capabilities-CLICvTxf.js → capabilities-BFDTVYr4.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-DgADqnHa.js → command-formatters-C336eRVS.js} +2 -2
- package/dist/{command-handlers-l_lVPNlB.js → command-handlers-DAHUSry9.js} +1233 -1222
- package/dist/{compact-CC5KhBzX.js → compact-D_uvHurS.js} +8 -8
- package/dist/{computer-use-Ip1-QGa-.js → computer-use-CYEc8U3w.js} +123 -115
- package/dist/{conversation-control-sNPsbTCP.js → conversation-control-xsIeXbo4.js} +6 -6
- package/dist/doctor-contract-api.js +24 -86
- package/dist/{dynamic-tools-CQI3UwqY.js → dynamic-tools-D2gYkSBO.js} +482 -91
- package/dist/effective-mcp-catalog-Bbd98Inw.js +114 -0
- package/dist/{event-projector-usage-D6tE7_qD.js → event-projector-usage-Xp4AlR2k.js} +20 -3
- package/dist/harness.js +19 -14
- package/dist/index.js +292 -328
- package/dist/media-understanding-provider.js +6 -1
- package/dist/{models-BNeMlHgg.js → models-BBMKU4jA.js} +2 -2
- package/dist/{notification-correlation-BGLixv5_.js → notification-correlation-CU6_AnOb.js} +3 -3
- package/dist/{plugin-app-cache-key-CvzvmBRz.js → plugin-app-cache-key-DztPafOA.js} +135 -42
- package/dist/{rate-limits-D0IJT-a6.js → rate-limits-CU-gVCCS.js} +1 -1
- package/dist/{request-BTccUTD3.js → request-qKh331yu.js} +3 -3
- package/dist/{run-attempt--858NXDl.js → run-attempt-CY9WlDLc.js} +1060 -402
- package/dist/{runtime-artifact-C2ITXdhM.js → runtime-artifact-CmtG_t1L.js} +90 -24
- package/dist/{sandbox-guard-D1Wky__S.js → sandbox-guard-NuhpXmPB.js} +4 -0
- package/dist/{session-binding-ZSMX1omP.js → session-binding-BXpo9ymA.js} +1006 -891
- package/dist/{session-catalog-DsKaezgR.js → session-catalog-DyOgR4WH.js} +289 -56
- package/dist/{session-cli-CYJTfRLG.js → session-cli-2PZaFLRh.js} +2 -2
- package/dist/{session-upstream-marker-D7XlI9us.js → session-upstream-marker-B6U7tLw5.js} +1 -1
- package/dist/{settled-turn-finalizer-DHltNgtF.js → settled-turn-finalizer-CXY2Z9dT.js} +19 -6
- package/dist/{shared-client-wmgNFNYp.js → shared-client-DTbvH-XV.js} +1993 -1720
- package/dist/{side-question-BfFZCsJ-.js → side-question-_ulBk1AL.js} +12 -10
- package/dist/{thread-lifecycle-cqrOlJkq.js → thread-lifecycle-DF53ogiA.js} +980 -346
- package/dist/{transcript-mirror-2p7kl6e4.js → transcript-mirror-DzsdNCf5.js} +80 -41
- package/dist/{upstream-session-fork-vPjwkT1i.js → upstream-session-fork-Dy4Xvuoj.js} +3 -3
- package/dist/{usage-DM_I3mPT.js → usage-CQ6GhD5-.js} +3 -3
- package/dist/{web-search-provider.runtime-Bx6HAc_k.js → web-search-provider.runtime-CCFhg2z5.js} +3 -3
- package/package.json +6 -8
- package/npm-shrinkwrap.json +0 -202
- package/dist/{auth-binding-C1czuHPA.js → auth-binding-B4FfbcCg.js} +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-
|
|
5
|
-
import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-
|
|
6
|
-
import { resolveAgentDir, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
|
|
1
|
+
import { W as isJsonObject, a as getLeasedSharedCodexAppServerClient, l as releaseLeasedSharedCodexAppServerClient, v as CodexAppServerRpcError } from "./shared-client-DTbvH-XV.js";
|
|
2
|
+
import { d as sessionBindingIdentity, t as CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS } from "./session-binding-BXpo9ymA.js";
|
|
3
|
+
import { _ as readCodexNotificationItem } from "./attempt-notifications-AP-a-Q5k.js";
|
|
4
|
+
import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-NuhpXmPB.js";
|
|
5
|
+
import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-CU6_AnOb.js";
|
|
7
6
|
import { embeddedAgentLog, resolveCompactionTimeoutMs } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
7
|
+
import { resolveAgentDir as resolveAgentDir$1, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
|
|
8
8
|
//#region extensions/codex/src/app-server/compact.ts
|
|
9
9
|
/**
|
|
10
10
|
* Native Codex app-server compaction bridge for bound OpenClaw sessions.
|
|
@@ -353,7 +353,7 @@ async function compactCodexNativeThread(params, options) {
|
|
|
353
353
|
authProfileId: requestedAuthProfileId ?? binding.authProfileId,
|
|
354
354
|
pluginConfig: options.pluginConfig,
|
|
355
355
|
config,
|
|
356
|
-
agentDir: resolveAgentDir(config, agentId)
|
|
356
|
+
agentDir: resolveAgentDir$1(config, agentId)
|
|
357
357
|
});
|
|
358
358
|
} catch (error) {
|
|
359
359
|
return {
|
|
@@ -371,7 +371,7 @@ async function compactCodexNativeThread(params, options) {
|
|
|
371
371
|
const shouldReleaseDefaultLease = !options.clientFactory;
|
|
372
372
|
const clientFactory = options.clientFactory ?? getLeasedSharedCodexAppServerClient;
|
|
373
373
|
const runtimeAuthPlan = params.runtimeAuthPlan ?? params.runtimePlan?.auth;
|
|
374
|
-
const usesPreparedApiKey = !usesSupervisionConnection && runtimeAuthPlan?.modelRoute?.authRequirement === "api-key";
|
|
374
|
+
const usesPreparedApiKey = !usesSupervisionConnection && appServer.start.homeScope !== "user" && runtimeAuthPlan?.modelRoute?.authRequirement === "api-key";
|
|
375
375
|
const preparedApiKey = usesPreparedApiKey ? params.resolvedApiKey?.trim() : void 0;
|
|
376
376
|
if (usesPreparedApiKey && !preparedApiKey) return {
|
|
377
377
|
ok: false,
|
|
@@ -1,9 +1,91 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { n as describeControlFailure } from "./capabilities-
|
|
4
|
-
import { r as requestCodexAppServerJson } from "./request-
|
|
1
|
+
import { C as isCodexAppServerIndeterminateRequestCancellationError, G as resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath, S as isCodexAppServerConnectionClosedError, _ as acquireCodexNativeConfigFence, a as getLeasedSharedCodexAppServerClient, l as releaseLeasedSharedCodexAppServerClient, u as resolveCodexNativeConfigFenceKey, w as isCodexAppServerIndeterminateTransportError } from "./shared-client-DTbvH-XV.js";
|
|
2
|
+
import { g as resolveCodexAppServerRuntimeOptions, v as resolveCodexComputerUseConfig } from "./session-binding-BXpo9ymA.js";
|
|
3
|
+
import { n as describeControlFailure } from "./capabilities-BFDTVYr4.js";
|
|
4
|
+
import { r as requestCodexAppServerJson } from "./request-qKh331yu.js";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
import { runExec } from "openclaw/plugin-sdk/process-runtime";
|
|
7
|
+
//#region extensions/codex/src/app-server/computer-use-process-repair.ts
|
|
8
|
+
const COMPUTER_USE_PROCESS_LIST_TIMEOUT_MS = 2e3;
|
|
9
|
+
const COMPUTER_USE_PROCESS_LIST_MAX_BUFFER_BYTES = 5 * 1024 * 1024;
|
|
10
|
+
function scopedRepairUnavailableStatus() {
|
|
11
|
+
return {
|
|
12
|
+
attempted: false,
|
|
13
|
+
killedPids: [],
|
|
14
|
+
warnings: ["Computer Use auto-repair skipped because no scoped Codex app-server process was available."],
|
|
15
|
+
message: "Computer Use stale child repair requires a scoped local app-server PID."
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async function killStaleComputerUseMcpChildren(options = {}) {
|
|
19
|
+
if (process.platform !== "darwin") return {
|
|
20
|
+
attempted: true,
|
|
21
|
+
killedPids: [],
|
|
22
|
+
warnings: [`Computer Use stale child repair is currently macOS-only, not ${process.platform}.`],
|
|
23
|
+
message: "Computer Use stale child repair skipped on this platform."
|
|
24
|
+
};
|
|
25
|
+
if (!options.ancestorPid || !Number.isSafeInteger(options.ancestorPid) || options.ancestorPid <= 0) return scopedRepairUnavailableStatus();
|
|
26
|
+
let stdout;
|
|
27
|
+
try {
|
|
28
|
+
stdout = (await runExec("/bin/ps", ["-axo", "pid=,ppid=,command="], {
|
|
29
|
+
logOutput: false,
|
|
30
|
+
maxBuffer: COMPUTER_USE_PROCESS_LIST_MAX_BUFFER_BYTES,
|
|
31
|
+
timeoutMs: COMPUTER_USE_PROCESS_LIST_TIMEOUT_MS
|
|
32
|
+
})).stdout;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return {
|
|
35
|
+
attempted: true,
|
|
36
|
+
killedPids: [],
|
|
37
|
+
warnings: [`Could not list processes for Computer Use repair: ${describeControlFailure(error)}`],
|
|
38
|
+
message: "Computer Use stale child repair could not inspect running processes."
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const killedPids = [];
|
|
42
|
+
const warnings = [];
|
|
43
|
+
const processInfos = parsePsOutput(stdout);
|
|
44
|
+
for (const processInfo of processInfos) {
|
|
45
|
+
if (!isStaleComputerUseMcpChild(processInfo.command)) continue;
|
|
46
|
+
if (!isDescendantOfPid(processInfo.pid, options.ancestorPid, processInfos)) continue;
|
|
47
|
+
try {
|
|
48
|
+
process.kill(processInfo.pid, "SIGTERM");
|
|
49
|
+
killedPids.push(processInfo.pid);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
warnings.push(`Could not terminate stale Computer Use MCP child pid ${processInfo.pid}: ${describeControlFailure(error)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
attempted: true,
|
|
56
|
+
killedPids,
|
|
57
|
+
warnings,
|
|
58
|
+
message: killedPids.length === 0 ? "No stale Computer Use MCP children were found under the scoped Codex app-server process." : `Terminated ${killedPids.length} stale Computer Use MCP child process${killedPids.length === 1 ? "" : "es"} under the scoped Codex app-server process.`
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function parsePsOutput(stdout) {
|
|
62
|
+
return stdout.split(/\r?\n/u).flatMap((line) => {
|
|
63
|
+
const match = /^\s*(\d+)\s+(\d+)\s+(.+)$/u.exec(line);
|
|
64
|
+
if (!match) return [];
|
|
65
|
+
return [{
|
|
66
|
+
pid: Number(match[1]),
|
|
67
|
+
ppid: Number(match[2]),
|
|
68
|
+
command: match[3] ?? ""
|
|
69
|
+
}];
|
|
70
|
+
}).filter((processInfo) => Number.isSafeInteger(processInfo.pid) && processInfo.pid > 0 && Number.isSafeInteger(processInfo.ppid) && processInfo.ppid >= 0);
|
|
71
|
+
}
|
|
72
|
+
function isStaleComputerUseMcpChild(command) {
|
|
73
|
+
return command.includes("SkyComputerUseClient") && /(?:^|\s)mcp(?:\s|$)/u.test(command);
|
|
74
|
+
}
|
|
75
|
+
function isDescendantOfPid(pid, ancestorPid, processInfos) {
|
|
76
|
+
const parents = new Map(processInfos.map((processInfo) => [processInfo.pid, processInfo.ppid]));
|
|
77
|
+
const seen = /* @__PURE__ */ new Set();
|
|
78
|
+
let current = pid;
|
|
79
|
+
while (!seen.has(current)) {
|
|
80
|
+
seen.add(current);
|
|
81
|
+
const parent = parents.get(current);
|
|
82
|
+
if (!parent || parent <= 0) return false;
|
|
83
|
+
if (parent === ancestorPid) return true;
|
|
84
|
+
current = parent;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
7
89
|
//#region extensions/codex/src/app-server/computer-use.ts
|
|
8
90
|
/**
|
|
9
91
|
* Computer Use plugin/MCP readiness checks and optional install flow for Codex
|
|
@@ -20,6 +102,8 @@ const CURATED_MARKETPLACE_POLL_INTERVAL_MS = 2e3;
|
|
|
20
102
|
const COMPUTER_USE_MARKETPLACE_NAME_PRIORITY = [
|
|
21
103
|
"openai-bundled",
|
|
22
104
|
"openai-curated",
|
|
105
|
+
"openai-api-curated",
|
|
106
|
+
"openai-curated-remote",
|
|
23
107
|
"local"
|
|
24
108
|
];
|
|
25
109
|
const COMPUTER_USE_LIVE_TEST_RETRY_COUNT = 1;
|
|
@@ -113,6 +197,7 @@ async function inspectCodexComputerUse(params) {
|
|
|
113
197
|
if (!runtime) throw new Error("Computer Use install could not resolve its app-server runtime");
|
|
114
198
|
client = await getLeasedSharedCodexAppServerClient({
|
|
115
199
|
startOptions: runtime.start,
|
|
200
|
+
pluginConfig: params.pluginConfig,
|
|
116
201
|
timeoutMs: params.timeoutMs ?? runtime.requestTimeoutMs,
|
|
117
202
|
config: params.config,
|
|
118
203
|
agentDir: params.agentDir,
|
|
@@ -178,18 +263,8 @@ async function ensureComputerUsePlugin(params) {
|
|
|
178
263
|
config: params.config,
|
|
179
264
|
plugin,
|
|
180
265
|
tools: [],
|
|
181
|
-
reason: pluginSetupReason(plugin
|
|
182
|
-
message: pluginSetupMessage(params.config, plugin
|
|
183
|
-
})
|
|
184
|
-
};
|
|
185
|
-
if (params.marketplace.kind === "remote") return {
|
|
186
|
-
ok: false,
|
|
187
|
-
status: statusFromPlugin({
|
|
188
|
-
config: params.config,
|
|
189
|
-
plugin,
|
|
190
|
-
tools: [],
|
|
191
|
-
reason: "remote_install_unsupported",
|
|
192
|
-
message: remoteInstallUnsupportedMessage(plugin, params.marketplace)
|
|
266
|
+
reason: pluginSetupReason(plugin),
|
|
267
|
+
message: pluginSetupMessage(params.config, plugin)
|
|
193
268
|
})
|
|
194
269
|
};
|
|
195
270
|
await params.request("plugin/install", pluginRequestParams(params.marketplace, params.config.pluginName));
|
|
@@ -202,8 +277,8 @@ async function ensureComputerUsePlugin(params) {
|
|
|
202
277
|
config: params.config,
|
|
203
278
|
plugin,
|
|
204
279
|
tools: [],
|
|
205
|
-
reason: pluginSetupReason(plugin
|
|
206
|
-
message: pluginSetupMessage(params.config, plugin
|
|
280
|
+
reason: pluginSetupReason(plugin),
|
|
281
|
+
message: pluginSetupMessage(params.config, plugin)
|
|
207
282
|
})
|
|
208
283
|
};
|
|
209
284
|
return {
|
|
@@ -213,9 +288,11 @@ async function ensureComputerUsePlugin(params) {
|
|
|
213
288
|
}
|
|
214
289
|
async function readComputerUseTools(params) {
|
|
215
290
|
let server = await readMcpServerStatus(params.request, params.config.mcpServerName);
|
|
216
|
-
|
|
291
|
+
let tools = Object.keys(server?.tools ?? {}).toSorted();
|
|
292
|
+
if ((!server || tools.length === 0) && params.installPlugin) {
|
|
217
293
|
await reloadMcpServers(params.request);
|
|
218
294
|
server = await readMcpServerStatus(params.request, params.config.mcpServerName);
|
|
295
|
+
tools = Object.keys(server?.tools ?? {}).toSorted();
|
|
219
296
|
}
|
|
220
297
|
if (!server) return statusFromPlugin({
|
|
221
298
|
config: params.config,
|
|
@@ -224,10 +301,17 @@ async function readComputerUseTools(params) {
|
|
|
224
301
|
reason: "mcp_missing",
|
|
225
302
|
message: `Computer Use is installed, but the ${params.config.mcpServerName} MCP server is not available.`
|
|
226
303
|
});
|
|
304
|
+
if (tools.length === 0) return statusFromPlugin({
|
|
305
|
+
config: params.config,
|
|
306
|
+
plugin: params.plugin,
|
|
307
|
+
tools,
|
|
308
|
+
reason: "mcp_missing",
|
|
309
|
+
message: `Computer Use is installed, but the ${params.config.mcpServerName} MCP server exposes no tools.`
|
|
310
|
+
});
|
|
227
311
|
const status = statusFromPlugin({
|
|
228
312
|
config: params.config,
|
|
229
313
|
plugin: params.plugin,
|
|
230
|
-
tools
|
|
314
|
+
tools,
|
|
231
315
|
reason: "ready",
|
|
232
316
|
message: "Computer Use is ready."
|
|
233
317
|
});
|
|
@@ -316,14 +400,6 @@ async function runCodexComputerUseLiveTest(params) {
|
|
|
316
400
|
async function cleanupComputerUseProbeThread(request, threadId, config) {
|
|
317
401
|
await Promise.allSettled([request("thread/unsubscribe", { threadId }, { timeoutMs: config.liveTestTimeoutMs }), request("thread/archive", { threadId }, { timeoutMs: config.liveTestTimeoutMs })]);
|
|
318
402
|
}
|
|
319
|
-
function scopedRepairUnavailableStatus() {
|
|
320
|
-
return {
|
|
321
|
-
attempted: false,
|
|
322
|
-
killedPids: [],
|
|
323
|
-
warnings: ["Computer Use auto-repair skipped because no scoped Codex app-server process was available."],
|
|
324
|
-
message: "Computer Use stale child repair requires a scoped local app-server PID."
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
403
|
async function resolveMarketplaceRef(params) {
|
|
328
404
|
let preferredMarketplaceName = params.config.marketplaceName;
|
|
329
405
|
if (params.config.marketplaceSource && params.allowAdd) {
|
|
@@ -380,17 +456,22 @@ function resolveBundledComputerUseMarketplacePath(params) {
|
|
|
380
456
|
return resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath({ candidates: params.defaultBundledMarketplacePathCandidates });
|
|
381
457
|
}
|
|
382
458
|
function findComputerUseMarketplaces(listed, pluginName) {
|
|
383
|
-
return listed.marketplaces.
|
|
384
|
-
|
|
459
|
+
return listed.marketplaces.flatMap((marketplace) => {
|
|
460
|
+
const plugin = marketplace.plugins.find((candidate) => candidate.name === pluginName || candidate.id === pluginName || candidate.id === `${pluginName}@${marketplace.name}`);
|
|
461
|
+
if (!plugin) return [];
|
|
462
|
+
if (marketplace.path) return [{
|
|
385
463
|
kind: "local",
|
|
386
464
|
name: marketplace.name,
|
|
387
465
|
path: marketplace.path
|
|
388
|
-
};
|
|
389
|
-
|
|
466
|
+
}];
|
|
467
|
+
const remotePluginId = plugin.remotePluginId?.trim();
|
|
468
|
+
if (!remotePluginId) return [];
|
|
469
|
+
return [{
|
|
390
470
|
kind: "remote",
|
|
391
471
|
name: marketplace.name,
|
|
392
|
-
remoteMarketplaceName: marketplace.name
|
|
393
|
-
|
|
472
|
+
remoteMarketplaceName: marketplace.name,
|
|
473
|
+
remotePluginId
|
|
474
|
+
}];
|
|
394
475
|
});
|
|
395
476
|
}
|
|
396
477
|
function chooseKnownComputerUseMarketplace(candidates) {
|
|
@@ -442,25 +523,21 @@ async function reloadMcpServers(request) {
|
|
|
442
523
|
await request("config/mcpServer/reload", void 0);
|
|
443
524
|
}
|
|
444
525
|
function pluginRequestParams(marketplace, pluginName) {
|
|
445
|
-
return {
|
|
446
|
-
|
|
447
|
-
...marketplace.kind === "remote" ? { remoteMarketplaceName: marketplace.remoteMarketplaceName } : {},
|
|
526
|
+
return marketplace.kind === "local" ? {
|
|
527
|
+
marketplacePath: marketplace.path,
|
|
448
528
|
pluginName
|
|
529
|
+
} : {
|
|
530
|
+
remoteMarketplaceName: marketplace.remoteMarketplaceName,
|
|
531
|
+
pluginName: marketplace.remotePluginId
|
|
449
532
|
};
|
|
450
533
|
}
|
|
451
|
-
function pluginSetupReason(plugin
|
|
452
|
-
if (marketplace.kind === "remote") return "remote_install_unsupported";
|
|
534
|
+
function pluginSetupReason(plugin) {
|
|
453
535
|
return plugin.summary.installed ? "plugin_disabled" : "plugin_not_installed";
|
|
454
536
|
}
|
|
455
|
-
function pluginSetupMessage(config, plugin
|
|
456
|
-
if (marketplace.kind === "remote") return remoteInstallUnsupportedMessage(plugin, marketplace);
|
|
537
|
+
function pluginSetupMessage(config, plugin) {
|
|
457
538
|
if (!plugin.summary.installed) return "Computer Use is available but not installed. Run /codex computer-use install or enable computerUse.autoInstall.";
|
|
458
539
|
return `Computer Use is installed, but the ${config.pluginName} plugin is disabled. Run /codex computer-use install or enable computerUse.autoInstall to re-enable it.`;
|
|
459
540
|
}
|
|
460
|
-
function remoteInstallUnsupportedMessage(plugin, marketplace) {
|
|
461
|
-
const marketplaceName = marketplace.name ?? plugin.marketplaceName;
|
|
462
|
-
return `Computer Use is ${plugin.summary.installed ? "installed but disabled" : "available"} in remote Codex marketplace ${marketplaceName}, but Codex app-server does not support remote plugin install yet. Configure computerUse.marketplaceSource or computerUse.marketplacePath for a local marketplace, then run /codex computer-use install.`;
|
|
463
|
-
}
|
|
464
541
|
function statusFromPlugin(params) {
|
|
465
542
|
return {
|
|
466
543
|
enabled: true,
|
|
@@ -582,75 +659,6 @@ function pluginWarnings(plugin) {
|
|
|
582
659
|
if (source && typeof source === "object" && "type" in source && source.type === "remote") warnings.push("Computer Use plugin is resolved from a remote marketplace; live local bundles are preferred.");
|
|
583
660
|
return warnings;
|
|
584
661
|
}
|
|
585
|
-
async function killStaleComputerUseMcpChildren(options = {}) {
|
|
586
|
-
if (process.platform !== "darwin") return {
|
|
587
|
-
attempted: true,
|
|
588
|
-
killedPids: [],
|
|
589
|
-
warnings: [`Computer Use stale child repair is currently macOS-only, not ${process.platform}.`],
|
|
590
|
-
message: "Computer Use stale child repair skipped on this platform."
|
|
591
|
-
};
|
|
592
|
-
if (!options.ancestorPid || !Number.isSafeInteger(options.ancestorPid) || options.ancestorPid <= 0) return scopedRepairUnavailableStatus();
|
|
593
|
-
let stdout;
|
|
594
|
-
try {
|
|
595
|
-
stdout = (await runExec("/bin/ps", ["-axo", "pid=,ppid=,command="], {
|
|
596
|
-
logOutput: false,
|
|
597
|
-
maxBuffer: 5 * 1024 * 1024
|
|
598
|
-
})).stdout;
|
|
599
|
-
} catch (error) {
|
|
600
|
-
return {
|
|
601
|
-
attempted: true,
|
|
602
|
-
killedPids: [],
|
|
603
|
-
warnings: [`Could not list processes for Computer Use repair: ${describeControlFailure(error)}`],
|
|
604
|
-
message: "Computer Use stale child repair could not inspect running processes."
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
const killedPids = [];
|
|
608
|
-
const warnings = [];
|
|
609
|
-
const processInfos = parsePsOutput(stdout);
|
|
610
|
-
for (const processInfo of processInfos) {
|
|
611
|
-
if (!isStaleComputerUseMcpChild(processInfo.command)) continue;
|
|
612
|
-
if (!isDescendantOfPid(processInfo.pid, options.ancestorPid, processInfos)) continue;
|
|
613
|
-
try {
|
|
614
|
-
process.kill(processInfo.pid, "SIGTERM");
|
|
615
|
-
killedPids.push(processInfo.pid);
|
|
616
|
-
} catch (error) {
|
|
617
|
-
warnings.push(`Could not terminate stale Computer Use MCP child pid ${processInfo.pid}: ${describeControlFailure(error)}`);
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
return {
|
|
621
|
-
attempted: true,
|
|
622
|
-
killedPids,
|
|
623
|
-
warnings,
|
|
624
|
-
message: killedPids.length === 0 ? "No stale Computer Use MCP children were found under the scoped Codex app-server process." : `Terminated ${killedPids.length} stale Computer Use MCP child process${killedPids.length === 1 ? "" : "es"} under the scoped Codex app-server process.`
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
function parsePsOutput(stdout) {
|
|
628
|
-
return stdout.split(/\r?\n/u).flatMap((line) => {
|
|
629
|
-
const match = /^\s*(\d+)\s+(\d+)\s+(.+)$/u.exec(line);
|
|
630
|
-
if (!match) return [];
|
|
631
|
-
return [{
|
|
632
|
-
pid: Number(match[1]),
|
|
633
|
-
ppid: Number(match[2]),
|
|
634
|
-
command: match[3] ?? ""
|
|
635
|
-
}];
|
|
636
|
-
}).filter((processInfo) => Number.isSafeInteger(processInfo.pid) && processInfo.pid > 0 && Number.isSafeInteger(processInfo.ppid) && processInfo.ppid >= 0);
|
|
637
|
-
}
|
|
638
|
-
function isStaleComputerUseMcpChild(command) {
|
|
639
|
-
return command.includes("SkyComputerUseClient") && /(?:^|\s)mcp(?:\s|$)/u.test(command);
|
|
640
|
-
}
|
|
641
|
-
function isDescendantOfPid(pid, ancestorPid, processInfos) {
|
|
642
|
-
const parents = new Map(processInfos.map((processInfo) => [processInfo.pid, processInfo.ppid]));
|
|
643
|
-
const seen = /* @__PURE__ */ new Set();
|
|
644
|
-
let current = pid;
|
|
645
|
-
while (!seen.has(current)) {
|
|
646
|
-
seen.add(current);
|
|
647
|
-
const parent = parents.get(current);
|
|
648
|
-
if (!parent || parent <= 0) return false;
|
|
649
|
-
if (parent === ancestorPid) return true;
|
|
650
|
-
current = parent;
|
|
651
|
-
}
|
|
652
|
-
return false;
|
|
653
|
-
}
|
|
654
662
|
function createComputerUseRequest(params) {
|
|
655
663
|
if (params.request) return params.request;
|
|
656
664
|
if (params.client) return async (method, requestParams, options) => await params.client.request(method, requestParams, {
|
|
@@ -682,4 +690,4 @@ function resolveComputerUseConfig(params) {
|
|
|
682
690
|
});
|
|
683
691
|
}
|
|
684
692
|
//#endregion
|
|
685
|
-
export {
|
|
693
|
+
export { killStaleComputerUseMcpChildren as a, runCodexComputerUseLiveTest as i, installCodexComputerUse as n, readCodexComputerUseStatus as r, ensureCodexComputerUse as t };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as getLeasedSharedCodexAppServerClient, c as
|
|
2
|
-
import { T as resolveCodexModelBackedReviewerPolicyContext,
|
|
3
|
-
import {
|
|
4
|
-
import { t as CODEX_CONTROL_METHODS } from "./capabilities-
|
|
5
|
-
import { r as formatCodexDisplayText } from "./command-formatters-
|
|
6
|
-
import { a as resolveCodexBindingAppServerConnection } from "./notification-correlation-
|
|
1
|
+
import { a as getLeasedSharedCodexAppServerClient, c as releaseCodexAppServerClientLease, h as withLeasedCodexAppServerClientStartSelectionRetry, l as releaseLeasedSharedCodexAppServerClient } from "./shared-client-DTbvH-XV.js";
|
|
2
|
+
import { T as resolveCodexModelBackedReviewerPolicyContext, g as resolveCodexAppServerRuntimeOptions, j as isCodexFastServiceTier, o as isCodexAppServerNativeAuthProfile, r as bindingStoreKey, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-BXpo9ymA.js";
|
|
3
|
+
import { S as resolveCodexBindingModelProviderFallback, b as resolveCodexAppServerRequestModelSelection } from "./thread-lifecycle-DF53ogiA.js";
|
|
4
|
+
import { t as CODEX_CONTROL_METHODS } from "./capabilities-BFDTVYr4.js";
|
|
5
|
+
import { r as formatCodexDisplayText } from "./command-formatters-C336eRVS.js";
|
|
6
|
+
import { a as resolveCodexBindingAppServerConnection } from "./notification-correlation-CU6_AnOb.js";
|
|
7
7
|
import { ModelSelectionLockedError } from "openclaw/plugin-sdk/model-session-runtime";
|
|
8
8
|
//#region extensions/codex/src/command-authorization.ts
|
|
9
9
|
const CODEX_NATIVE_EXECUTION_AUTH_ERROR = "Only an owner or operator.admin can control Codex native execution.";
|
|
@@ -3,37 +3,11 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { listAgentIds, resolveAgentDir, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
|
|
5
5
|
import { isDeepStrictEqual } from "node:util";
|
|
6
|
+
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
7
|
import { patchSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
8
|
+
import { canonicalPathFromExistingAncestor, isPathInside, pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
7
9
|
import { withFileLock } from "openclaw/plugin-sdk/file-lock";
|
|
8
|
-
|
|
9
|
-
async function pathExists$1(filePath) {
|
|
10
|
-
try {
|
|
11
|
-
await fs.access(filePath);
|
|
12
|
-
return true;
|
|
13
|
-
} catch {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
async function firstFreeArchivePath(sourcePath) {
|
|
18
|
-
for (let index = 2;; index++) {
|
|
19
|
-
const candidate = `${sourcePath}.migrated.${index}`;
|
|
20
|
-
if (!await pathExists$1(candidate)) return candidate;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
async function archiveBindingSidecar(sourcePath) {
|
|
24
|
-
const archivePath = `${sourcePath}.migrated`;
|
|
25
|
-
if (!await pathExists$1(archivePath)) {
|
|
26
|
-
await fs.rename(sourcePath, archivePath);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
const [sourceBytes, archiveBytes] = await Promise.all([fs.readFile(sourcePath), fs.readFile(archivePath)]);
|
|
30
|
-
if (sourceBytes.equals(archiveBytes)) {
|
|
31
|
-
await fs.rm(sourcePath, { force: true });
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
await fs.rename(sourcePath, await firstFreeArchivePath(sourcePath));
|
|
35
|
-
}
|
|
36
|
-
//#endregion
|
|
10
|
+
import { archiveLegacyStateSource, legacyStateFileExists } from "openclaw/plugin-sdk/runtime-doctor";
|
|
37
11
|
//#region extensions/codex/src/migration/session-binding-sidecars.ts
|
|
38
12
|
const LEGACY_BINDING_SUFFIX = ".codex-app-server.json";
|
|
39
13
|
const CODEX_AGENT_HARNESS_ID = "codex";
|
|
@@ -49,9 +23,9 @@ const LEGACY_BINDING_LOCK_OPTIONS = {
|
|
|
49
23
|
};
|
|
50
24
|
async function collectSessionSurfaces(params) {
|
|
51
25
|
const surfaces = /* @__PURE__ */ new Map();
|
|
52
|
-
const stateRoot = await
|
|
26
|
+
const stateRoot = await canonicalPathFromExistingAncestor(params.stateDir);
|
|
53
27
|
const add = async (root, storePath, agentId, scan) => {
|
|
54
|
-
const canonicalRoot = await
|
|
28
|
+
const canonicalRoot = await canonicalPathFromExistingAncestor(root);
|
|
55
29
|
const surface = surfaces.get(canonicalRoot) ?? {
|
|
56
30
|
root: canonicalRoot,
|
|
57
31
|
scan: false,
|
|
@@ -81,7 +55,7 @@ async function collectSessionSurfaces(params) {
|
|
|
81
55
|
env: params.env
|
|
82
56
|
});
|
|
83
57
|
const root = path.dirname(storePath);
|
|
84
|
-
await add(root, storePath, agentId,
|
|
58
|
+
await add(root, storePath, agentId, isPathInside(stateRoot, await canonicalPathFromExistingAncestor(root)));
|
|
85
59
|
}
|
|
86
60
|
const legacyRoot = path.join(params.stateDir, "sessions");
|
|
87
61
|
const defaultAgentId = resolveSessionAgentIds({ config: params.config }).defaultAgentId;
|
|
@@ -92,7 +66,7 @@ async function collectLegacyBindingSources(params, options = {}) {
|
|
|
92
66
|
const surfaces = await collectSessionSurfaces(params);
|
|
93
67
|
const sources = /* @__PURE__ */ new Map();
|
|
94
68
|
const addSource = async (sidecarPath, surface) => {
|
|
95
|
-
const canonicalSidecar = await
|
|
69
|
+
const canonicalSidecar = await canonicalPathFromExistingAncestor(sidecarPath);
|
|
96
70
|
const source = sources.get(canonicalSidecar) ?? {
|
|
97
71
|
sidecarPath: canonicalSidecar,
|
|
98
72
|
transcriptPath: sidecarPath.slice(0, -22),
|
|
@@ -167,7 +141,7 @@ async function* iterateIndexedSidecars(surface) {
|
|
|
167
141
|
continue;
|
|
168
142
|
}
|
|
169
143
|
const sidecarPath = `${transcriptPath}${LEGACY_BINDING_SUFFIX}`;
|
|
170
|
-
if (await
|
|
144
|
+
if (await legacyStateFileExists(sidecarPath)) yield sidecarPath;
|
|
171
145
|
}
|
|
172
146
|
}
|
|
173
147
|
}
|
|
@@ -190,7 +164,7 @@ async function* walkSidecars(root) {
|
|
|
190
164
|
}
|
|
191
165
|
}
|
|
192
166
|
async function collectBindingOwners(sources, surfaces, params) {
|
|
193
|
-
const sourcePaths = new Set(await Promise.all(sources.map((source) =>
|
|
167
|
+
const sourcePaths = new Set(await Promise.all(sources.map((source) => canonicalPathFromExistingAncestor(source.transcriptPath))));
|
|
194
168
|
const owners = /* @__PURE__ */ new Map();
|
|
195
169
|
const storePaths = new Set(surfaces.flatMap((surface) => [...surface.storePaths]));
|
|
196
170
|
const storeAgentIds = /* @__PURE__ */ new Map();
|
|
@@ -201,7 +175,7 @@ async function collectBindingOwners(sources, surfaces, params) {
|
|
|
201
175
|
}
|
|
202
176
|
const failures = [];
|
|
203
177
|
for (const storePath of storePaths) {
|
|
204
|
-
const canonicalStorePath = await
|
|
178
|
+
const canonicalStorePath = await canonicalPathFromExistingAncestor(storePath);
|
|
205
179
|
const index = await readLegacySessionIndex(storePath);
|
|
206
180
|
if ("failure" in index) {
|
|
207
181
|
failures.push(index.failure);
|
|
@@ -219,7 +193,7 @@ async function collectBindingOwners(sources, surfaces, params) {
|
|
|
219
193
|
let canonicalLegacyTranscriptPath;
|
|
220
194
|
try {
|
|
221
195
|
legacyTranscriptPath = await resolveLegacySessionFileLocator(sessionsDir, entry, sessionId);
|
|
222
|
-
canonicalLegacyTranscriptPath = await
|
|
196
|
+
canonicalLegacyTranscriptPath = await canonicalPathFromExistingAncestor(legacyTranscriptPath);
|
|
223
197
|
} catch {
|
|
224
198
|
failures.push(`session index ${storePath} has an invalid locator for ${sessionKey}`);
|
|
225
199
|
continue;
|
|
@@ -256,8 +230,8 @@ async function resolveLegacySessionFileLocator(sessionsDir, entry, sessionId) {
|
|
|
256
230
|
const sessionFile = entry.sessionFile?.trim();
|
|
257
231
|
if (!sessionFile) return fallback;
|
|
258
232
|
const candidate = path.resolve(base, sessionFile);
|
|
259
|
-
const [canonicalBase, canonicalCandidate] = await Promise.all([
|
|
260
|
-
if (!
|
|
233
|
+
const [canonicalBase, canonicalCandidate] = await Promise.all([canonicalPathFromExistingAncestor(base), canonicalPathFromExistingAncestor(candidate)]);
|
|
234
|
+
if (!isPathInside(canonicalBase, canonicalCandidate)) throw new Error("legacy session file locator escapes its session directory");
|
|
261
235
|
return candidate;
|
|
262
236
|
}
|
|
263
237
|
function resolveLegacyBindingOwnerAgentId(params) {
|
|
@@ -302,7 +276,7 @@ async function migrateSource(source, candidates, params, store) {
|
|
|
302
276
|
return await withFileLock(source.sidecarPath, LEGACY_BINDING_LOCK_OPTIONS, async () => {
|
|
303
277
|
const [contents, stat] = await Promise.all([fs.readFile(source.sidecarPath, "utf8"), fs.stat(source.sidecarPath)]);
|
|
304
278
|
const raw = JSON.parse(contents);
|
|
305
|
-
const [{ bindingStoreKey, createStoredCodexAppServerBinding, normalizeStoredCodexAppServerBindingFingerprints, readStoredCodexAppServerBinding }, { legacyCodexConversationBindingId }] = await Promise.all([import("./session-binding-
|
|
279
|
+
const [{ bindingStoreKey, createStoredCodexAppServerBinding, normalizeStoredCodexAppServerBindingFingerprints, readStoredCodexAppServerBinding }, { legacyCodexConversationBindingId }] = await Promise.all([import("./session-binding-BXpo9ymA.js").then((n) => n.f), import("./conversation-binding-data-BHRpYbX3.js").then((n) => n.t)]);
|
|
306
280
|
const agentId = owner?.agentId ?? (source.agentIds.size === 1 ? [...source.agentIds][0] : void 0);
|
|
307
281
|
const baseStored = createStoredCodexAppServerBinding(raw, {
|
|
308
282
|
now: stat.mtime.toISOString(),
|
|
@@ -402,7 +376,14 @@ async function migrateSource(source, candidates, params, store) {
|
|
|
402
376
|
}
|
|
403
377
|
for (const entry of entries) if (!hasExpected(await store.lookup(entry.key), entry.value)) return retain(`canonical plugin state changed at ${entry.key}`);
|
|
404
378
|
}
|
|
405
|
-
|
|
379
|
+
const archiveWarnings = [];
|
|
380
|
+
await archiveLegacyStateSource({
|
|
381
|
+
filePath: source.sidecarPath,
|
|
382
|
+
label: "Codex app-server binding",
|
|
383
|
+
changes: [],
|
|
384
|
+
warnings: archiveWarnings
|
|
385
|
+
});
|
|
386
|
+
if (archiveWarnings.length > 0 && await pathExists(source.sidecarPath)) return retain(archiveWarnings.join("; "));
|
|
406
387
|
return {
|
|
407
388
|
archived: true,
|
|
408
389
|
importedKeys
|
|
@@ -427,7 +408,7 @@ async function recordSessionOwner(owner, env) {
|
|
|
427
408
|
} catch {
|
|
428
409
|
return "its session owner changed before Codex ownership could be recorded";
|
|
429
410
|
}
|
|
430
|
-
if (await
|
|
411
|
+
if (await canonicalPathFromExistingAncestor(currentTranscriptPath) !== await canonicalPathFromExistingAncestor(owner.transcriptPath) || currentOwner.entry.lifecycleRevision !== owner.lifecycleRevision) return "its session owner changed before Codex ownership could be recorded";
|
|
431
412
|
const legacyHarnessId = currentOwner.entry.agentHarnessId?.trim();
|
|
432
413
|
if (currentOwner.entry.agentHarnessId !== void 0 && !legacyHarnessId) return "its session owner changed before Codex ownership could be recorded";
|
|
433
414
|
if (legacyHarnessId && legacyHarnessId !== CODEX_AGENT_HARNESS_ID) return `its session is owned by agent harness ${legacyHarnessId}`;
|
|
@@ -474,54 +455,11 @@ async function readDirectoryEntries(directory) {
|
|
|
474
455
|
throw error;
|
|
475
456
|
}
|
|
476
457
|
}
|
|
477
|
-
async function isRegularFile(filePath) {
|
|
478
|
-
try {
|
|
479
|
-
return (await fs.stat(filePath)).isFile();
|
|
480
|
-
} catch {
|
|
481
|
-
return false;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
function isRecord(value) {
|
|
485
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
486
|
-
}
|
|
487
458
|
function isSafeLegacySessionId(value) {
|
|
488
459
|
if (typeof value !== "string") return false;
|
|
489
460
|
const trimmed = value.trim();
|
|
490
461
|
return trimmed.length > 0 && trimmed.length <= 255 && /^[A-Za-z0-9][A-Za-z0-9._:@-]*$/.test(trimmed);
|
|
491
462
|
}
|
|
492
|
-
function isPathWithin(root, candidate) {
|
|
493
|
-
const relative = path.relative(root, candidate);
|
|
494
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
495
|
-
}
|
|
496
|
-
async function canonicalizePath(filePath) {
|
|
497
|
-
try {
|
|
498
|
-
return await fs.realpath(filePath);
|
|
499
|
-
} catch {
|
|
500
|
-
return path.resolve(filePath);
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
async function canonicalizePathForContainment(filePath) {
|
|
504
|
-
const resolved = path.resolve(filePath);
|
|
505
|
-
const suffix = [];
|
|
506
|
-
let probe = resolved;
|
|
507
|
-
while (true) try {
|
|
508
|
-
const realProbe = await fs.realpath(probe);
|
|
509
|
-
return suffix.length === 0 ? realProbe : path.join(realProbe, ...suffix.toReversed());
|
|
510
|
-
} catch {
|
|
511
|
-
const parent = path.dirname(probe);
|
|
512
|
-
if (parent === probe) return resolved;
|
|
513
|
-
suffix.push(path.basename(probe));
|
|
514
|
-
probe = parent;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
async function pathExists(filePath) {
|
|
518
|
-
try {
|
|
519
|
-
await fs.access(filePath);
|
|
520
|
-
return true;
|
|
521
|
-
} catch {
|
|
522
|
-
return false;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
463
|
const stateMigrations = [{
|
|
526
464
|
id: "codex-app-server-sidecars-to-plugin-state",
|
|
527
465
|
label: "Codex app-server thread bindings",
|
|
@@ -554,7 +492,7 @@ const stateMigrations = [{
|
|
|
554
492
|
let migrated = 0;
|
|
555
493
|
let partialImports = 0;
|
|
556
494
|
for (const source of sources) {
|
|
557
|
-
const result = await migrateSource(source, ownerCollection.owners.get(await
|
|
495
|
+
const result = await migrateSource(source, ownerCollection.owners.get(await canonicalPathFromExistingAncestor(source.transcriptPath)) ?? [], params, store);
|
|
558
496
|
if (result.warning) warnings.push(result.warning);
|
|
559
497
|
if (result.notice) notices.push(result.notice);
|
|
560
498
|
if (result.archived) migrated++;
|