import { createHash } from "node:crypto"; import { readFile } from "node:fs/promises"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const SOURCE_FILES = [ "index.html", "styles.css", "app.js", "workers/asr-worker.js", "workers/llm-worker.js", "workers/tts-worker.js", "tools/run-ui-smoke.mjs", "tools/run-evidence-export-smoke.mjs", "tools/run-client-side-smoke.mjs", "tools/run-hosted-smoke.mjs", "tools/run-loopback-series.mjs", "tools/run-fake-mic-benchmark.mjs", "tools/run-local-candidate-benchmark.mjs", "tools/run-real-mic-series.mjs", "tools/run-hosted-evidence-capture.mjs", "tools/run-webgpu-benchmark.mjs", "tools/audit-browser-evidence.mjs", "tools/audit-validation.mjs", "tools/summarize-evidence.mjs", "tools/source-fingerprint.mjs", ]; export async function sourceFingerprint() { const fileFingerprints = []; const aggregate = createHash("sha256"); for (const path of SOURCE_FILES) { const bytes = await readFile(resolve(projectRoot, path)); const hash = createHash("sha256").update(bytes).digest("hex"); fileFingerprints.push({ path, sha256: hash, bytes: bytes.length }); aggregate.update(`${path}\0${hash}\0`); } return { algorithm: "sha256", hash: aggregate.digest("hex"), files: fileFingerprints, }; }