@openclaw/acpx 2026.5.14-beta.1 → 2026.5.14-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.
@@ -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 withAcpxLeaseEnvironment(params) {
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 { OPENCLAW_GATEWAY_INSTANCE_ID_ARG as a, hashAcpxProcessCommand as c, OPENCLAW_ACPX_LEASE_ID_ARG as i, withAcpxLeaseEnvironment as l, isOpenClawOwnedAcpxProcessCommand as n, createAcpxProcessLeaseId as o, reapStaleOpenClawOwnedAcpxOrphans as r, createAcpxProcessLeaseStore as s, cleanupOpenClawOwnedAcpxProcessTree as t };
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 };
@@ -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-DzWriMSw.js");
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 { c as hashAcpxProcessCommand, l as withAcpxLeaseEnvironment, n as isOpenClawOwnedAcpxProcessCommand, o as createAcpxProcessLeaseId, t as cleanupOpenClawOwnedAcpxProcessTree } from "./process-reaper-DKzgrZt9.js";
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 { resolve } from "node:path";
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: () => delegate.ensureSession(input)
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, () => delegate.ensureSession(normalizedInput))
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
- yield* (await this.resolveDelegateForHandle(input.handle)).runTurn(input);
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 OPENCLAW_GATEWAY_INSTANCE_ID_ARG, i as OPENCLAW_ACPX_LEASE_ID_ARG, r as reapStaleOpenClawOwnedAcpxOrphans, s as createAcpxProcessLeaseStore, t as cleanupOpenClawOwnedAcpxProcessTree } from "./process-reaper-DKzgrZt9.js";
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
- function renderIsolatedCodexProjectTrustConfig(projectPaths) {
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
- ...Array.from(new Set(projectPaths.map((projectPath) => projectPath.trim()).filter(Boolean).map((projectPath) => path.resolve(projectPath)))).toSorted((left, right) => left.localeCompare(right)).flatMap((projectPath) => [
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 configuredArgs = stripOpenClawWrapperArgs(process.argv.slice(2));
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
- process.exit(1);
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
- process.exit(code);
899
+ childExitCode = code;
900
+ return;
581
901
  }
582
- process.exit(signal ? 1 : 0);
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"), renderIsolatedCodexProjectTrustConfig(trustedProjectPaths), "utf8");
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-DeOzZoZw.js");
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.14-beta.1",
3
+ "version": "2026.5.14-beta.2",
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.14-beta.1"
29
+ "pluginApi": ">=2026.5.14-beta.2"
30
30
  },
31
31
  "build": {
32
- "openclawVersion": "2026.5.14-beta.1",
32
+ "openclawVersion": "2026.5.14-beta.2",
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.14-beta.1"
62
+ "openclaw": ">=2026.5.14-beta.2"
63
63
  },
64
64
  "peerDependenciesMeta": {
65
65
  "openclaw": {