Files
openrig/scripts/regen-edge-digests.mjs
T
Mike Schwarz af7f660884 fix(skills): regenerate product skills from their one in-repo home (#1396)
Product skills now regenerate from one editable home inside this repository, so a skill fix is made once and the apply can't replace reviewed text with an outside copy.

- Each skill has one home: its spec copy when it has a spec edge, otherwise its plugin copy. `scripts/skill-edge-layout.generated.json` still lists which copies each skill has, and every other copy is generated from the home.
- The apply reads nothing outside the repository. `OPENRIG_SKILL_CANON_ROOT` is no longer needed; when it's set, the script says it's ignored.
- The apply can't erase a home. Every read and write is planned and every home is staged before any output is replaced, an output that overlaps a home is refused, and a home is never written. On an edge that holds homes, an undeclared skill is left in place and listed.
- The sanitization and leak rules now check the home. Generated copies stay byte-identical to it, and each generated file takes its home's mode.
- `--check` compares every generated copy with its home and reports `copy-diverged`, `copy-missing` or `copy-extra`, even after the digests are refreshed.
- `skills/README.md` and `ARCHITECTURE.md` describe the in-repo source.

One content change: `metadata.openrig.transfer_test: pending` is removed from `openrig-software-factory/SKILL.md` (its spec home and `_canonical` copy, with both digests updated). The sanitizer already strips that key from public copies, and nothing in the product reads it.

Directory modes aren't restored from homes; only file modes are.
2026-10-17 23:41:00 -07:00

36 lines
1.9 KiB
JavaScript

#!/usr/bin/env node
// Disk-truth regen of scripts/skill-edge-digests.generated.json.
//
// Recomputes every edge's file-integrity hashes from the files ON DISK, using the in-repo (already
// correct) scripts/skill-edge-layout.generated.json to know which edges to walk. NO external-canon
// YAMLs are required — the digests are purely disk + layout derived. Full mirror APPLY reads the same
// product policy JSON and regenerates each skill's copies from its home in this repo.
// THIS regen only refreshes the reality side (hashes of present files)
// to match folded main.
//
// PROPERTY (layout = authority, disk = reality, regen touches only reality): buildEdgeDigests hashes
// PRESENT files only. A layout-demanded file missing from disk is never given a digest here, so
// `mirror-skills.mjs --check` stays LOUD about it (via its layout-missing check + the narrow, named,
// self-policing external-canon-pending allowlist) — a future accidental deletion can never be silently
// blessed by a regen.
//
// Usage: node scripts/regen-edge-digests.mjs (writes in place; run when folded skill edges drift)
import { readFileSync, writeFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { buildEdgeDigests } from "../packages/daemon/scripts/gen-control-plane-json.mjs";
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
const layoutPath = join(repoRoot, "scripts/skill-edge-layout.generated.json");
const outPath = join(repoRoot, "scripts/skill-edge-digests.generated.json");
const layout = JSON.parse(readFileSync(layoutPath, "utf8"));
const digests = buildEdgeDigests({ repoRoot, layout });
writeFileSync(outPath, `${JSON.stringify(digests, null, 2)}\n`);
const fileCount = Object.values(digests.edges).reduce((n, files) => n + Object.keys(files).length, 0);
console.log(
`Regenerated ${outPath} from disk: ${Object.keys(digests.edges).length} edges, ${fileCount} files.`,
);