@erclx/canon 4.0.0

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.
Files changed (643) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -0
  3. package/claude/.claude-plugin/plugin.json +19 -0
  4. package/claude/skills/bash-cli-script/REQUIREMENT.md +42 -0
  5. package/claude/skills/bash-cli-script/SKILL.md +48 -0
  6. package/claude/skills/bash-cli-script/references/template.md +43 -0
  7. package/claude/skills/bash-script/REQUIREMENT.md +36 -0
  8. package/claude/skills/bash-script/SKILL.md +100 -0
  9. package/claude/skills/bash-script/references/patterns.md +349 -0
  10. package/claude/skills/canon-cli/REQUIREMENT.md +41 -0
  11. package/claude/skills/canon-cli/SKILL.md +103 -0
  12. package/claude/skills/canon-feedback-file/REQUIREMENT.md +40 -0
  13. package/claude/skills/canon-feedback-file/SKILL.md +80 -0
  14. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +40 -0
  15. package/claude/skills/canon-feedback-triage/SKILL.md +63 -0
  16. package/claude/skills/canon-operator/REQUIREMENT.md +61 -0
  17. package/claude/skills/canon-operator/SKILL.md +108 -0
  18. package/claude/skills/canon-rollout/REQUIREMENT.md +59 -0
  19. package/claude/skills/canon-rollout/SKILL.md +147 -0
  20. package/claude/skills/canon-screencast/REQUIREMENT.md +39 -0
  21. package/claude/skills/canon-screencast/SKILL.md +167 -0
  22. package/claude/skills/canon-slides-draft/REQUIREMENT.md +39 -0
  23. package/claude/skills/canon-slides-draft/SKILL.md +62 -0
  24. package/claude/skills/ci-workflow/REQUIREMENT.md +40 -0
  25. package/claude/skills/ci-workflow/SKILL.md +65 -0
  26. package/claude/skills/ci-workflow/references/workflows.md +98 -0
  27. package/claude/skills/claude-address-review/REQUIREMENT.md +57 -0
  28. package/claude/skills/claude-address-review/SKILL.md +212 -0
  29. package/claude/skills/claude-address-review/references/rebase-conflicts.md +39 -0
  30. package/claude/skills/claude-autoship/REQUIREMENT.md +50 -0
  31. package/claude/skills/claude-autoship/SKILL.md +207 -0
  32. package/claude/skills/claude-design-extract/REQUIREMENT.md +42 -0
  33. package/claude/skills/claude-design-extract/SKILL.md +102 -0
  34. package/claude/skills/claude-diagram/REQUIREMENT.md +45 -0
  35. package/claude/skills/claude-diagram/SKILL.md +177 -0
  36. package/claude/skills/claude-docs/REQUIREMENT.md +60 -0
  37. package/claude/skills/claude-docs/SKILL.md +287 -0
  38. package/claude/skills/claude-docs/references/anchor-sweep.md +58 -0
  39. package/claude/skills/claude-docs/references/wireframe-sweep.md +45 -0
  40. package/claude/skills/claude-feature/REQUIREMENT.md +36 -0
  41. package/claude/skills/claude-feature/SKILL.md +115 -0
  42. package/claude/skills/claude-groundwork/REQUIREMENT.md +48 -0
  43. package/claude/skills/claude-groundwork/SKILL.md +142 -0
  44. package/claude/skills/claude-intake/REQUIREMENT.md +49 -0
  45. package/claude/skills/claude-intake/SKILL.md +114 -0
  46. package/claude/skills/claude-intake-answer/REQUIREMENT.md +48 -0
  47. package/claude/skills/claude-intake-answer/SKILL.md +90 -0
  48. package/claude/skills/claude-markdown-propose/REQUIREMENT.md +48 -0
  49. package/claude/skills/claude-markdown-propose/SKILL.md +118 -0
  50. package/claude/skills/claude-markdown-propose/references/format.md +107 -0
  51. package/claude/skills/claude-memory-capture/REQUIREMENT.md +50 -0
  52. package/claude/skills/claude-memory-capture/SKILL.md +101 -0
  53. package/claude/skills/claude-memory-review/REQUIREMENT.md +50 -0
  54. package/claude/skills/claude-memory-review/SKILL.md +210 -0
  55. package/claude/skills/claude-memory-review/references/receipt-format.md +48 -0
  56. package/claude/skills/claude-orchestrate/REQUIREMENT.md +121 -0
  57. package/claude/skills/claude-orchestrate/SKILL.md +241 -0
  58. package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +132 -0
  59. package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +32 -0
  60. package/claude/skills/claude-orchestrate/references/orchestrator-parked.md +72 -0
  61. package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +87 -0
  62. package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +30 -0
  63. package/claude/skills/claude-orchestrate/references/orchestrator-sweep.md +21 -0
  64. package/claude/skills/claude-orchestrate/scripts/poll.sh +373 -0
  65. package/claude/skills/claude-orchestrate/scripts/watch.sh +181 -0
  66. package/claude/skills/claude-pr-review/REQUIREMENT.md +47 -0
  67. package/claude/skills/claude-pr-review/SKILL.md +295 -0
  68. package/claude/skills/claude-review/REQUIREMENT.md +39 -0
  69. package/claude/skills/claude-review/SKILL.md +142 -0
  70. package/claude/skills/claude-seed-sync/REQUIREMENT.md +45 -0
  71. package/claude/skills/claude-seed-sync/SKILL.md +156 -0
  72. package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
  73. package/claude/skills/claude-standards-audit/SKILL.md +99 -0
  74. package/claude/skills/claude-tasks/REQUIREMENT.md +43 -0
  75. package/claude/skills/claude-tasks/SKILL.md +161 -0
  76. package/claude/skills/claude-teach/REQUIREMENT.md +56 -0
  77. package/claude/skills/claude-teach/SKILL.md +196 -0
  78. package/claude/skills/claude-teach/references/lesson-craft.md +59 -0
  79. package/claude/skills/claude-teach/references/pedagogy.md +67 -0
  80. package/claude/skills/claude-teach/references/promotion.md +54 -0
  81. package/claude/skills/claude-ui-test/REQUIREMENT.md +40 -0
  82. package/claude/skills/claude-ui-test/SKILL.md +77 -0
  83. package/claude/skills/claude-ux-audit/REQUIREMENT.md +40 -0
  84. package/claude/skills/claude-ux-audit/SKILL.md +79 -0
  85. package/claude/skills/claude-ux-measure/REQUIREMENT.md +48 -0
  86. package/claude/skills/claude-ux-measure/SKILL.md +122 -0
  87. package/claude/skills/claude-worker/REQUIREMENT.md +54 -0
  88. package/claude/skills/claude-worker/SKILL.md +96 -0
  89. package/claude/skills/claude-worktree/REQUIREMENT.md +58 -0
  90. package/claude/skills/claude-worktree/SKILL.md +136 -0
  91. package/claude/skills/create-rule/REQUIREMENT.md +45 -0
  92. package/claude/skills/create-rule/SKILL.md +68 -0
  93. package/claude/skills/create-skill/REQUIREMENT.md +38 -0
  94. package/claude/skills/create-skill/SKILL.md +32 -0
  95. package/claude/skills/create-snippet/REQUIREMENT.md +39 -0
  96. package/claude/skills/create-snippet/SKILL.md +30 -0
  97. package/claude/skills/create-standard/REQUIREMENT.md +35 -0
  98. package/claude/skills/create-standard/SKILL.md +29 -0
  99. package/claude/skills/decision-escalate/REQUIREMENT.md +45 -0
  100. package/claude/skills/decision-escalate/SKILL.md +79 -0
  101. package/claude/skills/docs-sync/REQUIREMENT.md +41 -0
  102. package/claude/skills/docs-sync/SKILL.md +95 -0
  103. package/claude/skills/git-branch/REQUIREMENT.md +38 -0
  104. package/claude/skills/git-branch/SKILL.md +60 -0
  105. package/claude/skills/git-commit/REQUIREMENT.md +36 -0
  106. package/claude/skills/git-commit/SKILL.md +49 -0
  107. package/claude/skills/git-followup/REQUIREMENT.md +43 -0
  108. package/claude/skills/git-followup/SKILL.md +48 -0
  109. package/claude/skills/git-issue/REQUIREMENT.md +38 -0
  110. package/claude/skills/git-issue/SKILL.md +65 -0
  111. package/claude/skills/git-pr/REQUIREMENT.md +50 -0
  112. package/claude/skills/git-pr/SKILL.md +164 -0
  113. package/claude/skills/git-pr/references/labels.md +95 -0
  114. package/claude/skills/git-ship/REQUIREMENT.md +42 -0
  115. package/claude/skills/git-ship/SKILL.md +55 -0
  116. package/claude/skills/git-split/REQUIREMENT.md +39 -0
  117. package/claude/skills/git-split/SKILL.md +162 -0
  118. package/claude/skills/git-stage/REQUIREMENT.md +39 -0
  119. package/claude/skills/git-stage/SKILL.md +73 -0
  120. package/claude/skills/git-worktree/REQUIREMENT.md +38 -0
  121. package/claude/skills/git-worktree/SKILL.md +130 -0
  122. package/claude/skills/migration-claude-md/REQUIREMENT.md +40 -0
  123. package/claude/skills/migration-claude-md/SKILL.md +76 -0
  124. package/claude/skills/migration-context/REQUIREMENT.md +36 -0
  125. package/claude/skills/migration-context/SKILL.md +95 -0
  126. package/claude/skills/migration-standards-drop/REQUIREMENT.md +55 -0
  127. package/claude/skills/migration-standards-drop/SKILL.md +113 -0
  128. package/claude/skills/migration-superseded/REQUIREMENT.md +44 -0
  129. package/claude/skills/migration-superseded/SKILL.md +115 -0
  130. package/claude/skills/project-commands/REQUIREMENT.md +42 -0
  131. package/claude/skills/project-commands/SKILL.md +85 -0
  132. package/claude/skills/restate-plainly/REQUIREMENT.md +41 -0
  133. package/claude/skills/restate-plainly/SKILL.md +39 -0
  134. package/claude/skills/session-map/REQUIREMENT.md +57 -0
  135. package/claude/skills/session-map/SKILL.md +70 -0
  136. package/claude/skills/session-resume/REQUIREMENT.md +49 -0
  137. package/claude/skills/session-resume/SKILL.md +51 -0
  138. package/claude/skills/setup-gov/REQUIREMENT.md +37 -0
  139. package/claude/skills/setup-gov/SKILL.md +77 -0
  140. package/claude/skills/setup-indexes/REQUIREMENT.md +45 -0
  141. package/claude/skills/setup-indexes/SKILL.md +153 -0
  142. package/claude/skills/setup-init/REQUIREMENT.md +45 -0
  143. package/claude/skills/setup-init/SKILL.md +127 -0
  144. package/claude/skills/setup-plugins/REQUIREMENT.md +42 -0
  145. package/claude/skills/setup-plugins/SKILL.md +81 -0
  146. package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
  147. package/claude/skills/setup-verify/REQUIREMENT.md +39 -0
  148. package/claude/skills/setup-verify/SKILL.md +51 -0
  149. package/claude/skills/systematic-debugging/REQUIREMENT.md +41 -0
  150. package/claude/skills/systematic-debugging/SKILL.md +70 -0
  151. package/claude/skills/write-human/REQUIREMENT.md +46 -0
  152. package/claude/skills/write-human/SKILL.md +68 -0
  153. package/claude/skills/write-human/references/density.md +38 -0
  154. package/claude/skills/write-human/references/machine-tells.md +107 -0
  155. package/claude/skills/write-human/references/source-material.md +37 -0
  156. package/claude/skills/youtube-transcripts/REQUIREMENT.md +38 -0
  157. package/claude/skills/youtube-transcripts/SKILL.md +34 -0
  158. package/docs/agents/audits.md +98 -0
  159. package/docs/agents/capture.md +37 -0
  160. package/docs/agents/census.md +23 -0
  161. package/docs/agents/commands.md +146 -0
  162. package/docs/agents/comments.md +34 -0
  163. package/docs/agents/context-audit-checks.md +120 -0
  164. package/docs/agents/context-audit.md +83 -0
  165. package/docs/agents/counts.md +76 -0
  166. package/docs/agents/demo.md +86 -0
  167. package/docs/agents/docs.md +17 -0
  168. package/docs/agents/gate.md +84 -0
  169. package/docs/agents/index.md +47 -0
  170. package/docs/agents/indexes.md +35 -0
  171. package/docs/agents/install-and-sync.md +385 -0
  172. package/docs/agents/intake.md +81 -0
  173. package/docs/agents/key-changes.md +103 -0
  174. package/docs/agents/label-coverage.md +73 -0
  175. package/docs/agents/markdown-audit.md +197 -0
  176. package/docs/agents/output-shape.md +70 -0
  177. package/docs/agents/overview.md +26 -0
  178. package/docs/agents/records.md +170 -0
  179. package/docs/agents/restated.md +81 -0
  180. package/docs/agents/review-classification.md +77 -0
  181. package/docs/agents/routing.md +61 -0
  182. package/docs/agents/rule-citations.md +98 -0
  183. package/docs/agents/sandbox.md +71 -0
  184. package/docs/agents/scripting.md +149 -0
  185. package/docs/agents/sessions.md +120 -0
  186. package/docs/agents/skills-audit.md +94 -0
  187. package/docs/agents/skills-reach.md +64 -0
  188. package/docs/agents/standards-audit.md +38 -0
  189. package/docs/agents/state-scoped-risk.md +105 -0
  190. package/docs/agents/superseded.md +85 -0
  191. package/docs/agents/targets.md +83 -0
  192. package/docs/agents/tasks.md +200 -0
  193. package/docs/agents/teach.md +158 -0
  194. package/docs/agents/test-order.md +56 -0
  195. package/docs/agents/worktrees.md +62 -0
  196. package/docs/ai-workflow.md +317 -0
  197. package/docs/index.md +23 -0
  198. package/docs/operating-model.md +223 -0
  199. package/docs/target-projects.md +258 -0
  200. package/docs/visual-design-workflow.md +151 -0
  201. package/docs/zshrc-aliases.md +65 -0
  202. package/governance/rules/ci/700-ci-workflow.md +44 -0
  203. package/governance/rules/claude/500-prose.md +15 -0
  204. package/governance/rules/claude/501-markdown.md +14 -0
  205. package/governance/rules/claude/510-context.md +28 -0
  206. package/governance/rules/claude/511-indexes.md +14 -0
  207. package/governance/rules/claude/520-wireframes.md +12 -0
  208. package/governance/rules/claude/530-requirements.md +11 -0
  209. package/governance/rules/claude/540-architecture.md +11 -0
  210. package/governance/rules/claude/550-design.md +11 -0
  211. package/governance/rules/claude/555-tasks.md +12 -0
  212. package/governance/rules/claude/556-groundwork.md +11 -0
  213. package/governance/rules/claude/557-intake.md +11 -0
  214. package/governance/rules/claude/558-plan.md +22 -0
  215. package/governance/rules/claude/559-memory.md +11 -0
  216. package/governance/rules/claude/560-diagrams.md +18 -0
  217. package/governance/rules/claude/561-teach.md +13 -0
  218. package/governance/rules/claude/562-session.md +15 -0
  219. package/governance/rules/claude/570-skill.md +24 -0
  220. package/governance/rules/claude/575-hooks.md +17 -0
  221. package/governance/rules/claude/576-settings.md +14 -0
  222. package/governance/rules/claude/580-readme.md +11 -0
  223. package/governance/rules/claude/590-rule-authoring.md +12 -0
  224. package/governance/rules/claude/591-standard-authoring.md +12 -0
  225. package/governance/rules/claude/592-claude-md.md +19 -0
  226. package/governance/rules/core/000-constitution.md +30 -0
  227. package/governance/rules/core/005-behavior.md +27 -0
  228. package/governance/rules/core/010-testing.md +35 -0
  229. package/governance/rules/core/015-output.md +20 -0
  230. package/governance/rules/core/020-concurrency.md +22 -0
  231. package/governance/rules/core/025-indexes.md +9 -0
  232. package/governance/rules/core/030-error-handling.md +31 -0
  233. package/governance/rules/core/035-tasks.md +13 -0
  234. package/governance/rules/core/040-performance.md +20 -0
  235. package/governance/rules/core/045-memory.md +12 -0
  236. package/governance/rules/core/050-logging.md +20 -0
  237. package/governance/rules/core/055-scratch.md +9 -0
  238. package/governance/rules/core/060-naming.md +19 -0
  239. package/governance/rules/core/065-spelling.md +19 -0
  240. package/governance/rules/core/070-planning.md +18 -0
  241. package/governance/rules/core/075-dependencies.md +25 -0
  242. package/governance/rules/core/080-config-comments.md +22 -0
  243. package/governance/rules/core/085-worktrees.md +17 -0
  244. package/governance/rules/core/087-git.md +11 -0
  245. package/governance/rules/core/090-code-comments.md +39 -0
  246. package/governance/rules/framework/200-react.md +51 -0
  247. package/governance/rules/framework/210-astro.md +41 -0
  248. package/governance/rules/framework/220-fastapi.md +43 -0
  249. package/governance/rules/framework/230-nextjs.md +48 -0
  250. package/governance/rules/framework/250-tailwind.md +32 -0
  251. package/governance/rules/framework/260-shadcn.md +34 -0
  252. package/governance/rules/lang/100-typescript.md +40 -0
  253. package/governance/rules/lang/110-python.md +42 -0
  254. package/governance/rules/lang/120-bash.md +19 -0
  255. package/governance/rules/lib/300-testing-ts.md +39 -0
  256. package/governance/rules/lib/305-e2e-reliability.md +34 -0
  257. package/governance/rules/lib/306-test-scope.md +25 -0
  258. package/governance/rules/lib/310-zod.md +25 -0
  259. package/governance/rules/lib/320-tanstack-query.md +32 -0
  260. package/governance/rules/lib/330-testing-py.md +44 -0
  261. package/governance/rules/lib/340-pydantic.md +38 -0
  262. package/governance/rules/lib/350-security-web.md +32 -0
  263. package/governance/rules/lib/360-security-server.md +39 -0
  264. package/governance/rules/lib/370-database.md +35 -0
  265. package/governance/rules/snippets/505-at-references.md +9 -0
  266. package/governance/rules/ui/400-ui.md +36 -0
  267. package/governance/rules/ui/410-a11y.md +48 -0
  268. package/governance/rules/ui/420-forms.md +36 -0
  269. package/governance/rules/ui/430-ux-completeness.md +65 -0
  270. package/governance/rules/ui/440-surface-capture.md +34 -0
  271. package/governance/rules/ui/450-link-behavior.md +19 -0
  272. package/governance/stacks/astro.toml +2 -0
  273. package/governance/stacks/base.toml +8 -0
  274. package/governance/stacks/node-server.toml +2 -0
  275. package/governance/stacks/node.toml +2 -0
  276. package/governance/stacks/python-fastapi.toml +2 -0
  277. package/governance/stacks/python.toml +2 -0
  278. package/governance/stacks/react.toml +2 -0
  279. package/package.json +69 -0
  280. package/scripts/config.sh +11 -0
  281. package/scripts/core/bootstrap.sh +81 -0
  282. package/scripts/core/check-color-source.sh +41 -0
  283. package/scripts/core/check-ignore-parity.sh +162 -0
  284. package/scripts/core/check-plugin-boundary.sh +45 -0
  285. package/scripts/core/check-seed-independence.sh +59 -0
  286. package/scripts/core/check-skill-paths.sh +24 -0
  287. package/scripts/core/clean.sh +36 -0
  288. package/scripts/core/install-check.sh +101 -0
  289. package/scripts/core/list-seed-roots.sh +18 -0
  290. package/scripts/core/regen-claude-copies.sh +10 -0
  291. package/scripts/core/regen-hero.sh +217 -0
  292. package/scripts/core/regen-indexes.sh +10 -0
  293. package/scripts/core/regen-tooling-paths.sh +61 -0
  294. package/scripts/core/repair-bare-flag.sh +19 -0
  295. package/scripts/core/snapshot.sh +134 -0
  296. package/scripts/core/update.sh +35 -0
  297. package/scripts/docs/list.sh +165 -0
  298. package/scripts/lib/frontmatter.sh +30 -0
  299. package/scripts/lib/gov.sh +14 -0
  300. package/scripts/lib/sandbox-fixtures.sh +191 -0
  301. package/scripts/lib/sandbox-git.sh +125 -0
  302. package/scripts/lib/sandbox-path.sh +206 -0
  303. package/scripts/lib/tooling.sh +35 -0
  304. package/scripts/lib/ui.sh +266 -0
  305. package/scripts/lib/worktree.sh +20 -0
  306. package/scripts/manage-sandbox.sh +466 -0
  307. package/scripts/snippets/create.sh +156 -0
  308. package/scripts/standards/list.sh +115 -0
  309. package/scripts/tooling/create.sh +109 -0
  310. package/scripts/tooling/verify.sh +179 -0
  311. package/snippets/align.md +12 -0
  312. package/snippets/claude/decision-memo.md +39 -0
  313. package/snippets/claude/feature-recap.md +19 -0
  314. package/snippets/claude/figma-steps.md +24 -0
  315. package/snippets/compact-summary.md +5 -0
  316. package/snippets/decision-help.md +6 -0
  317. package/snippets/meta-prompt.md +14 -0
  318. package/snippets/research-prompt.md +7 -0
  319. package/snippets/session-notes.md +11 -0
  320. package/snippets/snippets.toml +5 -0
  321. package/snippets/step-by-step.md +10 -0
  322. package/snippets/web-research.md +21 -0
  323. package/src/audits/baseline.ts +201 -0
  324. package/src/audits/catalog.ts +876 -0
  325. package/src/audits/run.ts +204 -0
  326. package/src/autoship/classify.ts +75 -0
  327. package/src/autoship/paths.ts +51 -0
  328. package/src/binary.ts +16 -0
  329. package/src/browser/engine.ts +40 -0
  330. package/src/census/count.ts +113 -0
  331. package/src/claude/cases/all.ts +24 -0
  332. package/src/claude/cases/authoring.ts +53 -0
  333. package/src/claude/cases/claude-workflow.ts +158 -0
  334. package/src/claude/cases/git.ts +44 -0
  335. package/src/claude/cases/misc.ts +27 -0
  336. package/src/claude/cases/setup.ts +94 -0
  337. package/src/claude/gitignore.ts +51 -0
  338. package/src/claude/routing.ts +283 -0
  339. package/src/claude/seeds-list.ts +47 -0
  340. package/src/claude/seeds.ts +150 -0
  341. package/src/claude/settings.ts +151 -0
  342. package/src/claude/skills-audit.ts +228 -0
  343. package/src/claude/skills-drift.ts +156 -0
  344. package/src/claude/skills-list.ts +99 -0
  345. package/src/claude/skills-rank.ts +320 -0
  346. package/src/claude/skills-reach.ts +227 -0
  347. package/src/cli-run.ts +43 -0
  348. package/src/cli.ts +200 -0
  349. package/src/commands/audits.ts +350 -0
  350. package/src/commands/autoship.ts +129 -0
  351. package/src/commands/capture.ts +133 -0
  352. package/src/commands/census.ts +105 -0
  353. package/src/commands/claude.ts +1286 -0
  354. package/src/commands/comments.ts +240 -0
  355. package/src/commands/context.ts +857 -0
  356. package/src/commands/demo.ts +389 -0
  357. package/src/commands/deps.ts +173 -0
  358. package/src/commands/design.ts +36 -0
  359. package/src/commands/docs.ts +60 -0
  360. package/src/commands/feedback-format.ts +23 -0
  361. package/src/commands/feedback.ts +112 -0
  362. package/src/commands/gate.ts +189 -0
  363. package/src/commands/gov.ts +1265 -0
  364. package/src/commands/indexes.ts +184 -0
  365. package/src/commands/init.ts +113 -0
  366. package/src/commands/intake.ts +406 -0
  367. package/src/commands/inventory.ts +256 -0
  368. package/src/commands/labels.ts +361 -0
  369. package/src/commands/markdown.ts +544 -0
  370. package/src/commands/migrate.ts +175 -0
  371. package/src/commands/pass-through.ts +39 -0
  372. package/src/commands/pr.ts +411 -0
  373. package/src/commands/records.ts +728 -0
  374. package/src/commands/sandbox.ts +468 -0
  375. package/src/commands/secrets.ts +132 -0
  376. package/src/commands/serve.ts +159 -0
  377. package/src/commands/sessions.ts +408 -0
  378. package/src/commands/slides.ts +126 -0
  379. package/src/commands/snippets.ts +84 -0
  380. package/src/commands/standards.ts +247 -0
  381. package/src/commands/sync.ts +428 -0
  382. package/src/commands/targets.ts +319 -0
  383. package/src/commands/tasks.ts +743 -0
  384. package/src/commands/teach.ts +786 -0
  385. package/src/commands/tooling.ts +573 -0
  386. package/src/commands/transcripts.ts +44 -0
  387. package/src/commands/upgrade.ts +231 -0
  388. package/src/commands/wiki.ts +100 -0
  389. package/src/commands/worktrees.ts +191 -0
  390. package/src/comments/scan.ts +338 -0
  391. package/src/comments/trend.ts +207 -0
  392. package/src/comments/vocabulary.ts +85 -0
  393. package/src/context/architecture.ts +364 -0
  394. package/src/context/audit.ts +790 -0
  395. package/src/context/citations.ts +196 -0
  396. package/src/context/folders.ts +186 -0
  397. package/src/context/gate.ts +57 -0
  398. package/src/context/index-drift.ts +64 -0
  399. package/src/context/narration.ts +99 -0
  400. package/src/copy.ts +30 -0
  401. package/src/counts/catalogs.ts +96 -0
  402. package/src/counts/numbers.ts +79 -0
  403. package/src/counts/scan.ts +314 -0
  404. package/src/demo/beats.ts +135 -0
  405. package/src/demo/compile.ts +326 -0
  406. package/src/demo/container.ts +63 -0
  407. package/src/demo/cursors.ts +55 -0
  408. package/src/demo/drive.ts +357 -0
  409. package/src/demo/pointer.ts +178 -0
  410. package/src/demo/theme.ts +112 -0
  411. package/src/deps/audit.ts +153 -0
  412. package/src/design/parse.ts +116 -0
  413. package/src/design/render.ts +249 -0
  414. package/src/docs/read.ts +77 -0
  415. package/src/exec.ts +16 -0
  416. package/src/exempt-marker.ts +43 -0
  417. package/src/frontmatter.ts +13 -0
  418. package/src/gate/measures.ts +682 -0
  419. package/src/gate/sequencer.ts +386 -0
  420. package/src/gate/stages.ts +412 -0
  421. package/src/git-env.ts +36 -0
  422. package/src/git-files.ts +105 -0
  423. package/src/git-ignore.ts +46 -0
  424. package/src/github-format.ts +13 -0
  425. package/src/github.ts +24 -0
  426. package/src/gov/adapter.ts +103 -0
  427. package/src/gov/citations.ts +514 -0
  428. package/src/gov/consumed.ts +129 -0
  429. package/src/gov/install.ts +132 -0
  430. package/src/gov/list.ts +106 -0
  431. package/src/gov/payload.ts +39 -0
  432. package/src/gov/restated.ts +814 -0
  433. package/src/gov/stacks.ts +205 -0
  434. package/src/gov/superseded.ts +415 -0
  435. package/src/gov/test-order.ts +407 -0
  436. package/src/indexes/frontmatter.ts +46 -0
  437. package/src/indexes/regen.ts +84 -0
  438. package/src/indexes/render.ts +201 -0
  439. package/src/indexes/walk.ts +83 -0
  440. package/src/init/flags.ts +60 -0
  441. package/src/init/plan.ts +114 -0
  442. package/src/init/run.ts +46 -0
  443. package/src/init/steps.ts +77 -0
  444. package/src/intake/folder.ts +320 -0
  445. package/src/intake/items.ts +174 -0
  446. package/src/inventory/config.ts +117 -0
  447. package/src/inventory/group.ts +76 -0
  448. package/src/inventory/subjects.ts +114 -0
  449. package/src/inventory/walk.ts +129 -0
  450. package/src/labels/audit.ts +82 -0
  451. package/src/labels/coverage.ts +79 -0
  452. package/src/labels/map.ts +101 -0
  453. package/src/labels/phase.ts +95 -0
  454. package/src/markdown/bans.ts +94 -0
  455. package/src/markdown/files.ts +102 -0
  456. package/src/markdown/gate.ts +28 -0
  457. package/src/markdown/scan.ts +295 -0
  458. package/src/markdown/structure.ts +730 -0
  459. package/src/migrate/apply.ts +115 -0
  460. package/src/migrate/plan.ts +103 -0
  461. package/src/migrate/rename.ts +183 -0
  462. package/src/pr/bijection.ts +145 -0
  463. package/src/pr/paths.ts +335 -0
  464. package/src/process/harness.ts +167 -0
  465. package/src/project-root.ts +19 -0
  466. package/src/records/backup.ts +455 -0
  467. package/src/records/migrate.ts +78 -0
  468. package/src/records/size.ts +260 -0
  469. package/src/records/validate.ts +1162 -0
  470. package/src/sandbox/census.ts +228 -0
  471. package/src/sandbox/coverage.ts +115 -0
  472. package/src/sandbox/expect.ts +629 -0
  473. package/src/sandbox/tree.ts +47 -0
  474. package/src/secrets/marker.ts +30 -0
  475. package/src/secrets/patterns.ts +142 -0
  476. package/src/secrets/scan.ts +123 -0
  477. package/src/secrets/shipped.ts +111 -0
  478. package/src/seed-marker.ts +74 -0
  479. package/src/serve/static.ts +322 -0
  480. package/src/sessions/claim.ts +85 -0
  481. package/src/sessions/live.ts +79 -0
  482. package/src/sessions/registry.ts +137 -0
  483. package/src/sessions/resolve.ts +333 -0
  484. package/src/slides/layouts.ts +391 -0
  485. package/src/slides/open.ts +18 -0
  486. package/src/slides/parse.ts +84 -0
  487. package/src/slides/render.ts +88 -0
  488. package/src/slides/styles.ts +44 -0
  489. package/src/snippets/categories.ts +66 -0
  490. package/src/snippets/list.ts +32 -0
  491. package/src/snippets/presets.ts +50 -0
  492. package/src/standards/audit.ts +132 -0
  493. package/src/standards/read.ts +100 -0
  494. package/src/sync/check.ts +692 -0
  495. package/src/sync/engine.ts +576 -0
  496. package/src/sync/git.ts +225 -0
  497. package/src/sync/history.ts +123 -0
  498. package/src/sync/layout.ts +140 -0
  499. package/src/sync/reverse.ts +268 -0
  500. package/src/sync/seeds-report.ts +126 -0
  501. package/src/sync/stamp.ts +358 -0
  502. package/src/sync/target.ts +70 -0
  503. package/src/sync/workflow.ts +200 -0
  504. package/src/target.ts +43 -0
  505. package/src/targets/pulls.ts +250 -0
  506. package/src/targets/registry.ts +203 -0
  507. package/src/targets/resolve.ts +145 -0
  508. package/src/targets/sweep.ts +246 -0
  509. package/src/tasks/archive.ts +506 -0
  510. package/src/tasks/record.ts +311 -0
  511. package/src/tasks/trunk.ts +89 -0
  512. package/src/tasks/validate.ts +1001 -0
  513. package/src/teach/lesson.ts +180 -0
  514. package/src/teach/workspace.ts +842 -0
  515. package/src/tooling/gitignore.ts +122 -0
  516. package/src/tooling/inject.ts +193 -0
  517. package/src/tooling/list.ts +39 -0
  518. package/src/tooling/manifest.ts +176 -0
  519. package/src/tooling/package.ts +166 -0
  520. package/src/tooling/read.ts +65 -0
  521. package/src/tooling/scan.ts +147 -0
  522. package/src/tooling/stamp.ts +44 -0
  523. package/src/transcripts/fetch.ts +156 -0
  524. package/src/transcripts/metadata.ts +54 -0
  525. package/src/transcripts/vtt.ts +114 -0
  526. package/src/ui.ts +266 -0
  527. package/src/version/compare.ts +53 -0
  528. package/src/version/installed.ts +40 -0
  529. package/src/version/manager.ts +67 -0
  530. package/src/version/skew.ts +192 -0
  531. package/src/wiki/init.ts +85 -0
  532. package/src/worktree.ts +143 -0
  533. package/src/worktrees/reclaim.ts +306 -0
  534. package/standards/architecture.md +72 -0
  535. package/standards/branch.md +59 -0
  536. package/standards/commit.md +72 -0
  537. package/standards/context.md +151 -0
  538. package/standards/design.md +93 -0
  539. package/standards/diagrams.md +152 -0
  540. package/standards/glossary.md +75 -0
  541. package/standards/groundwork.md +211 -0
  542. package/standards/index.md +36 -0
  543. package/standards/intake.md +192 -0
  544. package/standards/issue.md +94 -0
  545. package/standards/markdown.md +137 -0
  546. package/standards/memory.md +144 -0
  547. package/standards/plan.md +172 -0
  548. package/standards/pr.md +139 -0
  549. package/standards/publish.md +51 -0
  550. package/standards/readme.md +208 -0
  551. package/standards/requirements.md +70 -0
  552. package/standards/rule.md +118 -0
  553. package/standards/session.md +109 -0
  554. package/standards/skill.md +300 -0
  555. package/standards/slug.md +39 -0
  556. package/standards/snippets.md +76 -0
  557. package/standards/standard.md +170 -0
  558. package/standards/tasks.md +254 -0
  559. package/standards/teach.md +153 -0
  560. package/standards/versioning.md +71 -0
  561. package/standards/wireframes.md +113 -0
  562. package/tooling/astro/configs/astro.config.mjs +31 -0
  563. package/tooling/astro/configs/eslint.config.js +79 -0
  564. package/tooling/astro/configs/playwright.config.ts +26 -0
  565. package/tooling/astro/configs/tsconfig.json +12 -0
  566. package/tooling/astro/configs/vitest.config.ts +22 -0
  567. package/tooling/astro/manifest.toml +34 -0
  568. package/tooling/astro/reference.md +60 -0
  569. package/tooling/base/configs/.editorconfig +5 -0
  570. package/tooling/base/configs/.github/pull_request_template.md +18 -0
  571. package/tooling/base/configs/.github/workflows/verify.yml +35 -0
  572. package/tooling/base/configs/.husky/commit-msg +1 -0
  573. package/tooling/base/configs/.husky/post-merge +61 -0
  574. package/tooling/base/configs/.husky/post-rewrite +21 -0
  575. package/tooling/base/configs/.husky/pre-commit +1 -0
  576. package/tooling/base/configs/.husky/pre-push +1 -0
  577. package/tooling/base/configs/.prettierrc +12 -0
  578. package/tooling/base/configs/.shellcheckrc +1 -0
  579. package/tooling/base/configs/.vscode/extensions.json +9 -0
  580. package/tooling/base/configs/.vscode/settings.json +3 -0
  581. package/tooling/base/configs/commitlint.config.js +11 -0
  582. package/tooling/base/configs/scripts/verify.sh +64 -0
  583. package/tooling/base/manifest.toml +30 -0
  584. package/tooling/base/reference.md +98 -0
  585. package/tooling/base/seeds/.claude/context/ci.md +33 -0
  586. package/tooling/base/seeds/.claude/context/development.md +37 -0
  587. package/tooling/base/seeds/.claude/context/index.md +11 -0
  588. package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
  589. package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
  590. package/tooling/base/seeds/.lintstagedrc +8 -0
  591. package/tooling/base/seeds/.prettierignore +0 -0
  592. package/tooling/base/seeds/cspell.json +20 -0
  593. package/tooling/claude/manifest.toml +14 -0
  594. package/tooling/claude/reference.md +79 -0
  595. package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
  596. package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
  597. package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
  598. package/tooling/claude/seeds/.claude/diagrams/index.md +8 -0
  599. package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +50 -0
  600. package/tooling/claude/seeds/.claude/hooks/memory-index.sh +68 -0
  601. package/tooling/claude/seeds/.claude/hooks/path-form.sh +57 -0
  602. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +52 -0
  603. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +86 -0
  604. package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +71 -0
  605. package/tooling/claude/seeds/.claude/memory/index.md +8 -0
  606. package/tooling/claude/seeds/.claude/settings.json +47 -0
  607. package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
  608. package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
  609. package/tooling/claude/seeds/CLAUDE.md +29 -0
  610. package/tooling/claude/user/settings.template.json +10 -0
  611. package/tooling/claude/user/statusline-command.sh +53 -0
  612. package/tooling/python/configs/.coveragerc +14 -0
  613. package/tooling/python/configs/.python-version +1 -0
  614. package/tooling/python/configs/mypy.ini +6 -0
  615. package/tooling/python/configs/pytest.ini +4 -0
  616. package/tooling/python/configs/ruff.toml +15 -0
  617. package/tooling/python/configs/scripts/verify.sh +77 -0
  618. package/tooling/python/manifest.toml +16 -0
  619. package/tooling/python/reference.md +66 -0
  620. package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
  621. package/tooling/python/seeds/tests/test_smoke.py +2 -0
  622. package/tooling/vite-react/configs/playwright.config.ts +26 -0
  623. package/tooling/vite-react/configs/tsconfig.json +35 -0
  624. package/tooling/vite-react/configs/vite.config.ts +24 -0
  625. package/tooling/vite-react/configs/vitest.config.ts +26 -0
  626. package/tooling/vite-react/manifest.toml +23 -0
  627. package/tooling/vite-react/reference.md +55 -0
  628. package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
  629. package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
  630. package/tooling/web/configs/.github/workflows/verify.yml +134 -0
  631. package/tooling/web/configs/.vscode/extensions.json +13 -0
  632. package/tooling/web/configs/.vscode/settings.json +10 -0
  633. package/tooling/web/configs/e2e/home.spec.ts +6 -0
  634. package/tooling/web/configs/e2e/screenshot.ts +53 -0
  635. package/tooling/web/configs/eslint.config.js +82 -0
  636. package/tooling/web/configs/scripts/screenshot.sh +28 -0
  637. package/tooling/web/configs/scripts/verify.sh +80 -0
  638. package/tooling/web/configs/scripts/worktree-port.sh +74 -0
  639. package/tooling/web/configs/src/test/setup.ts +8 -0
  640. package/tooling/web/manifest.toml +58 -0
  641. package/tooling/web/reference.md +115 -0
  642. package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
  643. package/tsconfig.json +14 -0
@@ -0,0 +1,204 @@
1
+ import { join } from 'node:path'
2
+ import { execa } from 'execa'
3
+ import type { Delta } from '@/audits/baseline'
4
+ import { type AuditResult, type AuditSpec, classify } from '@/audits/catalog'
5
+ import { gitEnv } from '@/git-env'
6
+ import { PROJECT_ROOT } from '@/project-root'
7
+
8
+ /** At least one audit reported a finding that is a fact. */
9
+ export const EXIT_FINDING = 2
10
+
11
+ /** At least one audit did not report, so the run measured less than the set. */
12
+ export const EXIT_UNMEASURED = 3
13
+
14
+ export type Verdict =
15
+ /** Every audit reported and every count it produced was zero. */
16
+ | 'clean'
17
+ /** Every audit reported and at least one carries a judgment finding. */
18
+ | 'reported'
19
+ /** At least one audit carries a finding that is a fact. */
20
+ | 'findings'
21
+ /** At least one audit did not report, so this is not a pass. */
22
+ | 'incomplete'
23
+
24
+ export interface SpawnResult {
25
+ readonly exitCode: number
26
+ readonly stdout: string
27
+ }
28
+
29
+ export type Spawn = (spec: AuditSpec) => Promise<SpawnResult>
30
+
31
+ /**
32
+ * Runs each verb out of the checkout this CLI is executing from.
33
+ *
34
+ * `process.execPath` and the resolved `cli.ts` rather than a bare `canon`, for
35
+ * the reason `cliRunner` in `src/gate/sequencer.ts` already names: a globally
36
+ * installed binary resolves to
37
+ * the main checkout no matter which worktree is running, so the aggregate would
38
+ * measure the wrong tree and report a pass over a branch it never read.
39
+ *
40
+ * `reject: false` because a findings exit is the ordinary outcome for half of
41
+ * these verbs, and a throw there would be an error path for a working check.
42
+ */
43
+ export function spawnAudit(root: string): Spawn {
44
+ const cli = join(PROJECT_ROOT, 'src', 'cli.ts')
45
+
46
+ return async (spec) => {
47
+ const result = await execa(process.execPath, [cli, ...spec.argv], {
48
+ cwd: root,
49
+ reject: false,
50
+ // `gitEnv` already returns the whole ambient environment minus git's
51
+ // resolution variables, so it replaces the environment rather than
52
+ // extending it. Spreading `process.env` alongside would put back the very
53
+ // variables it strips, and a hook's `GIT_DIR` would then point every
54
+ // history-reading verb at a repository nobody asked about.
55
+ env: { ...gitEnv(), CANON_NON_INTERACTIVE: '1' },
56
+ extendEnv: false,
57
+ })
58
+
59
+ return { exitCode: result.exitCode ?? 1, stdout: result.stdout }
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Runs every audit and reads each one's own record shape.
65
+ *
66
+ * The verbs walk separate trees and share no state, so they run together
67
+ * rather than in sequence. Serially, the aggregate would be the slowest thing
68
+ * in the verify pipeline for no reason beyond the order they were written in.
69
+ *
70
+ * A spawn that throws becomes an `unmeasured` result rather than a rejection.
71
+ * One absent binary would otherwise take the whole aggregate down and report
72
+ * nothing about the audits that did run.
73
+ */
74
+ export async function runAudits(
75
+ specs: readonly AuditSpec[],
76
+ spawn: Spawn,
77
+ ): Promise<AuditResult[]> {
78
+ return Promise.all(
79
+ specs.map(async (spec) => {
80
+ try {
81
+ const { exitCode, stdout } = await spawn(spec)
82
+ return classify(spec, exitCode, stdout)
83
+ } catch (error) {
84
+ return {
85
+ id: spec.id,
86
+ label: spec.label,
87
+ status: 'unmeasured' as const,
88
+ tracked: spec.corpus === 'tracked',
89
+ corpus: spec.corpus,
90
+ exitCode: 1,
91
+ reason: `could not be started: ${error instanceof Error ? error.message : String(error)}`,
92
+ }
93
+ }
94
+ }),
95
+ )
96
+ }
97
+
98
+ /**
99
+ * The single verdict over the set.
100
+ *
101
+ * `incomplete` outranks a quiet set on purpose. An aggregate reporting a pass
102
+ * over a tree it did not finish measuring is the failure this whole command
103
+ * exists against, and an empty set takes it for the same reason: nothing ran,
104
+ * so nothing passed.
105
+ *
106
+ * An `absent` per-machine corpus does not reach it. That folder is gitignored
107
+ * and missing on every fresh clone, so folding it in would pin the verdict at
108
+ * `incomplete` on every CI run and leave the word meaning nothing.
109
+ */
110
+ export function verdictOf(results: readonly AuditResult[]): Verdict {
111
+ if (results.length === 0) return 'incomplete'
112
+ if (results.some((result) => result.status === 'finding')) return 'findings'
113
+ if (results.some((result) => result.status === 'unmeasured')) {
114
+ return 'incomplete'
115
+ }
116
+ if (results.some((result) => result.status === 'reported')) return 'reported'
117
+ return 'clean'
118
+ }
119
+
120
+ /**
121
+ * Exits non-zero only on a fact, which is the split this aggregate inherits
122
+ * rather than moves. A growing judgment count reports as a delta and fails
123
+ * nothing, because the standards behind those measures set no hard cap.
124
+ *
125
+ * An audit that did not report takes its own code rather than the findings one.
126
+ * The two mean opposite things to whoever reads the exit: a fact is a defect in
127
+ * the tree, and an unmeasured audit is a defect in the run.
128
+ */
129
+ export function exitCodeFor(results: readonly AuditResult[]): number {
130
+ const verdict = verdictOf(results)
131
+ if (verdict === 'findings') return EXIT_FINDING
132
+ if (verdict === 'incomplete') return EXIT_UNMEASURED
133
+ return 0
134
+ }
135
+
136
+ export interface Summary {
137
+ readonly verdict: Verdict
138
+ /** Audits that reported, out of the whole set. */
139
+ readonly audited: number
140
+ /** Audits carrying a finding that is a fact. */
141
+ readonly facts: number
142
+ /** Audits that did not report at all. */
143
+ readonly unmeasured: number
144
+ /**
145
+ * Audits whose per-machine folder is not on this disk.
146
+ *
147
+ * Published rather than folded into `audited`, so a run stating twelve
148
+ * audits never implies twelve corpora were read.
149
+ */
150
+ readonly absent: number
151
+ /** Tracked counts that rose against the recorded floor. */
152
+ readonly grown: number
153
+ /** Tracked counts that fell against the recorded floor. */
154
+ readonly shrunk: number
155
+ /** Tracked audits with no recorded floor to compare against. */
156
+ readonly unrecorded: number
157
+ }
158
+
159
+ /**
160
+ * The flat reading a shell stage takes without parsing the nested record.
161
+ *
162
+ * Published rather than left to a consumer to derive, for the reason the
163
+ * context audit already gives about its own join: deriving it means restating
164
+ * which question each number answers, and one wrong restatement is growth
165
+ * reported against a measure that never moved. Every key here is unique across
166
+ * the whole record, so a grep for one reaches the top level alone.
167
+ */
168
+ export function summarize(
169
+ results: readonly AuditResult[],
170
+ deltas: readonly Delta[],
171
+ ): Summary {
172
+ let grown = 0
173
+ let shrunk = 0
174
+ let unrecorded = 0
175
+
176
+ for (const delta of deltas) {
177
+ if (delta.kind === 'unrecorded') {
178
+ unrecorded += 1
179
+ continue
180
+ }
181
+ if (delta.kind !== 'compared') continue
182
+
183
+ for (const moved of delta.moved) {
184
+ if (moved.delta > 0) grown += 1
185
+ else shrunk += 1
186
+ }
187
+ }
188
+
189
+ const counting = (status: AuditResult['status']) =>
190
+ results.filter((result) => result.status === status).length
191
+
192
+ return {
193
+ verdict: verdictOf(results),
194
+ audited: results.filter(
195
+ (result) => result.status !== 'unmeasured' && result.status !== 'absent',
196
+ ).length,
197
+ facts: counting('finding'),
198
+ unmeasured: counting('unmeasured'),
199
+ absent: counting('absent'),
200
+ grown,
201
+ shrunk,
202
+ unrecorded,
203
+ }
204
+ }
@@ -0,0 +1,75 @@
1
+ import {
2
+ BEHAVIOR_FILES,
3
+ BEHAVIOR_PREFIXES,
4
+ PROSE_EXTENSIONS,
5
+ } from '@/autoship/paths'
6
+
7
+ /**
8
+ * Which of the two tests a file failed.
9
+ *
10
+ * Named apart rather than folded into one boolean, because the repair differs.
11
+ * A non-prose extension means the branch carries code and review is ordinary. A
12
+ * behavior path means prose that states what an agent does, which is the half
13
+ * three sessions read past.
14
+ */
15
+ export type FailedTest = 'extension' | 'behavior-path'
16
+
17
+ /** Why a classification produced no reading. */
18
+ export type ClassifyRefusal = 'no-changes'
19
+
20
+ export type Classification =
21
+ | { readonly kind: 'skip' }
22
+ | {
23
+ readonly kind: 'review'
24
+ readonly test: FailedTest
25
+ readonly file: string
26
+ }
27
+ | { readonly kind: 'refused'; readonly reason: ClassifyRefusal }
28
+
29
+ /**
30
+ * Prefix-anchored against the folders, matching how `resolveCoverage` reads the
31
+ * label map, and equality against the whole paths a prefix cannot reach.
32
+ */
33
+ function underBehaviorPath(path: string): boolean {
34
+ if (BEHAVIOR_FILES.some((file) => file === path)) return true
35
+ return BEHAVIOR_PREFIXES.some((prefix) => path.startsWith(prefix))
36
+ }
37
+
38
+ function readsAsProse(path: string): boolean {
39
+ const lowered = path.toLowerCase()
40
+ return PROSE_EXTENSIONS.some((extension) => lowered.endsWith(extension))
41
+ }
42
+
43
+ /**
44
+ * Decides whether a branch's changed set skips the review pass.
45
+ *
46
+ * The skip needs both tests to pass: every name reads as prose, and no name
47
+ * sits under a behavior path. One behavior file sends the whole branch to
48
+ * review, since documentation shipped beside a behavior change does not cancel
49
+ * it.
50
+ *
51
+ * An empty set refuses rather than skipping. Both tests are universally
52
+ * quantified, so an empty set satisfies them vacuously, and reading that as
53
+ * prose-only would route a branch past review for having produced no output at
54
+ * all.
55
+ *
56
+ * Names only. The caller hands the set the ship chain already computed, so no
57
+ * second baseline is read here and the stale-baseline half stays closed.
58
+ */
59
+ export function classifyChanges(paths: readonly string[]): Classification {
60
+ if (paths.length === 0) return { kind: 'refused', reason: 'no-changes' }
61
+
62
+ // First failure in the caller's order wins, and each file is tested for its
63
+ // extension before its path. A set failing both tests reports one file and
64
+ // one test, which is all the branch needs to route.
65
+ for (const path of paths) {
66
+ if (!readsAsProse(path)) {
67
+ return { kind: 'review', test: 'extension', file: path }
68
+ }
69
+ if (underBehaviorPath(path)) {
70
+ return { kind: 'review', test: 'behavior-path', file: path }
71
+ }
72
+ }
73
+
74
+ return { kind: 'skip' }
75
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The surfaces where markdown states what an agent does, and the extensions
3
+ * that read as prose, held as data one command parses.
4
+ *
5
+ * Lifted verbatim in content from the list `claude-autoship/SKILL.md` Step 5
6
+ * carried, which a session was asked to apply by hand. It failed that
7
+ * application three times, so the set moved here and the body now calls a verb
8
+ * that reads it. Being machine-parsed makes it permanently exempt from any
9
+ * later design that folds a standard back into the surface citing it, per the
10
+ * machine-parsed clause in `.claude/ARCHITECTURE.md`.
11
+ */
12
+
13
+ /**
14
+ * Path prefixes under which a markdown change is a behavior change.
15
+ *
16
+ * Most carry two spellings, the one a surface authors at and the one it reaches
17
+ * a session at, so the rule reads the same in this toolkit and in a project
18
+ * that consumed one. `standards/` and `snippets/` carry one apiece: neither
19
+ * installs into a project, reaching a reader by resolution and through the
20
+ * `claude/snippets` symlink respectively, so no `.claude/` spelling exists to
21
+ * name.
22
+ */
23
+ export const BEHAVIOR_PREFIXES = [
24
+ 'claude/skills/',
25
+ '.claude/skills/',
26
+ 'governance/rules/',
27
+ '.claude/rules/',
28
+ 'standards/',
29
+ 'snippets/',
30
+ 'internal/',
31
+ 'tooling/',
32
+ ] as const
33
+
34
+ /**
35
+ * Behavior surfaces named as whole paths rather than as prefixes.
36
+ *
37
+ * A path prefix reaches nothing that sits in no folder, which is what the root
38
+ * instruction file is. Matching is equality rather than a suffix test, so a
39
+ * nested `docs/CLAUDE.md` stays informational the way the body's "at the
40
+ * repository root" qualifier says it should.
41
+ */
42
+ export const BEHAVIOR_FILES = ['CLAUDE.md'] as const
43
+
44
+ /**
45
+ * Extensions a changed file may carry for the branch to read as prose-only.
46
+ *
47
+ * Compared lowercased, so a `README.MD` is not routed to review for its
48
+ * spelling. Everything else is code, a config, or an asset, and one of them
49
+ * sends the whole branch to review.
50
+ */
51
+ export const PROSE_EXTENSIONS = ['.md', '.txt'] as const
package/src/binary.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Whether the bytes are something a line scanner should not read.
3
+ *
4
+ * A NUL byte rather than an extension list, since a shipped tree carries fonts
5
+ * and images under names no scanner has reason to enumerate, and a list would
6
+ * go stale the first time a format was added. Decoded text holds no NUL, so the
7
+ * test costs one scan and never rejects source.
8
+ *
9
+ * Neutral rather than owned by either sweep that calls it. The secret scan
10
+ * shaped it and the superseded-value sweep reads the same corpus, so leaving it
11
+ * in `src/secrets/` would put a `src/gov/` dependency on the secret scanner for
12
+ * a predicate about bytes.
13
+ */
14
+ export function isBinary(text: string): boolean {
15
+ return text.includes('\0')
16
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * What every browser-driving command needs to know before it can report a
3
+ * failure honestly: how the binary is installed, and how each of the two ways
4
+ * it can be absent reads when it is thrown.
5
+ *
6
+ * The two are different states with different remedies. A package that never
7
+ * resolved means the target installed the CLI without the engine, and a binary
8
+ * that was never downloaded means the engine is present and its browser is not.
9
+ * Both were spelled inside `src/demo/` when `demo` was the only command driving
10
+ * a browser, and a second command is what makes them shared rather than local.
11
+ */
12
+
13
+ /** Fetches the browser revision the pinned engine expects. */
14
+ export const INSTALL_BROWSER = 'bunx playwright install chromium'
15
+
16
+ /**
17
+ * Separates a browser binary that was never installed from every other launch
18
+ * failure, because the first is a setup step the operator has to run and the
19
+ * second is a defect. A target inherits that setup step, which is the stated
20
+ * cost of shipping a browser command outside the toolkit.
21
+ */
22
+ export function isBrowserMissing(error: unknown): boolean {
23
+ const text = error instanceof Error ? error.message : String(error)
24
+ return /executable doesn't exist|playwright install/i.test(text)
25
+ }
26
+
27
+ /**
28
+ * Reports the engine package failing to resolve, which is the case a target
29
+ * hits before installing it. Any other import failure is a defect inside the
30
+ * module being loaded and propagates, rather than being reported as a missing
31
+ * dependency.
32
+ */
33
+ export function isEngineMissing(error: unknown): boolean {
34
+ return (
35
+ typeof error === 'object' &&
36
+ error !== null &&
37
+ 'code' in error &&
38
+ error.code === 'ERR_MODULE_NOT_FOUND'
39
+ )
40
+ }
@@ -0,0 +1,113 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import { extname, join } from 'node:path'
3
+ import { isBinary } from '@/binary'
4
+ import { listRepositoryFiles } from '@/git-files'
5
+
6
+ export type CensusRefusal = 'no-git'
7
+
8
+ export interface ExtensionCount {
9
+ readonly extension: string
10
+ readonly files: number
11
+ readonly lines: number
12
+ }
13
+
14
+ export interface CensusResult {
15
+ readonly kind: 'measured'
16
+ readonly files: number
17
+ /** Binary or unreadable, counted toward `files` and excluded from `lines`. */
18
+ readonly skipped: number
19
+ readonly lines: number
20
+ readonly byExtension: readonly ExtensionCount[]
21
+ }
22
+
23
+ export interface CensusFailure {
24
+ readonly kind: 'refused'
25
+ readonly reason: CensusRefusal
26
+ }
27
+
28
+ /**
29
+ * Open descriptors allowed at once while reading the tree, matching
30
+ * `src/comments/scan.ts`. A single `Promise.all` over every path opens one
31
+ * descriptor per file, which exhausts a default 1024 limit on a large
32
+ * repository and fails the whole census with EMFILE.
33
+ */
34
+ const CONCURRENT_READS = 64
35
+
36
+ interface ReadOutcome {
37
+ readonly path: string
38
+ /** Absent when the read failed: a symlink leaving the tree, or a file git
39
+ * listed and the working tree no longer holds. */
40
+ readonly text?: string
41
+ }
42
+
43
+ async function readOne(root: string, path: string): Promise<ReadOutcome> {
44
+ try {
45
+ return { path, text: await readFile(join(root, path), 'utf8') }
46
+ } catch {
47
+ return { path }
48
+ }
49
+ }
50
+
51
+ function extensionFor(path: string): string {
52
+ const ext = extname(path)
53
+ return ext === '' ? 'no-extension' : ext.slice(1).toLowerCase()
54
+ }
55
+
56
+ /**
57
+ * A trailing newline is the file's terminator rather than an empty final line,
58
+ * which is what keeps a file ending `a\nb\n` at two lines rather than three.
59
+ */
60
+ function countLines(text: string): number {
61
+ if (text === '') return 0
62
+ const lines = text.split('\n')
63
+ return text.endsWith('\n') ? lines.length - 1 : lines.length
64
+ }
65
+
66
+ /**
67
+ * Censuses the tracked-plus-untracked tree under `root`: a file count, a
68
+ * breakdown by extension, and a line total that skips whatever reads as
69
+ * binary.
70
+ *
71
+ * Reads `listRepositoryFiles`, the same corpus the citation check, the
72
+ * markdown corpus, and the secret scan already share, so this is not a
73
+ * fourth definition of what counts.
74
+ */
75
+ export async function census(
76
+ root: string,
77
+ ): Promise<CensusResult | CensusFailure> {
78
+ const listed = await listRepositoryFiles(root)
79
+ if (listed === undefined) return { kind: 'refused', reason: 'no-git' }
80
+
81
+ const totals = new Map<string, { files: number; lines: number }>()
82
+ let skipped = 0
83
+ let lines = 0
84
+
85
+ for (let start = 0; start < listed.length; start += CONCURRENT_READS) {
86
+ const batch = listed.slice(start, start + CONCURRENT_READS)
87
+ const outcomes = await Promise.all(batch.map((path) => readOne(root, path)))
88
+
89
+ for (const outcome of outcomes) {
90
+ const extension = extensionFor(outcome.path)
91
+ const entry = totals.get(extension) ?? { files: 0, lines: 0 }
92
+ entry.files += 1
93
+
94
+ // A read that failed and a file that read as binary are counted the
95
+ // same way: toward `files`, excluded from every line count.
96
+ if (outcome.text === undefined || isBinary(outcome.text)) {
97
+ skipped += 1
98
+ } else {
99
+ const counted = countLines(outcome.text)
100
+ entry.lines += counted
101
+ lines += counted
102
+ }
103
+
104
+ totals.set(extension, entry)
105
+ }
106
+ }
107
+
108
+ const byExtension = [...totals.entries()]
109
+ .map(([extension, counts]) => ({ extension, ...counts }))
110
+ .sort((a, b) => b.files - a.files || a.extension.localeCompare(b.extension))
111
+
112
+ return { kind: 'measured', files: listed.length, skipped, lines, byExtension }
113
+ }
@@ -0,0 +1,24 @@
1
+ import type { SkillCase } from '@/claude/skills-rank'
2
+ import { AUTHORING_CASES } from '@/claude/cases/authoring'
3
+ import { CLAUDE_WORKFLOW_CASES } from '@/claude/cases/claude-workflow'
4
+ import { GIT_CASES } from '@/claude/cases/git'
5
+ import { MISC_CASES } from '@/claude/cases/misc'
6
+ import { SETUP_CASES } from '@/claude/cases/setup'
7
+
8
+ /**
9
+ * The full routing case corpus, one file per domain so a description change
10
+ * in one family touches only the file beside it.
11
+ *
12
+ * Bootstrapped from each skill's own quoted trigger phrases and then
13
+ * rephrased and supplemented rather than shipped verbatim, since a positive
14
+ * lifted unchanged from a trigger passes by construction and never tests a
15
+ * person's own words. See `.claude/groundwork/42-ai-blueprint/08-spikes.md`
16
+ * for the extraction arm this corpus replaces as the shipped measure.
17
+ */
18
+ export const SKILL_CASES: readonly SkillCase[] = [
19
+ ...CLAUDE_WORKFLOW_CASES,
20
+ ...GIT_CASES,
21
+ ...SETUP_CASES,
22
+ ...AUTHORING_CASES,
23
+ ...MISC_CASES,
24
+ ]
@@ -0,0 +1,53 @@
1
+ import type { SkillCase } from '@/claude/skills-rank'
2
+
3
+ /**
4
+ * Script, skill, snippet, standard, and doc authoring, plus the two prose
5
+ * skills that revise rather than generate.
6
+ */
7
+ export const AUTHORING_CASES: readonly SkillCase[] = [
8
+ {
9
+ prompt:
10
+ 'I need a shell tool with prompts and a nice terminal UI for people to run by hand.',
11
+ expect: 'bash-script',
12
+ },
13
+ {
14
+ prompt:
15
+ 'Wire up a GitHub Actions pipeline with parallel jobs for this repo.',
16
+ expect: 'ci-workflow',
17
+ },
18
+ {
19
+ prompt:
20
+ 'Write me a headless automation script with no interactive prompts.',
21
+ expect: 'bash-cli-script',
22
+ },
23
+ {
24
+ prompt: 'Scaffold a brand-new SKILL.md for this capability.',
25
+ expect: 'create-skill',
26
+ },
27
+ {
28
+ prompt: 'I need a new reusable prompt snippet added to the corpus.',
29
+ expect: 'create-snippet',
30
+ },
31
+ {
32
+ prompt: 'Write a fresh authoring convention as a new standard file.',
33
+ expect: 'create-standard',
34
+ },
35
+ {
36
+ prompt:
37
+ "The docs folder and README are stale against what's on main, refresh them.",
38
+ expect: 'docs-sync',
39
+ },
40
+ {
41
+ prompt: 'Say what that dense answer actually means in plain terms.',
42
+ expect: 'restate-plainly',
43
+ },
44
+ {
45
+ prompt: 'This passage reads flat and robotic, give it some real cadence.',
46
+ expect: 'write-human',
47
+ },
48
+ {
49
+ prompt:
50
+ 'Pull the captions off this YouTube link and save them with metadata.',
51
+ expect: 'youtube-transcripts',
52
+ },
53
+ ]