#!/usr/bin/env node const assert = require("assert"); const cp = require("child_process"); const crypto = require("crypto"); const net = require("net"); const path = require("path"); const repo = path.resolve(__dirname, ".."); const project = path.join(repo, "examples/launch-build-demo"); const agentPublicKey = "agent-cli-smoke-public-key"; function sha256(value) { return `sha256:${crypto.createHash("sha256").update(value).digest("hex")}`; } function waitForJsonLine(child) { return new Promise((resolve, reject) => { let buffer = ""; child.stdout.on("data", (chunk) => { buffer += chunk.toString(); const newline = buffer.indexOf("\n"); if (newline < 0) return; try { resolve(JSON.parse(buffer.slice(0, newline).trim())); } catch (error) { reject(error); } }); child.once("exit", (code) => { reject(new Error(`process exited before JSON line with code ${code}`)); }); }); } function send(addr, message) { return new Promise((resolve, reject) => { const socket = net.connect(addr.port, addr.host, () => { socket.write(`${JSON.stringify(message)}\n`); }); let buffer = ""; socket.on("data", (chunk) => { buffer += chunk.toString(); const newline = buffer.indexOf("\n"); if (newline < 0) return; socket.end(); try { resolve(JSON.parse(buffer.slice(0, newline))); } catch (error) { reject(error); } }); socket.on("error", reject); }); } function runCli(args, env = {}) { return new Promise((resolve, reject) => { const child = cp.spawn( "cargo", ["run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--", ...args], { cwd: repo, env: { ...process.env, ...env } } ); const cliPid = child.pid; let stdout = ""; let stderr = ""; child.stdout.on("data", (chunk) => { stdout += chunk.toString(); }); child.stderr.on("data", (chunk) => { stderr += chunk.toString(); }); child.on("exit", (code) => { if (code !== 0) { reject(new Error(`CLI run failed with code ${code}\n${stderr}`)); return; } try { resolve({ pid: cliPid, report: JSON.parse(stdout) }); } catch (error) { reject(new Error(`CLI output was not JSON: ${stdout}\n${error.stack || error.message}`)); } }); }); } (async () => { const coordinator = cp.spawn( "cargo", [ "run", "-q", "-p", "disasmer-coordinator", "--bin", "disasmer-coordinator", "--", "--listen", "127.0.0.1:0" ], { cwd: repo } ); assert(Number.isInteger(coordinator.pid)); try { const ready = await waitForJsonLine(coordinator); const [host, portText] = ready.listen.split(":"); const addr = { host, port: Number(portText) }; assert.strictEqual((await send(addr, { type: "ping" })).type, "pong"); const { pid: cliPid, report } = await runCli( ["run", "--coordinator", `${addr.host}:${addr.port}`, "--project", project, "--json"], { DISASMER_AGENT_PUBLIC_KEY: agentPublicKey } ); assert(Number.isInteger(cliPid)); assert.notStrictEqual(cliPid, coordinator.pid); assert.strictEqual(report.plan.entry, "build"); assert.deepStrictEqual(report.plan.session, { AgentPublicKey: { agent: "agent", public_key_fingerprint: sha256(agentPublicKey), browser_interaction_required: false } }); assert.strictEqual(report.boundary.cli_process_started_node_process, true); assert.strictEqual(report.boundary.cli_process_started_coordinator_process, false); assert(Number.isInteger(report.boundary.spawned_node_process_id)); assert.notStrictEqual(report.boundary.spawned_node_process_id, cliPid); assert.notStrictEqual(report.boundary.spawned_node_process_id, coordinator.pid); assert.strictEqual(report.boundary.node_session_requests, 10); assert.strictEqual(report.node_report.node_status, "completed"); assert.strictEqual(report.node_report.status_code, 0); assert.strictEqual(report.node_report.large_bytes_uploaded, false); assert.strictEqual(report.node_report.capability_response.type, "node_capabilities_recorded"); assert.strictEqual(report.node_report.task_assignment_response.type, "task_placement"); assert.strictEqual(report.node_report.debug_command_response.type, "debug_command"); assert.strictEqual(report.node_report.log_event_response.type, "task_log_recorded"); assert.strictEqual(report.node_report.vfs_metadata_response.type, "vfs_metadata_recorded"); assert.strictEqual(report.node_report.staged_artifact.path, "/vfs/artifacts/cli-run-output.txt"); const events = await send(addr, { type: "list_task_events", tenant: "tenant", project: "project", actor_user: "user", process: "vp-cli-local" }); assert.strictEqual(events.type, "task_events"); assert.strictEqual(events.events.length, 1); assert.strictEqual(events.events[0].node, "node-cli-local"); assert.strictEqual(events.events[0].process, "vp-cli-local"); assert.strictEqual(events.events[0].task, "compile-linux"); assert.strictEqual(events.events[0].artifact_path, "/vfs/artifacts/cli-run-output.txt"); } finally { coordinator.kill("SIGTERM"); } const { pid: autoCliPid, report: autoReport } = await runCli([ "run", "--local", "--project", project, "--json", ]); assert(Number.isInteger(autoCliPid)); assert.strictEqual(autoReport.plan.entry, "build"); assert.deepStrictEqual(autoReport.plan.coordinator, "LocalOnly"); assert.deepStrictEqual(autoReport.plan.session, "Anonymous"); assert.strictEqual(autoReport.boundary.cli_process_started_node_process, true); assert.strictEqual(autoReport.boundary.cli_process_started_coordinator_process, true); assert.match(autoReport.boundary.coordinator_address, /^127\.0\.0\.1:\d+$/); assert(Number.isInteger(autoReport.boundary.coordinator_process_id)); assert(Number.isInteger(autoReport.boundary.spawned_node_process_id)); assert.notStrictEqual(autoReport.boundary.coordinator_process_id, autoCliPid); assert.notStrictEqual(autoReport.boundary.spawned_node_process_id, autoCliPid); assert.notStrictEqual( autoReport.boundary.spawned_node_process_id, autoReport.boundary.coordinator_process_id ); assert.strictEqual(autoReport.boundary.node_session_requests, 10); assert.strictEqual(autoReport.node_report.node_status, "completed"); assert.strictEqual(autoReport.node_report.status_code, 0); assert.strictEqual(autoReport.node_report.large_bytes_uploaded, false); assert.strictEqual(autoReport.node_report.capability_response.type, "node_capabilities_recorded"); assert.strictEqual(autoReport.node_report.task_assignment_response.type, "task_placement"); assert.strictEqual(autoReport.node_report.debug_command_response.type, "debug_command"); assert.strictEqual(autoReport.node_report.log_event_response.type, "task_log_recorded"); assert.strictEqual(autoReport.node_report.vfs_metadata_response.type, "vfs_metadata_recorded"); assert.strictEqual( autoReport.node_report.staged_artifact.path, "/vfs/artifacts/cli-run-output.txt" ); console.log("CLI local run smoke passed"); })().catch((error) => { console.error(error.stack || error.message); process.exit(1); });