Skip to content

Commit cdea38a

Browse files
committed
build(sdk): automate README sync to prevent npm/repo drift (0.11.2)
Adds infrastructure to keep packages/governance/README.md (the file npm publishes) in sync with the repo-root README: - scripts/sync-readme.mjs — generates the package README from the root, normalizing repo-relative links to absolute GitHub URLs so they resolve on npmjs.com. Idempotent. - prepublishOnly hook runs sync-readme before tsc, guaranteeing every npm release ships an in-sync README. - npm run sync-readme at the monorepo root for manual runs. - CI guard added to .github/workflows/ci.yml — fails the build if anyone commits a manual edit to the package README without running the sync. No code changes. SDK behavior identical to 0.11.1.
1 parent 5cff579 commit cdea38a

5 files changed

Lines changed: 83 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,11 @@ jobs:
2121
- run: npm run build
2222
- run: npm run lint
2323
- run: npm test
24+
- name: Verify packages/governance/README.md is in sync with root README
25+
run: |
26+
node scripts/sync-readme.mjs
27+
git diff --exit-code packages/governance/README.md || (
28+
echo "::error::packages/governance/README.md is out of sync with root README.md.";
29+
echo "::error::Run 'npm run sync-readme' locally and commit the result.";
30+
exit 1
31+
)

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"scripts": {
1616
"build": "npm run build -w packages/governance && npm run build -w packages/governance-platform",
1717
"test": "npm test -w packages/governance && npm test -w packages/governance-platform",
18-
"lint": "npm run lint -w packages/governance && npm run lint -w packages/governance-platform"
18+
"lint": "npm run lint -w packages/governance && npm run lint -w packages/governance-platform",
19+
"sync-readme": "node scripts/sync-readme.mjs"
1920
},
2021
"engines": {
2122
"node": ">=20"

packages/governance/CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## [0.11.2] - 2026-04-16 — Automate README sync
4+
5+
Adds infrastructure to prevent the npm README from drifting out of sync
6+
with the repo-root README again:
7+
8+
- New `scripts/sync-readme.mjs` — generates `packages/governance/README.md`
9+
from the root `README.md`, normalizing repo-relative links to absolute
10+
GitHub URLs so they resolve on npmjs.com. Idempotent.
11+
- Wired into `prepublishOnly` so every npm release ships an in-sync README
12+
automatically.
13+
- New `npm run sync-readme` at the monorepo root for manual runs.
14+
- CI guard added to `.github/workflows/ci.yml` — fails the build if anyone
15+
commits a manual edit to the package README without running the sync.
16+
17+
No code changes. SDK behavior identical to 0.11.1.
18+
319
## [0.11.1] - 2026-04-16 — Sync npm README with repo
420

521
The `packages/governance/README.md` (the file npm publishes) had drifted ~3

packages/governance/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "governance-sdk",
3-
"version": "0.11.1",
3+
"version": "0.11.2",
44
"description": "AI Agent Governance for TypeScript — policy enforcement, scoring, compliance, and audit for AI agents",
55
"type": "module",
66
"main": "./dist/index.js",
@@ -201,7 +201,7 @@
201201
"dev": "tsc --watch",
202202
"test": "tsx --test src/*.test.ts src/**/*.test.ts",
203203
"lint": "tsc --noEmit",
204-
"prepublishOnly": "tsc"
204+
"prepublishOnly": "node ../../scripts/sync-readme.mjs && tsc"
205205
},
206206
"keywords": [
207207
"ai-governance",

scripts/sync-readme.mjs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env node
2+
/**
3+
* sync-readme.mjs — Sync packages/governance/README.md from the repo-root README.
4+
*
5+
* Why: npm publishes the package-local README (the one inside packages/governance/),
6+
* not the repo-root one. Without sync, npm users see a stale doc. This script
7+
* runs in `prepublishOnly` so every release ships an in-sync README, and is
8+
* also enforced in CI to catch drift on PRs.
9+
*
10+
* Transforms repo-relative links into absolute GitHub URLs so they resolve
11+
* correctly when read on npmjs.com (where there's no monorepo context).
12+
*
13+
* Idempotent — running twice is a no-op.
14+
*/
15+
import { readFileSync, writeFileSync } from "node:fs";
16+
import { fileURLToPath } from "node:url";
17+
import { dirname, join } from "node:path";
18+
19+
const REPO = "lua-ai-global/governance";
20+
const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
21+
const SRC = join(ROOT, "README.md");
22+
const DST = join(ROOT, "packages", "governance", "README.md");
23+
24+
const root = readFileSync(SRC, "utf8");
25+
26+
// Map repo-relative links → absolute GitHub URLs. Order matters: more
27+
// specific patterns first so they don't get clobbered by broader ones.
28+
const transforms = [
29+
// Directory references (use /tree/main/)
30+
[/\]\(\.\/packages\/governance\)/g, `](https://github.com/${REPO}/tree/main/packages/governance)`],
31+
[/\]\(\.\/packages\/governance-platform\)/g, `](https://github.com/${REPO}/tree/main/packages/governance-platform)`],
32+
// File references inside packages (use /blob/main/)
33+
[/\]\(\.\/packages\/([^)]+)\)/g, `](https://github.com/${REPO}/blob/main/packages/$1)`],
34+
// Top-level files
35+
[/\]\(\.\/LICENSE\)/g, `](https://github.com/${REPO}/blob/main/LICENSE)`],
36+
[/\]\(\.\/CONTRIBUTING\.md\)/g, `](https://github.com/${REPO}/blob/main/CONTRIBUTING.md)`],
37+
[/\]\(\.\/SECURITY\.md\)/g, `](https://github.com/${REPO}/blob/main/SECURITY.md)`],
38+
[/\]\(\.\/CODE_OF_CONDUCT\.md\)/g, `](https://github.com/${REPO}/blob/main/CODE_OF_CONDUCT.md)`],
39+
];
40+
41+
let synced = root;
42+
for (const [pattern, replacement] of transforms) {
43+
synced = synced.replace(pattern, replacement);
44+
}
45+
46+
// Sanity check: any remaining `](./` link is suspicious — flag but don't fail.
47+
const stragglers = synced.match(/\]\(\.\/[^)]+\)/g);
48+
if (stragglers) {
49+
console.warn(`[sync-readme] WARNING: ${stragglers.length} relative link(s) remain unconverted:`);
50+
for (const s of stragglers) console.warn(` ${s}`);
51+
console.warn("[sync-readme] Add a transform rule in scripts/sync-readme.mjs if these should be absolute.");
52+
}
53+
54+
writeFileSync(DST, synced);
55+
console.log(`[sync-readme] Wrote ${synced.length} bytes to packages/governance/README.md`);

0 commit comments

Comments
 (0)