Download src/commands/agent-exec-plugin.e2e.test.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 13.1 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/commands/agent-exec-plugin.e2e.test.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/commands/agent-exec-plugin.e2e.test.ts
-
curl -L -o agent-exec-plugin.e2e.test.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/commands/agent-exec-plugin.e2e.test.ts
13.1 kB
| import { execFile } from "node:child_process"; | |
| import fs from "node:fs/promises"; | |
| import path from "node:path"; | |
| import { promisify } from "node:util"; | |
| import { afterEach, describe, expect, it } from "vitest"; | |
| import { waitForDead } from "../../test/helpers/process-wait.js"; | |
| import { runNodeScript } from "../../test/helpers/run-node-script.js"; | |
| import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js"; | |
| import type { OpenClawConfig } from "../config/types.openclaw.js"; | |
| import { seedInstalledPluginIndex } from "../plugins/test-helpers/installed-plugin-index.js"; | |
| const execFileAsync = promisify(execFile); | |
| const tempDirs = useAutoCleanupTempDirTracker(afterEach); | |
| async function writeHarnessPlugin(stateDir: string): Promise<void> { | |
| const pluginDir = path.join(stateDir, "extensions", "exec-proof"); | |
| await fs.mkdir(pluginDir, { recursive: true }); | |
| await fs.writeFile( | |
| path.join(pluginDir, "openclaw.plugin.json"), | |
| JSON.stringify({ | |
| id: "exec-proof", | |
| name: "Agent exec proof harness", | |
| activation: { onStartup: false, onAgentHarnesses: ["exec-proof"] }, | |
| configSchema: { type: "object", additionalProperties: false }, | |
| }), | |
| "utf8", | |
| ); | |
| await fs.writeFile( | |
| path.join(pluginDir, "package.json"), | |
| JSON.stringify({ | |
| name: "exec-proof", | |
| version: "1.0.0", | |
| type: "module", | |
| openclaw: { extensions: ["./index.js"] }, | |
| }), | |
| "utf8", | |
| ); | |
| await fs.writeFile( | |
| path.join(pluginDir, "index.js"), | |
| `export default { | |
| id: "exec-proof", | |
| register(api) { | |
| api.registerAgentHarness({ | |
| id: "exec-proof", | |
| label: "Agent exec proof harness", | |
| authBootstrap: "harness", | |
| supports: ({ provider }) => provider === "exec-proof" | |
| ? { supported: true, priority: 100 } | |
| : { supported: false }, | |
| async runAttempt() { | |
| const text = "PLUGIN_HARNESS_OK"; | |
| const assistant = { | |
| role: "assistant", | |
| content: [{ type: "text", text }], | |
| api: "openai-responses", | |
| provider: "exec-proof", | |
| model: "proof-model", | |
| usage: { | |
| input: 0, | |
| output: 0, | |
| cacheRead: 0, | |
| cacheWrite: 0, | |
| totalTokens: 0, | |
| cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, | |
| }, | |
| stopReason: "stop", | |
| timestamp: Date.now(), | |
| }; | |
| return { | |
| terminal: { kind: "ok" }, | |
| sessionIdUsed: "exec-proof-session", | |
| messagesSnapshot: [assistant], | |
| assistantTexts: [text], | |
| toolMetas: [], | |
| lastAssistant: assistant, | |
| didSendViaMessagingTool: false, | |
| messagingToolSentTexts: [], | |
| messagingToolSentMediaUrls: [], | |
| messagingToolSentTargets: [], | |
| cloudCodeAssistFormatError: false, | |
| replayMetadata: { hadPotentialSideEffects: false, replaySafe: true }, | |
| itemLifecycle: { startedCount: 0, completedCount: 0, activeCount: 0 }, | |
| }; | |
| }, | |
| }); | |
| }, | |
| };\n`, | |
| "utf8", | |
| ); | |
| await seedInstalledPluginIndex( | |
| { | |
| "exec-proof": { | |
| source: "path", | |
| sourcePath: pluginDir, | |
| installPath: pluginDir, | |
| }, | |
| }, | |
| { | |
| stateDir, | |
| config: buildExecProofConfig(), | |
| candidates: [ | |
| { | |
| idHint: "exec-proof", | |
| source: path.join(pluginDir, "index.js"), | |
| rootDir: pluginDir, | |
| origin: "global", | |
| }, | |
| ], | |
| }, | |
| ); | |
| } | |
| function buildExecProofConfig(): OpenClawConfig { | |
| return { | |
| plugins: { | |
| allow: ["exec-proof"], | |
| entries: { "exec-proof": { enabled: true } }, | |
| }, | |
| models: { | |
| providers: { | |
| "exec-proof": { | |
| api: "openai-responses", | |
| baseUrl: "https://example.invalid/v1", | |
| models: [ | |
| { | |
| id: "proof-model", | |
| name: "Proof model", | |
| reasoning: false, | |
| input: ["text"], | |
| cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, | |
| contextWindow: 128000, | |
| maxTokens: 4096, | |
| agentRuntime: { id: "exec-proof" }, | |
| }, | |
| ], | |
| }, | |
| }, | |
| }, | |
| agents: { defaults: { model: { primary: "exec-proof/proof-model" } } }, | |
| }; | |
| } | |
| async function writeConfig( | |
| stateDir: string, | |
| config: OpenClawConfig = buildExecProofConfig(), | |
| ): Promise<void> { | |
| await fs.writeFile(path.join(stateDir, "openclaw.json"), JSON.stringify(config), "utf8"); | |
| } | |
| function buildChildEnv(stateDir: string): NodeJS.ProcessEnv { | |
| const childEnv: NodeJS.ProcessEnv = { | |
| ...process.env, | |
| OPENCLAW_DISABLE_BUNDLED_PLUGINS: "1", | |
| OPENCLAW_STATE_DIR: stateDir, | |
| }; | |
| delete childEnv.NODE_ENV; | |
| delete childEnv.OPENCLAW_RUN_NODE_OUTPUT_LOG; | |
| delete childEnv.VITEST; | |
| delete childEnv.VITEST_POOL_ID; | |
| delete childEnv.VITEST_WORKER_ID; | |
| return childEnv; | |
| } | |
| function buildCliSource(args: string[]): string { | |
| return ` | |
| import { runMainOrRootHelp } from "./dist/entry.js"; | |
| await runMainOrRootHelp(${JSON.stringify(["node", "openclaw", ...args])}); | |
| `; | |
| } | |
| describe("agent exec built runtime", () => { | |
| it.skipIf(process.platform === "win32")( | |
| "reclaims CLI transport descendants when the run times out", | |
| async () => { | |
| const root = tempDirs.make("openclaw-agent-exec-auth-timeout-"); | |
| const binDir = path.join(root, "bin"); | |
| const processPath = path.join(root, "processes.jsonl"); | |
| const stopPath = path.join(root, "stop"); | |
| const repoRoot = path.resolve(import.meta.dirname, "../.."); | |
| await fs.mkdir(binDir); | |
| await fs.writeFile( | |
| path.join(binDir, "claude"), | |
| `#!${process.execPath} | |
| const fs = require("node:fs"); | |
| const { spawn } = require("node:child_process"); | |
| if (process.argv[2] === "--version") { | |
| console.log("2.1.0 (Claude Code)"); | |
| } else { | |
| const child = spawn(process.execPath, ["-e", ${JSON.stringify(` | |
| const fs = require("node:fs"); | |
| setInterval(() => { | |
| if (fs.existsSync(${JSON.stringify(stopPath)})) process.exit(0); | |
| }, 25); | |
| `)}], { stdio: "inherit" }); | |
| child.once("spawn", () => { | |
| fs.appendFileSync(${JSON.stringify(processPath)}, JSON.stringify({ | |
| phase: process.argv[2] === "auth" ? "auth" : "agent", | |
| pids: [process.pid, child.pid, process.ppid], | |
| }) + "\\n"); | |
| }); | |
| } | |
| `, | |
| { mode: 0o755 }, | |
| ); | |
| await writeConfig(root, { | |
| agents: { | |
| defaults: { | |
| model: { primary: "anthropic/claude-opus-4-7" }, | |
| models: { | |
| "anthropic/claude-opus-4-7": { agentRuntime: { id: "claude-cli" } }, | |
| }, | |
| }, | |
| }, | |
| }); | |
| type ProcessReceipt = { | |
| phase: "auth" | "agent"; | |
| pids: number[]; | |
| }; | |
| const readProcesses = async (): Promise<ProcessReceipt[]> => | |
| (await fs.readFile(processPath, "utf8").catch(() => "")) | |
| .trim() | |
| .split("\n") | |
| .filter(Boolean) | |
| .map((line) => JSON.parse(line) as ProcessReceipt); | |
| try { | |
| const result = await runNodeScript( | |
| [ | |
| path.join(repoRoot, "openclaw.mjs"), | |
| "agent", | |
| "exec", | |
| "probe", | |
| "--config", | |
| path.join(root, "openclaw.json"), | |
| "--cwd", | |
| root, | |
| "--timeout", | |
| "1", | |
| "--json", | |
| ], | |
| { | |
| PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ""}`, | |
| HOME: root, | |
| USERPROFILE: root, | |
| OPENCLAW_STATE_DIR: root, | |
| CLAUDE_CONFIG_DIR: path.join(root, ".claude"), | |
| ANTHROPIC_API_KEY: "synthetic-proof-key", | |
| OPENCLAW_SERVICE_MARKER: "openclaw", | |
| }, | |
| 30_000, | |
| { cwd: root }, | |
| ); | |
| expect(result.error, result.stderr).toBeUndefined(); | |
| expect(result.status, result.stderr).toBe(2); | |
| expect(JSON.parse(result.stdout)).toMatchObject({ ok: false, status: "timeout" }); | |
| const receipts = await readProcesses(); | |
| expect(receipts.map(({ phase }) => phase)).toContain("agent"); | |
| await Promise.all( | |
| receipts.flatMap(({ pids }) => pids.map((pid) => waitForDead(pid, 5_000))), | |
| ); | |
| } finally { | |
| // Assert extinction before asking any leaked fixture children to exit. | |
| await fs.writeFile(stopPath, ""); | |
| await Promise.all( | |
| (await readProcesses()).flatMap(({ pids }) => pids.map((pid) => waitForDead(pid, 5_000))), | |
| ); | |
| } | |
| }, | |
| ); | |
| it("runs an operator-installed harness without retaining run state", async () => { | |
| const stateDir = tempDirs.make("openclaw-agent-exec-plugin-e2e-"); | |
| await writeHarnessPlugin(stateDir); | |
| await writeConfig(stateDir); | |
| const source = buildCliSource(["agent", "exec", "prove plugin discovery", "--json"]); | |
| const childEnv = buildChildEnv(stateDir); | |
| const { stdout, stderr } = await execFileAsync( | |
| process.execPath, | |
| ["--input-type=module", "--eval", source], | |
| { | |
| cwd: path.resolve(import.meta.dirname, "../.."), | |
| encoding: "utf8", | |
| env: childEnv, | |
| timeout: 30_000, | |
| }, | |
| ); | |
| expect(stdout, stderr).not.toBe(""); | |
| expect(JSON.parse(stdout)).toMatchObject({ | |
| ok: true, | |
| status: "ok", | |
| final: "PLUGIN_HARNESS_OK", | |
| model: "proof-model", | |
| provider: "exec-proof", | |
| }); | |
| let isolatedExitCode: number | undefined; | |
| let isolatedStdout = ""; | |
| try { | |
| await execFileAsync( | |
| process.execPath, | |
| [ | |
| "--input-type=module", | |
| "--eval", | |
| buildCliSource([ | |
| "agent", | |
| "exec", | |
| "prove isolated discovery", | |
| "--isolated", | |
| "--model", | |
| "exec-proof/proof-model", | |
| "--json", | |
| ]), | |
| ], | |
| { | |
| cwd: path.resolve(import.meta.dirname, "../.."), | |
| encoding: "utf8", | |
| env: childEnv, | |
| timeout: 30_000, | |
| }, | |
| ); | |
| } catch (error) { | |
| const failure = error as Error & { code?: number; stdout?: string }; | |
| isolatedExitCode = failure.code; | |
| isolatedStdout = failure.stdout ?? ""; | |
| } | |
| expect(isolatedExitCode).toBe(1); | |
| expect(isolatedStdout).not.toContain("PLUGIN_HARNESS_OK"); | |
| await expect(fs.readdir(stateDir)).resolves.toEqual(["extensions", "openclaw.json", "state"]); | |
| const registryFiles = await fs.readdir(path.join(stateDir, "state")); | |
| expect(registryFiles).toContain("openclaw.sqlite"); | |
| expect(registryFiles.every((file) => file.startsWith("openclaw.sqlite"))).toBe(true); | |
| await expect(fs.stat(path.join(stateDir, "agents"))).rejects.toMatchObject({ code: "ENOENT" }); | |
| }); | |
| it("exits naturally after a one-shot ingress turn with workspace skills", async () => { | |
| const stateDir = tempDirs.make("openclaw-agent-ingress-one-shot-"); | |
| const workspace = path.join(stateDir, "workspace"); | |
| const skillDir = path.join(workspace, "skills", "exit-proof"); | |
| const outputPath = path.join(stateDir, "ingress-result.json"); | |
| await fs.mkdir(skillDir, { recursive: true }); | |
| await fs.writeFile( | |
| path.join(skillDir, "SKILL.md"), | |
| "---\nname: exit-proof\ndescription: One-shot ingress proof\n---\nUse the fixture.\n", | |
| "utf8", | |
| ); | |
| await writeHarnessPlugin(stateDir); | |
| const config = buildExecProofConfig(); | |
| config.agents = { | |
| defaults: { ...config.agents?.defaults, workspace, skipBootstrap: true }, | |
| }; | |
| await writeConfig(stateDir, config); | |
| const source = ` | |
| import fs from "node:fs"; | |
| import { agentCommandFromIngress } from "openclaw/plugin-sdk/agent-runtime"; | |
| const result = await agentCommandFromIngress({ | |
| agentId: "main", | |
| sessionId: "ingress-one-shot-session", | |
| message: "prove one-shot ingress completion", | |
| model: "exec-proof/proof-model", | |
| allowModelOverride: true, | |
| json: true, | |
| cleanupBundleMcpOnRunEnd: true, | |
| cleanupCliLiveSessionOnRunEnd: true, | |
| oneShotCliRun: true, | |
| }, { | |
| log() {}, | |
| error: (...args) => console.error(...args), | |
| exit: (code) => { throw new Error("unexpected runtime exit " + code); }, | |
| }); | |
| fs.writeFileSync(${JSON.stringify(outputPath)}, JSON.stringify(result)); | |
| `; | |
| const [completion] = await Promise.allSettled([ | |
| execFileAsync(process.execPath, ["--input-type=module", "--eval", source], { | |
| cwd: path.resolve(import.meta.dirname, "../.."), | |
| encoding: "utf8", | |
| env: buildChildEnv(stateDir), | |
| timeout: 30_000, | |
| }), | |
| ]); | |
| // A completed result followed by a timeout identifies retained process resources. | |
| expect(JSON.parse(await fs.readFile(outputPath, "utf8"))).toMatchObject({ | |
| payloads: [{ text: "PLUGIN_HARNESS_OK" }], | |
| }); | |
| expect(completion).toMatchObject({ status: "fulfilled" }); | |
| }); | |
| }); | |