2026-06-19 20:13:43 +08:00
|
|
|
#!/usr/bin/env node
|
2026-06-20 05:51:17 +08:00
|
|
|
// Stamps sha256 + bytes for real fixture assets into manifest.json.
|
|
|
|
|
// Provenance (sourceUrl/license) is filled by hand -- this only fills hashes.
|
2026-06-19 20:13:43 +08:00
|
|
|
import { createHash } from "node:crypto";
|
2026-06-20 05:51:17 +08:00
|
|
|
import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
2026-06-19 20:13:43 +08:00
|
|
|
import { dirname, join } from "node:path";
|
|
|
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
|
|
|
|
|
|
const ROOT = dirname(fileURLToPath(import.meta.url));
|
|
|
|
|
const existing = JSON.parse(readFileSync(join(ROOT, "manifest.json"), "utf8"));
|
|
|
|
|
const byPath = new Map(existing.assets.map((a) => [a.path, a]));
|
|
|
|
|
|
2026-06-20 05:51:17 +08:00
|
|
|
// Scan each modality valid dir (replaces the old content/ scan)
|
2026-07-27 15:37:30 +08:00
|
|
|
const SCAN_DIRS = ["image/valid", "video/valid", "audio/valid", "document/valid"];
|
2026-06-20 05:51:17 +08:00
|
|
|
|
|
|
|
|
for (const dir of SCAN_DIRS) {
|
|
|
|
|
const absDir = join(ROOT, dir);
|
|
|
|
|
if (!existsSync(absDir)) continue;
|
|
|
|
|
for (const name of readdirSync(absDir)) {
|
|
|
|
|
const rel = `${dir}/${name}`;
|
|
|
|
|
const bytes = readFileSync(join(absDir, name));
|
|
|
|
|
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
2026-07-27 15:37:30 +08:00
|
|
|
const prev = byPath.get(rel) ?? {
|
|
|
|
|
path: rel,
|
|
|
|
|
sourceUrl: "UNVERIFIED",
|
|
|
|
|
license: "UNVERIFIED",
|
|
|
|
|
toolsServed: [],
|
|
|
|
|
};
|
2026-06-20 05:51:17 +08:00
|
|
|
byPath.set(rel, { ...prev, sha256, bytes: bytes.length });
|
|
|
|
|
}
|
2026-06-19 20:13:43 +08:00
|
|
|
}
|
|
|
|
|
const assets = [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
|
|
|
|
|
writeFileSync(join(ROOT, "manifest.json"), JSON.stringify({ assets }, null, 2));
|
|
|
|
|
console.log(`manifest: ${assets.length} assets`);
|