63 lines
2.8 KiB
JavaScript
63 lines
2.8 KiB
JavaScript
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import { dirname, resolve } from "node:path";
|
|
import {
|
|
buildInventories,
|
|
encodeInventory,
|
|
renderContractModule,
|
|
renderDocumentation,
|
|
validateInventorySchema,
|
|
validateInventories,
|
|
} from "./lib/capability-inventory.mjs";
|
|
|
|
const packageRoot = resolve(import.meta.dirname, "..");
|
|
const repoRoot = resolve(packageRoot, "../..");
|
|
const evalCandidates = [
|
|
resolve(repoRoot, "../paperclip-evals/paperclip-skill-optimization"),
|
|
resolve(repoRoot, "../../../../paperclip-evals/paperclip-skill-optimization"),
|
|
];
|
|
const evalRoot = process.env.PAPERCLIP_EVALS_ROOT
|
|
?? (await (async () => {
|
|
for (const candidate of evalCandidates) {
|
|
if (await access(candidate).then(() => true, () => false)) return candidate;
|
|
}
|
|
throw new Error(`Paperclip eval corpus not found. Set PAPERCLIP_EVALS_ROOT. Checked:\n${evalCandidates.join("\n")}`);
|
|
})());
|
|
const outputPaths = {
|
|
capabilities: resolve(packageRoot, "spec/capability/capabilities.yaml"),
|
|
evaluations: resolve(packageRoot, "spec/capability/eval-traceability.yaml"),
|
|
legacyMcpAliases: resolve(packageRoot, "spec/capability/mcp-tool-map.yaml"),
|
|
contract: resolve(packageRoot, "src/generated/capability-contract.ts"),
|
|
documentation: resolve(packageRoot, "docs/capability-contract.md"),
|
|
};
|
|
|
|
const inventories = await buildInventories({ repoRoot, evalRoot });
|
|
const inventorySchema = JSON.parse(await readFile(resolve(packageRoot, "spec/capability/inventory.schema.json"), "utf8"));
|
|
const errors = [
|
|
...validateInventorySchema(inventories, inventorySchema),
|
|
...validateInventories(inventories),
|
|
];
|
|
if (errors.length > 0) throw new Error(`Capability inventory generation failed:\n${errors.join("\n")}`);
|
|
|
|
const outputs = {
|
|
[outputPaths.capabilities]: encodeInventory(inventories.capabilities),
|
|
[outputPaths.evaluations]: encodeInventory(inventories.evaluations),
|
|
[outputPaths.legacyMcpAliases]: encodeInventory(inventories.legacyMcpAliases),
|
|
[outputPaths.contract]: renderContractModule(inventories),
|
|
[outputPaths.documentation]: renderDocumentation(inventories),
|
|
};
|
|
|
|
if (process.argv.includes("--check")) {
|
|
const stale = [];
|
|
for (const [path, content] of Object.entries(outputs)) {
|
|
if (await readFile(path, "utf8").catch(() => "") !== content) stale.push(path);
|
|
}
|
|
if (stale.length > 0) throw new Error(`Capability generated outputs are stale:\n${stale.join("\n")}`);
|
|
process.stdout.write("Capability inventories and generated contract match the canonical baselines.\n");
|
|
} else {
|
|
await Promise.all(Object.entries(outputs).map(async ([path, content]) => {
|
|
await mkdir(dirname(path), { recursive: true });
|
|
await writeFile(path, content);
|
|
}));
|
|
process.stdout.write("Generated Capability inventories, TypeScript contract, and documentation.\n");
|
|
}
|