@openclaw/acpx 2026.7.1 → 2026.7.2-beta.2
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/config-schema-lrk5nlcV.js +39 -0
- package/dist/index.js +1049 -2
- package/dist/{process-reaper-cncoDfwV.js → process-reaper-CoGRyMJ_.js} +40 -50
- package/dist/{register.runtime-Yz704dK5.js → register.runtime-CysfMsSr.js} +1 -1
- package/dist/register.runtime.js +1 -1
- package/dist/{runtime-WjNm2DKO.js → runtime-BEOGc4Ik.js} +51 -54
- package/dist/{service-CzJr7Koj.js → service-DJchyiuU.js} +221 -49
- package/dist/setup-api.js +1 -1
- package/npm-shrinkwrap.json +299 -58
- package/openclaw.plugin.json +13 -3
- package/package.json +6 -5
- package/skills/acp-router/SKILL.md +1 -1
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import { n as createLazyAcpRuntimeProxy } from "./register.runtime-
|
|
1
|
+
import { n as createLazyAcpRuntimeProxy } from "./register.runtime-CysfMsSr.js";
|
|
2
|
+
import "./config-schema-lrk5nlcV.js";
|
|
2
3
|
import { a as createAcpxProcessLeaseStore, d as ACPX_GATEWAY_INSTANCE_KEY, f as ACPX_GATEWAY_INSTANCE_NAMESPACE, h as normalizeAcpxGatewayInstanceRecord, l as openAcpxProcessLeaseStateStore, n as OPENCLAW_ACPX_LEASE_ID_ENV, r as OPENCLAW_GATEWAY_INSTANCE_ID_ARG, t as OPENCLAW_ACPX_LEASE_ID_ARG } from "./process-lease-DiKkFj6F.js";
|
|
3
4
|
import { registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "./runtime-api.js";
|
|
4
|
-
import { a as resolveAcpxPluginRoot, c as splitCommandParts, i as resolveAcpxPluginConfig, o as toAcpMcpServers, r as reapStaleOpenClawOwnedAcpxOrphans, s as quoteCommandPart, t as cleanupOpenClawOwnedAcpxProcessTree } from "./process-reaper-
|
|
5
|
+
import { a as resolveAcpxPluginRoot, c as splitCommandParts, d as LEGACY_CODEX_ACP_PACKAGE, f as OPENCLAW_CODEX_CONFIG_ARG, i as resolveAcpxPluginConfig, l as CODEX_ACP_BIN, o as toAcpMcpServers, r as reapStaleOpenClawOwnedAcpxOrphans, s as quoteCommandPart, t as cleanupOpenClawOwnedAcpxProcessTree, u as CODEX_ACP_PACKAGE } from "./process-reaper-CoGRyMJ_.js";
|
|
5
6
|
import { createRequire } from "node:module";
|
|
7
|
+
import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
|
|
6
8
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
7
|
-
import
|
|
9
|
+
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import fs$1 from "node:fs/promises";
|
|
8
12
|
import path from "node:path";
|
|
13
|
+
import os from "node:os";
|
|
9
14
|
import { randomUUID } from "node:crypto";
|
|
10
|
-
import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
|
|
11
15
|
import { inspect } from "node:util";
|
|
12
|
-
import fs$1 from "node:fs";
|
|
13
16
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
14
|
-
import os from "node:os";
|
|
15
17
|
import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
|
|
18
|
+
import { parse, stringify } from "smol-toml";
|
|
16
19
|
//#region extensions/acpx/src/codex-trust-config.ts
|
|
17
20
|
/**
|
|
18
21
|
* Builds isolated Codex config for ACPX sessions. It preserves safe inherited
|
|
@@ -123,9 +126,11 @@ function extractTrustedCodexProjectPaths(configToml) {
|
|
|
123
126
|
continue;
|
|
124
127
|
}
|
|
125
128
|
const assignment = /^(?<key>"(?:\\.|[^"\\])*"|'[^']*'|[A-Za-z0-9_\-/.~:]+)\s*=\s*(?<value>.+)$/.exec(line);
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
+
const rawKey = assignment?.groups?.key;
|
|
130
|
+
const rawValue = assignment?.groups?.value;
|
|
131
|
+
if (!rawKey || rawValue === void 0) continue;
|
|
132
|
+
const key = parseTomlString(rawKey) ?? rawKey;
|
|
133
|
+
const value = rawValue.trim();
|
|
129
134
|
if (inProjectsTable && /^\{.*\}$/.test(value)) {
|
|
130
135
|
if (/\btrust_level\s*=\s*["']trusted["']/.test(value) && key) trusted.add(key);
|
|
131
136
|
continue;
|
|
@@ -221,15 +226,13 @@ function renderIsolatedCodexConfig(params) {
|
|
|
221
226
|
* Prepares isolated Codex and Claude ACP wrapper commands for ACPX. The bridge
|
|
222
227
|
* copies safe auth/config state into plugin-owned homes and redacts diagnostics.
|
|
223
228
|
*/
|
|
224
|
-
const CODEX_ACP_PACKAGE = "@zed-industries/codex-acp";
|
|
225
|
-
const CODEX_ACP_BIN = "codex-acp";
|
|
226
229
|
const CLAUDE_ACP_PACKAGE = "@agentclientprotocol/claude-agent-acp";
|
|
227
230
|
const CLAUDE_ACP_BIN = "claude-agent-acp";
|
|
228
231
|
const RUN_CONFIGURED_COMMAND_SENTINEL = "--openclaw-run-configured";
|
|
229
232
|
const requireFromHere = createRequire(import.meta.url);
|
|
230
233
|
function readSelfManifest() {
|
|
231
234
|
const manifestPath = path.join(resolveAcpxPluginRoot(import.meta.url), "package.json");
|
|
232
|
-
return JSON.parse(fs
|
|
235
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
233
236
|
}
|
|
234
237
|
function readManifestDependencyVersion(packageName) {
|
|
235
238
|
const version = readSelfManifest().dependencies?.[packageName];
|
|
@@ -254,7 +257,7 @@ async function resolveInstalledAcpPackageBinPath(packageName, binName) {
|
|
|
254
257
|
if (manifest.name !== packageName) return;
|
|
255
258
|
const binPath = resolvePackageBinPath(packageJsonPath, manifest, binName);
|
|
256
259
|
if (!binPath) return;
|
|
257
|
-
await fs.access(binPath);
|
|
260
|
+
await fs$1.access(binPath);
|
|
258
261
|
return binPath;
|
|
259
262
|
} catch {
|
|
260
263
|
return;
|
|
@@ -378,9 +381,10 @@ function renderDiagnosticRedactionRuleSpecs() {
|
|
|
378
381
|
}
|
|
379
382
|
function buildAdapterWrapperScript(params) {
|
|
380
383
|
return `#!/usr/bin/env node
|
|
381
|
-
import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
384
|
+
import { appendFileSync, existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
382
385
|
import path from "node:path";
|
|
383
386
|
import { spawn } from "node:child_process";
|
|
387
|
+
import { StringDecoder } from "node:string_decoder";
|
|
384
388
|
import { fileURLToPath } from "node:url";
|
|
385
389
|
|
|
386
390
|
${params.envSetup}
|
|
@@ -390,6 +394,7 @@ const stderrLogMaxChars = 256 * 1024;
|
|
|
390
394
|
const openClawWrapperArgs = new Set([
|
|
391
395
|
${quoteCommandPart(OPENCLAW_ACPX_LEASE_ID_ARG)},
|
|
392
396
|
${quoteCommandPart(OPENCLAW_GATEWAY_INSTANCE_ID_ARG)},
|
|
397
|
+
${(params.openClawWrapperArgs ?? []).map(quoteCommandPart).join(",\n ")}
|
|
393
398
|
]);
|
|
394
399
|
|
|
395
400
|
function readOpenClawWrapperArg(args, name) {
|
|
@@ -401,6 +406,21 @@ function readOpenClawWrapperArg(args, name) {
|
|
|
401
406
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
402
407
|
}
|
|
403
408
|
|
|
409
|
+
function readOpenClawWrapperArgs(args, name) {
|
|
410
|
+
const values = [];
|
|
411
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
412
|
+
if (args[index] !== name) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const value = args[index + 1];
|
|
416
|
+
if (typeof value === "string" && value.trim()) {
|
|
417
|
+
values.push(value.trim());
|
|
418
|
+
}
|
|
419
|
+
index += 1;
|
|
420
|
+
}
|
|
421
|
+
return values;
|
|
422
|
+
}
|
|
423
|
+
|
|
404
424
|
function safeDiagnosticFilePart(value) {
|
|
405
425
|
const sanitized = String(value || "").replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 120);
|
|
406
426
|
return sanitized || "pid-" + process.pid;
|
|
@@ -431,7 +451,25 @@ function redactDiagnosticText(text) {
|
|
|
431
451
|
return redacted;
|
|
432
452
|
}
|
|
433
453
|
|
|
454
|
+
function tailUtf16Safe(text, maxChars) {
|
|
455
|
+
let start = Math.max(0, text.length - maxChars);
|
|
456
|
+
const startsInsideSurrogatePair =
|
|
457
|
+
start > 0 &&
|
|
458
|
+
start < text.length &&
|
|
459
|
+
text.charCodeAt(start) >= 0xdc00 &&
|
|
460
|
+
text.charCodeAt(start) <= 0xdfff &&
|
|
461
|
+
text.charCodeAt(start - 1) >= 0xd800 &&
|
|
462
|
+
text.charCodeAt(start - 1) <= 0xdbff;
|
|
463
|
+
if (startsInsideSurrogatePair) {
|
|
464
|
+
start += 1;
|
|
465
|
+
}
|
|
466
|
+
return text.slice(start);
|
|
467
|
+
}
|
|
468
|
+
|
|
434
469
|
let pendingStderrLogText = "";
|
|
470
|
+
// Pipe chunks can split a UTF-8 sequence. Preserve decoder state so diagnostic
|
|
471
|
+
// capture does not manufacture replacement characters between chunks.
|
|
472
|
+
const stderrDecoder = new StringDecoder("utf8");
|
|
435
473
|
const stderrPrivateKeyEndPattern = /-----END [A-Z ]*PRIVATE KEY-----/;
|
|
436
474
|
|
|
437
475
|
function hasUnclosedPrivateKeyBlock(text) {
|
|
@@ -456,7 +494,7 @@ function writeRedactedStderrLog(text) {
|
|
|
456
494
|
appendFileSync(stderrLogPath, redactDiagnosticText(text), "utf8");
|
|
457
495
|
const current = readFileSync(stderrLogPath, "utf8");
|
|
458
496
|
if (current.length > stderrLogMaxChars) {
|
|
459
|
-
writeFileSync(stderrLogPath, current
|
|
497
|
+
writeFileSync(stderrLogPath, tailUtf16Safe(current, stderrLogMaxChars), "utf8");
|
|
460
498
|
}
|
|
461
499
|
} catch {
|
|
462
500
|
// Stderr capture is diagnostic-only; never break the ACP adapter.
|
|
@@ -475,7 +513,7 @@ function flushFinalizedStderrLogText() {
|
|
|
475
513
|
const lastLineBreak = pendingStderrLogText.lastIndexOf("\\n");
|
|
476
514
|
if (lastLineBreak === -1) {
|
|
477
515
|
if (pendingStderrLogText.length > stderrLogMaxChars) {
|
|
478
|
-
pendingStderrLogText = pendingStderrLogText
|
|
516
|
+
pendingStderrLogText = tailUtf16Safe(pendingStderrLogText, stderrLogMaxChars);
|
|
479
517
|
}
|
|
480
518
|
return;
|
|
481
519
|
}
|
|
@@ -488,7 +526,7 @@ function flushFinalizedStderrLogText() {
|
|
|
488
526
|
}
|
|
489
527
|
if (flushEnd <= 0) {
|
|
490
528
|
if (pendingStderrLogText.length > stderrLogMaxChars) {
|
|
491
|
-
pendingStderrLogText = pendingStderrLogText
|
|
529
|
+
pendingStderrLogText = tailUtf16Safe(pendingStderrLogText, stderrLogMaxChars);
|
|
492
530
|
}
|
|
493
531
|
return;
|
|
494
532
|
}
|
|
@@ -498,7 +536,7 @@ function flushFinalizedStderrLogText() {
|
|
|
498
536
|
}
|
|
499
537
|
|
|
500
538
|
function appendStderrLog(chunk) {
|
|
501
|
-
const text =
|
|
539
|
+
const text = stderrDecoder.write(chunk);
|
|
502
540
|
if (!text) {
|
|
503
541
|
return;
|
|
504
542
|
}
|
|
@@ -507,6 +545,7 @@ function appendStderrLog(chunk) {
|
|
|
507
545
|
}
|
|
508
546
|
|
|
509
547
|
function finishStderrLog() {
|
|
548
|
+
pendingStderrLogText += stderrDecoder.end();
|
|
510
549
|
const text = redactIncompletePrivateKeyTail(pendingStderrLogText);
|
|
511
550
|
pendingStderrLogText = "";
|
|
512
551
|
writeRedactedStderrLog(text);
|
|
@@ -526,14 +565,14 @@ function stripOpenClawWrapperArgs(args) {
|
|
|
526
565
|
}
|
|
527
566
|
|
|
528
567
|
const rawConfiguredArgs = process.argv.slice(2);
|
|
568
|
+
${params.envConfigSetup ?? ""}
|
|
529
569
|
const stderrLogPath = resolveStderrLogPath(rawConfiguredArgs);
|
|
530
|
-
|
|
531
|
-
try {
|
|
532
|
-
|
|
533
|
-
|
|
570
|
+
if (stderrLogPath) {
|
|
571
|
+
try {
|
|
572
|
+
rmSync(stderrLogPath, { force: true });
|
|
573
|
+
} catch {
|
|
574
|
+
// Diagnostic cleanup must never prevent the adapter from starting.
|
|
534
575
|
}
|
|
535
|
-
} catch {
|
|
536
|
-
// Stderr capture is diagnostic-only; never break the ACP adapter.
|
|
537
576
|
}
|
|
538
577
|
|
|
539
578
|
const configuredArgs = stripOpenClawWrapperArgs(rawConfiguredArgs);
|
|
@@ -682,6 +721,7 @@ function buildCodexAcpWrapperScript(installedBinPath) {
|
|
|
682
721
|
binName: CODEX_ACP_BIN,
|
|
683
722
|
installedBinPath,
|
|
684
723
|
stderrLogFileNamePrefix: "codex-acp-wrapper.stderr",
|
|
724
|
+
openClawWrapperArgs: [OPENCLAW_CODEX_CONFIG_ARG],
|
|
685
725
|
envSetup: `const codexHome = fileURLToPath(new URL("./codex-home/", import.meta.url));
|
|
686
726
|
const codexAuthPath = fileURLToPath(new URL("./codex-home/auth.json", import.meta.url));
|
|
687
727
|
const codexApiKey = (process.env.CODEX_API_KEY || process.env.OPENAI_API_KEY || "").trim();
|
|
@@ -715,7 +755,59 @@ if (shouldWriteCodexApiKeyAuth) {
|
|
|
715
755
|
const env = {
|
|
716
756
|
...process.env,
|
|
717
757
|
CODEX_HOME: codexHome,
|
|
718
|
-
}
|
|
758
|
+
};`,
|
|
759
|
+
envConfigSetup: `function isCodexConfigObject(value) {
|
|
760
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function mergeCodexConfig(base, override) {
|
|
764
|
+
const merged = Object.assign(Object.create(null), base);
|
|
765
|
+
for (const [key, value] of Object.entries(override)) {
|
|
766
|
+
const existing = merged[key];
|
|
767
|
+
merged[key] =
|
|
768
|
+
isCodexConfigObject(existing) && isCodexConfigObject(value)
|
|
769
|
+
? mergeCodexConfig(existing, value)
|
|
770
|
+
: value;
|
|
771
|
+
}
|
|
772
|
+
return merged;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
const openClawCodexConfigs = readOpenClawWrapperArgs(
|
|
776
|
+
rawConfiguredArgs,
|
|
777
|
+
${quoteCommandPart(OPENCLAW_CODEX_CONFIG_ARG)},
|
|
778
|
+
);
|
|
779
|
+
if (openClawCodexConfigs.length > 0) {
|
|
780
|
+
let existingCodexConfig = {};
|
|
781
|
+
if (typeof env.CODEX_CONFIG === "string" && env.CODEX_CONFIG.trim()) {
|
|
782
|
+
try {
|
|
783
|
+
const parsedCodexConfig = JSON.parse(env.CODEX_CONFIG);
|
|
784
|
+
if (!parsedCodexConfig || typeof parsedCodexConfig !== "object" || Array.isArray(parsedCodexConfig)) {
|
|
785
|
+
throw new Error("CODEX_CONFIG must be a JSON object");
|
|
786
|
+
}
|
|
787
|
+
existingCodexConfig = parsedCodexConfig;
|
|
788
|
+
} catch {
|
|
789
|
+
console.error("[openclaw] CODEX_CONFIG must be a valid JSON object");
|
|
790
|
+
process.exit(1);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
for (const openClawCodexConfig of openClawCodexConfigs) {
|
|
794
|
+
try {
|
|
795
|
+
const parsedOpenClawCodexConfig = JSON.parse(openClawCodexConfig);
|
|
796
|
+
if (
|
|
797
|
+
!parsedOpenClawCodexConfig ||
|
|
798
|
+
typeof parsedOpenClawCodexConfig !== "object" ||
|
|
799
|
+
Array.isArray(parsedOpenClawCodexConfig)
|
|
800
|
+
) {
|
|
801
|
+
throw new Error("invalid OpenClaw Codex config");
|
|
802
|
+
}
|
|
803
|
+
existingCodexConfig = mergeCodexConfig(existingCodexConfig, parsedOpenClawCodexConfig);
|
|
804
|
+
} catch {
|
|
805
|
+
console.error("[openclaw] invalid generated Codex ACP startup config");
|
|
806
|
+
process.exit(1);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
env.CODEX_CONFIG = JSON.stringify(existingCodexConfig);
|
|
810
|
+
}`
|
|
719
811
|
});
|
|
720
812
|
}
|
|
721
813
|
function buildClaudeAcpWrapperScript(installedBinPath) {
|
|
@@ -731,7 +823,7 @@ function buildClaudeAcpWrapperScript(installedBinPath) {
|
|
|
731
823
|
}
|
|
732
824
|
async function readSourceCodexConfig(codexHome) {
|
|
733
825
|
try {
|
|
734
|
-
return await fs.readFile(path.join(codexHome, "config.toml"), "utf8");
|
|
826
|
+
return await fs$1.readFile(path.join(codexHome, "config.toml"), "utf8");
|
|
735
827
|
} catch (error) {
|
|
736
828
|
if (error.code === "ENOENT") return;
|
|
737
829
|
throw error;
|
|
@@ -741,8 +833,8 @@ async function prepareIsolatedCodexHome(params) {
|
|
|
741
833
|
const sourceConfig = await readSourceCodexConfig(process.env.CODEX_HOME || path.join(os.homedir(), ".codex"));
|
|
742
834
|
const trustedProjectPaths = [...sourceConfig ? extractTrustedCodexProjectPaths(sourceConfig) : [], params.workspaceDir];
|
|
743
835
|
const codexHome = path.join(params.baseDir, "codex-home");
|
|
744
|
-
await fs.mkdir(codexHome, { recursive: true });
|
|
745
|
-
await fs.writeFile(path.join(codexHome, "config.toml"), renderIsolatedCodexConfig({
|
|
836
|
+
await fs$1.mkdir(codexHome, { recursive: true });
|
|
837
|
+
await fs$1.writeFile(path.join(codexHome, "config.toml"), renderIsolatedCodexConfig({
|
|
746
838
|
sourceConfigToml: sourceConfig,
|
|
747
839
|
projectPaths: trustedProjectPaths
|
|
748
840
|
}), "utf8");
|
|
@@ -750,20 +842,20 @@ async function prepareIsolatedCodexHome(params) {
|
|
|
750
842
|
}
|
|
751
843
|
async function makeGeneratedWrapperExecutableIfPossible(wrapperPath) {
|
|
752
844
|
try {
|
|
753
|
-
await fs.chmod(wrapperPath, 493);
|
|
845
|
+
await fs$1.chmod(wrapperPath, 493);
|
|
754
846
|
} catch {}
|
|
755
847
|
}
|
|
756
848
|
async function writeCodexAcpWrapper(baseDir, installedBinPath) {
|
|
757
|
-
await fs.mkdir(baseDir, { recursive: true });
|
|
849
|
+
await fs$1.mkdir(baseDir, { recursive: true });
|
|
758
850
|
const wrapperPath = path.join(baseDir, "codex-acp-wrapper.mjs");
|
|
759
|
-
await fs.writeFile(wrapperPath, buildCodexAcpWrapperScript(installedBinPath), { encoding: "utf8" });
|
|
851
|
+
await fs$1.writeFile(wrapperPath, buildCodexAcpWrapperScript(installedBinPath), { encoding: "utf8" });
|
|
760
852
|
await makeGeneratedWrapperExecutableIfPossible(wrapperPath);
|
|
761
853
|
return wrapperPath;
|
|
762
854
|
}
|
|
763
855
|
async function writeClaudeAcpWrapper(baseDir, installedBinPath) {
|
|
764
|
-
await fs.mkdir(baseDir, { recursive: true });
|
|
856
|
+
await fs$1.mkdir(baseDir, { recursive: true });
|
|
765
857
|
const wrapperPath = path.join(baseDir, "claude-agent-acp-wrapper.mjs");
|
|
766
|
-
await fs.writeFile(wrapperPath, buildClaudeAcpWrapperScript(installedBinPath), { encoding: "utf8" });
|
|
858
|
+
await fs$1.writeFile(wrapperPath, buildClaudeAcpWrapperScript(installedBinPath), { encoding: "utf8" });
|
|
767
859
|
await makeGeneratedWrapperExecutableIfPossible(wrapperPath);
|
|
768
860
|
return wrapperPath;
|
|
769
861
|
}
|
|
@@ -802,15 +894,94 @@ function extractConfiguredAdapterArgs(params) {
|
|
|
802
894
|
if (isAcpBinName(parts[0] ?? "", params.binName)) return parts.slice(1);
|
|
803
895
|
if (basename(parts[0] ?? "") === "node" && isAcpBinName(parts[1] ?? "", params.binName)) return parts.slice(2);
|
|
804
896
|
}
|
|
805
|
-
function
|
|
806
|
-
|
|
897
|
+
function isConfigRecord(value) {
|
|
898
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
899
|
+
}
|
|
900
|
+
function mergeConfigRecords(base, override) {
|
|
901
|
+
const merged = { ...base };
|
|
902
|
+
for (const [key, value] of Object.entries(override)) {
|
|
903
|
+
const existing = merged[key];
|
|
904
|
+
const nextValue = isConfigRecord(existing) && isConfigRecord(value) ? mergeConfigRecords(existing, value) : value;
|
|
905
|
+
Object.defineProperty(merged, key, {
|
|
906
|
+
value: nextValue,
|
|
907
|
+
configurable: true,
|
|
908
|
+
enumerable: true,
|
|
909
|
+
writable: true
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
return merged;
|
|
913
|
+
}
|
|
914
|
+
function parseLegacyCodexConfigAssignment(assignment) {
|
|
915
|
+
const separator = assignment.indexOf("=");
|
|
916
|
+
if (separator <= 0) throw new Error(`Invalid legacy Codex ACP config override: ${assignment}`);
|
|
917
|
+
const rawKey = assignment.slice(0, separator).trim();
|
|
918
|
+
const key = rawKey === "use_legacy_landlock" ? "features.use_legacy_landlock" : rawKey;
|
|
919
|
+
const rawValue = assignment.slice(separator + 1).trim();
|
|
920
|
+
try {
|
|
921
|
+
return parse(`${key} = ${rawValue}`);
|
|
922
|
+
} catch {
|
|
923
|
+
const literal = rawValue.replace(/^["']+|["']+$/g, "");
|
|
924
|
+
return parse(`${key} = ${JSON.stringify(literal)}`);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
function migrateLegacyCodexArgs(args) {
|
|
928
|
+
let config = {};
|
|
929
|
+
const forwardedArgs = [];
|
|
930
|
+
let hadOverrides = false;
|
|
931
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
932
|
+
const arg = args[index] ?? "";
|
|
933
|
+
let assignment;
|
|
934
|
+
if (arg === "-c" || arg === "--config") assignment = args[index += 1];
|
|
935
|
+
else if (arg.startsWith("--config=")) assignment = arg.slice(9);
|
|
936
|
+
else if (arg.startsWith("-c=")) assignment = arg.slice(3);
|
|
937
|
+
else if (arg.startsWith("-c") && arg.length > 2) assignment = arg.slice(2);
|
|
938
|
+
else {
|
|
939
|
+
forwardedArgs.push(arg);
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
if (!assignment) throw new Error(`Missing value for legacy Codex ACP option ${arg}`);
|
|
943
|
+
hadOverrides = true;
|
|
944
|
+
config = mergeConfigRecords(config, parseLegacyCodexConfigAssignment(assignment));
|
|
945
|
+
}
|
|
946
|
+
return {
|
|
947
|
+
config,
|
|
948
|
+
forwardedArgs,
|
|
949
|
+
hadOverrides
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
function resolveCodexAdapterLaunch(configuredCommand) {
|
|
953
|
+
const legacyAdapterArgs = extractConfiguredAdapterArgs({
|
|
954
|
+
configuredCommand,
|
|
955
|
+
packageName: LEGACY_CODEX_ACP_PACKAGE,
|
|
956
|
+
binName: CODEX_ACP_BIN
|
|
957
|
+
});
|
|
958
|
+
if (legacyAdapterArgs) {
|
|
959
|
+
const migration = migrateLegacyCodexArgs(legacyAdapterArgs);
|
|
960
|
+
return {
|
|
961
|
+
args: [...migration.hadOverrides ? [OPENCLAW_CODEX_CONFIG_ARG, JSON.stringify(migration.config)] : [], ...migration.forwardedArgs],
|
|
962
|
+
...migration.hadOverrides ? { migratedConfig: migration.config } : {}
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
const maintainedAdapterArgs = extractConfiguredAdapterArgs({
|
|
807
966
|
configuredCommand,
|
|
808
967
|
packageName: CODEX_ACP_PACKAGE,
|
|
809
968
|
binName: CODEX_ACP_BIN
|
|
810
969
|
});
|
|
811
|
-
if (
|
|
970
|
+
if (!maintainedAdapterArgs) return;
|
|
971
|
+
return { args: maintainedAdapterArgs };
|
|
972
|
+
}
|
|
973
|
+
function buildCodexAcpWrapperCommand(wrapperPath, configuredCommand) {
|
|
974
|
+
const launch = resolveCodexAdapterLaunch(configuredCommand);
|
|
975
|
+
if (launch) return buildWrapperCommand(wrapperPath, launch.args);
|
|
812
976
|
return buildWrapperCommand(wrapperPath, [RUN_CONFIGURED_COMMAND_SENTINEL, ...splitCommandParts(configuredCommand?.trim() ?? "")]);
|
|
813
977
|
}
|
|
978
|
+
async function persistMigratedCodexMcpConfig(params) {
|
|
979
|
+
const mcpServers = params.migratedConfig?.mcp_servers;
|
|
980
|
+
if (!isConfigRecord(mcpServers)) return;
|
|
981
|
+
const configPath = path.join(params.codexHome, "config.toml");
|
|
982
|
+
const merged = mergeConfigRecords(parse(await fs$1.readFile(configPath, "utf8")), { mcp_servers: mcpServers });
|
|
983
|
+
await fs$1.writeFile(configPath, stringify(merged), "utf8");
|
|
984
|
+
}
|
|
814
985
|
function buildClaudeAcpWrapperCommand(wrapperPath, configuredCommand) {
|
|
815
986
|
const configuredAdapterArgs = extractConfiguredAdapterArgs({
|
|
816
987
|
configuredCommand,
|
|
@@ -824,16 +995,20 @@ function buildClaudeAcpWrapperCommand(wrapperPath, configuredCommand) {
|
|
|
824
995
|
async function prepareAcpxCodexAuthConfig(params) {
|
|
825
996
|
params.logger;
|
|
826
997
|
const codexBaseDir = path.join(params.stateDir, "acpx");
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
998
|
+
const configuredCodexCommand = params.pluginConfig.agents.codex;
|
|
999
|
+
const configuredClaudeCommand = params.pluginConfig.agents.claude;
|
|
1000
|
+
const codexLaunch = resolveCodexAdapterLaunch(configuredCodexCommand);
|
|
1001
|
+
await persistMigratedCodexMcpConfig({
|
|
1002
|
+
codexHome: await prepareIsolatedCodexHome({
|
|
1003
|
+
baseDir: codexBaseDir,
|
|
1004
|
+
workspaceDir: params.pluginConfig.cwd
|
|
1005
|
+
}),
|
|
1006
|
+
migratedConfig: codexLaunch?.migratedConfig
|
|
830
1007
|
});
|
|
831
1008
|
const installedCodexBinPath = await (params.resolveInstalledCodexAcpBinPath ?? resolveInstalledCodexAcpBinPath)();
|
|
832
1009
|
const installedClaudeBinPath = await (params.resolveInstalledClaudeAcpBinPath ?? resolveInstalledClaudeAcpBinPath)();
|
|
833
1010
|
const wrapperPath = await writeCodexAcpWrapper(codexBaseDir, installedCodexBinPath);
|
|
834
1011
|
const claudeWrapperPath = await writeClaudeAcpWrapper(codexBaseDir, installedClaudeBinPath);
|
|
835
|
-
const configuredCodexCommand = params.pluginConfig.agents.codex;
|
|
836
|
-
const configuredClaudeCommand = params.pluginConfig.agents.claude;
|
|
837
1012
|
return {
|
|
838
1013
|
...params.pluginConfig,
|
|
839
1014
|
agents: {
|
|
@@ -852,7 +1027,7 @@ async function prepareAcpxCodexAuthConfig(params) {
|
|
|
852
1027
|
const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE";
|
|
853
1028
|
const SKIP_RUNTIME_PROBE_ENV = "OPENCLAW_SKIP_ACPX_RUNTIME_PROBE";
|
|
854
1029
|
const ACPX_BACKEND_ID = "acpx";
|
|
855
|
-
const loadRuntimeModule = createLazyRuntimeModule(() => import("./runtime-
|
|
1030
|
+
const loadRuntimeModule = createLazyRuntimeModule(() => import("./runtime-BEOGc4Ik.js"));
|
|
856
1031
|
/** Convert ACPX timeout seconds into timer-safe milliseconds. */
|
|
857
1032
|
function resolveAcpxTimerTimeoutMs(timeoutSeconds) {
|
|
858
1033
|
if (timeoutSeconds === void 0) return;
|
|
@@ -873,6 +1048,7 @@ function createLazyDefaultRuntime(params) {
|
|
|
873
1048
|
agentRegistry: module.createAgentRegistry({ overrides: params.pluginConfig.agents }),
|
|
874
1049
|
probeAgent: params.pluginConfig.probeAgent,
|
|
875
1050
|
mcpServers: toAcpMcpServers(params.pluginConfig.mcpServers),
|
|
1051
|
+
pluginToolsMcpBridgeEnabled: params.pluginConfig.pluginToolsMcpBridge,
|
|
876
1052
|
openclawToolsMcpBridgeEnabled: params.pluginConfig.openClawToolsMcpBridge,
|
|
877
1053
|
permissionMode: params.pluginConfig.permissionMode,
|
|
878
1054
|
nonInteractivePermissions: params.pluginConfig.nonInteractivePermissions,
|
|
@@ -924,13 +1100,9 @@ function formatDoctorFailureMessage(report) {
|
|
|
924
1100
|
const detailText = report.details?.map(formatDoctorDetail).filter(Boolean).join("; ").trim();
|
|
925
1101
|
return detailText ? `${report.message} (${detailText})` : report.message;
|
|
926
1102
|
}
|
|
927
|
-
function normalizeProbeAgent(value) {
|
|
928
|
-
const normalized = value?.trim().toLowerCase();
|
|
929
|
-
return normalized ? normalized : void 0;
|
|
930
|
-
}
|
|
931
1103
|
function resolveAllowedAgentsProbeAgent(ctx) {
|
|
932
1104
|
for (const agent of ctx.config.acp?.allowedAgents ?? []) {
|
|
933
|
-
const normalized =
|
|
1105
|
+
const normalized = normalizeLowercaseStringOrEmpty(agent);
|
|
934
1106
|
if (normalized) return normalized;
|
|
935
1107
|
}
|
|
936
1108
|
}
|
|
@@ -1043,8 +1215,8 @@ function createAcpxRuntimeService(params = {}) {
|
|
|
1043
1215
|
}));
|
|
1044
1216
|
const wrapperRoot = path.join(ctx.stateDir, "acpx");
|
|
1045
1217
|
await measureAcpxStartup(ctx, "filesystem.prepare", async () => {
|
|
1046
|
-
await fs.mkdir(pluginConfig.stateDir, { recursive: true });
|
|
1047
|
-
await fs.mkdir(wrapperRoot, { recursive: true });
|
|
1218
|
+
await fs$1.mkdir(pluginConfig.stateDir, { recursive: true });
|
|
1219
|
+
await fs$1.mkdir(wrapperRoot, { recursive: true });
|
|
1048
1220
|
});
|
|
1049
1221
|
const gatewayInstanceId = await measureAcpxStartup(ctx, "gateway-instance-id", () => resolveGatewayInstanceId(openKeyedStore));
|
|
1050
1222
|
const processLeaseStore = createAcpxProcessLeaseStore({ store: openAcpxProcessLeaseStateStore(openKeyedStore) });
|
package/dist/setup-api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
1
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
|
+
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
3
3
|
//#region extensions/acpx/setup-api.ts
|
|
4
4
|
/**
|
|
5
5
|
* ACPX setup plugin entry. It auto-enables setup when ACP config already points
|