@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,201 @@
1
+ import { basename, dirname, resolve } from 'node:path'
2
+ import { readField, readFrontmatter } from '@/indexes/frontmatter'
3
+ import { INDEX_FILE, listIndexes } from '@/indexes/walk'
4
+
5
+ export interface IndexEntry {
6
+ readonly name: string
7
+ readonly title: string
8
+ readonly description: string
9
+ readonly category?: string
10
+ }
11
+
12
+ export interface SubCatalog {
13
+ readonly name: string
14
+ readonly title: string
15
+ readonly subtitle: string
16
+ }
17
+
18
+ export type RenderResult =
19
+ | { readonly ok: true; readonly content: string }
20
+ | { readonly ok: false; readonly errors: string[] }
21
+
22
+ interface IndexHead {
23
+ readonly raw: string
24
+ readonly title: string
25
+ readonly subtitle: string
26
+ }
27
+
28
+ /**
29
+ * Builds a folder's `index.md` from its own frontmatter plus every sibling's.
30
+ *
31
+ * Frontmatter is re-emitted verbatim rather than re-serialized, so key order
32
+ * and any `auto: false` marker survive a regeneration untouched.
33
+ */
34
+ export async function computeIndex(dir: string): Promise<RenderResult> {
35
+ const indexPath = `${dir}/${INDEX_FILE}`
36
+ const head = await readIndexHead(indexPath)
37
+ if (!head.ok) return head
38
+
39
+ const entries = await collectEntries(dir)
40
+ if (!entries.ok) return entries
41
+
42
+ const subCatalogs = await collectSubCatalogs(dir)
43
+
44
+ return {
45
+ ok: true,
46
+ content: renderIndex(head.head, entries.entries, subCatalogs),
47
+ }
48
+ }
49
+
50
+ async function readIndexHead(
51
+ indexPath: string,
52
+ ): Promise<{ ok: true; head: IndexHead } | { ok: false; errors: string[] }> {
53
+ const frontmatter = await readFrontmatter(indexPath)
54
+ const title = readField(frontmatter, 'title')
55
+ const subtitle = readField(frontmatter, 'subtitle')
56
+
57
+ const errors: string[] = []
58
+ if (!title) errors.push(`missing frontmatter field "title" in ${indexPath}`)
59
+ if (!subtitle) {
60
+ errors.push(`missing frontmatter field "subtitle" in ${indexPath}`)
61
+ }
62
+ if (!frontmatter || !title || !subtitle) return { ok: false, errors }
63
+
64
+ return { ok: true, head: { raw: frontmatter.raw, title, subtitle } }
65
+ }
66
+
67
+ async function collectEntries(
68
+ dir: string,
69
+ ): Promise<
70
+ { ok: true; entries: IndexEntry[] } | { ok: false; errors: string[] }
71
+ > {
72
+ const glob = new Bun.Glob('*.md')
73
+ const paths: string[] = []
74
+
75
+ for await (const rel of glob.scan({ cwd: dir, onlyFiles: true, dot: true })) {
76
+ if (rel === INDEX_FILE) continue
77
+ paths.push(resolve(dir, rel))
78
+ }
79
+ paths.sort()
80
+
81
+ const entries: IndexEntry[] = []
82
+ const errors: string[] = []
83
+
84
+ for (const path of paths) {
85
+ const frontmatter = await readFrontmatter(path)
86
+ const title = readField(frontmatter, 'title')
87
+ const description = readField(frontmatter, 'description')
88
+
89
+ if (!title) errors.push(`missing frontmatter field "title" in ${path}`)
90
+ if (!description) {
91
+ errors.push(`missing frontmatter field "description" in ${path}`)
92
+ }
93
+ if (!title || !description) continue
94
+
95
+ entries.push({
96
+ name: basename(path),
97
+ title,
98
+ description,
99
+ category: readField(frontmatter, 'category'),
100
+ })
101
+ }
102
+
103
+ if (errors.length > 0) {
104
+ errors.push(`${errors.length} missing frontmatter field(s) in ${dir}`)
105
+ return { ok: false, errors }
106
+ }
107
+
108
+ return { ok: true, entries }
109
+ }
110
+
111
+ /**
112
+ * Reuses the shared walker so nested discovery inherits the same prune and
113
+ * gitignore rules, then keeps only direct children of this folder.
114
+ */
115
+ async function collectSubCatalogs(dir: string): Promise<SubCatalog[]> {
116
+ const nested = await listIndexes(dir)
117
+ const catalogs: SubCatalog[] = []
118
+
119
+ for (const indexPath of nested.sort()) {
120
+ const childDir = dirname(indexPath)
121
+ if (dirname(childDir) !== resolve(dir)) continue
122
+
123
+ const frontmatter = await readFrontmatter(indexPath)
124
+ const title = readField(frontmatter, 'title')
125
+ const subtitle = readField(frontmatter, 'subtitle')
126
+
127
+ if (!title || !subtitle) {
128
+ process.stderr.write(
129
+ `WARNING: skipping nested index ${childDir}/${INDEX_FILE} (missing title or subtitle)\n`,
130
+ )
131
+ continue
132
+ }
133
+
134
+ catalogs.push({ name: basename(childDir), title, subtitle })
135
+ }
136
+
137
+ return catalogs
138
+ }
139
+
140
+ function renderIndex(
141
+ head: IndexHead,
142
+ entries: IndexEntry[],
143
+ subCatalogs: SubCatalog[],
144
+ ): string {
145
+ const hasCategories = entries.some((entry) => Boolean(entry.category))
146
+
147
+ let out = `${head.raw}\n\n# ${head.title}\n\n${head.subtitle}\n`
148
+ if (entries.length > 0 || subCatalogs.length > 0) out += '\n'
149
+
150
+ if (hasCategories) {
151
+ const categories = [
152
+ ...new Set(entries.map((entry) => entry.category).filter(Boolean)),
153
+ ].sort() as string[]
154
+
155
+ categories.forEach((category, position) => {
156
+ if (position > 0) out += '\n'
157
+ out += `## ${category}\n\n`
158
+ for (const entry of entries) {
159
+ if (entry.category !== category) continue
160
+ out += formatEntry(entry)
161
+ }
162
+ })
163
+ } else {
164
+ /**
165
+ * Flat mode sorts sub-catalogs among the files rather than after them. A
166
+ * folder and a file are both one domain to a reader scanning the catalog,
167
+ * so a trailing folder reads as absent from the alphabetical run it belongs
168
+ * in. Grouped mode keeps its own heading below, where a category is the
169
+ * organizing key and alphabetical position carries no meaning.
170
+ */
171
+ const lines = [
172
+ ...entries.map((entry) => ({
173
+ key: entry.name,
174
+ text: formatEntry(entry),
175
+ })),
176
+ ...subCatalogs.map((catalog) => ({
177
+ key: catalog.name,
178
+ text: formatSubCatalog(catalog),
179
+ })),
180
+ ].sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))
181
+
182
+ for (const line of lines) out += line.text
183
+ }
184
+
185
+ if (hasCategories && subCatalogs.length > 0) {
186
+ out += '\n## Sub-catalogs\n\n'
187
+ for (const catalog of subCatalogs) {
188
+ out += formatSubCatalog(catalog)
189
+ }
190
+ }
191
+
192
+ return out
193
+ }
194
+
195
+ function formatSubCatalog(catalog: SubCatalog): string {
196
+ return `- [${catalog.title}](${catalog.name}/${INDEX_FILE}): ${catalog.subtitle}\n`
197
+ }
198
+
199
+ function formatEntry(entry: IndexEntry): string {
200
+ return `- [${entry.title}](${entry.name}): ${entry.description}\n`
201
+ }
@@ -0,0 +1,83 @@
1
+ import { existsSync, statSync } from 'node:fs'
2
+ import { dirname, resolve } from 'node:path'
3
+ import { listIgnored } from '@/git-ignore'
4
+
5
+ const INDEX_FILE = 'index.md'
6
+
7
+ const PRUNED_SEGMENTS = ['node_modules', '.git']
8
+
9
+ function isPruned(relativePath: string): boolean {
10
+ return relativePath
11
+ .split('/')
12
+ .some((segment) => PRUNED_SEGMENTS.includes(segment))
13
+ }
14
+
15
+ /**
16
+ * Lists every folder index under `root`.
17
+ *
18
+ * Vendored and git trees are pruned by path segment, since `Bun.Glob` has no
19
+ * exclude. Everything else is dropped via `git check-ignore`, so a project's
20
+ * own `.gitignore` governs what the walker sees. Outside a git repo the
21
+ * segment prune is the only filter that applies.
22
+ */
23
+ export async function listIndexes(root: string): Promise<string[]> {
24
+ const glob = new Bun.Glob(`**/${INDEX_FILE}`)
25
+ const candidates: string[] = []
26
+
27
+ for await (const rel of glob.scan({
28
+ cwd: root,
29
+ onlyFiles: true,
30
+ dot: true,
31
+ })) {
32
+ if (isPruned(rel)) continue
33
+ candidates.push(resolve(root, rel))
34
+ }
35
+ candidates.sort()
36
+
37
+ if (candidates.length === 0) return []
38
+
39
+ const ignored = await listIgnored(root, candidates)
40
+ if (ignored.size === 0) return candidates
41
+
42
+ return candidates.filter((path) => !ignored.has(path))
43
+ }
44
+
45
+ /**
46
+ * Reports whether git ignores `path`.
47
+ *
48
+ * Positional regen reaches an ignored folder, because `findIndexedAncestor`
49
+ * walks the filesystem and never consults git. Staging what it writes there
50
+ * always fails, so the caller checks this first and skips the attempt rather
51
+ * than warning on a no-op.
52
+ */
53
+ export async function isIgnored(root: string, path: string): Promise<boolean> {
54
+ const ignored = await listIgnored(root, [resolve(path)])
55
+ return ignored.has(resolve(path))
56
+ }
57
+
58
+ /**
59
+ * Walks up from `path` to the nearest folder holding an index, stopping at
60
+ * `root`. Returns undefined when the path escapes the boundary or nothing
61
+ * indexed is found.
62
+ */
63
+ export function findIndexedAncestor(
64
+ path: string,
65
+ root: string,
66
+ ): string | undefined {
67
+ if (!existsSync(path)) return undefined
68
+
69
+ const rootAbs = resolve(root)
70
+ let dir = statSync(path).isDirectory()
71
+ ? resolve(path)
72
+ : dirname(resolve(path))
73
+
74
+ while (dir === rootAbs || dir.startsWith(`${rootAbs}/`)) {
75
+ if (existsSync(`${dir}/${INDEX_FILE}`)) return dir
76
+ if (dir === rootAbs) return undefined
77
+ dir = dirname(dir)
78
+ }
79
+
80
+ return undefined
81
+ }
82
+
83
+ export { INDEX_FILE, PRUNED_SEGMENTS }
@@ -0,0 +1,60 @@
1
+ import type { Command } from 'commander'
2
+ import { DEFAULT_STACK, SKIPPABLE_DOMAINS } from '@/init/plan'
3
+
4
+ interface InitOptionSpec {
5
+ /** The option value key commander stores the parsed value under. */
6
+ readonly key: string
7
+ readonly flags: string
8
+ readonly description: string
9
+ readonly defaultValue?: string
10
+ }
11
+
12
+ /**
13
+ * The option surface of `canon init`, declared once so the flag list and the
14
+ * provenance check cannot drift apart. Reading the key from the spec is what
15
+ * keeps a renamed flag from silently dropping out of `flagsProvided`.
16
+ */
17
+ export const INIT_OPTIONS: readonly InitOptionSpec[] = [
18
+ {
19
+ key: 'stack',
20
+ flags: '--stack <name>',
21
+ description: 'Governance stack (e.g., base, astro, react)',
22
+ defaultValue: DEFAULT_STACK,
23
+ },
24
+ {
25
+ key: 'add',
26
+ flags: '--add <rules>',
27
+ description: 'Comma-separated governance rules to layer on',
28
+ },
29
+ {
30
+ key: 'skip',
31
+ flags: '--skip <list>',
32
+ description: `Skip core domains: ${SKIPPABLE_DOMAINS.join(', ')}`,
33
+ },
34
+ ]
35
+
36
+ /** Declares every init option on the command, defaults included. */
37
+ export function applyInitOptions(command: Command): Command {
38
+ for (const option of INIT_OPTIONS) {
39
+ if (option.defaultValue === undefined) {
40
+ command.option(option.flags, option.description)
41
+ continue
42
+ }
43
+
44
+ command.option(option.flags, option.description, option.defaultValue)
45
+ }
46
+
47
+ return command
48
+ }
49
+
50
+ /**
51
+ * Whether the operator passed any flag, which is what makes the command
52
+ * scriptable by suppressing the confirmation prompt. `--stack` carries a
53
+ * default, so presence has to be read from where the value came from rather
54
+ * than from the value itself.
55
+ */
56
+ export function flagsProvided(cmd: Command): boolean {
57
+ return INIT_OPTIONS.some(
58
+ (option) => cmd.getOptionValueSource(option.key) === 'cli',
59
+ )
60
+ }
@@ -0,0 +1,114 @@
1
+ export const SKIPPABLE_DOMAINS = ['wiki', 'governance'] as const
2
+
3
+ export type SkippableDomain = (typeof SKIPPABLE_DOMAINS)[number]
4
+
5
+ /**
6
+ * The stack a caller gets without asking. Governance installs on every init so
7
+ * a scaffolded project arrives with the rules that route it, and
8
+ * `--skip governance` is the one spelling for declining.
9
+ */
10
+ export const DEFAULT_STACK = 'base'
11
+
12
+ export interface SkipPlan {
13
+ readonly skipped: ReadonlySet<SkippableDomain>
14
+ /** Values that named nothing skippable. Warned about, never fatal. */
15
+ readonly unknown: readonly string[]
16
+ }
17
+
18
+ export type PreviewLevel = 'info' | 'warn'
19
+
20
+ export interface PreviewLine {
21
+ readonly level: PreviewLevel
22
+ readonly text: string
23
+ }
24
+
25
+ export interface InitPlan {
26
+ readonly preview: readonly PreviewLine[]
27
+ readonly total: number
28
+ }
29
+
30
+ export interface InitFlags {
31
+ readonly stack?: string
32
+ readonly add?: string
33
+ readonly skip: SkipPlan
34
+ }
35
+
36
+ /**
37
+ * Resolves the stack the run will install. An empty `--stack` reads as absent
38
+ * rather than as a way to decline, so the flag carries a real name or nothing
39
+ * and `--skip governance` stays the only spelling for opting out.
40
+ */
41
+ export function resolveStack(stack: string | undefined): string {
42
+ return stack === undefined || stack === '' ? DEFAULT_STACK : stack
43
+ }
44
+
45
+ /**
46
+ * Reads the `--skip` list. An unrecognized value is reported and dropped rather
47
+ * than aborting, because the flag names optional domains and a typo should not
48
+ * cost the operator the whole init.
49
+ */
50
+ export function parseSkip(csv: string | undefined): SkipPlan {
51
+ const skipped = new Set<SkippableDomain>()
52
+ const unknown: string[] = []
53
+
54
+ for (const raw of (csv ?? '').split(',')) {
55
+ const item = raw.trim()
56
+ if (item === '') continue
57
+
58
+ if (isSkippable(item)) skipped.add(item)
59
+ else unknown.push(item)
60
+ }
61
+
62
+ return { skipped, unknown }
63
+ }
64
+
65
+ /**
66
+ * Builds the preview and the count from one pass, so the two cannot disagree.
67
+ * Every `info` line is a domain that will run, which is what makes the count a
68
+ * filter rather than a second tally kept in step by hand. A skipped domain
69
+ * prints nothing at all and declined governance prints a warning, so neither
70
+ * reaches the total.
71
+ *
72
+ * The skip drops `--add`, which names rules the caller asked for. Input
73
+ * that goes nowhere is reported for the same reason `parseSkip` reports an
74
+ * unrecognized value, so the warning names the flag rather than dropping it
75
+ * without a word.
76
+ */
77
+ export function planInit(flags: InitFlags): InitPlan {
78
+ const preview: PreviewLine[] = [
79
+ { level: 'info', text: 'base tooling (configs, seeds, deps, scripts)' },
80
+ { level: 'info', text: 'claude (workflow docs, settings)' },
81
+ ]
82
+
83
+ const stack = resolveStack(flags.stack)
84
+
85
+ if (flags.skip.skipped.has('governance')) {
86
+ const detail =
87
+ flags.add === undefined || flags.add === ''
88
+ ? ''
89
+ : `, --add ${flags.add} not installed`
90
+ preview.push({ level: 'warn', text: `governance (skipped${detail})` })
91
+ } else if (flags.add === undefined || flags.add === '') {
92
+ preview.push({ level: 'info', text: `governance (stack: ${stack})` })
93
+ } else {
94
+ preview.push({
95
+ level: 'info',
96
+ text: `governance (stack: ${stack}, extras: ${flags.add})`,
97
+ })
98
+ }
99
+
100
+ if (!flags.skip.skipped.has('wiki')) {
101
+ preview.push({
102
+ level: 'info',
103
+ text: 'wiki (.claude/wiki/ with a stub index)',
104
+ })
105
+ }
106
+
107
+ const total = preview.filter((line) => line.level === 'info').length
108
+
109
+ return { preview, total }
110
+ }
111
+
112
+ function isSkippable(value: string): value is SkippableDomain {
113
+ return (SKIPPABLE_DOMAINS as readonly string[]).includes(value)
114
+ }
@@ -0,0 +1,46 @@
1
+ import { logInfo, logStep, logWarn } from '@/ui'
2
+
3
+ /**
4
+ * A domain either runs or announces why it did not. Governance under
5
+ * `--skip governance` is the second kind: it reports in sequence so the
6
+ * timeline still accounts for every core domain, without counting as a failure.
7
+ */
8
+ export type DomainStep =
9
+ | { readonly kind: 'run'; readonly label: string; run(): Promise<boolean> }
10
+ | { readonly kind: 'skip'; readonly label: string; readonly notice: string }
11
+
12
+ /**
13
+ * Runs each step in order and returns the labels that failed.
14
+ *
15
+ * Partial failure is a first-class outcome rather than an error path. An init
16
+ * that aborts on the first failing domain would look tidier and leave the
17
+ * operator with no idea which of the remaining domains would have worked, so
18
+ * the run continues and the caller reports the failures at the end.
19
+ *
20
+ * The sequence is deliberate. Base tooling seeds the files the later domains
21
+ * install alongside, so these are not independent operations to batch.
22
+ */
23
+ export async function runDomains(
24
+ steps: readonly DomainStep[],
25
+ ): Promise<string[]> {
26
+ const failed: string[] = []
27
+
28
+ for (const step of steps) {
29
+ logStep(step.label)
30
+
31
+ if (step.kind === 'skip') {
32
+ logWarn(step.notice)
33
+ continue
34
+ }
35
+
36
+ if (await step.run()) {
37
+ logInfo('Done')
38
+ continue
39
+ }
40
+
41
+ logWarn('Failed, run manually')
42
+ failed.push(step.label)
43
+ }
44
+
45
+ return failed
46
+ }
@@ -0,0 +1,77 @@
1
+ import { type InitFlags, resolveStack } from '@/init/plan'
2
+ import type { DomainStep } from '@/init/run'
3
+
4
+ /** Builds the child-process invocation for one domain. */
5
+ export type RunFactory = (args: readonly string[]) => () => Promise<boolean>
6
+
7
+ /**
8
+ * Orders the domains an init installs. Base tooling seeds the files the later
9
+ * domains install alongside, so the sequence is part of the contract rather
10
+ * than an arbitrary listing.
11
+ *
12
+ * The caller supplies the run factory so the list can be read for its labels
13
+ * and kinds without spawning anything.
14
+ */
15
+ export function buildSteps(
16
+ target: string,
17
+ resolved: string,
18
+ flags: InitFlags,
19
+ child: RunFactory,
20
+ ): DomainStep[] {
21
+ const steps: DomainStep[] = [
22
+ {
23
+ kind: 'run',
24
+ label: 'Base tooling',
25
+ run: child(['tooling', 'sync', 'base', resolved, '--write']),
26
+ },
27
+ {
28
+ kind: 'run',
29
+ label: 'Claude workflow',
30
+ run: child(['claude', 'init', resolved]),
31
+ },
32
+ ]
33
+
34
+ const stack = resolveStack(flags.stack)
35
+
36
+ if (flags.skip.skipped.has('governance')) {
37
+ const recovery = govArgs(stack, flags.add, target).join(' ')
38
+ steps.push({
39
+ kind: 'skip',
40
+ label: 'Governance',
41
+ notice: `Skipped: --skip governance. Run 'canon ${recovery}' to install rules.`,
42
+ })
43
+ } else {
44
+ steps.push({
45
+ kind: 'run',
46
+ label: 'Governance',
47
+ run: child(govArgs(stack, flags.add, resolved)),
48
+ })
49
+ }
50
+
51
+ if (!flags.skip.skipped.has('wiki')) {
52
+ steps.push({
53
+ kind: 'run',
54
+ label: 'Wiki',
55
+ run: child(['wiki', 'init', resolved]),
56
+ })
57
+ }
58
+
59
+ return steps
60
+ }
61
+
62
+ /**
63
+ * Builds the `gov install` argv. The run and the recovery command a skip prints
64
+ * come from here both, so the command a caller is told to paste installs what
65
+ * the run would have.
66
+ */
67
+ function govArgs(
68
+ stack: string,
69
+ add: string | undefined,
70
+ path: string,
71
+ ): string[] {
72
+ const args = ['gov', 'install', stack]
73
+ if (add !== undefined && add !== '') args.push('--add', add)
74
+ args.push(path)
75
+
76
+ return args
77
+ }