Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,236 @@
#!/usr/bin/env bun
/**
* delib-monorepo-refs — scrub genesis / monorepo / stage / OpenSpec metadata
* from individual library README.md files so they read as standalone packages.
*
* Usage:
* bun scripts/delib-monorepo-refs.ts # rewrite
* bun scripts/delib-monorepo-refs.ts --dry-run # preview
*/
import { readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { CONFIG } from "./lib/config.js";
import { walkMd } from "./lib/doc-tree.js";
const ROOT = CONFIG.paths.root;
const PACKAGES_ROOT = join(ROOT, CONFIG.paths.packagesRoot);
const REPLACEMENTS: { pattern: RegExp; replacement: string; note?: string }[] = [
// 1. Strip OpenSpec link blocks (won't resolve on npm)
{
pattern: /\n?<!-- begin:auto-spec-link -->[\s\S]*?<!-- end:auto-spec-link -->\n?/g,
replacement: "\n",
note: "OpenSpec block",
},
// 2. Stand-alone "## OpenSpec" heading + following spec-link line
{
pattern: /\n?## OpenSpec\n\nCanonical capability spec: `?[^`\n]+`?\.[ \t]*\n?/g,
replacement: "\n",
note: "OpenSpec heading",
},
// 3. Remove Stage-N.N prefix from H1 title lines
{
pattern:
/^(# @suaveplan\/[\w-]+)\s+-\s+Stage-?\d+(?:\.\d+)?\s+/gim,
replacement: "$1 — ",
note: "Stage in H1",
},
// 4. Remove Stage-N.N at start of sentences / lines (common prose prefix)
{
pattern:
/([.\n]|^)\s*Stage-?\d+(?:\.\d+)?\s+(concrete|abstract|trivial|bridge|rolled|Better-Auth|contract|package|audit|fixed-principal|session resolver|JWT|service-to-service|in-memory|reference|HTTP|WebSocket|in-process|fixed-Principal|concrete Hono|concrete GraphQL|concrete WebAssembly|concrete Apollo|concrete static|concrete tenant|concrete database|concrete event|concrete job|concrete logger|concrete manifest|concrete migration|concrete OpenAPI|concrete rate-limit|concrete router|concrete saga|concrete sandbox|concrete secrets|concrete SSE|concrete WS|concrete worker|concrete WS broker|concrete WS Bun)\b/gi,
replacement: "$1$2",
note: "Stage prefix",
},
// 5. Remove orphaned "Stage-N.N" that stands alone mid-sentence
{
pattern: /\bStage-?\d+(?:\.\d+)?\b/gi,
replacement: "",
note: "orphaned Stage",
},
// 6. "Genesis Stage N — …" sentences
{
pattern:
/\bGenesis Stage \d+(?:\.\d+)?[^.]*\.\s*/gi,
replacement: "",
note: "Genesis Stage sentence",
},
// 7. "Genesis-wave package …" sentences
{
pattern: /\bGenesis-wave package[^.]*\.\s*/gi,
replacement: "",
note: "Genesis-wave sentence",
},
// 8. "Per design doc §N.N, genesis ships …" sentences
{
pattern:
/\bPer design doc §\d+(?:\.\d+)*,\s+genesis\s+[^.]*\.\s*/gi,
replacement: "",
note: "design-doc genesis sentence",
},
// 9. "the Suaveplan monorepo" / "for the Suaveplan monorepo"
{
pattern: /\bfor the Suaveplan monorepo\b/gi,
replacement: "for Suaveplan",
note: "monorepo ref",
},
{
pattern: /\bthe Suaveplan monorepo\b/gi,
replacement: "Suaveplan",
note: "monorepo ref",
},
// 10. "the genesis monorepo"
{
pattern: /\bthe genesis monorepo\b/gi,
replacement: "Suaveplan",
note: "genesis monorepo",
},
// 11. "genesis `@suaveplan/...`" -> just the package name
{
pattern: /\bgenesis\s+(`@suaveplan\/[^`]+`)/gi,
replacement: "$1",
note: "genesis pkg prefix",
},
// 12. "for the `@suaveplan/api` plugin foundation"
{
pattern:
/\bfor the `@suaveplan\/api` plugin foundation\b/gi,
replacement: "for `@suaveplan/api`",
note: "plugin foundation",
},
{
pattern:
/\bthe `@suaveplan\/api` plugin foundation\b/gi,
replacement: "`@suaveplan/api`",
note: "plugin foundation",
},
{
pattern: /\bplugin foundation\b/gi,
replacement: "plugin system",
note: "plugin foundation",
},
// 13. Loose "genesis" when clearly referring to the project (not a name)
{
pattern: /\bgenesis (fix|package|design|crypto|wave|monorepo)\b/gi,
replacement: "$1",
note: "genesis adjective",
},
// 14. "openspec/changes/..." paths in prose
{
pattern: /`?\.\.\/\.\.\/\.\.\/\.\.\/openspec\/[^`\n]+`?/g,
replacement: "the spec",
note: "openspec path",
},
// 15. "OpenSpec change" / "OpenSpec-tracked"
{
pattern: /\bOpenSpec change\b/gi,
replacement: "spec change",
note: "OpenSpec change",
},
{
pattern: /\bOpenSpec-tracked\b/gi,
replacement: "tracked",
note: "OpenSpec-tracked",
},
// 16. "of the umbrella plan (openspec/changes/...)"
{
pattern:
/\bof the umbrella plan\s*\([^)]+openspec[^)]+\)\b/gi,
replacement: "of the design",
note: "umbrella plan",
},
// 17. "Stage N of the umbrella plan"
{
pattern:
/\bStage \d+(?:\.\d+)?\s+of the umbrella plan\b/gi,
replacement: "the design",
note: "Stage umbrella plan",
},
];
function scrub(content: string): { next: string; hits: string[] } {
let next = content;
const hits: string[] = [];
for (const { pattern, replacement, note } of REPLACEMENTS) {
const before = next;
next = next.replace(pattern, replacement);
if (next !== before && note) {
hits.push(note);
}
}
// Collapse multiple blank lines left behind
next = next.replace(/\n{3,}/g, "\n\n");
return { next, hits };
}
function main(): void {
const dryRun = process.argv.slice(2).includes("--dry-run");
const readmes = walkMd(PACKAGES_ROOT, {
ignoreDirs: ["node_modules", "dist", "build", "coverage", ".turbo"],
}).filter((p) => basename(p) === "README.md");
let changed = 0;
let unchanged = 0;
const report: string[] = [];
for (const readmePath of readmes) {
const content = readFileSync(readmePath, "utf-8");
const { next, hits } = scrub(content);
if (next === content) {
unchanged++;
continue;
}
const rel = readmePath.replace(ROOT + "/", "");
const uniqueHits = [...new Set(hits)];
report.push(`${rel} (${uniqueHits.join(", ")})`);
if (!dryRun) {
writeFileSync(readmePath, next);
}
changed++;
}
console.log("");
console.log(`✏️ Changed: ${changed}`);
console.log(`⏭️ Unchanged: ${unchanged}`);
if (report.length > 0) {
console.log("");
console.log("Files touched:");
for (const line of report) console.log(` ${line}`);
}
if (dryRun) {
console.log("");
console.log("(Dry-run — no files were written.)");
}
}
function basename(p: string): string {
return p.slice(p.lastIndexOf("/") + 1);
}
main();