@openclaw/acpx 2026.5.14-beta.1 → 2026.5.16-beta.1
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
-
import fs from "node:fs/promises";
|
|
4
4
|
import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
|
|
5
5
|
import { execFile } from "node:child_process";
|
|
6
6
|
import { promisify } from "node:util";
|
|
@@ -90,12 +90,8 @@ function hashAcpxProcessCommand(command) {
|
|
|
90
90
|
function quoteEnvValue(value) {
|
|
91
91
|
return /^[A-Za-z0-9_./:=@+-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
92
92
|
}
|
|
93
|
-
function
|
|
94
|
-
if ((params.platform ?? process.platform) === "win32") return params.command;
|
|
93
|
+
function appendAcpxLeaseArgs(params) {
|
|
95
94
|
return [
|
|
96
|
-
"env",
|
|
97
|
-
`${OPENCLAW_ACPX_LEASE_ID_ENV}=${quoteEnvValue(params.leaseId)}`,
|
|
98
|
-
`${OPENCLAW_GATEWAY_INSTANCE_ID_ENV}=${quoteEnvValue(params.gatewayInstanceId)}`,
|
|
99
95
|
params.command,
|
|
100
96
|
OPENCLAW_ACPX_LEASE_ID_ARG,
|
|
101
97
|
quoteEnvValue(params.leaseId),
|
|
@@ -103,6 +99,15 @@ function withAcpxLeaseEnvironment(params) {
|
|
|
103
99
|
quoteEnvValue(params.gatewayInstanceId)
|
|
104
100
|
].join(" ");
|
|
105
101
|
}
|
|
102
|
+
function withAcpxLeaseEnvironment(params) {
|
|
103
|
+
if ((params.platform ?? process.platform) === "win32") return appendAcpxLeaseArgs(params);
|
|
104
|
+
return [
|
|
105
|
+
"env",
|
|
106
|
+
`${OPENCLAW_ACPX_LEASE_ID_ENV}=${quoteEnvValue(params.leaseId)}`,
|
|
107
|
+
`${OPENCLAW_GATEWAY_INSTANCE_ID_ENV}=${quoteEnvValue(params.gatewayInstanceId)}`,
|
|
108
|
+
appendAcpxLeaseArgs(params)
|
|
109
|
+
].join(" ");
|
|
110
|
+
}
|
|
106
111
|
//#endregion
|
|
107
112
|
//#region extensions/acpx/src/process-reaper.ts
|
|
108
113
|
const execFileAsync = promisify(execFile);
|
|
@@ -328,4 +333,4 @@ async function reapStaleOpenClawOwnedAcpxOrphans(params) {
|
|
|
328
333
|
};
|
|
329
334
|
}
|
|
330
335
|
//#endregion
|
|
331
|
-
export {
|
|
336
|
+
export { OPENCLAW_ACPX_LEASE_ID_ENV as a, createAcpxProcessLeaseStore as c, OPENCLAW_ACPX_LEASE_ID_ARG as i, hashAcpxProcessCommand as l, isOpenClawOwnedAcpxProcessCommand as n, OPENCLAW_GATEWAY_INSTANCE_ID_ARG as o, reapStaleOpenClawOwnedAcpxOrphans as r, createAcpxProcessLeaseId as s, cleanupOpenClawOwnedAcpxProcessTree as t, withAcpxLeaseEnvironment as u };
|
package/dist/register.runtime.js
CHANGED
|
@@ -5,7 +5,7 @@ const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE";
|
|
|
5
5
|
const SKIP_RUNTIME_PROBE_ENV = "OPENCLAW_SKIP_ACPX_RUNTIME_PROBE";
|
|
6
6
|
let serviceModulePromise = null;
|
|
7
7
|
function loadServiceModule() {
|
|
8
|
-
serviceModulePromise ??= import("./service-
|
|
8
|
+
serviceModulePromise ??= import("./service-DPrf6fF8.js");
|
|
9
9
|
return serviceModulePromise;
|
|
10
10
|
}
|
|
11
11
|
function shouldRunStartupProbe(env = process.env) {
|
|
@@ -1,9 +1,37 @@
|
|
|
1
1
|
import { AcpRuntimeError } from "./runtime-api.js";
|
|
2
|
-
import {
|
|
2
|
+
import { l as hashAcpxProcessCommand, n as isOpenClawOwnedAcpxProcessCommand, s as createAcpxProcessLeaseId, t as cleanupOpenClawOwnedAcpxProcessTree, u as withAcpxLeaseEnvironment } from "./process-reaper-biYb35VD.js";
|
|
3
3
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
-
import
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import path, { resolve } from "node:path";
|
|
5
6
|
import { ACPX_BACKEND_ID, AcpxRuntime as AcpxRuntime$1, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState } from "acpx/runtime";
|
|
7
|
+
import { redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
|
|
6
8
|
//#region extensions/acpx/src/runtime.ts
|
|
9
|
+
const CODEX_WRAPPER_STDERR_LOG_PREFIX = "codex-acp-wrapper.stderr";
|
|
10
|
+
const CODEX_WRAPPER_ERROR_TAIL_MAX_CHARS = 6e3;
|
|
11
|
+
function safeDiagnosticFilePart(value) {
|
|
12
|
+
return value.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 120) || "unknown";
|
|
13
|
+
}
|
|
14
|
+
function codexWrapperStderrLogFileName(leaseId) {
|
|
15
|
+
return `${CODEX_WRAPPER_STDERR_LOG_PREFIX}.${safeDiagnosticFilePart(leaseId)}.log`;
|
|
16
|
+
}
|
|
17
|
+
function compactDiagnosticText(value) {
|
|
18
|
+
return value.replace(/\s+/g, " ").trim();
|
|
19
|
+
}
|
|
20
|
+
function isGenericInternalAcpErrorMessage(message) {
|
|
21
|
+
return message.trim() === "Internal error";
|
|
22
|
+
}
|
|
23
|
+
function isGenericInternalAcpError(error) {
|
|
24
|
+
if (!(error instanceof Error)) return false;
|
|
25
|
+
return isGenericInternalAcpErrorMessage(error.message);
|
|
26
|
+
}
|
|
27
|
+
async function readCodexWrapperStderrTail(params) {
|
|
28
|
+
if (!params.wrapperRoot || !params.leaseId) return "";
|
|
29
|
+
try {
|
|
30
|
+
return compactDiagnosticText(redactSensitiveText((await fs.readFile(path.join(params.wrapperRoot, codexWrapperStderrLogFileName(params.leaseId)), "utf8")).slice(-CODEX_WRAPPER_ERROR_TAIL_MAX_CHARS)));
|
|
31
|
+
} catch {
|
|
32
|
+
return "";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
7
35
|
function readSessionRecordName(record) {
|
|
8
36
|
if (typeof record !== "object" || record === null) return "";
|
|
9
37
|
const { name } = record;
|
|
@@ -431,6 +459,26 @@ var AcpxRuntime = class {
|
|
|
431
459
|
});
|
|
432
460
|
return await this.launchLeaseScope.run(launch, params.run);
|
|
433
461
|
}
|
|
462
|
+
async withCodexWrapperDiagnostics(params) {
|
|
463
|
+
try {
|
|
464
|
+
return await params.run();
|
|
465
|
+
} catch (error) {
|
|
466
|
+
if (!isCodexAcpCommand(params.command) || !isGenericInternalAcpError(error)) throw error;
|
|
467
|
+
const stderrTail = await readCodexWrapperStderrTail({
|
|
468
|
+
wrapperRoot: this.wrapperRoot,
|
|
469
|
+
leaseId: this.launchLeaseScope.getStore()?.leaseId
|
|
470
|
+
});
|
|
471
|
+
if (!stderrTail) throw error;
|
|
472
|
+
throw new AcpRuntimeError(params.fallbackCode, `Internal error: ${stderrTail}`, { cause: error });
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
async readCodexTurnFailureStderr(params) {
|
|
476
|
+
const record = await this.sessionStore.load(params.handle.acpxRecordId ?? params.handle.sessionKey);
|
|
477
|
+
return readCodexWrapperStderrTail({
|
|
478
|
+
wrapperRoot: this.wrapperRoot,
|
|
479
|
+
leaseId: readOpenClawLeaseIdFromRecord(record)
|
|
480
|
+
});
|
|
481
|
+
}
|
|
434
482
|
async cleanupProcessTreeForRecord(handle, record) {
|
|
435
483
|
const leaseId = readOpenClawLeaseIdFromRecord(record);
|
|
436
484
|
const rootPid = readAgentPidFromRecord(record);
|
|
@@ -496,7 +544,11 @@ var AcpxRuntime = class {
|
|
|
496
544
|
sessionKey: input.sessionKey,
|
|
497
545
|
command: stableLaunchCommand,
|
|
498
546
|
enabled: shouldStartWithLease,
|
|
499
|
-
run: () =>
|
|
547
|
+
run: () => this.withCodexWrapperDiagnostics({
|
|
548
|
+
command: stableLaunchCommand,
|
|
549
|
+
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
|
550
|
+
run: () => delegate.ensureSession(input)
|
|
551
|
+
})
|
|
500
552
|
});
|
|
501
553
|
const normalizedInput = {
|
|
502
554
|
...input,
|
|
@@ -506,11 +558,39 @@ var AcpxRuntime = class {
|
|
|
506
558
|
sessionKey: input.sessionKey,
|
|
507
559
|
command: stableLaunchCommand,
|
|
508
560
|
enabled: shouldStartWithLease,
|
|
509
|
-
run: () => this.codexAcpModelOverrideScope.run(codexModelOverride, () =>
|
|
561
|
+
run: () => this.codexAcpModelOverrideScope.run(codexModelOverride, () => this.withCodexWrapperDiagnostics({
|
|
562
|
+
command: stableLaunchCommand,
|
|
563
|
+
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
|
564
|
+
run: () => delegate.ensureSession(normalizedInput)
|
|
565
|
+
}))
|
|
510
566
|
});
|
|
511
567
|
}
|
|
512
568
|
async *runTurn(input) {
|
|
513
|
-
|
|
569
|
+
const command = await this.resolveCommandForHandle(input.handle);
|
|
570
|
+
const delegate = await this.resolveDelegateForHandle(input.handle);
|
|
571
|
+
try {
|
|
572
|
+
for await (const event of delegate.runTurn(input)) {
|
|
573
|
+
if (event.type !== "error" || !isCodexAcpCommand(command) || !isGenericInternalAcpErrorMessage(event.message)) {
|
|
574
|
+
yield event;
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
const stderrTail = await this.readCodexTurnFailureStderr({ handle: input.handle });
|
|
578
|
+
if (!stderrTail) {
|
|
579
|
+
yield event;
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
yield {
|
|
583
|
+
...event,
|
|
584
|
+
code: "ACP_TURN_FAILED",
|
|
585
|
+
message: `Internal error: ${stderrTail}`
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
} catch (error) {
|
|
589
|
+
if (!isCodexAcpCommand(command) || !isGenericInternalAcpError(error)) throw error;
|
|
590
|
+
const stderrTail = await this.readCodexTurnFailureStderr({ handle: input.handle });
|
|
591
|
+
if (!stderrTail) throw error;
|
|
592
|
+
throw new AcpRuntimeError("ACP_TURN_FAILED", `Internal error: ${stderrTail}`, { cause: error });
|
|
593
|
+
}
|
|
514
594
|
}
|
|
515
595
|
getCapabilities() {
|
|
516
596
|
return this.delegate.getCapabilities();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "./runtime-api.js";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as OPENCLAW_ACPX_LEASE_ID_ENV, c as createAcpxProcessLeaseStore, i as OPENCLAW_ACPX_LEASE_ID_ARG, o as OPENCLAW_GATEWAY_INSTANCE_ID_ARG, r as reapStaleOpenClawOwnedAcpxOrphans, t as cleanupOpenClawOwnedAcpxProcessTree } from "./process-reaper-biYb35VD.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import fs from "node:fs/promises";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { randomUUID } from "node:crypto";
|
|
7
|
-
import fs from "node:fs/promises";
|
|
8
8
|
import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
|
|
9
9
|
import { inspect } from "node:util";
|
|
10
10
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
@@ -129,16 +129,85 @@ function extractTrustedCodexProjectPaths(configToml) {
|
|
|
129
129
|
}
|
|
130
130
|
return Array.from(trusted);
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
const INHERITED_TOP_LEVEL_CODEX_CONFIG_KEYS = new Set([
|
|
133
|
+
"model",
|
|
134
|
+
"model_provider",
|
|
135
|
+
"model_reasoning_effort",
|
|
136
|
+
"sandbox_mode"
|
|
137
|
+
]);
|
|
138
|
+
const INHERITED_MODEL_PROVIDER_CONFIG_KEYS = new Set([
|
|
139
|
+
"name",
|
|
140
|
+
"base_url",
|
|
141
|
+
"wire_api",
|
|
142
|
+
"env_key",
|
|
143
|
+
"env_key_instructions",
|
|
144
|
+
"requires_openai_auth",
|
|
145
|
+
"request_max_retries",
|
|
146
|
+
"stream_max_retries",
|
|
147
|
+
"stream_idle_timeout_ms"
|
|
148
|
+
]);
|
|
149
|
+
function parseTableHeader(line) {
|
|
150
|
+
const trimmed = line.trim();
|
|
151
|
+
if (!trimmed.startsWith("[") || !trimmed.endsWith("]") || trimmed.startsWith("[[")) return;
|
|
152
|
+
return parseTomlDottedKey(trimmed.slice(1, -1));
|
|
153
|
+
}
|
|
154
|
+
function isInheritedModelProviderTable(parts) {
|
|
155
|
+
return parts?.[0] === "model_providers" && parts.length === 2;
|
|
156
|
+
}
|
|
157
|
+
function parseTopLevelAssignmentKey(line) {
|
|
158
|
+
return /^(?<key>[A-Za-z0-9_-]+)\s*=\s*(?<value>.+)$/.exec(line)?.groups?.key;
|
|
159
|
+
}
|
|
160
|
+
function extractInheritedCodexRuntimeConfig(configToml) {
|
|
161
|
+
const inheritedLines = [];
|
|
162
|
+
let inAnyTable = false;
|
|
163
|
+
let inInheritedTable = false;
|
|
164
|
+
let pendingInheritedTableHeader = "";
|
|
165
|
+
function flushInheritedTableHeader() {
|
|
166
|
+
if (!pendingInheritedTableHeader) return;
|
|
167
|
+
if (inheritedLines.length > 0 && inheritedLines[inheritedLines.length - 1] !== "") inheritedLines.push("");
|
|
168
|
+
inheritedLines.push(pendingInheritedTableHeader);
|
|
169
|
+
pendingInheritedTableHeader = "";
|
|
170
|
+
}
|
|
171
|
+
for (const rawLine of configToml.split(/\r?\n/)) {
|
|
172
|
+
const trimmedLine = rawLine.trim();
|
|
173
|
+
const semanticLine = stripTomlComment(rawLine).trim();
|
|
174
|
+
if (trimmedLine.startsWith("[")) {
|
|
175
|
+
const tableParts = parseTableHeader(trimmedLine);
|
|
176
|
+
inAnyTable = true;
|
|
177
|
+
inInheritedTable = isInheritedModelProviderTable(tableParts);
|
|
178
|
+
if (inInheritedTable) pendingInheritedTableHeader = rawLine.trimEnd();
|
|
179
|
+
else pendingInheritedTableHeader = "";
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (inInheritedTable) {
|
|
183
|
+
if (!semanticLine) continue;
|
|
184
|
+
const key = parseTopLevelAssignmentKey(semanticLine);
|
|
185
|
+
if (!key || !INHERITED_MODEL_PROVIDER_CONFIG_KEYS.has(key)) continue;
|
|
186
|
+
flushInheritedTableHeader();
|
|
187
|
+
inheritedLines.push(rawLine.trimEnd());
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (inAnyTable) continue;
|
|
191
|
+
const key = parseTopLevelAssignmentKey(semanticLine);
|
|
192
|
+
if (!key) continue;
|
|
193
|
+
if (!INHERITED_TOP_LEVEL_CODEX_CONFIG_KEYS.has(key)) continue;
|
|
194
|
+
inheritedLines.push(rawLine.trimEnd());
|
|
195
|
+
}
|
|
196
|
+
while (inheritedLines.length > 0 && inheritedLines[inheritedLines.length - 1] === "") inheritedLines.pop();
|
|
197
|
+
return inheritedLines.join("\n");
|
|
198
|
+
}
|
|
199
|
+
function renderIsolatedCodexConfig(params) {
|
|
200
|
+
const normalized = Array.from(new Set(params.projectPaths.map((projectPath) => projectPath.trim()).filter(Boolean).map((projectPath) => path.resolve(projectPath)))).toSorted((left, right) => left.localeCompare(right));
|
|
133
201
|
return [
|
|
134
202
|
"# Generated by OpenClaw for Codex ACP sessions.",
|
|
135
|
-
|
|
203
|
+
params.sourceConfigToml ? extractInheritedCodexRuntimeConfig(params.sourceConfigToml) : "",
|
|
204
|
+
...normalized.flatMap((projectPath) => [
|
|
136
205
|
"",
|
|
137
206
|
`[projects.${JSON.stringify(projectPath)}]`,
|
|
138
207
|
"trust_level = \"trusted\""
|
|
139
208
|
]),
|
|
140
209
|
""
|
|
141
|
-
].join("\n");
|
|
210
|
+
].filter((line, index, lines) => !(line === "" && lines[index - 1] === "")).join("\n");
|
|
142
211
|
}
|
|
143
212
|
//#endregion
|
|
144
213
|
//#region extensions/acpx/src/config-schema.ts
|
|
@@ -436,19 +505,252 @@ async function resolveInstalledCodexAcpBinPath() {
|
|
|
436
505
|
async function resolveInstalledClaudeAcpBinPath() {
|
|
437
506
|
return await resolveInstalledAcpPackageBinPath(CLAUDE_ACP_PACKAGE, CLAUDE_ACP_BIN);
|
|
438
507
|
}
|
|
508
|
+
const DIAGNOSTIC_REDACTION_RULES = [
|
|
509
|
+
{
|
|
510
|
+
source: String.raw`(authorization\s*[:=]\s*bearer\s+)[^\s'"<>]+`,
|
|
511
|
+
flags: "gi",
|
|
512
|
+
replacement: "$1[REDACTED]"
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
source: String.raw`((?:api[_-]?key|apiKey|access[_-]?token|refresh[_-]?token|client[_-]?secret|token|secret|password|passwd|credential)\s*[:=]\s*)[^\s'"<>]+`,
|
|
516
|
+
flags: "gi",
|
|
517
|
+
replacement: "$1[REDACTED]"
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
source: String.raw`("(?:apiKey|token|secret|password|passwd|accessToken|refreshToken)"\s*:\s*")[^"]+`,
|
|
521
|
+
flags: "g",
|
|
522
|
+
replacement: "$1[REDACTED]"
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
source: String.raw`(["']?(?:api[-_]?key|apiKey|access[-_]?token|accessToken|refresh[-_]?token|refreshToken|id[-_]?token|idToken|auth[-_]?token|authToken|client[-_]?secret|clientSecret|app[-_]?secret|appSecret|token|secret|password|passwd|credential)["']?\s*[:=]\s*["']?)[^"',}\s<>]+`,
|
|
526
|
+
flags: "gi",
|
|
527
|
+
replacement: "$1[REDACTED]"
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
source: String.raw`([?&](?:access[-_]?token|auth[-_]?token|refresh[-_]?token|api[-_]?key|client[-_]?secret|token|key|secret|password|pass|passwd|auth|signature)=)[^&\s'"<>]+`,
|
|
531
|
+
flags: "gi",
|
|
532
|
+
replacement: "$1[REDACTED]"
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
source: String.raw`(--(?:api[-_]?key|token|secret|password|passwd)\s+)[^\s'"]+`,
|
|
536
|
+
flags: "gi",
|
|
537
|
+
replacement: "$1[REDACTED]"
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
source: String.raw`-----BEGIN [A-Z ]*PRI` + String.raw`VATE KEY-----[\s\S]+?-----END [A-Z ]*PRI` + String.raw`VATE KEY-----`,
|
|
541
|
+
flags: "g",
|
|
542
|
+
replacement: "[REDACTED_PRIVATE_KEY]"
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
source: String.raw`\b(sk-[A-Za-z0-9_-]{8,})\b`,
|
|
546
|
+
flags: "g",
|
|
547
|
+
replacement: "[REDACTED_OPENAI_KEY]"
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
source: String.raw`\b(gh[pousr]_[A-Za-z0-9_]{20,})\b`,
|
|
551
|
+
flags: "g",
|
|
552
|
+
replacement: "[REDACTED_GITHUB_TOKEN]"
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
source: String.raw`\b(github_pat_[A-Za-z0-9_]{20,})\b`,
|
|
556
|
+
flags: "g",
|
|
557
|
+
replacement: "[REDACTED_GITHUB_TOKEN]"
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
source: String.raw`\b(xox[baprs]-[A-Za-z0-9-]{10,})\b`,
|
|
561
|
+
flags: "g",
|
|
562
|
+
replacement: "[REDACTED_SLACK_TOKEN]"
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
source: String.raw`\b(gsk_[A-Za-z0-9_-]{10,})\b`,
|
|
566
|
+
flags: "g",
|
|
567
|
+
replacement: "[REDACTED_API_KEY]"
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
source: String.raw`\b(AIza[0-9A-Za-z\-_]{20,})\b`,
|
|
571
|
+
flags: "g",
|
|
572
|
+
replacement: "[REDACTED_GOOGLE_KEY]"
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
source: String.raw`\b(ya29\.[0-9A-Za-z_\-./+=]{10,})\b`,
|
|
576
|
+
flags: "g",
|
|
577
|
+
replacement: "[REDACTED_GOOGLE_TOKEN]"
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
source: String.raw`\b(eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,})\b`,
|
|
581
|
+
flags: "g",
|
|
582
|
+
replacement: "[REDACTED_JWT]"
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
source: String.raw`\b(pplx-[A-Za-z0-9_-]{10,})\b`,
|
|
586
|
+
flags: "g",
|
|
587
|
+
replacement: "[REDACTED_API_KEY]"
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
source: String.raw`\b(npm_[A-Za-z0-9]{10,})\b`,
|
|
591
|
+
flags: "g",
|
|
592
|
+
replacement: "[REDACTED_NPM_TOKEN]"
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
source: String.raw`\b(LTAI[A-Za-z0-9]{10,})\b`,
|
|
596
|
+
flags: "g",
|
|
597
|
+
replacement: "[REDACTED_ACCESS_KEY]"
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
source: String.raw`\b(hf_[A-Za-z0-9]{10,})\b`,
|
|
601
|
+
flags: "g",
|
|
602
|
+
replacement: "[REDACTED_API_KEY]"
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
source: String.raw`\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b`,
|
|
606
|
+
flags: "g",
|
|
607
|
+
replacement: "bot[REDACTED_TELEGRAM_TOKEN]"
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
source: String.raw`\b(\d{6,}:[A-Za-z0-9_-]{20,})\b`,
|
|
611
|
+
flags: "g",
|
|
612
|
+
replacement: "[REDACTED_TELEGRAM_TOKEN]"
|
|
613
|
+
}
|
|
614
|
+
];
|
|
615
|
+
function renderDiagnosticRedactionRuleSpecs() {
|
|
616
|
+
return JSON.stringify(DIAGNOSTIC_REDACTION_RULES);
|
|
617
|
+
}
|
|
439
618
|
function buildAdapterWrapperScript(params) {
|
|
440
619
|
return `#!/usr/bin/env node
|
|
441
|
-
import { existsSync } from "node:fs";
|
|
620
|
+
import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
442
621
|
import path from "node:path";
|
|
443
622
|
import { spawn } from "node:child_process";
|
|
444
623
|
import { fileURLToPath } from "node:url";
|
|
445
624
|
|
|
446
625
|
${params.envSetup}
|
|
626
|
+
const stderrLogFileNamePrefix = ${params.stderrLogFileNamePrefix ? JSON.stringify(params.stderrLogFileNamePrefix) : "undefined"};
|
|
627
|
+
const stderrLogMaxChars = 256 * 1024;
|
|
628
|
+
|
|
447
629
|
const openClawWrapperArgs = new Set([
|
|
448
630
|
${quoteCommandPart(OPENCLAW_ACPX_LEASE_ID_ARG)},
|
|
449
631
|
${quoteCommandPart(OPENCLAW_GATEWAY_INSTANCE_ID_ARG)},
|
|
450
632
|
]);
|
|
451
633
|
|
|
634
|
+
function readOpenClawWrapperArg(args, name) {
|
|
635
|
+
const index = args.indexOf(name);
|
|
636
|
+
if (index < 0) {
|
|
637
|
+
return undefined;
|
|
638
|
+
}
|
|
639
|
+
const value = args[index + 1];
|
|
640
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function safeDiagnosticFilePart(value) {
|
|
644
|
+
const sanitized = String(value || "").replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 120);
|
|
645
|
+
return sanitized || "pid-" + process.pid;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function resolveStderrLogPath(args) {
|
|
649
|
+
if (!stderrLogFileNamePrefix) {
|
|
650
|
+
return undefined;
|
|
651
|
+
}
|
|
652
|
+
const leaseId =
|
|
653
|
+
process.env[${JSON.stringify(OPENCLAW_ACPX_LEASE_ID_ENV)}] ||
|
|
654
|
+
readOpenClawWrapperArg(args, ${quoteCommandPart(OPENCLAW_ACPX_LEASE_ID_ARG)}) ||
|
|
655
|
+
"pid-" + process.pid;
|
|
656
|
+
const fileName = stderrLogFileNamePrefix + "." + safeDiagnosticFilePart(leaseId) + ".log";
|
|
657
|
+
return fileURLToPath(new URL("./" + fileName, import.meta.url));
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
const diagnosticRedactionRules = ${renderDiagnosticRedactionRuleSpecs()}.map((rule) => [
|
|
661
|
+
new RegExp(rule.source, rule.flags),
|
|
662
|
+
rule.replacement,
|
|
663
|
+
]);
|
|
664
|
+
|
|
665
|
+
function redactDiagnosticText(text) {
|
|
666
|
+
let redacted = text;
|
|
667
|
+
for (const [pattern, replacement] of diagnosticRedactionRules) {
|
|
668
|
+
redacted = redacted.replace(pattern, replacement);
|
|
669
|
+
}
|
|
670
|
+
return redacted;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
let pendingStderrLogText = "";
|
|
674
|
+
const stderrPrivateKeyEndPattern = /-----END [A-Z ]*PRIVATE KEY-----/;
|
|
675
|
+
|
|
676
|
+
function hasUnclosedPrivateKeyBlock(text) {
|
|
677
|
+
let lastBeginIndex = -1;
|
|
678
|
+
for (const match of text.matchAll(/-----BEGIN [A-Z ]*PRIVATE KEY-----/g)) {
|
|
679
|
+
lastBeginIndex = match.index ?? lastBeginIndex;
|
|
680
|
+
}
|
|
681
|
+
if (lastBeginIndex === -1) {
|
|
682
|
+
return -1;
|
|
683
|
+
}
|
|
684
|
+
return stderrPrivateKeyEndPattern.test(text.slice(lastBeginIndex)) ? -1 : lastBeginIndex;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function writeRedactedStderrLog(text) {
|
|
688
|
+
if (!stderrLogPath) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
if (!text) {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
try {
|
|
695
|
+
appendFileSync(stderrLogPath, redactDiagnosticText(text), "utf8");
|
|
696
|
+
const current = readFileSync(stderrLogPath, "utf8");
|
|
697
|
+
if (current.length > stderrLogMaxChars) {
|
|
698
|
+
writeFileSync(stderrLogPath, current.slice(-stderrLogMaxChars), "utf8");
|
|
699
|
+
}
|
|
700
|
+
} catch {
|
|
701
|
+
// Stderr capture is diagnostic-only; never break the ACP adapter.
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function redactIncompletePrivateKeyTail(text) {
|
|
706
|
+
const unclosedPrivateKeyStart = hasUnclosedPrivateKeyBlock(text);
|
|
707
|
+
if (unclosedPrivateKeyStart === -1) {
|
|
708
|
+
return text;
|
|
709
|
+
}
|
|
710
|
+
return text.slice(0, unclosedPrivateKeyStart) + "[REDACTED_PRIVATE_KEY]";
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function flushFinalizedStderrLogText() {
|
|
714
|
+
const lastLineBreak = pendingStderrLogText.lastIndexOf("\\n");
|
|
715
|
+
if (lastLineBreak === -1) {
|
|
716
|
+
if (pendingStderrLogText.length > stderrLogMaxChars) {
|
|
717
|
+
pendingStderrLogText = pendingStderrLogText.slice(-stderrLogMaxChars);
|
|
718
|
+
}
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
let flushEnd = lastLineBreak + 1;
|
|
722
|
+
const unclosedPrivateKeyStart = hasUnclosedPrivateKeyBlock(
|
|
723
|
+
pendingStderrLogText.slice(0, flushEnd),
|
|
724
|
+
);
|
|
725
|
+
if (unclosedPrivateKeyStart !== -1) {
|
|
726
|
+
flushEnd = unclosedPrivateKeyStart;
|
|
727
|
+
}
|
|
728
|
+
if (flushEnd <= 0) {
|
|
729
|
+
if (pendingStderrLogText.length > stderrLogMaxChars) {
|
|
730
|
+
pendingStderrLogText = pendingStderrLogText.slice(-stderrLogMaxChars);
|
|
731
|
+
}
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
const finalizedText = pendingStderrLogText.slice(0, flushEnd);
|
|
735
|
+
pendingStderrLogText = pendingStderrLogText.slice(flushEnd);
|
|
736
|
+
writeRedactedStderrLog(finalizedText);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
function appendStderrLog(chunk) {
|
|
740
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
741
|
+
if (!text) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
pendingStderrLogText += text;
|
|
745
|
+
flushFinalizedStderrLogText();
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function finishStderrLog() {
|
|
749
|
+
const text = redactIncompletePrivateKeyTail(pendingStderrLogText);
|
|
750
|
+
pendingStderrLogText = "";
|
|
751
|
+
writeRedactedStderrLog(text);
|
|
752
|
+
}
|
|
753
|
+
|
|
452
754
|
function stripOpenClawWrapperArgs(args) {
|
|
453
755
|
const stripped = [];
|
|
454
756
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -462,7 +764,18 @@ function stripOpenClawWrapperArgs(args) {
|
|
|
462
764
|
return stripped;
|
|
463
765
|
}
|
|
464
766
|
|
|
465
|
-
const
|
|
767
|
+
const rawConfiguredArgs = process.argv.slice(2);
|
|
768
|
+
const stderrLogPath = resolveStderrLogPath(rawConfiguredArgs);
|
|
769
|
+
|
|
770
|
+
try {
|
|
771
|
+
if (stderrLogPath) {
|
|
772
|
+
writeFileSync(stderrLogPath, "", "utf8");
|
|
773
|
+
}
|
|
774
|
+
} catch {
|
|
775
|
+
// Stderr capture is diagnostic-only; never break the ACP adapter.
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const configuredArgs = stripOpenClawWrapperArgs(rawConfiguredArgs);
|
|
466
779
|
|
|
467
780
|
function resolveNpmCliPath() {
|
|
468
781
|
const candidate = path.resolve(
|
|
@@ -506,12 +819,18 @@ if (!command) {
|
|
|
506
819
|
const child = spawn(command, args, {
|
|
507
820
|
detached: process.platform !== "win32",
|
|
508
821
|
env,
|
|
509
|
-
stdio: "inherit",
|
|
822
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
510
823
|
windowsHide: true,
|
|
511
824
|
});
|
|
512
825
|
|
|
826
|
+
child.stderr?.on("data", (chunk) => {
|
|
827
|
+
appendStderrLog(chunk);
|
|
828
|
+
process.stderr.write(chunk);
|
|
829
|
+
});
|
|
830
|
+
|
|
513
831
|
let forceKillTimer;
|
|
514
832
|
let orphanCleanupStarted = false;
|
|
833
|
+
let childExitCode = 1;
|
|
515
834
|
|
|
516
835
|
function killChildTree(signal, options = {}) {
|
|
517
836
|
if (!child.pid || (!options.force && child.killed)) {
|
|
@@ -556,7 +875,7 @@ const parentWatcher =
|
|
|
556
875
|
// a forced fallback signal after SIGTERM.
|
|
557
876
|
forceKillTimer = setTimeout(() => {
|
|
558
877
|
killChildTree("SIGKILL", { force: true });
|
|
559
|
-
|
|
878
|
+
childExitCode = 1;
|
|
560
879
|
}, 1_500);
|
|
561
880
|
}, 1_000);
|
|
562
881
|
parentWatcher?.unref?.();
|
|
@@ -577,9 +896,15 @@ child.on("exit", (code, signal) => {
|
|
|
577
896
|
clearTimeout(forceKillTimer);
|
|
578
897
|
}
|
|
579
898
|
if (code !== null) {
|
|
580
|
-
|
|
899
|
+
childExitCode = code;
|
|
900
|
+
return;
|
|
581
901
|
}
|
|
582
|
-
|
|
902
|
+
childExitCode = signal ? 1 : 0;
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
child.on("close", () => {
|
|
906
|
+
finishStderrLog();
|
|
907
|
+
process.exit(childExitCode);
|
|
583
908
|
});
|
|
584
909
|
`;
|
|
585
910
|
}
|
|
@@ -589,6 +914,7 @@ function buildCodexAcpWrapperScript(installedBinPath) {
|
|
|
589
914
|
packageSpec: `${CODEX_ACP_PACKAGE}@${CODEX_ACP_PACKAGE_VERSION}`,
|
|
590
915
|
binName: CODEX_ACP_BIN,
|
|
591
916
|
installedBinPath,
|
|
917
|
+
stderrLogFileNamePrefix: "codex-acp-wrapper.stderr",
|
|
592
918
|
envSetup: `const codexHome = fileURLToPath(new URL("./codex-home/", import.meta.url));
|
|
593
919
|
const env = {
|
|
594
920
|
...process.env,
|
|
@@ -620,7 +946,10 @@ async function prepareIsolatedCodexHome(params) {
|
|
|
620
946
|
const trustedProjectPaths = [...sourceConfig ? extractTrustedCodexProjectPaths(sourceConfig) : [], params.workspaceDir];
|
|
621
947
|
const codexHome = path.join(params.baseDir, "codex-home");
|
|
622
948
|
await fs.mkdir(codexHome, { recursive: true });
|
|
623
|
-
await fs.writeFile(path.join(codexHome, "config.toml"),
|
|
949
|
+
await fs.writeFile(path.join(codexHome, "config.toml"), renderIsolatedCodexConfig({
|
|
950
|
+
sourceConfigToml: sourceConfig,
|
|
951
|
+
projectPaths: trustedProjectPaths
|
|
952
|
+
}), "utf8");
|
|
624
953
|
return codexHome;
|
|
625
954
|
}
|
|
626
955
|
async function makeGeneratedWrapperExecutableIfPossible(wrapperPath) {
|
|
@@ -724,7 +1053,7 @@ const SKIP_RUNTIME_PROBE_ENV = "OPENCLAW_SKIP_ACPX_RUNTIME_PROBE";
|
|
|
724
1053
|
const ACPX_BACKEND_ID = "acpx";
|
|
725
1054
|
let runtimeModulePromise = null;
|
|
726
1055
|
function loadRuntimeModule() {
|
|
727
|
-
runtimeModulePromise ??= import("./runtime-
|
|
1056
|
+
runtimeModulePromise ??= import("./runtime-HSzTNfOq.js");
|
|
728
1057
|
return runtimeModulePromise;
|
|
729
1058
|
}
|
|
730
1059
|
function createLazyDefaultRuntime(params) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/acpx",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.16-beta.1",
|
|
4
4
|
"description": "OpenClaw ACP runtime backend",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"minHostVersion": ">=2026.4.25"
|
|
27
27
|
},
|
|
28
28
|
"compat": {
|
|
29
|
-
"pluginApi": ">=2026.5.
|
|
29
|
+
"pluginApi": ">=2026.5.16-beta.1"
|
|
30
30
|
},
|
|
31
31
|
"build": {
|
|
32
|
-
"openclawVersion": "2026.5.
|
|
32
|
+
"openclawVersion": "2026.5.16-beta.1",
|
|
33
33
|
"staticAssets": [
|
|
34
34
|
{
|
|
35
35
|
"source": "./src/runtime-internals/mcp-proxy.mjs",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"skills/**"
|
|
60
60
|
],
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"openclaw": ">=2026.5.
|
|
62
|
+
"openclaw": ">=2026.5.16-beta.1"
|
|
63
63
|
},
|
|
64
64
|
"peerDependenciesMeta": {
|
|
65
65
|
"openclaw": {
|