feat(queue): queue as data A2, migration, render and dispatch (#1508)
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]>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
// `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++;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user