@forwardimpact/libcoaligned
Advanced tools
+1
-1
| { | ||
| "name": "@forwardimpact/libcoaligned", | ||
| "version": "0.1.5", | ||
| "version": "0.1.6", | ||
| "description": "Co-Aligned architecture checks — enforce instruction-layer length caps and JTBD invariants across the repo.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
+4
-3
@@ -14,3 +14,3 @@ # libcoaligned | ||
| npx coaligned # run every check (instructions + jtbd) | ||
| npx coaligned instructions # enforce L1–L6 length and checklist caps | ||
| npx coaligned instructions # enforce L1–L7 length and checklist caps | ||
| npx coaligned jtbd # validate JTBD entries against package.json | ||
@@ -24,6 +24,7 @@ npx coaligned jtbd --fix # regenerate catalog and job blocks in place | ||
| - `instructions` — every layer (L1 CLAUDE.md, L2 CONTRIBUTING.md / JTBD.md, | ||
| L3 agent profile, L4 SKILL.md, L5 reference, L6 checklist block) is gated by | ||
| a line cap **and** a word cap. Either breach fails. | ||
| L3 agent profile, L4 agent reference, L5 SKILL.md, L6 skill reference, | ||
| L7 checklist block) is gated by a line cap **and** a word cap. Either breach | ||
| fails. | ||
| - `jtbd` — each `package.json .jobs` entry is validated against the JTBD | ||
| schema; with `--fix`, marker-delimited blocks in `<dir>/README.md`, | ||
| `<dir>/<pkg>/README.md`, and root `JTBD.md` are regenerated. |
+30
-10
@@ -17,4 +17,4 @@ import { readFile, readdir } from "node:fs/promises"; | ||
| const L6_MAX_ITEMS = 9; | ||
| const L6_MAX_WORDS_PER_ITEM = 32; | ||
| const L7_MAX_ITEMS = 9; | ||
| const L7_MAX_WORDS_PER_ITEM = 32; | ||
@@ -82,2 +82,15 @@ const CHECKLIST_RE = | ||
| async function findAgentReferences(root, claudeDirs) { | ||
| const out = []; | ||
| for (const d of claudeDirs) { | ||
| const files = await listFiles( | ||
| root, | ||
| `${d}/agents/references`, | ||
| (e) => e.isFile() && e.name.endsWith(".md"), | ||
| ); | ||
| out.push(...files); | ||
| } | ||
| return out; | ||
| } | ||
| async function findSkillDirs(root, claudeDirs) { | ||
@@ -152,2 +165,9 @@ const out = []; | ||
| id: "L4", | ||
| name: "agent reference", | ||
| maxLines: 192, | ||
| maxWords: 1280, | ||
| files: await findAgentReferences(root, claudeDirs), | ||
| }, | ||
| { | ||
| id: "L5", | ||
| name: "skill procedure", | ||
@@ -159,3 +179,3 @@ maxLines: 192, | ||
| { | ||
| id: "L5", | ||
| id: "L6", | ||
| name: "skill reference", | ||
@@ -248,8 +268,8 @@ maxLines: 128, | ||
| { | ||
| id: "L6.too-many-items", | ||
| id: "L7.too-many-items", | ||
| scope: "checklist-block", | ||
| severity: "fail", | ||
| check: (s) => | ||
| s.items.length > L6_MAX_ITEMS | ||
| ? { count: s.items.length, max: L6_MAX_ITEMS } | ||
| s.items.length > L7_MAX_ITEMS | ||
| ? { count: s.items.length, max: L7_MAX_ITEMS } | ||
| : null, | ||
@@ -261,3 +281,3 @@ message: (s, r) => | ||
| { | ||
| id: "L6.item-too-many-words", | ||
| id: "L7.item-too-many-words", | ||
| scope: "checklist-block", | ||
@@ -268,7 +288,7 @@ severity: "fail", | ||
| s.items.forEach((item, i) => { | ||
| if (item.words > L6_MAX_WORDS_PER_ITEM) { | ||
| if (item.words > L7_MAX_WORDS_PER_ITEM) { | ||
| offenders.push({ | ||
| itemIndex: i + 1, | ||
| words: item.words, | ||
| max: L6_MAX_WORDS_PER_ITEM, | ||
| max: L7_MAX_WORDS_PER_ITEM, | ||
| }); | ||
@@ -288,3 +308,3 @@ } | ||
| /** | ||
| * Walk the repo rooted at `root`, applying the L1–L6 caps from COALIGNED.md. | ||
| * Walk the repo rooted at `root`, applying the L1–L7 caps from COALIGNED.md. | ||
| * Each layer is gated by a line cap AND a word cap; either breach fails. | ||
@@ -291,0 +311,0 @@ * |
42493
1.17%878
2.21%29
3.57%