import { readFileSync, writeFileSync } from "node:fs"; import { resolve } from "node:path"; const root = resolve(import.meta.dirname, ".."); const source = readFileSync(resolve(root, "skills/paperclip/references/api-reference.md"), "utf8"); const key = (method, path) => `${method} ${path.replace(/:[A-Za-z][A-Za-z0-9_]*|\{[^}]+\}/g, "{}")}`; const entries = {}; let section = "Paperclip API Reference"; for (const line of source.split("\n")) { if (/^#{2,5} /.test(line)) section = line.replace(/^#+ /, ""); const table = /^\|\s*(GET|POST|PATCH|PUT|DELETE)\s*\|\s*`([^`]+)`\s*\|\s*(.*?)\s*\|/.exec(line); if (table) entries[key(table[1], table[2])] = { section, description: table[3] }; } for (const match of source.matchAll(/^(GET|POST|PATCH|PUT|DELETE) (\/api\/[^\s]+)\n(\{[\s\S]*?\n\})/gm)) { try { const body = JSON.parse(match[3]); const id = key(match[1], match[2]); entries[id] ??= { section: "Worked example" }; (entries[id].examples ??= []).push({ body }); entries[id].examples = entries[id].examples.slice(0, 2); } catch { /* Narrative/pseudocode blocks are not executable examples. */ } } const destination = resolve(root, "server/src/services/native-runtime/runner-api-reference.ts"); const output = `// Generated by scripts/generate-runner-api-reference.mjs from the legacy skill reference.\nexport const runnerApiReference: Record = ${JSON.stringify(entries, null, 2)};\n`; if (process.argv.includes("--check")) { if (readFileSync(destination, "utf8") !== output) throw new Error("Runner API skill enrichment is stale"); } else writeFileSync(destination, output);