import { test } from "node:test"; import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { join } from "node:path"; import { busExit, humanTransport, refuseInsideAgent } from "../src/transport.mjs"; import { fakeCli, humanEnv, tmp } from "./helpers.mjs"; // The fake records argv and stdin, then answers per verb. The real // human-cli.mjs is never run here: its proof needs a human shell. const BODY = ` import { readFileSync, writeFileSync } from "node:fs"; const input = readFileSync(0, "utf8"); writeFileSync(process.env.FAKE_LOG, JSON.stringify({ argv: process.argv.slice(2), input })); const { verb } = JSON.parse(input); if (verb === "inbox") process.stdout.write(JSON.stringify([{ id: "d1" }]) + "\\n"); else if (verb === "garbage") process.stdout.write("not json"); else if (verb === "hang") setTimeout(() => {}, 60000); else { process.stderr.write("some noise\\n" + verb + "\\n"); process.exit(2); } `; function setup(t) { const root = tmp(t); const log = join(root, "log.json"); const cli = fakeCli(root, BODY); const call = humanTransport({ socket: "/run/fake.sock", business: "acme", env: humanEnv({ FAKE_LOG: log }), cli, timeoutMs: 2000 }); return { call, seen: () => JSON.parse(readFileSync(log, "utf8")) }; } test("the transport writes {business, verb, args} to the child and reads its JSON", async (t) => { const s = setup(t); assert.deepEqual(await s.call("inbox"), [{ id: "d1" }]); assert.deepEqual(s.seen().argv, ["/run/fake.sock"]); assert.deepEqual(JSON.parse(s.seen().input), { business: "acme", verb: "inbox", args: {} }); }); test("a bus code on stderr becomes the exit code; garbage and timeouts are outcome problems", async (t) => { const s = setup(t); for (const [code, exit] of [["human-required", 3], ["read-only", 3], ["decision-closed", 2], ["outcome-unknown", 1]]) { await assert.rejects(s.call(code), (e) => e.code === code && e.exitCode === exit, code); } await assert.rejects(s.call("garbage"), (e) => e.code === "invalid-response" && e.exitCode === 1); await assert.rejects(s.call("hang"), (e) => e.exitCode === 1 && /outcome-unknown/.test(e.message)); }); test("busExit and refuseInsideAgent", () => { assert.equal(busExit("unauthenticated"), 3); assert.equal(busExit("invalid-request"), 2); assert.doesNotThrow(() => refuseInsideAgent(humanEnv())); assert.throws(() => refuseInsideAgent({ PI_AGENT_DIR: "/x" }), (e) => e.exitCode === 3 && /PI_AGENT_DIR/.test(e.message)); });