Files

106 lines
3.6 KiB
JavaScript
Raw Permalink Normal View History

import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { createHash } from "node:crypto";
import { readFile, readdir, realpath } from "node:fs/promises";
import { join, relative } from "node:path";
import { fileURLToPath } from "node:url";
const sha = (value) => createHash("sha256").update(value).digest("hex");
/** Bind a trial to its source checkout and compiled runtime, including deferred assets. */
export const captureRuntimeBinding = async (runtime, kind = "cli") => {
assert.ok(kind === "cli" || kind === "mcp", "Unknown runtime entry");
const root = await realpath(runtime);
const git = (args) =>
execFileSync("git", args, { cwd: root, maxBuffer: 16 * 1024 * 1024 });
const gitRevision = git(["rev-parse", "HEAD"]).toString().trim();
const sourcePaths = ["src", "scripts", "package.json", "package-lock.json"];
const sourceDiff = git([
"diff",
"--no-ext-diff",
"--no-textconv",
"--binary",
"HEAD",
"--",
...sourcePaths,
]);
const untracked = git([
"ls-files",
"--others",
"--exclude-standard",
"-z",
"--",
...sourcePaths,
])
.toString()
.split("\0")
.filter(Boolean)
.sort();
const untrackedEntries = [];
for (const name of untracked)
untrackedEntries.push([name, sha(await readFile(join(root, name)))]);
const files = ["scripts/rea.mjs", "package.json", "package-lock.json"];
const visit = async (directory) => {
const entries = await readdir(directory, { withFileTypes: true });
for (const entry of entries.sort((a, b) =>
a.name < b.name ? -1 : a.name > b.name ? 1 : 0,
)) {
const path = join(directory, entry.name);
assert.ok(!entry.isSymbolicLink(), `Unbound compiled CLI link: ${path}`);
if (entry.isDirectory()) await visit(path);
else if (entry.isFile() && /\.(?:[cm]?js|json)$/.test(entry.name))
files.push(relative(root, path));
}
};
// MCP materializes additional workers and reads build-owned JSON after
// discovery. Bind every compiled JS/JSON asset, rather than only its entry.
await visit(join(root, kind === "mcp" ? "dist" : "dist/cli-runtime"));
assert.ok(
files.includes(
kind === "mcp"
? join("dist", "mcp", "main.js")
: join("dist", "cli-runtime", "cli.js"),
),
"Missing compiled runtime entry",
);
const hash = createHash("sha256");
let bytes = 0;
for (const name of files.sort()) {
const value = await readFile(join(root, name));
bytes += value.length;
hash.update(JSON.stringify([name, value.length, sha(value)]) + "\n");
}
return {
binding_version: kind === "mcp" ? 2 : 1,
root,
node: process.version,
git_revision: gitRevision,
source_diff_sha256: sha(sourceDiff),
untracked_source_sha256: sha(JSON.stringify(untrackedEntries)),
...(kind === "mcp"
? {
compiled_runtime_sha256: hash.digest("hex"),
compiled_runtime_files: files.length,
compiled_runtime_bytes: bytes,
}
: {
compiled_cli_sha256: hash.digest("hex"),
compiled_cli_files: files.length,
compiled_cli_bytes: bytes,
}),
};
};
export const assertRuntimeBinding = (actual, expected, mode) => {
assert.ok(expected, `Missing expected runtime binding for ${mode}`);
assert.deepEqual(actual, expected, `Runtime binding differs for ${mode}`);
};
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
console.log(
JSON.stringify(
await captureRuntimeBinding(process.argv[2], process.argv[3]),
null,
2,
),
);
}