Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled

Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
2026-07-05 09:36:54 +00:00
parent 3216769225
commit bedb527145
21108 changed files with 6010766 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
/**
* Command-line parser for ACPX MCP proxy targets. It handles simple quoting and
* Windows executable paths before spawning the configured MCP target.
*/
const WINDOWS_DIRECT_EXECUTABLE_PATH_RE =
/^(?<command>(?:[A-Za-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+[\\/]).*?\.(?:exe|com))(?=\s|$)(?:\s+(?<rest>.*))?$/i;
// Windows wrapper scripts need their host shell or interpreter (`cmd.exe`,
// `powershell.exe`, or `node`) instead of direct spawning.
const WINDOWS_WRAPPER_PATH_RE =
/^(?:[A-Za-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+[\\/]).*?\.(?:bat|cmd|cjs|js|mjs|ps1)$/i;
function splitCommandParts(value, platform = process.platform) {
const parts = [];
let current = "";
let quote = null;
let escaping = false;
for (let index = 0; index < value.length; index += 1) {
const ch = value[index];
const next = value[index + 1];
if (escaping) {
current += ch;
escaping = false;
continue;
}
if (ch === "\\") {
if (quote === "'") {
current += ch;
continue;
}
if (platform === "win32") {
if (quote === '"') {
if (next === '"' || next === "\\") {
escaping = true;
continue;
}
current += ch;
continue;
}
if (!quote) {
current += ch;
continue;
}
}
escaping = true;
continue;
}
if (quote) {
if (ch === quote) {
quote = null;
} else {
current += ch;
}
continue;
}
if (ch === "'" || ch === '"') {
quote = ch;
continue;
}
if (/\s/.test(ch)) {
if (current.length > 0) {
parts.push(current);
current = "";
}
continue;
}
current += ch;
}
if (escaping) {
current += "\\";
}
if (quote) {
throw new Error("Invalid agent command: unterminated quote");
}
if (current.length > 0) {
parts.push(current);
}
return parts;
}
function splitWindowsExecutableCommand(value, platform = process.platform) {
if (platform !== "win32") {
return null;
}
const trimmed = value.trim();
if (!trimmed || trimmed.startsWith('"') || trimmed.startsWith("'")) {
return null;
}
const match = trimmed.match(WINDOWS_DIRECT_EXECUTABLE_PATH_RE);
if (!match?.groups?.command) {
return null;
}
const rest = match.groups.rest?.trim() ?? "";
return {
command: match.groups.command,
args: rest ? splitCommandParts(rest, platform) : [],
};
}
function assertSupportedWindowsCommand(command, platform = process.platform) {
if (platform !== "win32" || !WINDOWS_WRAPPER_PATH_RE.test(command)) {
return;
}
throw new Error(
`Unsupported Windows agent command wrapper: ${command}. ` +
"Invoke wrapper scripts through their shell or interpreter instead " +
"(for example `cmd.exe /c`, `powershell.exe -File`, or `node <script>`).",
);
}
/** Split a configured command string into `{ command, args }` for child_process.spawn. */
export function splitCommandLine(value, platform = process.platform) {
const windowsCommand = splitWindowsExecutableCommand(value, platform);
const parts = windowsCommand ?? splitCommandParts(value, platform);
if (parts.length === 0) {
throw new Error("Invalid agent command: empty command");
}
const parsed = Array.isArray(parts)
? {
command: parts[0],
args: parts.slice(1),
}
: parts;
assertSupportedWindowsCommand(parsed.command, platform);
return parsed;
}

View File

@@ -0,0 +1,60 @@
// ACPX tests cover mcp command line plugin behavior.
import { describe, expect, it } from "vitest";
type SplitCommandLine = (
value: string,
platform?: string,
) => {
command: string;
args: string[];
};
async function loadSplitCommandLine(): Promise<SplitCommandLine> {
const moduleUrl = new URL("./mcp-command-line.mjs", import.meta.url);
return (await import(moduleUrl.href)).splitCommandLine as SplitCommandLine;
}
describe("mcp-command-line", () => {
it("parses quoted Windows executable paths without dropping backslashes", async () => {
const splitCommandLine = await loadSplitCommandLine();
const parsed = splitCommandLine(
'"C:\\Program Files\\Claude\\claude.exe" --stdio --flag "two words"',
"win32",
);
expect(parsed).toEqual({
command: "C:\\Program Files\\Claude\\claude.exe",
args: ["--stdio", "--flag", "two words"],
});
});
it("parses unquoted Windows executable paths without mangling backslashes", async () => {
const splitCommandLine = await loadSplitCommandLine();
const parsed = splitCommandLine("C:\\Users\\alerl\\.local\\bin\\claude.exe --version", "win32");
expect(parsed).toEqual({
command: "C:\\Users\\alerl\\.local\\bin\\claude.exe",
args: ["--version"],
});
});
it("preserves unquoted Windows path arguments after the executable", async () => {
const splitCommandLine = await loadSplitCommandLine();
const parsed = splitCommandLine(
'"C:\\Program Files\\Claude\\claude.exe" --config C:\\Users\\me\\cfg.json',
"win32",
);
expect(parsed).toEqual({
command: "C:\\Program Files\\Claude\\claude.exe",
args: ["--config", "C:\\Users\\me\\cfg.json"],
});
});
it("rejects direct Windows wrapper-script commands with a helpful error", async () => {
const splitCommandLine = await loadSplitCommandLine();
expect(() =>
splitCommandLine('"C:\\Users\\me\\bin\\claude-wrapper.cmd" --stdio', "win32"),
).toThrow(/Invoke wrapper scripts through their shell or interpreter instead/);
});
});

View File

@@ -0,0 +1,159 @@
#!/usr/bin/env node
/**
* Stdio MCP proxy used by ACPX wrappers. It injects OpenClaw-provided MCP
* servers into session creation/load/fork requests before forwarding to target.
*/
import { spawn } from "node:child_process";
import path from "node:path";
import { createInterface } from "node:readline";
import { pathToFileURL } from "node:url";
import { splitCommandLine } from "./mcp-command-line.mjs";
function formatErrorMessage(error) {
if (error instanceof Error) {
return error.message || error.name || "Error";
}
return String(error);
}
function decodePayload(argv) {
const payloadIndex = argv.indexOf("--payload");
if (payloadIndex < 0) {
throw new Error("Missing --payload");
}
const encoded = argv[payloadIndex + 1];
if (!encoded) {
throw new Error("Missing MCP proxy payload value");
}
const parsed = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
throw new Error("Invalid MCP proxy payload");
}
if (typeof parsed.targetCommand !== "string" || parsed.targetCommand.trim() === "") {
throw new Error("MCP proxy payload missing targetCommand");
}
const mcpServers = Array.isArray(parsed.mcpServers) ? parsed.mcpServers : [];
return {
targetCommand: parsed.targetCommand,
mcpServers,
};
}
function shouldInject(method) {
return method === "session/new" || method === "session/load" || method === "session/fork";
}
function rewriteLine(line, mcpServers) {
if (!line.trim()) {
return line;
}
try {
const parsed = JSON.parse(line);
if (
!parsed ||
typeof parsed !== "object" ||
Array.isArray(parsed) ||
!shouldInject(parsed.method) ||
!parsed.params ||
typeof parsed.params !== "object" ||
Array.isArray(parsed.params)
) {
return line;
}
const next = {
...parsed,
params: {
...parsed.params,
mcpServers,
},
};
return JSON.stringify(next);
} catch {
return line;
}
}
/** Build spawn options for the proxied MCP target process. */
export function createTargetSpawnOptions(platform = process.platform) {
const options = {
stdio: ["pipe", "pipe", "inherit"],
env: process.env,
};
if (platform === "win32") {
options.windowsHide = true;
}
return options;
}
function isMainModule() {
const mainPath = process.argv[1];
if (!mainPath) {
return false;
}
return import.meta.url === pathToFileURL(path.resolve(mainPath)).href;
}
function main() {
const { targetCommand, mcpServers } = decodePayload(process.argv.slice(2));
const target = splitCommandLine(targetCommand);
const child = spawn(target.command, target.args, createTargetSpawnOptions());
if (!child.stdin || !child.stdout) {
throw new Error("Failed to create MCP proxy stdio pipes");
}
const input = createInterface({ input: process.stdin });
let exiting = false;
const exitWithError = (error) => {
if (exiting) {
return;
}
exiting = true;
input.close();
child.kill();
process.stderr.write(`${formatErrorMessage(error)}\n`);
process.exit(1);
};
child.stdin.on("error", exitWithError);
process.stdout.on("error", exitWithError);
input.on("line", (line) => {
if (exiting) {
return;
}
child.stdin.write(`${rewriteLine(line, mcpServers)}\n`, (error) => {
if (error) {
exitWithError(error);
}
});
});
input.on("close", () => {
if (exiting || child.stdin.destroyed || child.stdin.writableEnded) {
return;
}
child.stdin.end();
});
child.stdout.pipe(process.stdout);
child.on("error", exitWithError);
child.on("close", (code, signal) => {
if (exiting) {
return;
}
exiting = true;
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 0);
});
}
if (isMainModule()) {
main();
}

View File

@@ -0,0 +1,241 @@
// ACPX tests cover mcp proxy plugin behavior.
import { spawn } from "node:child_process";
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { bundledPluginFile } from "openclaw/plugin-sdk/test-fixtures";
import { afterEach, describe, expect, it } from "vitest";
const tempDirs: string[] = [];
const proxyPath = path.resolve(bundledPluginFile("acpx", "src/runtime-internals/mcp-proxy.mjs"));
function encodePayload(payload: Record<string, unknown>): string {
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
}
async function makeTempScript(name: string, content: string): Promise<string> {
const dir = await mkdtemp(path.join(os.tmpdir(), "openclaw-acpx-mcp-proxy-"));
tempDirs.push(dir);
const scriptPath = path.join(dir, name);
await writeFile(scriptPath, content, "utf8");
await chmod(scriptPath, 0o755);
return scriptPath;
}
afterEach(async () => {
while (tempDirs.length > 0) {
const dir = tempDirs.pop();
if (!dir) {
continue;
}
await rm(dir, { recursive: true, force: true });
}
});
describe("mcp-proxy", () => {
it("hides the target MCP process window on Windows only", async () => {
const moduleUrl = pathToFileURL(proxyPath).href;
const { createTargetSpawnOptions } = (await import(moduleUrl)) as {
createTargetSpawnOptions: (platform?: NodeJS.Platform) => Record<string, unknown>;
};
expect(createTargetSpawnOptions("win32")).toEqual({
env: process.env,
stdio: ["pipe", "pipe", "inherit"],
windowsHide: true,
});
expect(createTargetSpawnOptions("darwin")).not.toHaveProperty("windowsHide");
expect(createTargetSpawnOptions("linux")).not.toHaveProperty("windowsHide");
});
it("injects configured MCP servers into ACP session bootstrap requests", async () => {
const echoServerPath = await makeTempScript(
"echo-server.cjs",
String.raw`#!/usr/bin/env node
const { createInterface } = require("node:readline");
const rl = createInterface({ input: process.stdin });
rl.on("line", (line) => process.stdout.write(line + "\n"));
`,
);
const payload = encodePayload({
targetCommand: `${process.execPath} ${echoServerPath}`,
mcpServers: [
{
name: "canva",
command: "npx",
args: ["-y", "mcp-remote@latest", "https://mcp.canva.com/mcp"],
env: [{ name: "CANVA_TOKEN", value: "secret" }],
},
],
});
const child = spawn(process.execPath, [proxyPath, "--payload", payload], {
stdio: ["pipe", "pipe", "inherit"],
cwd: process.cwd(),
});
let stdout = "";
child.stdout.on("data", (chunk) => {
stdout += String(chunk);
});
child.stdin.write(
`${JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "session/new",
params: { cwd: process.cwd(), mcpServers: [] },
})}\n`,
);
child.stdin.write(
`${JSON.stringify({
jsonrpc: "2.0",
id: 2,
method: "session/load",
params: { cwd: process.cwd(), sessionId: "sid-1", mcpServers: [] },
})}\n`,
);
child.stdin.write(
`${JSON.stringify({
jsonrpc: "2.0",
id: 3,
method: "session/prompt",
params: { sessionId: "sid-1", prompt: [{ type: "text", text: "hello" }] },
})}\n`,
);
child.stdin.end();
const exitCode = await new Promise<number | null>((resolve) => {
child.once("close", (code) => resolve(code));
});
expect(exitCode).toBe(0);
const lines = stdout
.trim()
.split(/\r?\n/)
.map((line) => JSON.parse(line) as { method: string; params: Record<string, unknown> });
expect(lines[0].params.mcpServers).toEqual([
{
name: "canva",
command: "npx",
args: ["-y", "mcp-remote@latest", "https://mcp.canva.com/mcp"],
env: [{ name: "CANVA_TOKEN", value: "secret" }],
},
]);
expect(lines[1].params.mcpServers).toEqual(lines[0].params.mcpServers);
expect(lines[2].method).toBe("session/prompt");
expect(lines[2].params.mcpServers).toBeUndefined();
});
it("reports target stdin pipe failures without an unhandled stream error", async () => {
const closedStdinServerPath = await makeTempScript(
"closed-stdin-server.cjs",
String.raw`#!/usr/bin/env node
const fs = require("node:fs");
fs.closeSync(0);
process.stdout.write("ready\n");
setTimeout(() => {}, 30_000);
`,
);
const payload = encodePayload({
targetCommand: `${process.execPath} ${closedStdinServerPath}`,
mcpServers: [],
});
const child = spawn(process.execPath, [proxyPath, "--payload", payload], {
stdio: ["pipe", "pipe", "pipe"],
cwd: process.cwd(),
});
let stdout = "";
let stderr = "";
const ready = new Promise<void>((resolve) => {
child.stdout.on("data", (chunk) => {
stdout += String(chunk);
if (stdout.includes("ready\n")) {
resolve();
}
});
});
child.stderr.on("data", (chunk) => {
stderr += String(chunk);
});
await ready;
child.stdin.write(
`${JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "session/new",
params: { cwd: process.cwd(), mcpServers: [] },
})}\n`,
);
child.stdin.end();
const exitCode = await new Promise<number | null>((resolve) => {
child.once("close", (code) => resolve(code));
});
expect(exitCode).toBe(1);
expect(stderr).toMatch(/EPIPE|write/i);
expect(stderr).not.toContain("Unhandled 'error' event");
});
it("reports proxy stdout pipe failures without an unhandled stream error", async () => {
const outputServerPath = await makeTempScript(
"output-server.cjs",
String.raw`#!/usr/bin/env node
const { createInterface } = require("node:readline");
process.stderr.write("ready\n");
createInterface({ input: process.stdin }).once("line", () => {
process.stdout.write("x".repeat(1024 * 1024));
});
setTimeout(() => {}, 30_000);
`,
);
const payload = encodePayload({
targetCommand: `${process.execPath} ${outputServerPath}`,
mcpServers: [],
});
const child = spawn(process.execPath, [proxyPath, "--payload", payload], {
stdio: ["pipe", "pipe", "pipe"],
cwd: process.cwd(),
});
let stderr = "";
const ready = new Promise<void>((resolve) => {
child.stderr.on("data", (chunk) => {
stderr += String(chunk);
if (stderr.includes("ready\n")) {
resolve();
}
});
});
await ready;
child.stdout.destroy();
child.stdin.write(
`${JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "session/new",
params: { cwd: process.cwd(), mcpServers: [] },
})}\n`,
);
child.stdin.end();
const exitCode = await new Promise<number | null>((resolve) => {
child.once("close", (code) => resolve(code));
});
expect(exitCode).toBe(1);
expect(stderr).toMatch(/EPIPE|write/i);
expect(stderr).not.toContain("Unhandled 'error' event");
});
});