Skill Tracer
Skills › Anatomy › anatomy › fingerprint.mjs

fingerprint.mjs

31 lines · scripts/fingerprint.mjs at 1482e84

1import { createHash } from "node:crypto";
2import { readdirSync, readFileSync, statSync } from "node:fs";
3import { join, relative, sep } from "node:path";
4
5export const KIT_FILES = (path) => path === "scripts/inline-kit.mjs" || (path.startsWith("kit/") && !path.split("/").some((part) => part.startsWith(".")));
6
7const sha256 = (data) => createHash("sha256").update(data).digest("hex");
8
9export function fingerprintOf(entries) {
10 const lines = entries
11 .filter(([path]) => KIT_FILES(path))
12 .map(([path, content]) => `${path}\0${sha256(content)}\n`)
13 .sort();
14 if (!lines.length) throw new Error("fingerprint: no kit files found");
15 return `sha256:${sha256(lines.join(""))}`;
18function walk(root, dir = root, out = []) {
19 for (const name of readdirSync(dir)) {
20 const full = join(dir, name);
21 const stat = statSync(full);
22 if (stat.isDirectory()) walk(root, full, out);
23 else if (stat.isFile()) out.push(relative(root, full).split(sep).join("/"));
24 }
25 return out;
28export function fingerprintOfSkill(skillRoot) {
29 const files = [...walk(join(skillRoot, "kit")).map((path) => `kit/${path}`), "scripts/inline-kit.mjs"];
30 return fingerprintOf(files.map((path) => [path, readFileSync(join(skillRoot, path))]));