Filbert approved round 1 (f167b85e). Manifest 782bcb62, 21 files, plus the QUEUE.md markers and the TOOLS.md section. Lead decision 35. Co-Authored-By: Claude Opus 5.5 <[email protected]>
101 lines
4.4 KiB
JavaScript
101 lines
4.4 KiB
JavaScript
// `scripts/mosaic queue` (A2). The dispatch must leave every other call to
|
|
// scripts/mosaic exactly as it was: the seat CLI sees the same argv, working
|
|
// directory, environment and stdin under the new script as under the pre-A2
|
|
// copy in fixtures/mosaic-pre-a2.sh. Both CLIs are fakes that record what
|
|
// they got; nothing here runs a seat or touches a queue.
|
|
import assert from "node:assert/strict";
|
|
import { spawnSync } from "node:child_process";
|
|
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { test } from "node:test";
|
|
import { SCRIPTS } from "./helpers.mjs";
|
|
|
|
const HERE = new URL(".", import.meta.url).pathname;
|
|
|
|
const FAKE = `import { readFileSync, writeFileSync } from "node:fs";
|
|
writeFileSync(process.env.CAPTURE, JSON.stringify({
|
|
cli: process.argv[1].slice(process.env.ROOT.length), argv: process.argv.slice(2), cwd: process.cwd(),
|
|
env: process.env, stdin: readFileSync(0, "utf8"),
|
|
}));
|
|
process.stdout.write("fake out\\n");
|
|
process.stderr.write("fake err\\n");
|
|
process.exitCode = Number(process.env.EXIT);
|
|
`;
|
|
|
|
// A root holding `script` as scripts/mosaic and both fake CLIs.
|
|
function root(t, script) {
|
|
const r = realpathSync(mkdtempSync(join(tmpdir(), "mosaic-queue-dispatch-")));
|
|
t.after(() => rmSync(r, { recursive: true, force: true }));
|
|
mkdirSync(join(r, "scripts"));
|
|
cpSync(script, join(r, "scripts/mosaic"));
|
|
for (const pkg of ["seat", "queue"]) {
|
|
mkdirSync(join(r, `packages/${pkg}/src`), { recursive: true });
|
|
writeFileSync(join(r, `packages/${pkg}/src/cli.mjs`), FAKE);
|
|
}
|
|
mkdirSync(join(r, "work"));
|
|
return r;
|
|
}
|
|
|
|
// Runs scripts/mosaic from `work` and returns everything the fake saw, with
|
|
// the root replaced so two roots compare.
|
|
function call(r, args, exit = 7) {
|
|
const capture = join(r, "capture.json");
|
|
rmSync(capture, { force: true });
|
|
const env = { PATH: process.env.PATH, HOME: r, LANG: "C", ROOT: r, CAPTURE: capture, EXIT: String(exit), MOSAIC_AGENT_NAME: "darkwing", SPACED: "a b" };
|
|
const p = spawnSync("bash", [join(r, "scripts/mosaic"), ...args], { cwd: join(r, "work"), env, input: "stdin line\nsecond\n", encoding: "utf8" });
|
|
if (p.error) throw p.error;
|
|
const got = existsSync(capture) ? readFileSync(capture, "utf8") : null;
|
|
return { status: p.status, out: p.stdout, err: p.stderr, capture: got === null ? null : got.replaceAll(r, "<ROOT>") };
|
|
}
|
|
|
|
const SEAT_CALLS = [
|
|
["launch", "--repo", "/srv/repo", "--harness", "pi", "darkwing"],
|
|
["seat", "task", "darkwing", "text with two spaces", ""],
|
|
[],
|
|
[""],
|
|
["launch", "queue"],
|
|
["Queue", "list"],
|
|
["queue-x"],
|
|
["--", "queue"],
|
|
["--help"],
|
|
];
|
|
|
|
test("every call but `queue` reaches the seat CLI exactly as before A2", (t) => {
|
|
const before = root(t, join(HERE, "fixtures", "mosaic-pre-a2.sh"));
|
|
const after = root(t, join(SCRIPTS, "mosaic"));
|
|
for (const args of SEAT_CALLS) {
|
|
const a = call(before, args);
|
|
const b = call(after, args);
|
|
assert.notEqual(a.capture, null, `${JSON.stringify(args)}: the pre-A2 script reached no CLI`);
|
|
assert.equal(JSON.parse(a.capture).cli, "/packages/seat/src/cli.mjs");
|
|
assert.deepEqual(b, a, JSON.stringify(args));
|
|
}
|
|
});
|
|
|
|
test("`queue` reaches the queue CLI with the rest of the arguments", (t) => {
|
|
const r = root(t, join(SCRIPTS, "mosaic"));
|
|
for (const rest of [["list"], [], ["note", "9", "text with spaces", "--op", "note-9-000001"], ["queue"], [""]]) {
|
|
const got = call(r, ["queue", ...rest]);
|
|
assert.deepEqual([got.status, got.out, got.err], [7, "fake out\n", "fake err\n"]);
|
|
const c = JSON.parse(got.capture);
|
|
assert.deepEqual([c.cli, c.argv, c.cwd, c.stdin], ["/packages/queue/src/cli.mjs", rest, "<ROOT>/work", "stdin line\nsecond\n"]);
|
|
}
|
|
// A queue CLI that succeeds must not fall through to the seat CLI.
|
|
const ok = call(r, ["queue", "list"], 0);
|
|
assert.deepEqual([ok.status, ok.out, JSON.parse(ok.capture).cli], [0, "fake out\n", "/packages/queue/src/cli.mjs"]);
|
|
});
|
|
|
|
test("the pre-A2 fixture is the script A2 changed", () => {
|
|
const fixture = readFileSync(join(HERE, "fixtures", "mosaic-pre-a2.sh"), "utf8");
|
|
const now = readFileSync(join(SCRIPTS, "mosaic"), "utf8");
|
|
// A2 adds lines and removes none.
|
|
const lines = now.split("\n");
|
|
let i = 0;
|
|
for (const l of fixture.split("\n")) {
|
|
while (i < lines.length && lines[i] !== l) i++;
|
|
assert.ok(i < lines.length, `pre-A2 line missing: ${l}`);
|
|
i++;
|
|
}
|
|
});
|