@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,143 @@
1
+ import { $ } from 'bun'
2
+ import { gitEnv } from '@/git-env'
3
+
4
+ /**
5
+ * Resolves the root of the checkout the caller is standing in, which is the
6
+ * linked worktree rather than the main one when a session is inside one.
7
+ *
8
+ * A tracked tree differs per worktree, so a verb reading one answers about the
9
+ * files the session has edited only if it resolves the root this way. The
10
+ * working directory is not a substitute, since a caller invoking from a
11
+ * subdirectory would resolve a root holding none of the trees a verb reads.
12
+ */
13
+ export async function currentWorktreeRoot(): Promise<string> {
14
+ const result = await $`git rev-parse --show-toplevel`
15
+ .env(gitEnv())
16
+ .quiet()
17
+ .nothrow()
18
+ if (result.exitCode !== 0) return process.cwd()
19
+
20
+ return result.stdout.toString().trim() || process.cwd()
21
+ }
22
+
23
+ /**
24
+ * Resolves the root every shared-scratch folder lives under. `git worktree
25
+ * list` puts the main worktree first, and trusting the working directory
26
+ * instead would write a second board nothing else reads, or validate a linked
27
+ * worktree's empty folder and report it clean.
28
+ *
29
+ * A caller reaching this from a linked worktree is the case it exists for: the
30
+ * file-editing tools refuse a main-root path there, so a verb resolving the
31
+ * root in-process is the route a skill body has.
32
+ */
33
+ export async function mainWorktreeRoot(): Promise<string> {
34
+ const result = await $`git worktree list --porcelain`
35
+ .env(gitEnv())
36
+ .quiet()
37
+ .nothrow()
38
+ if (result.exitCode !== 0) return process.cwd()
39
+
40
+ const line = result.stdout
41
+ .toString()
42
+ .split('\n')
43
+ .find((entry) => entry.startsWith('worktree '))
44
+
45
+ return line ? line.slice('worktree '.length).trim() : process.cwd()
46
+ }
47
+
48
+ export interface WorktreeEntry {
49
+ readonly path: string
50
+ readonly branch: string | null
51
+ }
52
+
53
+ export interface RefReport {
54
+ /** False when the ref read itself failed, so an empty `refs` says nothing about whether the branch exists. */
55
+ readonly readable: boolean
56
+ readonly refs: readonly string[]
57
+ }
58
+
59
+ /**
60
+ * Reports which of the local head and the `origin` remote-tracking ref already
61
+ * name a branch, separating an absent branch from a read that failed.
62
+ *
63
+ * `git for-each-ref` is what carries that separation. `git show-ref --verify`
64
+ * handed the same two ref paths exits 128 when one of them is missing, which is
65
+ * the code it also exits when the directory is no repository, so a caller
66
+ * cannot tell a half match from an unreadable tree. `for-each-ref` exits zero
67
+ * with empty output for absent and non-zero only for a failed read.
68
+ *
69
+ * A ref path is a pattern here rather than an exact name, so `refs/heads/x`
70
+ * also matches `refs/heads/x/y`. Git forbids both existing at once, so the
71
+ * over-match names the branch that blocks the candidate rather than a wrong
72
+ * one.
73
+ *
74
+ * The remote-tracking ref is read at whatever the last fetch left, so a branch
75
+ * pushed from another machine since then is invisible here. Closing that needs
76
+ * `git ls-remote`, measured at 0.438s against 0.001s for a local read.
77
+ */
78
+ export async function branchRefs(
79
+ branch: string,
80
+ cwd: string = process.cwd(),
81
+ ): Promise<RefReport> {
82
+ // Every argument is interpolated rather than written inline, since Bun's
83
+ // shell parses the bare parentheses in `%(refname)` as syntax of its own.
84
+ const args = [
85
+ '--format=%(refname)',
86
+ `refs/heads/${branch}`,
87
+ `refs/remotes/origin/${branch}`,
88
+ ]
89
+
90
+ const result = await $`git -C ${cwd} for-each-ref ${args}`
91
+ .env(gitEnv())
92
+ .quiet()
93
+ .nothrow()
94
+ if (result.exitCode !== 0) return { readable: false, refs: [] }
95
+
96
+ return {
97
+ readable: true,
98
+ refs: result.stdout
99
+ .toString()
100
+ .split('\n')
101
+ .map((line) => line.trim())
102
+ .filter((line) => line.length > 0),
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Parses `git worktree list --porcelain`, which emits one block per worktree
108
+ * separated by a blank line. A detached worktree carries no `branch` line,
109
+ * reported here as `null` rather than a guessed name.
110
+ */
111
+ export async function listWorktrees(
112
+ cwd: string = process.cwd(),
113
+ ): Promise<readonly WorktreeEntry[]> {
114
+ const result = await $`git -C ${cwd} worktree list --porcelain`
115
+ .env(gitEnv())
116
+ .quiet()
117
+ .nothrow()
118
+ if (result.exitCode !== 0) return []
119
+
120
+ const entries: WorktreeEntry[] = []
121
+ let path: string | undefined
122
+ let branch: string | null = null
123
+
124
+ for (const line of result.stdout.toString().split('\n')) {
125
+ if (line.startsWith('worktree ')) {
126
+ if (path !== undefined) entries.push({ path, branch })
127
+ path = line.slice('worktree '.length).trim()
128
+ branch = null
129
+ continue
130
+ }
131
+
132
+ if (line.startsWith('branch ')) {
133
+ const ref = line.slice('branch '.length).trim()
134
+ branch = ref.startsWith('refs/heads/')
135
+ ? ref.slice('refs/heads/'.length)
136
+ : ref
137
+ }
138
+ }
139
+
140
+ if (path !== undefined) entries.push({ path, branch })
141
+
142
+ return entries
143
+ }
@@ -0,0 +1,306 @@
1
+ import { $ } from 'bun'
2
+ import { execa } from 'execa'
3
+ import { gitEnv } from '@/git-env'
4
+ import {
5
+ repositoryOf,
6
+ type ResolvedSession,
7
+ resolveSessions,
8
+ type SessionReport,
9
+ } from '@/sessions/resolve'
10
+ import { listWorktrees, type WorktreeEntry } from '@/worktree'
11
+
12
+ const GH_TIMEOUT_MS = 30_000
13
+
14
+ /**
15
+ * How many merged pull requests one read covers. A worktree older than this
16
+ * many merges reads as having none and is refused, which is the safe direction:
17
+ * the failure keeps a directory rather than removing one.
18
+ */
19
+ const MERGED_LIMIT = 200
20
+
21
+ /** Why one worktree cannot be reclaimed, one entry per failing condition. */
22
+ export type Refusal =
23
+ | 'main-worktree'
24
+ | 'detached-head'
25
+ | 'no-merged-pull-request'
26
+ | 'uncommitted-changes'
27
+ | 'unreadable-worktree'
28
+ | 'held-by-session'
29
+
30
+ /** Why the whole reading was refused, so no verdict was produced at all. */
31
+ export type Unreadable = 'gh-missing' | 'gh-failed' | 'sessions-unreadable'
32
+
33
+ /**
34
+ * Which removal shape applies. `session` removes the background session and its
35
+ * worktree together, and `worktree` removes a directory whose session has
36
+ * ended. Picking the wrong one strands state, so this is reported rather than
37
+ * assumed.
38
+ */
39
+ export type Route = 'session' | 'worktree'
40
+
41
+ /** No removal shape reaches the main worktree, which is what `null` says. */
42
+ export type RemovalRoute = Route | null
43
+
44
+ export interface WorktreeVerdict {
45
+ readonly path: string
46
+ readonly branch: string | null
47
+ readonly reclaimable: boolean
48
+ /** Every failing condition, so a reader sees what to fix rather than a bare refusal. */
49
+ readonly refusals: readonly Refusal[]
50
+ /** The pull request that retired the branch, so a report can name what it read. */
51
+ readonly pullRequest: number | null
52
+ /** The names of the live sessions holding this worktree, which is what `claude rm` takes. */
53
+ readonly sessions: readonly string[]
54
+ readonly route: RemovalRoute
55
+ }
56
+
57
+ export interface MergedPullRequest {
58
+ readonly branch: string
59
+ readonly number: number
60
+ }
61
+
62
+ export type MergedReport =
63
+ | { readonly kind: 'read'; readonly merged: readonly MergedPullRequest[] }
64
+ | {
65
+ readonly kind: 'unreadable'
66
+ readonly reason: Extract<Unreadable, 'gh-missing' | 'gh-failed'>
67
+ readonly detail: string
68
+ }
69
+
70
+ export interface StatusReport {
71
+ /** False when the status read itself failed, so a clean `dirty` says nothing. */
72
+ readonly readable: boolean
73
+ readonly dirty: boolean
74
+ }
75
+
76
+ export type ReclaimReport =
77
+ | {
78
+ readonly kind: 'unreadable'
79
+ readonly reason: Unreadable
80
+ readonly detail: string
81
+ }
82
+ | { readonly kind: 'read'; readonly worktrees: readonly WorktreeVerdict[] }
83
+
84
+ export interface ReclaimOptions {
85
+ readonly cwd?: string
86
+ readonly listWorktrees?: (cwd: string) => Promise<readonly WorktreeEntry[]>
87
+ readonly mergedPullRequests?: (cwd: string) => Promise<MergedReport>
88
+ readonly worktreeStatus?: (path: string) => Promise<StatusReport>
89
+ readonly resolve?: () => Promise<SessionReport>
90
+ }
91
+
92
+ /**
93
+ * Reads the pull request state for the whole repository in one call.
94
+ *
95
+ * One call rather than one per worktree, since the per-worktree shape is a
96
+ * network round trip inside a loop and the branches being matched are already
97
+ * known before any of them runs.
98
+ */
99
+ async function mergedPullRequests(cwd: string): Promise<MergedReport> {
100
+ if (Bun.which('gh') === null) {
101
+ return {
102
+ kind: 'unreadable',
103
+ reason: 'gh-missing',
104
+ detail: 'gh is not on the path, so no merge state could be read.',
105
+ }
106
+ }
107
+
108
+ const args = [
109
+ 'pr',
110
+ 'list',
111
+ '--state',
112
+ 'merged',
113
+ '--limit',
114
+ String(MERGED_LIMIT),
115
+ '--json',
116
+ 'headRefName,number',
117
+ ]
118
+
119
+ try {
120
+ // `gh` resolves its repository through git, so it reads the same
121
+ // resolution variables a hook exports and they take precedence over `cwd`.
122
+ // A run from inside one would answer with another repository's merged
123
+ // branches, and a branch name that recurs across repositories would then
124
+ // match a merge that happened somewhere else and read a live worktree as
125
+ // reclaimable, which is the unsafe direction on an unrecoverable removal.
126
+ const result = await execa('gh', args, {
127
+ cwd,
128
+ timeout: GH_TIMEOUT_MS,
129
+ env: gitEnv(),
130
+ extendEnv: false,
131
+ })
132
+ const rows = JSON.parse(result.stdout) as readonly {
133
+ headRefName: string
134
+ number: number
135
+ }[]
136
+
137
+ return {
138
+ kind: 'read',
139
+ merged: rows.map((row) => ({
140
+ branch: row.headRefName,
141
+ number: row.number,
142
+ })),
143
+ }
144
+ } catch (error) {
145
+ return {
146
+ kind: 'unreadable',
147
+ reason: 'gh-failed',
148
+ detail: error instanceof Error ? error.message : String(error),
149
+ }
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Reports whether a worktree holds work no history is behind.
155
+ *
156
+ * Untracked files count, since a worktree is gitignored scratch and a directory
157
+ * removed with them takes them nowhere recoverable. A failed read is separated
158
+ * from a clean tree, because the two produce the same empty output and only one
159
+ * of them is safe to act on.
160
+ */
161
+ async function worktreeStatus(path: string): Promise<StatusReport> {
162
+ const result = await $`git -C ${path} status --porcelain`
163
+ .env(gitEnv())
164
+ .quiet()
165
+ .nothrow()
166
+ if (result.exitCode !== 0) return { readable: false, dirty: false }
167
+
168
+ return { readable: true, dirty: result.stdout.toString().trim().length > 0 }
169
+ }
170
+
171
+ /**
172
+ * Names the live sessions holding one worktree.
173
+ *
174
+ * The path match is the direct reading and the branch match is what survives a
175
+ * path spelled differently on either side, such as a symlinked temporary
176
+ * directory. The branch half is scoped to the repository, since a branch name
177
+ * identifies a branch inside one and nothing across a machine.
178
+ */
179
+ function holders(
180
+ entry: WorktreeEntry,
181
+ sessions: readonly ResolvedSession[],
182
+ repository: string | null,
183
+ ): readonly string[] {
184
+ return sessions
185
+ .filter(
186
+ (candidate) =>
187
+ candidate.worktree === entry.path ||
188
+ (entry.branch !== null &&
189
+ candidate.branch === entry.branch &&
190
+ candidate.repository === repository),
191
+ )
192
+ .map((candidate) => candidate.name)
193
+ }
194
+
195
+ function verdict(
196
+ entry: WorktreeEntry,
197
+ isMain: boolean,
198
+ status: StatusReport,
199
+ merged: ReadonlyMap<string, number>,
200
+ sessions: readonly ResolvedSession[],
201
+ repository: string | null,
202
+ ): WorktreeVerdict {
203
+ const held = holders(entry, sessions, repository)
204
+ const pullRequest =
205
+ entry.branch === null ? null : (merged.get(entry.branch) ?? null)
206
+ const refusals: Refusal[] = []
207
+
208
+ if (isMain) refusals.push('main-worktree')
209
+ if (entry.branch === null) refusals.push('detached-head')
210
+ else if (pullRequest === null) refusals.push('no-merged-pull-request')
211
+
212
+ if (!status.readable) refusals.push('unreadable-worktree')
213
+ else if (status.dirty) refusals.push('uncommitted-changes')
214
+
215
+ if (held.length > 0) refusals.push('held-by-session')
216
+
217
+ return {
218
+ path: entry.path,
219
+ branch: entry.branch,
220
+ reclaimable: refusals.length === 0,
221
+ refusals,
222
+ pullRequest,
223
+ sessions: held,
224
+ // No removal shape reaches the main worktree, and reporting one there
225
+ // offers a command whose only effect is to break the checkout. Deciding it
226
+ // here rather than in the reporter keeps the record and the framed output
227
+ // answering the same way, since the two consumers act on different halves.
228
+ route: isMain ? null : held.length > 0 ? 'session' : 'worktree',
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Reports which worktrees are reclaimable and which are not, with the reason on
234
+ * each.
235
+ *
236
+ * Reclaimable means all three of a merged pull request, a clean working tree,
237
+ * and no live session holding the directory. Each alone has a case where
238
+ * removal loses something, and removal is unrecoverable here since a worktree
239
+ * is gitignored and no history stands behind it.
240
+ *
241
+ * The pull request is what decides the first condition rather than git
242
+ * ancestry. A repository that squash merges never makes a merged branch an
243
+ * ancestor of its trunk, so the ancestry reading calls shipped work unmerged
244
+ * and calls an abandoned branch sitting at a release commit merged, which is
245
+ * wrong in the one direction that removes a directory.
246
+ *
247
+ * An unreadable input refuses the whole reading rather than producing verdicts
248
+ * around it. An absent merge state and a branch with no merged pull request
249
+ * produce the same empty answer, as do an absent session roster and a worktree
250
+ * nobody holds, and reporting the second when it was the first is a false clean
251
+ * that ends in a removal.
252
+ */
253
+ export async function reclaimReport(
254
+ opts: ReclaimOptions = {},
255
+ ): Promise<ReclaimReport> {
256
+ const cwd = opts.cwd ?? process.cwd()
257
+ const listAll = opts.listWorktrees ?? listWorktrees
258
+ const readMerged = opts.mergedPullRequests ?? mergedPullRequests
259
+ const readStatus = opts.worktreeStatus ?? worktreeStatus
260
+ const resolve = opts.resolve ?? resolveSessions
261
+
262
+ const [entries, merged, sessions, repository] = await Promise.all([
263
+ listAll(cwd),
264
+ readMerged(cwd),
265
+ resolve(),
266
+ repositoryOf(cwd),
267
+ ])
268
+
269
+ if (merged.kind === 'unreadable') {
270
+ return {
271
+ kind: 'unreadable',
272
+ reason: merged.reason,
273
+ detail: merged.detail,
274
+ }
275
+ }
276
+
277
+ if (sessions.kind !== 'resolved') {
278
+ return {
279
+ kind: 'unreadable',
280
+ reason: 'sessions-unreadable',
281
+ detail: `No session registry at ${sessions.dir}, so nothing was read about which worktrees are still held.`,
282
+ }
283
+ }
284
+
285
+ const byBranch = new Map(
286
+ merged.merged.map((request) => [request.branch, request.number]),
287
+ )
288
+ const statuses = await Promise.all(
289
+ entries.map((entry) => readStatus(entry.path)),
290
+ )
291
+
292
+ // `git worktree list` puts the main worktree first, which is the only signal
293
+ // separating it from a linked one in the porcelain output.
294
+ const worktrees = entries.map((entry, index) =>
295
+ verdict(
296
+ entry,
297
+ index === 0,
298
+ statuses[index] ?? { readable: false, dirty: false },
299
+ byBranch,
300
+ sessions.sessions,
301
+ repository,
302
+ ),
303
+ )
304
+
305
+ return { kind: 'read', worktrees }
306
+ }
@@ -0,0 +1,72 @@
1
+ ---
2
+ title: Architecture reference
3
+ description: Shape and content rules for .claude/ARCHITECTURE.md
4
+ ---
5
+
6
+ # Architecture reference
7
+
8
+ Applies to `.claude/ARCHITECTURE.md`. Describes the system shape and the decisions behind it, not a tutorial, setup guide, or implementation walkthrough. Pair it with `CLAUDE.md`: principles live there, patterns and decisions live here. Update when a decision is made or a risk is resolved.
9
+
10
+ ## Scope
11
+
12
+ Governs the system-shape document at `.claude/ARCHITECTURE.md`: the overview, the decision entries, and the open risks.
13
+
14
+ Does not govern:
15
+
16
+ - Per-domain structure and narrative: `context.md`
17
+ - Setup commands and install instructions: `readme.md`
18
+ - Product scope, goals, and non-goals: `requirements.md`
19
+
20
+ ## What goes in
21
+
22
+ - A high-level overview of how the system is structured and why
23
+ - Key technical decisions as named H3 entries: what was chosen and why over the alternatives, including stack and library choices
24
+ - Risks and open questions still unresolved
25
+
26
+ ## What does not go in
27
+
28
+ - How individual functions work line by line. The code carries its own behavior.
29
+ - Full type definitions. They live in code. Reference the shape conceptually if needed.
30
+
31
+ ## Sections
32
+
33
+ Use `## Overview`, `## Key technical decisions` with one named H3 per decision, and `## Risks / open questions`. Name each decision and give the reasoning, especially for non-obvious choices. Skip entries where the rationale is self-evident.
34
+
35
+ ## Verification anchors
36
+
37
+ A decision's reasoning stays correct while the numbers it cites move. The anchor records what a measured claim was read against, so a reader can tell a number that was checked and held from one nobody has looked at since.
38
+
39
+ - Close a decision entry whose reasoning cites a measured number with a trailing sentence naming the short commit SHA and the ISO date that number was read: `Measured at <short-sha> on <YYYY-MM-DD>.`
40
+ - Anchor on the number alone. A decision citing none takes no anchor whatever its reasoning rests on, because a marker over a claim nobody can re-measure is one no reader can falsify.
41
+ - Anchor a decision when writing it or when amending its reasoning. Leave an entry written before the rule unanchored rather than dating it by blame, which is archaeology for a marker nothing reads back.
42
+ - Read an absent anchor as unchecked rather than as current. On an entry citing no number there is nothing to check. On one citing a number the number is due a read.
43
+ - Do not edit a claim in the pass that first anchors it. The anchor states what the claim was measured against, so changing both at once leaves nothing to check the anchor against.
44
+ - Refresh the anchor whenever the number is re-read, whether or not it moved. A confirmed number and an unread one are the same text without the date.
45
+
46
+ ## Length
47
+
48
+ Every session pays for this file before any work starts, so it carries a budget. The budget counts decisions rather than lines, because a bare line total is satisfied by merging paragraph pairs and the merged paragraphs then fail the weight checkpoint in `markdown.md`. A file over budget is carrying too many decisions, not decisions written too long.
49
+
50
+ - Budget six lines per decision entry, being the H3, two paragraphs, and the blank lines separating them.
51
+ - Budget the frame outside `## Key technical decisions` separately, covering the H1, the overview, and the risks. State the number the project takes where it records the budget, since a frame carries no fixed structure to derive one from.
52
+ - Read the ceiling as the frame plus six lines against the decision count, rather than as the total the two multiply out to.
53
+ - Bring an over-budget file back by merging two decisions or retiring one, never by compressing a decision's prose.
54
+ - Yield the budget to the paragraph weight checkpoint when the two disagree. A paragraph past the checkpoint is a defect no budget licenses.
55
+
56
+ ## Template
57
+
58
+ The anchor sentence closes a decision whose reasoning cites a measured number and is absent from one that cites none.
59
+
60
+ ```markdown
61
+ # Architecture
62
+
63
+ ## Overview
64
+
65
+ ## Key technical decisions
66
+
67
+ ### Decision name
68
+
69
+ Reasoning and tradeoffs, carrying the measured number the choice rested on. Measured at <short-sha> on <YYYY-MM-DD>.
70
+
71
+ ## Risks / open questions
72
+ ```
@@ -0,0 +1,59 @@
1
+ ---
2
+ title: Branch reference
3
+ description: Branch naming format and type conventions
4
+ ---
5
+
6
+ # Branch reference
7
+
8
+ ## Scope
9
+
10
+ Governs a git branch name: its structure, its length, and the type vocabulary it draws from.
11
+
12
+ Does not govern:
13
+
14
+ - Commit subject format, which shares the type vocabulary: `commit.md`
15
+ - Pull request title and body: `pr.md`
16
+ - Whether a phase label may appear in a branch name: `versioning.md`
17
+ - Deriving a slug from a branch name for use in an output filename: `slug.md`
18
+
19
+ ## Format
20
+
21
+ - Structure: `<type>/<description>` or `<type>/<ticket>-<description>`
22
+ - Length: 50 characters maximum
23
+ - Casing: kebab-case only, no underscores or camelCase
24
+ - Description: 2 words maximum, 3 only when genuinely needed for specificity
25
+ - Capture the core change, not the commit message verbatim
26
+ - For branches with multiple commits, use the unifying concern as the description.
27
+ - Do not duplicate type in description (e.g., `feat/feature-login`)
28
+
29
+ ## Types
30
+
31
+ - `feat`: new feature or capability
32
+ - `fix`: bug fix
33
+ - `refactor`: structural changes (not a fix or feature)
34
+ - `docs`: documentation only (README)
35
+ - `chore`: maintenance tasks (deps, tooling, configs)
36
+ - `perf`: performance improvements
37
+ - `test`: add or modify tests
38
+ - `style`: code formatting (whitespace, semicolons)
39
+ - `build`: build system changes (webpack, npm scripts)
40
+ - `ci`: CI/CD pipeline changes (GitHub Actions)
41
+ - `revert`: revert a previous commit
42
+
43
+ ## Examples
44
+
45
+ ### Correct
46
+
47
+ ```plaintext
48
+ feat/jwt-expiration # clear feature scope
49
+ fix/AUTH-123-connection-pool # includes ticket ID
50
+ refactor/remove-deprecated-endpoints # clear refactor intent
51
+ ```
52
+
53
+ ### Incorrect
54
+
55
+ ```plaintext
56
+ feature/auth_stuff # wrong type + underscore
57
+ feat/feature-add-login # duplicates type in description
58
+ fix/DB-456-fix-the-database-connection-pool-memory-leak # exceeds 50 chars + verbatim message
59
+ ```
@@ -0,0 +1,72 @@
1
+ ---
2
+ title: Commit reference
3
+ description: Commit message format and type conventions
4
+ ---
5
+
6
+ # Commit message reference
7
+
8
+ ## Scope
9
+
10
+ Governs a git commit message: subject structure, the type and scope vocabulary, and the body.
11
+
12
+ Does not govern:
13
+
14
+ - Branch naming, which shares the type vocabulary: `branch.md`
15
+ - Pull request title and body, which share the subject form: `pr.md`
16
+ - Whether a phase label or a semver tag may appear in a subject: `versioning.md`
17
+
18
+ ## Format
19
+
20
+ - Structure: `<type>(<scope>): <subject>`
21
+ - Casing: lowercase for `<type>`, `<scope>`, and first word of `<subject>`
22
+ - Subject: 72 characters maximum, no trailing period
23
+
24
+ ## Types
25
+
26
+ - `feat`: new feature or capability
27
+ - `fix`: bug fix
28
+ - `refactor`: structural changes (not a fix or feature)
29
+ - `docs`: documentation only (README)
30
+ - `chore`: maintenance tasks (deps, tooling, configs)
31
+ - `perf`: performance improvements
32
+ - `test`: add or modify tests
33
+ - `style`: code formatting (whitespace, semicolons)
34
+ - `build`: build system changes (webpack, npm scripts)
35
+ - `ci`: CI/CD pipeline changes (GitHub Actions)
36
+ - `revert`: revert a previous commit
37
+
38
+ ## Scope vocabulary
39
+
40
+ - Single lowercase word representing a system component
41
+ - Prefer single word
42
+ - Use kebab-case only when two words are genuinely needed for specificity
43
+ - Do not use specific filenames as scopes
44
+ - Do not use a scope that duplicates the type
45
+ - Write scopes for release readability. They surface in `changelogithub` release notes.
46
+
47
+ ## Subject
48
+
49
+ - Use imperative mood (`add` not `added`)
50
+ - Describe the actual technical change, not that something changed
51
+ - Do not use vague verbs (`improve`, `refine`, `enhance`)
52
+ - Do not repeat the scope in the subject line
53
+ - Use single quotes if quoting
54
+ - No backslash escaping or internal double quotes
55
+ - No conversational filler or introductory phrases
56
+
57
+ ## Examples
58
+
59
+ ### Correct
60
+
61
+ ```plaintext
62
+ feat(api): add retry logic for failed webhooks # specific verb + clear change
63
+ fix(auth): update 'UserSession' validation logic # scoped + imperative + single quotes
64
+ ```
65
+
66
+ ### Incorrect
67
+
68
+ ```plaintext
69
+ fix(user-auth): Fixed the redirect loop. # wrong casing + period + multi-word scope
70
+ docs(docs): update the readme. # duplicate scope + period
71
+ docs(api): improve documentation # vague verb + lacks specificity
72
+ ```