@forwardimpact/libcoaligned 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ invariants across the repo.
11
11
 
12
12
  ```sh
13
13
  npx coaligned # run every check (instructions + jtbd)
14
- npx coaligned instructions # enforce L1–L6 length and checklist caps
14
+ npx coaligned instructions # enforce L1–L7 length and checklist caps
15
15
  npx coaligned jtbd # validate JTBD entries against package.json
16
16
  npx coaligned jtbd --fix # regenerate catalog and job blocks in place
17
17
  ```
@@ -20,8 +20,9 @@ The two subcommands implement the contract described in
20
20
  [COALIGNED.md](https://github.com/forwardimpact/monorepo/blob/main/COALIGNED.md):
21
21
 
22
22
  - `instructions` — every layer (L1 CLAUDE.md, L2 CONTRIBUTING.md / JTBD.md,
23
- L3 agent profile, L4 SKILL.md, L5 reference, L6 checklist block) is gated by
24
- a line cap **and** a word cap. Either breach fails.
23
+ L3 agent profile, L4 agent reference, L5 SKILL.md, L6 skill reference,
24
+ L7 checklist block) is gated by a line cap **and** a word cap. Either breach
25
+ fails.
25
26
  - `jtbd` — each `package.json .jobs` entry is validated against the JTBD
26
27
  schema; with `--fix`, marker-delimited blocks in `<dir>/README.md`,
27
28
  `<dir>/<pkg>/README.md`, and root `JTBD.md` are regenerated.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/libcoaligned",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Co-Aligned architecture checks — enforce instruction-layer length caps and JTBD invariants across the repo.",
5
5
  "keywords": [
6
6
  "coaligned",
@@ -14,8 +14,8 @@ const SKIP_DIRS = new Set([
14
14
  "worktrees",
15
15
  ]);
16
16
 
17
- const L6_MAX_ITEMS = 9;
18
- const L6_MAX_WORDS_PER_ITEM = 32;
17
+ const L7_MAX_ITEMS = 9;
18
+ const L7_MAX_WORDS_PER_ITEM = 32;
19
19
 
20
20
  const CHECKLIST_RE =
21
21
  /<(read_do_checklist|do_confirm_checklist)\b[^>]*>([\s\S]*?)<\/\1>/g;
@@ -78,6 +78,19 @@ async function findAgentProfiles(root, claudeDirs) {
78
78
  return out;
79
79
  }
80
80
 
81
+ async function findAgentReferences(root, claudeDirs) {
82
+ const out = [];
83
+ for (const d of claudeDirs) {
84
+ const files = await listFiles(
85
+ root,
86
+ `${d}/agents/references`,
87
+ (e) => e.isFile() && e.name.endsWith(".md"),
88
+ );
89
+ out.push(...files);
90
+ }
91
+ return out;
92
+ }
93
+
81
94
  async function findSkillDirs(root, claudeDirs) {
82
95
  const out = [];
83
96
  for (const d of claudeDirs) {
@@ -147,13 +160,20 @@ async function buildLayers(root) {
147
160
  },
148
161
  {
149
162
  id: "L4",
163
+ name: "agent reference",
164
+ maxLines: 192,
165
+ maxWords: 1280,
166
+ files: await findAgentReferences(root, claudeDirs),
167
+ },
168
+ {
169
+ id: "L5",
150
170
  name: "skill procedure",
151
171
  maxLines: 192,
152
172
  maxWords: 1280,
153
173
  files: skillDirs.map((d) => `${d}/SKILL.md`),
154
174
  },
155
175
  {
156
- id: "L5",
176
+ id: "L6",
157
177
  name: "skill reference",
158
178
  maxLines: 128,
159
179
  maxWords: 768,
@@ -241,29 +261,29 @@ export const INSTRUCTION_RULES = [
241
261
  hint: HINT_LAYER_BUDGET,
242
262
  },
243
263
  {
244
- id: "L6.too-many-items",
264
+ id: "L7.too-many-items",
245
265
  scope: "checklist-block",
246
266
  severity: "fail",
247
267
  check: (s) =>
248
- s.items.length > L6_MAX_ITEMS
249
- ? { count: s.items.length, max: L6_MAX_ITEMS }
268
+ s.items.length > L7_MAX_ITEMS
269
+ ? { count: s.items.length, max: L7_MAX_ITEMS }
250
270
  : null,
251
271
  message: (s, r) =>
252
272
  `checklist #${s.blockIndex} (${s.type}) has ${r.count} items (max ${r.max})`,
253
273
  hint: "split the checklist into multiple sections, or remove items not load-bearing for the goal",
254
274
  },
255
275
  {
256
- id: "L6.item-too-many-words",
276
+ id: "L7.item-too-many-words",
257
277
  scope: "checklist-block",
258
278
  severity: "fail",
259
279
  check: (s) => {
260
280
  const offenders = [];
261
281
  s.items.forEach((item, i) => {
262
- if (item.words > L6_MAX_WORDS_PER_ITEM) {
282
+ if (item.words > L7_MAX_WORDS_PER_ITEM) {
263
283
  offenders.push({
264
284
  itemIndex: i + 1,
265
285
  words: item.words,
266
- max: L6_MAX_WORDS_PER_ITEM,
286
+ max: L7_MAX_WORDS_PER_ITEM,
267
287
  });
268
288
  }
269
289
  });
@@ -278,7 +298,7 @@ export const INSTRUCTION_RULES = [
278
298
  // -- Public entry --------------------------------------------------------
279
299
 
280
300
  /**
281
- * Walk the repo rooted at `root`, applying the L1–L6 caps from COALIGNED.md.
301
+ * Walk the repo rooted at `root`, applying the L1–L7 caps from COALIGNED.md.
282
302
  * Each layer is gated by a line cap AND a word cap; either breach fails.
283
303
  *
284
304
  * @param {{ root: string }} options