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,469 @@
// Plugin Lifecycle Measure tests cover plugin lifecycle measure script behavior.
import { spawn, spawnSync, type ChildProcess } from "node:child_process";
import {
chmodSync,
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
const tempDirs: string[] = [];
const scriptPath = "scripts/e2e/lib/plugin-lifecycle-matrix/measure.mjs";
function makeTempDir(): string {
const dir = mkdtempSync(path.join(tmpdir(), "openclaw-plugin-lifecycle-measure-"));
tempDirs.push(dir);
return dir;
}
function writeFakeGetconf(dir: string, body: string): string {
const binDir = path.join(dir, "bin");
mkdirSync(binDir);
const getconfPath = path.join(binDir, "getconf");
writeFileSync(getconfPath, `#!/bin/sh\n${body}\n`, "utf8");
chmodSync(getconfPath, 0o755);
return binDir;
}
function pidExists(pid: number): boolean {
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
function waitForPidExit(pid: number, timeoutMs: number): boolean {
const waitBuffer = new SharedArrayBuffer(4);
const waitView = new Int32Array(waitBuffer);
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
if (!pidExists(pid)) {
return true;
}
Atomics.wait(waitView, 0, 0, 25);
}
return !pidExists(pid);
}
function waitForPath(filePath: string, timeoutMs: number): boolean {
const waitBuffer = new SharedArrayBuffer(4);
const waitView = new Int32Array(waitBuffer);
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
if (existsSync(filePath)) {
return true;
}
Atomics.wait(waitView, 0, 0, 25);
}
return existsSync(filePath);
}
function waitForChildClose(
child: ChildProcess,
timeoutMs: number,
): Promise<{ code: number | null; signal: NodeJS.Signals | null }> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
child.kill("SIGKILL");
reject(new Error("timed out waiting for measured wrapper to exit"));
}, timeoutMs);
child.once("close", (code, signal) => {
clearTimeout(timer);
resolve({ code, signal });
});
});
}
afterEach(() => {
for (const dir of tempDirs.splice(0)) {
rmSync(dir, { recursive: true, force: true });
}
});
describe("plugin lifecycle resource sampler", () => {
it.runIf(process.platform === "linux")(
"derives proc units from getconf when overrides are absent",
() => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const logPath = path.join(dir, "getconf.log");
const binDir = writeFakeGetconf(
dir,
'printf "%s\\n" "$1" >>"$GETCONF_LOG"\ncase "$1" in PAGESIZE) echo 16384 ;; CLK_TCK) echo 250 ;; esac',
);
const env = {
...process.env,
GETCONF_LOG: logPath,
PATH: `${binDir}:${process.env.PATH ?? ""}`,
};
delete env.OPENCLAW_PROC_PAGE_SIZE;
delete env.OPENCLAW_PROC_CLK_TCK;
const result = spawnSync(
process.execPath,
[scriptPath, summary, "getconf-units", "--", process.execPath, "-e", ""],
{
cwd: process.cwd(),
encoding: "utf8",
env,
timeout: 5000,
},
);
expect(readFileSync(logPath, "utf8")).toBe("PAGESIZE\nCLK_TCK\n");
expect(result.stderr).not.toContain("failed to derive OPENCLAW_PROC");
},
);
it("rejects loose numeric env values instead of parsing prefixes", () => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const result = spawnSync("node", [scriptPath, summary, "invalid-env", "--", "node", "-e", ""], {
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "150ms",
},
timeout: 5000,
});
expect(result.status).not.toBe(0);
expect(result.stderr).toContain(
"OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS must be a positive integer; got: 150ms",
);
});
it("rejects zero lifecycle timeouts instead of disabling the guard", () => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const result = spawnSync("node", [scriptPath, summary, "invalid-env", "--", "node", "-e", ""], {
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "0",
},
timeout: 5000,
});
expect(result.status).not.toBe(0);
expect(result.stderr).toContain(
"OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS must be a positive integer; got: 0",
);
});
it("rejects loose resource ceiling env values instead of parsing prefixes", () => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const result = spawnSync("node", [scriptPath, summary, "invalid-env", "--", "node", "-e", ""], {
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_MAX_CPU_CORE_RATIO: "1x",
},
timeout: 5000,
});
expect(result.status).not.toBe(0);
expect(result.stderr).toContain(
"OPENCLAW_PLUGIN_LIFECYCLE_MAX_CPU_CORE_RATIO must be a positive number; got: 1x",
);
});
it("configures a phase timeout with process-group cleanup", () => {
const script = readFileSync(scriptPath, "utf8");
expect(script).toContain("OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS");
expect(script).toContain("OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS");
expect(script).toContain("OPENCLAW_PLUGIN_LIFECYCLE_MAX_RSS_KB");
expect(script).toContain("OPENCLAW_PLUGIN_LIFECYCLE_MAX_WALL_MS");
expect(script).toContain("OPENCLAW_PLUGIN_LIFECYCLE_MAX_CPU_CORE_RATIO");
expect(script).toContain("detached: true");
expect(script).toContain("process.kill(-child.pid, signal)");
expect(script).toContain("plugin lifecycle resource ceiling exceeded");
expect(script).toContain('const summarySignal = timedOut ? "timeout"');
expect(script).toContain("process.exit(124)");
});
it.runIf(process.platform === "linux")(
"fails successful phases that exceed wall ceilings",
() => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const result = spawnSync(
"node",
[scriptPath, summary, "slow-success", "--", "node", "-e", "setTimeout(() => {}, 40)"],
{
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "5000",
OPENCLAW_PLUGIN_LIFECYCLE_MAX_WALL_MS: "1",
},
timeout: 5000,
},
);
expect(result.status).toBe(1);
expect(result.stderr).toContain("plugin lifecycle resource ceiling exceeded");
expect(result.stderr).toContain("wall_ms=");
expect(readFileSync(summary, "utf8")).toMatch(/^slow-success\t\d+\t[\d.]+\t\d+\t[\d.]+\t$/mu);
},
);
it.runIf(process.platform === "linux")(
"times out wedged phases and records the timeout signal",
() => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const result = spawnSync(
"node",
[scriptPath, summary, "wedged", "--", "node", "-e", "setInterval(() => {}, 1000)"],
{
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "150",
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "50",
},
timeout: 5000,
},
);
expect(result.status).toBe(124);
expect(result.stdout).toContain("signal=timeout");
expect(readFileSync(summary, "utf8")).toMatch(
/^wedged\t\d+\t[\d.]+\t\d+\t[\d.]+\ttimeout$/mu,
);
},
);
it.runIf(process.platform === "linux")("clamps oversized timer env values", () => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const oversizedTimerMs = "2147000001";
const result = spawnSync(
"node",
[
scriptPath,
summary,
"oversized-timers",
"--",
"node",
"-e",
"setTimeout(() => process.exit(0), 25)",
],
{
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_METRIC_POLL_MS: oversizedTimerMs,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: oversizedTimerMs,
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: oversizedTimerMs,
},
timeout: 5000,
},
);
expect(result.status).toBe(0);
expect(result.stderr).not.toContain("TimeoutOverflowWarning");
expect(readFileSync(summary, "utf8")).toMatch(
/^oversized-timers\t\d+\t[\d.]+\t\d+\t[\d.]+\t$/mu,
);
});
it.runIf(process.platform === "linux")(
"kills stubborn descendants after the timeout grace period",
() => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const pidFile = path.join(dir, "descendant.pid");
let descendantPid;
try {
const result = spawnSync(
"node",
[
scriptPath,
summary,
"stubborn-descendant",
"--",
"bash",
"-lc",
[
'bash -c \'trap "" TERM; printf "%s\\n" "$$" >"$PID_FILE"; while :; do sleep 1; done\' &',
'while [ ! -s "$PID_FILE" ]; do sleep 0.01; done',
"exit 0",
].join("\n"),
],
{
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "1000",
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "200",
PID_FILE: pidFile,
},
timeout: 5000,
},
);
descendantPid = Number.parseInt(readFileSync(pidFile, "utf8"), 10);
expect(result.status).toBe(124);
expect(result.stdout).toContain("signal=timeout");
expect(readFileSync(summary, "utf8")).toMatch(
/^stubborn-descendant\t\d+\t[\d.]+\t\d+\t[\d.]+\ttimeout$/mu,
);
expect(waitForPidExit(descendantPid, 1000)).toBe(true);
} finally {
if (descendantPid > 0 && pidExists(descendantPid)) {
process.kill(descendantPid, "SIGKILL");
}
}
},
);
it.runIf(process.platform === "linux")(
"forwards external termination to the measured process group",
async () => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const pidFile = path.join(dir, "descendant.pid");
let descendantPid;
try {
const result = spawn(
process.execPath,
[
scriptPath,
summary,
"external-stop",
"--",
"bash",
"-lc",
'bash -c \'trap "" TERM; printf "%s\\n" "$$" >"$PID_FILE"; while :; do sleep 1; done\' & wait',
],
{
cwd: process.cwd(),
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "5000",
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "200",
PID_FILE: pidFile,
},
stdio: "ignore",
},
);
expect(waitForPath(pidFile, 2000)).toBe(true);
descendantPid = Number.parseInt(readFileSync(pidFile, "utf8"), 10);
result.kill("SIGTERM");
const close = await waitForChildClose(result, 5000);
expect(close.signal).toBe("SIGTERM");
expect(waitForPidExit(descendantPid, 1000)).toBe(true);
} finally {
if (descendantPid > 0 && pidExists(descendantPid)) {
process.kill(descendantPid, "SIGKILL");
}
}
},
);
it.runIf(process.platform === "linux")(
"exits promptly when externally terminated phases stop during grace",
async () => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const readyFile = path.join(dir, "ready.pid");
const result = spawn(
"node",
[
scriptPath,
summary,
"external-fast-stop",
"--",
"node",
"--input-type=module",
"--eval",
[
"import { writeFileSync } from 'node:fs';",
"writeFileSync(process.env.READY_FILE, String(process.pid));",
"process.on('SIGTERM', () => process.exit(0));",
"setInterval(() => {}, 1000);",
].join("\n"),
],
{
cwd: process.cwd(),
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "5000",
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "1500",
READY_FILE: readyFile,
},
stdio: "ignore",
},
);
expect(waitForPath(readyFile, 1000)).toBe(true);
const started = Date.now();
result.kill("SIGTERM");
const close = await waitForChildClose(result, 5000);
expect(Date.now() - started).toBeLessThan(1000);
expect(close.signal).toBe("SIGTERM");
},
);
it.runIf(process.platform === "linux")(
"exits promptly when shell descendants drain during termination grace",
async () => {
const dir = makeTempDir();
const summary = path.join(dir, "summary.tsv");
const readyFile = path.join(dir, "ready.pid");
const result = spawn(
"node",
[
scriptPath,
summary,
"external-descendant-drain",
"--",
"bash",
"-lc",
'trap "exit 0" TERM; bash -c \'trap "sleep 0.15; exit 0" TERM; printf "%s\\n" "$$" >"$READY_FILE"; while :; do sleep 1; done\' & wait',
],
{
cwd: process.cwd(),
env: {
...process.env,
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "5000",
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "1500",
READY_FILE: readyFile,
},
stdio: "ignore",
},
);
expect(waitForPath(readyFile, 1000)).toBe(true);
const started = Date.now();
result.kill("SIGTERM");
const close = await waitForChildClose(result, 5000);
expect(Date.now() - started).toBeLessThan(1000);
expect(close.signal).toBe("SIGTERM");
},
);
});