@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,184 @@
1
+ import { stat } from 'node:fs/promises'
2
+ import { dirname, resolve } from 'node:path'
3
+ import { $ } from 'bun'
4
+ import type { Command } from 'commander'
5
+ import { exitCodeFor, type RegenResult, regenOne } from '@/indexes/regen'
6
+ import { gitEnv } from '@/git-env'
7
+ import { findIndexedAncestor, isIgnored, listIndexes } from '@/indexes/walk'
8
+ import { intro, logAdd, logInfo, logStep, logWarn, outro } from '@/ui'
9
+
10
+ interface RegenCommandOptions {
11
+ readonly dryRun?: boolean
12
+ readonly json?: boolean
13
+ readonly root?: string
14
+ readonly stage?: boolean
15
+ }
16
+
17
+ export function register(program: Command): void {
18
+ const indexes = program
19
+ .command('indexes')
20
+ .description('Regenerate index.md files from sibling frontmatter')
21
+ .helpOption('-h, --help', 'Show this help message')
22
+
23
+ indexes
24
+ .command('regen')
25
+ .description('Regenerate index.md files from sibling frontmatter')
26
+ .argument(
27
+ '[paths...]',
28
+ 'Paths to resolve up to their nearest indexed folder',
29
+ )
30
+ .helpOption('-h, --help', 'Show this help message')
31
+ .option('--dry-run', 'Report changes without writing')
32
+ .option('--json', 'Emit a machine-readable record per index on stdout')
33
+ .option('--root <path>', 'Walk-up boundary for positional paths')
34
+ .option('--no-stage', 'Skip the auto git add on modified indexes')
35
+ .addHelpText(
36
+ 'after',
37
+ [
38
+ '',
39
+ 'Exit codes:',
40
+ ' 0 no drift, nothing to do',
41
+ ' 1 frontmatter error or missing index.md',
42
+ ' 2 --dry-run found folders that would change',
43
+ '',
44
+ 'Examples:',
45
+ ' canon indexes regen',
46
+ ' canon indexes regen --dry-run',
47
+ ' canon indexes regen --json docs/',
48
+ '',
49
+ ].join('\n'),
50
+ )
51
+ .action(async (paths: string[], opts: RegenCommandOptions) => {
52
+ process.exitCode = await runRegen(paths, opts)
53
+ })
54
+ }
55
+
56
+ async function runRegen(
57
+ paths: string[],
58
+ opts: RegenCommandOptions,
59
+ ): Promise<number> {
60
+ const root = resolve(opts.root ?? process.cwd())
61
+ const dryRun = opts.dryRun ?? false
62
+ const emitJson = opts.json ?? false
63
+
64
+ if (!(await isDirectory(root))) {
65
+ if (emitJson) {
66
+ process.stdout.write(
67
+ `${JSON.stringify({ error: `root not a directory: ${root}` })}\n`,
68
+ )
69
+ return 1
70
+ }
71
+ process.stderr.write(`Root is not a directory: ${root}\n`)
72
+ return 1
73
+ }
74
+
75
+ const dirs =
76
+ paths.length > 0
77
+ ? collectFromPaths(paths, root)
78
+ : (await listIndexes(root)).map(dirname)
79
+
80
+ const shouldStage =
81
+ paths.length > 0 && opts.stage !== false && !dryRun && !emitJson
82
+
83
+ const results: RegenResult[] = []
84
+
85
+ if (!emitJson) {
86
+ intro('canon indexes')
87
+ logStep(dryRun ? 'Indexes (dry-run)' : 'Indexes')
88
+ }
89
+
90
+ for (const dir of dirs) {
91
+ const result = await regenOne(dir, { dryRun })
92
+ results.push(result)
93
+
94
+ for (const message of result.errors ?? []) {
95
+ process.stderr.write(`ERROR: ${message}\n`)
96
+ }
97
+
98
+ if (!emitJson) await reportResult(result, root, shouldStage)
99
+ }
100
+
101
+ if (emitJson) {
102
+ process.stdout.write(
103
+ `${JSON.stringify({
104
+ root,
105
+ dryRun,
106
+ results: results.map(({ path, action, reason }) =>
107
+ reason ? { path, action, reason } : { path, action },
108
+ ),
109
+ })}\n`,
110
+ )
111
+ } else {
112
+ outro()
113
+ }
114
+
115
+ return exitCodeFor(results, { dryRun })
116
+ }
117
+
118
+ function collectFromPaths(paths: string[], root: string): string[] {
119
+ const dirs: string[] = []
120
+
121
+ for (const path of paths) {
122
+ const dir = findIndexedAncestor(resolve(root, path), root)
123
+ if (!dir) {
124
+ process.stderr.write(
125
+ `WARN: ${path} has no index.md ancestor under ${root}\n`,
126
+ )
127
+ continue
128
+ }
129
+ if (!dirs.includes(dir)) dirs.push(dir)
130
+ }
131
+
132
+ return dirs
133
+ }
134
+
135
+ async function reportResult(
136
+ result: RegenResult,
137
+ root: string,
138
+ shouldStage: boolean,
139
+ ): Promise<void> {
140
+ const rel = result.path.startsWith(`${root}/`)
141
+ ? result.path.slice(root.length + 1)
142
+ : result.path
143
+
144
+ switch (result.action) {
145
+ case 'written':
146
+ logAdd(rel)
147
+ if (shouldStage) await stage(result.path, rel, root)
148
+ break
149
+ case 'would-write':
150
+ logWarn(`${rel} would change`)
151
+ break
152
+ case 'unchanged':
153
+ logInfo(`${rel} unchanged`)
154
+ break
155
+ case 'skipped':
156
+ logInfo(`${rel} skipped (auto:false)`)
157
+ break
158
+ case 'error':
159
+ logWarn(`${rel} error`)
160
+ break
161
+ }
162
+ }
163
+
164
+ async function stage(path: string, rel: string, root: string): Promise<void> {
165
+ if (await isIgnored(root, path)) return
166
+
167
+ const staged = await $`git -C ${root} add -- ${path}`
168
+ .env(gitEnv())
169
+ .quiet()
170
+ .nothrow()
171
+ .then((result) => result.exitCode === 0)
172
+
173
+ if (staged) {
174
+ logInfo(`staged ${rel}`)
175
+ } else {
176
+ logWarn(`failed to stage ${rel}`)
177
+ }
178
+ }
179
+
180
+ async function isDirectory(path: string): Promise<boolean> {
181
+ return stat(path)
182
+ .then((info) => info.isDirectory())
183
+ .catch(() => false)
184
+ }
@@ -0,0 +1,113 @@
1
+ import type { Command } from 'commander'
2
+ import { cliPath, cliRun } from '@/cli-run'
3
+ import { PROJECT_ROOT } from '@/project-root'
4
+ import { applyInitOptions, flagsProvided } from '@/init/flags'
5
+ import { type InitFlags, parseSkip, planInit } from '@/init/plan'
6
+ import { runDomains } from '@/init/run'
7
+ import { buildSteps } from '@/init/steps'
8
+ import { resolveTarget } from '@/target'
9
+ import { intro, logInfo, logStep, logWarn, outro, palette, select } from '@/ui'
10
+
11
+ interface InitOptions {
12
+ /** Always present: the option falls back to `DEFAULT_STACK`. */
13
+ readonly stack: string
14
+ readonly add?: string
15
+ readonly skip?: string
16
+ }
17
+
18
+ export function register(program: Command): void {
19
+ const command = program
20
+ .command('init')
21
+ .description('Bootstrap a project with base tooling and toolkit domains')
22
+ .argument('[target]', 'Target directory', '.')
23
+
24
+ applyInitOptions(command)
25
+ .helpOption('-h, --help', 'Show this help message')
26
+ .addHelpText(
27
+ 'after',
28
+ [
29
+ '',
30
+ 'Passing any option skips the confirmation prompt.',
31
+ '',
32
+ 'Examples:',
33
+ ' canon init',
34
+ ' canon init ../my-app',
35
+ ' canon init --stack astro --add 260-shadcn ../my-app',
36
+ ' canon init --skip governance ../my-app',
37
+ '',
38
+ ].join('\n'),
39
+ )
40
+ .action(async (target: string, options: InitOptions, cmd: Command) => {
41
+ process.exitCode = await runInit(target, options, flagsProvided(cmd))
42
+ })
43
+ }
44
+
45
+ async function runInit(
46
+ target: string,
47
+ options: InitOptions,
48
+ skipPrompt: boolean,
49
+ ): Promise<number> {
50
+ intro('canon init')
51
+
52
+ const resolved = resolveTarget(target, PROJECT_ROOT)
53
+ if (typeof resolved === 'number') return resolved
54
+
55
+ const skip = parseSkip(options.skip)
56
+ for (const value of skip.unknown) {
57
+ logWarn(`Unknown --skip value: ${value} (ignoring)`)
58
+ }
59
+
60
+ const flags: InitFlags = {
61
+ stack: options.stack,
62
+ add: options.add,
63
+ skip,
64
+ }
65
+
66
+ const plan = planInit(flags)
67
+
68
+ logStep('Core domains')
69
+ for (const line of plan.preview) {
70
+ if (line.level === 'info') logInfo(line.text)
71
+ else logWarn(line.text)
72
+ }
73
+
74
+ if (!skipPrompt) {
75
+ const shouldInstall = await select({
76
+ message: `Install ${plan.total} domains to ${target}?`,
77
+ options: [
78
+ { value: true, label: 'Yes' },
79
+ { value: false, label: 'Cancel' },
80
+ ],
81
+ nonInteractiveDefault: true,
82
+ })
83
+
84
+ if (!shouldInstall) {
85
+ logWarn('Cancelled')
86
+ outro()
87
+ return 0
88
+ }
89
+ }
90
+
91
+ const path = cliPath(PROJECT_ROOT)
92
+ const child = (args: readonly string[]): (() => Promise<boolean>) =>
93
+ cliRun(path, args, { nonInteractive: true, stdin: 'ignore' })
94
+
95
+ const failed = await runDomains(buildSteps(target, resolved, flags, child))
96
+
97
+ outro()
98
+ process.stderr.write('\n')
99
+
100
+ const { GREEN, NC, YELLOW } = palette(process.stderr)
101
+
102
+ if (failed.length === 0) {
103
+ process.stderr.write(
104
+ `${GREEN}✓ Project initialized (${plan.total} domains)${NC}\n`,
105
+ )
106
+ return 0
107
+ }
108
+
109
+ process.stderr.write(
110
+ `${YELLOW}! Project initialized with ${failed.length} failure(s): ${failed.join(', ')}${NC}\n`,
111
+ )
112
+ return 1
113
+ }
@@ -0,0 +1,406 @@
1
+ import { relative } from 'node:path'
2
+ import type { Command } from 'commander'
3
+ import {
4
+ type AnswerOutcome,
5
+ answerItems,
6
+ type IntakeRefused,
7
+ type ListOutcome,
8
+ listFolders,
9
+ type ReadOutcome,
10
+ readFolder,
11
+ type Selection,
12
+ } from '@/intake/folder'
13
+ import { isUnread } from '@/intake/items'
14
+ import {
15
+ intro,
16
+ logAdd,
17
+ logError,
18
+ logInfo,
19
+ logStep,
20
+ logWarn,
21
+ outro,
22
+ pipeOutput,
23
+ } from '@/ui'
24
+ import { mainWorktreeRoot } from '@/worktree'
25
+
26
+ /**
27
+ * A selection as the command line spells it, splitting on the first `=`. The
28
+ * label accepts a letter suffix, matching the headings a cluster file carries,
29
+ * and everything after the separator is the answer, so one carrying its own
30
+ * `=` survives intact.
31
+ */
32
+ const SELECTION = /^(\d+[a-z]*)=([\s\S]*)$/i
33
+
34
+ interface ListCommandOptions {
35
+ readonly json?: boolean
36
+ readonly unread?: boolean
37
+ readonly root?: string
38
+ }
39
+
40
+ interface AnswerCommandOptions {
41
+ readonly cluster?: string
42
+ readonly json?: boolean
43
+ readonly root?: string
44
+ readonly set?: readonly string[]
45
+ }
46
+
47
+ export function register(program: Command): void {
48
+ const intake = program
49
+ .command('intake')
50
+ .description('Read and answer intake folders in .claude/intake/')
51
+ .helpOption('-h, --help', 'Show this help message')
52
+
53
+ intake
54
+ .command('list')
55
+ .description('List intake folders, or the items one folder holds')
56
+ .argument('[slug]', 'Intake folder name, as in toolkit-overview')
57
+ .helpOption('-h, --help', 'Show this help message')
58
+ .option(
59
+ '--unread',
60
+ 'Keep only what is unread, as folders carrying one or as empty slots',
61
+ )
62
+ .option('--json', 'Emit a machine-readable record on stdout')
63
+ .option('--root <path>', 'Intake root, defaulting to the main worktree')
64
+ .addHelpText(
65
+ 'after',
66
+ [
67
+ '',
68
+ 'Exit codes:',
69
+ ' 0 the folders or items were listed',
70
+ ' 1 refused, with the reason on stderr or in the JSON record',
71
+ '',
72
+ 'With no slug it reports per-folder counts. With one it reports every',
73
+ 'item grouped by the cluster file holding it. An empty answer slot',
74
+ 'means unread and never agreement, so a count is the report and no',
75
+ 'verb here decides one.',
76
+ '',
77
+ 'An item carrying no answer slot is counted apart from both, since the',
78
+ 'answer verb cannot reach it and folding it into either count hides a',
79
+ 'file that needs fixing.',
80
+ '',
81
+ 'Examples:',
82
+ ' canon intake list',
83
+ ' canon intake list toolkit-overview --unread --json',
84
+ '',
85
+ ].join('\n'),
86
+ )
87
+ .action(async (slug: string | undefined, opts: ListCommandOptions) => {
88
+ process.exitCode = await runList(slug, opts)
89
+ })
90
+
91
+ intake
92
+ .command('answer')
93
+ .description("Write selections into a cluster's answer slots")
94
+ .argument('<slug>', 'Intake folder name, as in toolkit-overview')
95
+ .helpOption('-h, --help', 'Show this help message')
96
+ .option('--cluster <file>', 'Cluster file the items live in')
97
+ .option(
98
+ '--set <item=answer>',
99
+ 'Answer to land on an item, repeatable',
100
+ collectSelection,
101
+ [] as string[],
102
+ )
103
+ .option('--json', 'Emit a machine-readable record on stdout')
104
+ .option('--root <path>', 'Intake root, defaulting to the main worktree')
105
+ .addHelpText(
106
+ 'after',
107
+ [
108
+ '',
109
+ 'Exit codes:',
110
+ ' 0 every named item now carries its answer',
111
+ ' 1 refused, with the reason on stderr or in the JSON record',
112
+ '',
113
+ 'Items are numbered per cluster file, so a selection names the cluster',
114
+ 'and the number together. One call writes one cluster, which is what',
115
+ 'keeps a batch from racing on the file every selection shares.',
116
+ '',
117
+ 'An item already carrying an answer is refused rather than overwritten.',
118
+ 'A filled slot is a decision already made.',
119
+ '',
120
+ 'Examples:',
121
+ ' canon intake answer toolkit-overview --cluster 05-coverage.md --set 3=ok',
122
+ ' canon intake answer toolkit-overview --cluster 05-coverage.md --set 3=ok --set 4="not worth it" --json',
123
+ '',
124
+ ].join('\n'),
125
+ )
126
+ .action(async (slug: string, opts: AnswerCommandOptions) => {
127
+ process.exitCode = await runAnswer(slug, opts)
128
+ })
129
+ }
130
+
131
+ function collectSelection(value: string, previous: string[]): string[] {
132
+ return [...previous, value]
133
+ }
134
+
135
+ async function runList(
136
+ slug: string | undefined,
137
+ opts: ListCommandOptions,
138
+ ): Promise<number> {
139
+ const emitJson = opts.json ?? false
140
+ const root = opts.root ?? (await mainWorktreeRoot())
141
+
142
+ if (slug === undefined) {
143
+ return reportList(
144
+ await listFolders(root),
145
+ emitJson,
146
+ root,
147
+ opts.unread ?? false,
148
+ )
149
+ }
150
+
151
+ return reportFolder(
152
+ await readFolder(root, slug),
153
+ emitJson,
154
+ root,
155
+ opts.unread ?? false,
156
+ )
157
+ }
158
+
159
+ async function runAnswer(
160
+ slug: string,
161
+ opts: AnswerCommandOptions,
162
+ ): Promise<number> {
163
+ const emitJson = opts.json ?? false
164
+
165
+ if (!opts.cluster) {
166
+ return reportRefusal(
167
+ 'canon intake answer',
168
+ {
169
+ ok: false,
170
+ reason: 'bad-input',
171
+ message: 'No cluster named. Pass --cluster <file>.',
172
+ detail: [],
173
+ },
174
+ emitJson,
175
+ process.cwd(),
176
+ )
177
+ }
178
+
179
+ const raw = opts.set ?? []
180
+
181
+ if (raw.length === 0) {
182
+ return reportRefusal(
183
+ 'canon intake answer',
184
+ {
185
+ ok: false,
186
+ reason: 'bad-input',
187
+ message: 'No selection given. Pass --set <item>=<answer>.',
188
+ detail: [],
189
+ },
190
+ emitJson,
191
+ process.cwd(),
192
+ )
193
+ }
194
+
195
+ const selections: Selection[] = []
196
+ const invalid: string[] = []
197
+
198
+ for (const entry of raw) {
199
+ const match = SELECTION.exec(entry)
200
+ const answer = match?.[2].trim()
201
+
202
+ if (!match || !answer) {
203
+ invalid.push(entry)
204
+ continue
205
+ }
206
+
207
+ selections.push({ label: match[1].toLowerCase(), answer })
208
+ }
209
+
210
+ if (invalid.length > 0) {
211
+ return reportRefusal(
212
+ 'canon intake answer',
213
+ {
214
+ ok: false,
215
+ reason: 'bad-input',
216
+ message: `Not an item and answer: ${invalid.join(', ')}`,
217
+ detail: invalid,
218
+ },
219
+ emitJson,
220
+ process.cwd(),
221
+ )
222
+ }
223
+
224
+ const duplicated = selections
225
+ .map((selection) => selection.label)
226
+ .filter((label, index, all) => all.indexOf(label) !== index)
227
+
228
+ if (duplicated.length > 0) {
229
+ return reportRefusal(
230
+ 'canon intake answer',
231
+ {
232
+ ok: false,
233
+ reason: 'bad-input',
234
+ message: `Two answers for item ${[...new Set(duplicated)].join(', ')}.`,
235
+ detail: [],
236
+ },
237
+ emitJson,
238
+ process.cwd(),
239
+ )
240
+ }
241
+
242
+ const root = opts.root ?? (await mainWorktreeRoot())
243
+ const outcome = await answerItems(root, slug, opts.cluster, selections)
244
+
245
+ return reportAnswer(outcome, emitJson, root)
246
+ }
247
+
248
+ function reportRefusal(
249
+ title: string,
250
+ refused: IntakeRefused,
251
+ emitJson: boolean,
252
+ root: string,
253
+ ): number {
254
+ // The framed branch reaches stderr through logError, so the bare write is
255
+ // what keeps the JSON mode from reporting the reason on stdout alone.
256
+ if (emitJson) {
257
+ process.stderr.write(`${refused.message}\n`)
258
+ process.stdout.write(
259
+ `${JSON.stringify({
260
+ ok: false,
261
+ root,
262
+ reason: refused.reason,
263
+ message: refused.message,
264
+ detail: refused.detail,
265
+ })}\n`,
266
+ )
267
+ return 1
268
+ }
269
+
270
+ intro(title)
271
+ logStep('Refused')
272
+ logError(refused.message)
273
+ if (refused.detail.length > 0) pipeOutput(refused.detail.join('\n'))
274
+ outro()
275
+
276
+ return 1
277
+ }
278
+
279
+ function reportList(
280
+ outcome: ListOutcome,
281
+ emitJson: boolean,
282
+ root: string,
283
+ unreadOnly: boolean,
284
+ ): number {
285
+ if (!outcome.ok) {
286
+ return reportRefusal('canon intake list', outcome, emitJson, root)
287
+ }
288
+
289
+ // Malformed items are counted over every folder rather than the filtered
290
+ // set, since a folder whose only defect is an item nobody can answer carries
291
+ // no unread count to survive the filter and is exactly what the warning is
292
+ // for.
293
+ const listed = unreadOnly
294
+ ? outcome.folders.filter((folder) => folder.unread > 0)
295
+ : outcome.folders
296
+
297
+ if (emitJson) {
298
+ process.stdout.write(
299
+ `${JSON.stringify({ ok: true, root, folders: listed })}\n`,
300
+ )
301
+ return 0
302
+ }
303
+
304
+ intro('canon intake list')
305
+ logStep(listed.length > 0 ? 'Folders' : 'No folders')
306
+
307
+ for (const folder of listed) {
308
+ logInfo(
309
+ `${folder.slug}: ${folder.items} item(s), ${folder.open} open, ${folder.unread} unread`,
310
+ )
311
+ }
312
+
313
+ const malformed = outcome.folders.filter((folder) => folder.malformed > 0)
314
+
315
+ if (malformed.length > 0) {
316
+ logStep('Carrying no answer slot')
317
+ for (const folder of malformed) {
318
+ logWarn(
319
+ `${folder.slug}: ${folder.malformed} item(s), which none of these verbs can answer`,
320
+ )
321
+ }
322
+ }
323
+
324
+ outro()
325
+
326
+ return 0
327
+ }
328
+
329
+ function reportFolder(
330
+ outcome: ReadOutcome,
331
+ emitJson: boolean,
332
+ root: string,
333
+ unreadOnly: boolean,
334
+ ): number {
335
+ if (!outcome.ok) {
336
+ return reportRefusal('canon intake list', outcome, emitJson, root)
337
+ }
338
+
339
+ const clusters = outcome.clusters
340
+ .map((cluster) => ({
341
+ cluster: cluster.cluster,
342
+ items: unreadOnly ? cluster.items.filter(isUnread) : cluster.items,
343
+ }))
344
+ .filter((cluster) => cluster.items.length > 0)
345
+
346
+ if (emitJson) {
347
+ process.stdout.write(
348
+ `${JSON.stringify({ ok: true, root, slug: outcome.slug, clusters })}\n`,
349
+ )
350
+ return 0
351
+ }
352
+
353
+ intro('canon intake list')
354
+
355
+ for (const cluster of clusters) {
356
+ logStep(cluster.cluster)
357
+ for (const item of cluster.items) {
358
+ const state = isUnread(item) ? 'unread' : (item.answer ?? 'no slot')
359
+ logInfo(`${item.label}. ${item.title} (${state})`)
360
+ }
361
+ }
362
+
363
+ if (clusters.length === 0) {
364
+ logStep(unreadOnly ? 'Nothing unread' : 'No items')
365
+ }
366
+
367
+ outro()
368
+
369
+ return 0
370
+ }
371
+
372
+ function reportAnswer(
373
+ outcome: AnswerOutcome,
374
+ emitJson: boolean,
375
+ root: string,
376
+ ): number {
377
+ if (!outcome.ok) {
378
+ return reportRefusal('canon intake answer', outcome, emitJson, root)
379
+ }
380
+
381
+ if (emitJson) {
382
+ process.stdout.write(
383
+ `${JSON.stringify({
384
+ ok: true,
385
+ root,
386
+ slug: outcome.slug,
387
+ cluster: outcome.cluster,
388
+ path: relative(root, outcome.path),
389
+ answered: outcome.answered,
390
+ })}\n`,
391
+ )
392
+ return 0
393
+ }
394
+
395
+ intro('canon intake answer')
396
+ logStep('Answered')
397
+
398
+ for (const entry of outcome.answered) {
399
+ logInfo(`${entry.label}. ${entry.answer}`)
400
+ }
401
+
402
+ logAdd(relative(root, outcome.path))
403
+ outro()
404
+
405
+ return 0
406
+ }