@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,125 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # The sandbox reaches GitHub over HTTPS with the gh token so a headless run needs
4
+ # no SSH key and no agent. `gh auth login` authenticates the CLI but leaves git
5
+ # itself without a credential, so the harness supplies the helper rather than
6
+ # assuming the machine carries one.
7
+ SANDBOX_GIT_CREDENTIAL_HELPER='!gh auth git-credential'
8
+
9
+ # Call from the main shell before any scenario runs. sandbox_anchor_url is used
10
+ # inside command substitutions, where log_error would exit only the subshell and
11
+ # leave the caller building an empty remote, so the run has to stop here instead.
12
+ require_sandbox_anchor_config() {
13
+ if [ -z "${GITHUB_ORG:-}" ]; then
14
+ log_error "GITHUB_ORG is empty. Export GITHUB_ORG=<org>, or run from a clone whose remote.origin.url points at GitHub."
15
+ fi
16
+ }
17
+
18
+ resolve_sandbox_anchor_repo() {
19
+ printf '%s\n' "${1:-${ANCHOR_REPO:-}}"
20
+ }
21
+
22
+ sandbox_anchor_url() {
23
+ local repo_name
24
+ repo_name="$(resolve_sandbox_anchor_repo "$@")"
25
+
26
+ if [ -z "$repo_name" ] || [ -z "${GITHUB_ORG:-}" ]; then
27
+ log_error "sandbox_anchor_url needs GITHUB_ORG and a repository name. Call require_sandbox_anchor_config first."
28
+ fi
29
+
30
+ printf 'https://github.com/%s/%s.git\n' "$GITHUB_ORG" "$repo_name"
31
+ }
32
+
33
+ # credential.helper is multi-valued and git concatenates it across system, global,
34
+ # and local, trying each in order until one returns a credential. A plain set
35
+ # leaves an operator's existing helper ahead of this one, so a stale token wins
36
+ # and gh never runs. The empty value resets the inherited list first.
37
+ configure_sandbox_git_credentials() {
38
+ git config credential.helper ""
39
+ git config --add credential.helper "$SANDBOX_GIT_CREDENTIAL_HELPER"
40
+ }
41
+
42
+ resolve_sandbox_git_identity() {
43
+ SANDBOX_GIT_NAME="${SANDBOX_GIT_NAME:-$(git config --global user.name 2>/dev/null || true)}"
44
+ SANDBOX_GIT_EMAIL="${SANDBOX_GIT_EMAIL:-$(git config --global user.email 2>/dev/null || true)}"
45
+
46
+ : "${SANDBOX_GIT_NAME:=aitk-sandbox}"
47
+ : "${SANDBOX_GIT_EMAIL:=sandbox@example.com}"
48
+
49
+ export SANDBOX_GIT_NAME SANDBOX_GIT_EMAIL
50
+ }
51
+
52
+ configure_sandbox_git_identity() {
53
+ resolve_sandbox_git_identity
54
+ git config user.name "$SANDBOX_GIT_NAME"
55
+ git config user.email "$SANDBOX_GIT_EMAIL"
56
+ }
57
+
58
+ # Every scenario that needs a remote points at the same throwaway repository, so
59
+ # the name lives here rather than in each one.
60
+ SANDBOX_ANCHOR_REPO="aitk-sandbox"
61
+
62
+ # A scenario calls this from its own use_anchor hook rather than this file
63
+ # defining the hook. manage-sandbox.sh keys off `type -t use_anchor`, so
64
+ # declaring it here would hand an anchor to the scenarios that source this file
65
+ # for the identity helpers alone.
66
+ use_sandbox_anchor() {
67
+ export ANCHOR_REPO="${1:-$SANDBOX_ANCHOR_REPO}"
68
+ }
69
+
70
+ # gh answers an absent repository and an unreachable host with the same exit
71
+ # status, so the 404 is the only thing separating them. Anything else is a
72
+ # network or credential fault, where creating a repository would be the wrong
73
+ # answer and would fail for the same reason the read did.
74
+ ensure_sandbox_anchor_repo() {
75
+ local repo_name gh_error
76
+
77
+ repo_name="$(resolve_sandbox_anchor_repo "$@")"
78
+
79
+ if [ -z "$repo_name" ] || [ -z "${GITHUB_ORG:-}" ]; then
80
+ log_error "ensure_sandbox_anchor_repo needs GITHUB_ORG and a repository name. Call require_sandbox_anchor_config first."
81
+ fi
82
+
83
+ if gh_error="$(gh api "repos/${GITHUB_ORG}/${repo_name}" --silent 2>&1)"; then
84
+ return 0
85
+ fi
86
+
87
+ case "$gh_error" in
88
+ *"HTTP 404"*) ;;
89
+ *) log_error "Cannot reach ${GITHUB_ORG}/${repo_name}: ${gh_error}" ;;
90
+ esac
91
+
92
+ # An absent anchor is nearly always a wrong GITHUB_ORG or a rename nobody
93
+ # performed, and provisioning stages a fixture rather than cloning while every
94
+ # scenario force-pushes to main, so a repository created here would carry all
95
+ # nine to a pass against something that is not the anchor. Refusing is the safe
96
+ # default and creating is the opt-in, the shape `canon tooling sync --write`
97
+ # already sets. `canon records push` refuses outright for the reason
98
+ # `.claude/context/development/scratch.md` records, so the two still differ.
99
+ # The sibling SANDBOX_ flags are presence tests, so any non-empty value turns
100
+ # them on. This one allowlists instead, because a presence test would have
101
+ # SANDBOX_ANCHOR_CREATE=false provisioning a repository. Both spellings are
102
+ # accepted so the `true` those siblings are set to does not land on a refusal.
103
+ case "${SANDBOX_ANCHOR_CREATE:-}" in
104
+ 1 | true) ;;
105
+ *) log_error "${GITHUB_ORG}/${repo_name} does not exist. Check GITHUB_ORG and whether a rename is pending, then create it with 'gh repo create ${GITHUB_ORG}/${repo_name} --private' or re-run with SANDBOX_ANCHOR_CREATE=true." ;;
106
+ esac
107
+
108
+ log_warn "${GITHUB_ORG}/${repo_name} does not exist and SANDBOX_ANCHOR_CREATE is set. Creating it as private."
109
+ if ! gh_error="$(gh repo create "${GITHUB_ORG}/${repo_name}" --private 2>&1)"; then
110
+ log_error "Could not create ${GITHUB_ORG}/${repo_name}: ${gh_error}"
111
+ fi
112
+ log_info "Created ${GITHUB_ORG}/${repo_name} as a private repository."
113
+ }
114
+
115
+ # A remote is useless without an author, so the scenarios that reach one always
116
+ # configure both. configure_sandbox_git_identity stays callable on its own for
117
+ # the scenarios that never push. The probe runs first so an absent remote is
118
+ # reported before the scenario stages anything. The remove keeps this idempotent
119
+ # against a sandbox tree that already carries an origin.
120
+ configure_sandbox_anchor_remote() {
121
+ ensure_sandbox_anchor_repo "$@"
122
+ configure_sandbox_git_identity
123
+ git remote remove origin 2>/dev/null || true
124
+ git remote add origin "$(sandbox_anchor_url "$@")"
125
+ }
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # The sandbox tree lives outside the toolkit worktree. `scripts/sandbox/run.sh`
4
+ # sets cwd to it for `claude -p`, and every `CLAUDE.md` between that cwd and the
5
+ # filesystem root loads into the session. Under the repository the toolkit's own
6
+ # instructions join that chain beside the seeded copy the scenario installed,
7
+ # both carry the rule sending shared session scratch to the main worktree root,
8
+ # and nothing decides which root wins. A session picking the toolkit writes its
9
+ # output where no manifest reads it, so the run reports success while the verdict
10
+ # reports no writes at all. `scripts/eval/run.sh` keeps its fixture outside the
11
+ # repository for the same reason.
12
+ #
13
+ # Mints a short random per-run identifier the first time it is asked for, then
14
+ # holds it in CANON_SANDBOX_RUN_ID for the rest of this process. A direct call
15
+ # (not `$(...)`) exports it into the caller's own shell, which is what lets
16
+ # `run.sh` mint once and have manage-sandbox.sh and the check it shells out to
17
+ # both inherit the same id as ordinary children. A call already carrying the
18
+ # variable, inherited from such a parent, reuses it rather than minting a new one.
19
+ #
20
+ # Twin of `mintSandboxRunId` in `src/commands/sandbox.ts`.
21
+ mint_sandbox_run_id() {
22
+ if [ -z "${CANON_SANDBOX_RUN_ID:-}" ]; then
23
+ CANON_SANDBOX_RUN_ID="$(date +%s)-$$-$RANDOM"
24
+ fi
25
+ export CANON_SANDBOX_RUN_ID
26
+ }
27
+
28
+ # The base every per-run tree nests under, with no run id appended. Split out
29
+ # of `resolve_sandbox_dir` so a caller that needs to recognize any run's tree,
30
+ # such as `require_project_root` in `scripts/lib/ui.sh`, tests against this
31
+ # prefix instead of a single resolved path that changes on every call.
32
+ sandbox_dir_prefix() {
33
+ printf '%s/canon/sandbox\n' "${XDG_STATE_HOME:-$HOME/.local/state}"
34
+ }
35
+
36
+ # Twin of `sandboxTree` in `src/commands/sandbox.ts`. The exec boundary rules out
37
+ # a shared constant, so a change to the default lands on both sides.
38
+ #
39
+ # A bare fall-through with no per-run component is one path per machine, so
40
+ # two sessions resolving the default at once would provision over each other
41
+ # with neither told. `mint_sandbox_run_id` is what makes two such sessions
42
+ # land on two different trees rather than one.
43
+ resolve_sandbox_dir() {
44
+ if [ -n "${CANON_SANDBOX_DIR:-}" ]; then
45
+ printf '%s\n' "$CANON_SANDBOX_DIR"
46
+ return 0
47
+ fi
48
+
49
+ mint_sandbox_run_id
50
+ printf '%s-%s\n' "$(sandbox_dir_prefix)" "$CANON_SANDBOX_RUN_ID"
51
+ }
52
+
53
+ # Collapses repeated separators, folds `.` and `..` segments, and strips every
54
+ # trailing separator, leaving a bare root as `/`. Every comparison below is a
55
+ # string test, so `//`, `$HOME//`, and `$HOME/../../usr` each read as a path no
56
+ # rule names until this runs, and an unresolved `..` defeats the allowlist and
57
+ # both directions of the repository test at once.
58
+ #
59
+ # The fold is lexical because the guard runs before provisioning creates the
60
+ # tree, which rules out `cd` with `pwd -P` and any resolution needing the path
61
+ # to exist. Nothing here follows a symlink, so a `..` below one resolves against
62
+ # the link's own path rather than its target. A `..` climbing past the root
63
+ # clamps to `/`, matching the kernel, which leaves the allowlist to refuse it
64
+ # under the rule that already covers every root path.
65
+ normalize_sandbox_path() {
66
+ local path="$1"
67
+
68
+ [ -n "$path" ] || return 0
69
+
70
+ while [ "$path" != "${path//\/\//\/}" ]; do
71
+ path="${path//\/\//\/}"
72
+ done
73
+
74
+ local root=""
75
+ if [ "${path#/}" != "$path" ]; then
76
+ root="/"
77
+ path="${path#/}"
78
+ fi
79
+
80
+ # `resolved` carries each kept segment behind its own separator, so a pop is
81
+ # one suffix removal and popping an empty stack is the no-op that clamps at
82
+ # the root. `climbed` holds the leading `..` a relative path has no segment to
83
+ # pop against, which dropping would change the directory it names.
84
+ local resolved="" climbed="" segment
85
+ local remaining=4096
86
+
87
+ while [ -n "$path" ] && [ "$remaining" -gt 0 ]; do
88
+ remaining=$((remaining - 1))
89
+
90
+ segment="${path%%/*}"
91
+ if [ "$segment" = "$path" ]; then
92
+ path=""
93
+ else
94
+ path="${path#*/}"
95
+ fi
96
+
97
+ case "$segment" in
98
+ "" | .) ;;
99
+ ..)
100
+ if [ -n "$resolved" ]; then
101
+ resolved="${resolved%/*}"
102
+ elif [ -z "$root" ]; then
103
+ climbed="$climbed../"
104
+ fi
105
+ ;;
106
+ *) resolved="$resolved/$segment" ;;
107
+ esac
108
+ done
109
+
110
+ if [ -n "$root" ]; then
111
+ path="${resolved:-/}"
112
+ else
113
+ path="${climbed}${resolved#/}"
114
+ path="${path:-.}"
115
+ fi
116
+
117
+ while [ "${#path}" -gt 1 ] && [ "${path%/}" != "$path" ]; do
118
+ path="${path%/}"
119
+ done
120
+
121
+ printf '%s' "$path"
122
+ }
123
+
124
+ # Whether `candidate` is `target` or a directory containing it. Removing the
125
+ # former removes the latter, which is what makes an ancestor as dangerous as an
126
+ # exact match.
127
+ is_at_or_above() {
128
+ local candidate="$1"
129
+ local target="$2"
130
+
131
+ [ "$candidate" = "$target" ] || [ "${target#"$candidate"/}" != "$target" ]
132
+ }
133
+
134
+ # Prints the reason a location is unusable and returns non-zero, so the caller
135
+ # reports one message naming the path rather than a bare refusal.
136
+ #
137
+ # Provisioning runs `rm -rf` on this path at three sites before staging, so the
138
+ # test is an allowlist rather than a list of paths to refuse. A blocklist has to
139
+ # name every system directory to be right once and stays wrong as soon as one is
140
+ # missed, while requiring a strict descendant of the home directory or of the
141
+ # temp root admits the default and every reasonable override and refuses `/`,
142
+ # `/usr`, `/etc`, and `$HOME` itself without naming any of them.
143
+ #
144
+ # The repository test is separate and runs both ways. A path under the worktree
145
+ # restores the ancestor chain the relocation removed, and a path above it is one
146
+ # `rm -rf` away from deleting the repository. It resolves the main worktree root
147
+ # rather than trusting `$PROJECT_ROOT`, since a linked worktree is itself inside
148
+ # that root.
149
+ assert_sandbox_dir_safe() {
150
+ local raw="$1"
151
+ local root="${2:-${PROJECT_ROOT:-$PWD}}"
152
+
153
+ if [ -z "$raw" ] || [ "${raw#/}" = "$raw" ]; then
154
+ printf 'CANON_SANDBOX_DIR must be an absolute path, got: %s\n' "${raw:-<empty>}"
155
+ return 1
156
+ fi
157
+
158
+ # `normalize_sandbox_path` stops at 4096 segments and drops the remainder,
159
+ # which would hand the tests below an ancestor of the path provisioning
160
+ # removes. Refusing past `PATH_MAX` keeps that bound out of reach, since a
161
+ # segment costs at least two bytes and no syscall accepts the string anyway.
162
+ if [ "${#raw}" -gt 4096 ]; then
163
+ printf 'Refusing the sandbox path. It is %s characters, past the longest path any filesystem here accepts.\n' "${#raw}"
164
+ return 1
165
+ fi
166
+
167
+ local dir home temp
168
+ dir="$(normalize_sandbox_path "$raw")"
169
+ home="$(normalize_sandbox_path "${HOME:-/root}")"
170
+ temp="$(normalize_sandbox_path "${TMPDIR:-/tmp}")"
171
+
172
+ # Every message below names `$raw`, which is what the operator set. The tests
173
+ # compare `$dir`, so a path carrying `..` is refused for a location its own
174
+ # spelling does not show.
175
+ local resolution=""
176
+ [ "$dir" = "$raw" ] || resolution=" It resolves to $dir."
177
+
178
+ if ! is_at_or_above "$home" "$dir" && ! is_at_or_above "$temp" "$dir"; then
179
+ printf 'Refusing %s as the sandbox. Provisioning removes the tree first, so the path has to sit under %s or %s.%s\n' "$raw" "$home" "$temp" "$resolution"
180
+ return 1
181
+ fi
182
+
183
+ if [ "$dir" = "$home" ] || [ "$dir" = "$temp" ]; then
184
+ printf 'Refusing %s as the sandbox. Provisioning removes the tree first, so the path has to sit under %s rather than be it.\n' "$raw" "$dir"
185
+ return 1
186
+ fi
187
+
188
+ local main_root
189
+ main_root="$(git -C "$root" worktree list --porcelain 2>/dev/null |
190
+ grep -m 1 '^worktree ' | cut -d' ' -f2-)"
191
+ main_root="$(normalize_sandbox_path "${main_root:-$root}")"
192
+
193
+ if is_at_or_above "$dir" "$main_root"; then
194
+ printf 'Refusing %s as the sandbox. Provisioning removes the tree first, and that path contains %s.%s\n' "$raw" "$main_root" "$resolution"
195
+ return 1
196
+ fi
197
+
198
+ case "$dir" in
199
+ "$main_root"/*)
200
+ printf 'Sandbox at %s sits inside %s, which puts the toolkit CLAUDE.md back on the session ancestor chain.%s Point CANON_SANDBOX_DIR outside the repository.\n' "$raw" "$main_root" "$resolution"
201
+ return 1
202
+ ;;
203
+ esac
204
+
205
+ return 0
206
+ }
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+
3
+ TOOLING_STACK_EXCLUDE=("claude")
4
+
5
+ is_tooling_stack_excluded() {
6
+ local name="$1"
7
+ local excluded
8
+ for excluded in "${TOOLING_STACK_EXCLUDE[@]}"; do
9
+ if [ "$name" = "$excluded" ]; then
10
+ return 0
11
+ fi
12
+ done
13
+ return 1
14
+ }
15
+
16
+ list_tooling_stacks() {
17
+ local tooling_dir="${1:-$PROJECT_ROOT/tooling}"
18
+ local name
19
+ while IFS= read -r entry; do
20
+ name=$(basename "$entry")
21
+ is_tooling_stack_excluded "$name" && continue
22
+ echo "$name"
23
+ done < <(find "$tooling_dir" -mindepth 1 -maxdepth 1 -type d | sort)
24
+ }
25
+
26
+ # Seed roots that carry a `.claude/`, emitted relative to `PROJECT_ROOT`. Every
27
+ # stage measuring seed content discovers through this rather than naming a stack,
28
+ # so a stack seeding `.claude/` later arrives covered with no edit to any caller.
29
+ collect_seed_roots() {
30
+ local dir
31
+ for dir in "$PROJECT_ROOT"/tooling/*/seeds; do
32
+ [ -d "$dir/.claude" ] || continue
33
+ printf '%s\n' "${dir#"$PROJECT_ROOT"/}"
34
+ done
35
+ }
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/env bash
2
+
3
+ if [ "${BASH_VERSINFO[0]:-0}" -lt 4 ]; then
4
+ echo "canon requires bash 4 or newer. Current: ${BASH_VERSION:-unknown}." >&2
5
+ echo "Install via Homebrew: brew install bash" >&2
6
+ exit 1
7
+ fi
8
+
9
+ # Resolved from this file's own location rather than `$PROJECT_ROOT`, because
10
+ # `require_project_root` is what several scripts call before anything has
11
+ # established a root.
12
+ # shellcheck source=/dev/null
13
+ source "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/sandbox-path.sh"
14
+
15
+ # `NO_COLOR` follows the published convention, where any non-empty value turns
16
+ # color off whatever the value says.
17
+ supports_color() {
18
+ [ -z "${NO_COLOR:-}" ] && [ -t "$1" ]
19
+ }
20
+
21
+ # Assigns the six palette names for one file descriptor. The blank palette keeps
22
+ # every frame character and drops only the escapes, so a captured run still
23
+ # reads as one block.
24
+ #
25
+ # Bash returns a string and nothing richer, so the palette arrives through the
26
+ # caller's own scope. A writer declaring all six `local` before calling this
27
+ # keeps the assignment to itself, which is what leaves the source-time answer
28
+ # below standing for anything that sources this file.
29
+ set_palette() {
30
+ if supports_color "$1"; then
31
+ GREEN='\033[0;32m'
32
+ RED='\033[0;31m'
33
+ YELLOW='\033[0;33m'
34
+ WHITE='\033[1;37m'
35
+ GREY='\033[0;90m'
36
+ NC='\033[0m'
37
+ else
38
+ GREEN=''
39
+ RED=''
40
+ YELLOW=''
41
+ WHITE=''
42
+ GREY=''
43
+ NC=''
44
+ fi
45
+ }
46
+
47
+ # Every writer below frames to stderr and asks about that stream at write time,
48
+ # so no answer is frozen before a caller's redirect is in place. This one answers
49
+ # for stdout instead, because it is read by a sourcing script writing its own
50
+ # frame with a bare `echo`, and that is the stream a bare `echo` reaches.
51
+ set_palette 1
52
+
53
+ log_info() {
54
+ local GREEN RED YELLOW WHITE GREY NC
55
+ set_palette 2
56
+ echo -e "${GREY}│${NC} ${GREEN}✓${NC} $1" >&2
57
+ }
58
+ log_warn() {
59
+ local GREEN RED YELLOW WHITE GREY NC
60
+ set_palette 2
61
+ echo -e "${GREY}│${NC} ${YELLOW}!${NC} $1" >&2
62
+ }
63
+ log_error() {
64
+ local GREEN RED YELLOW WHITE GREY NC
65
+ set_palette 2
66
+ echo -e "${GREY}│${NC} ${RED}✗${NC} $1" >&2
67
+ exit 1
68
+ }
69
+ log_step() {
70
+ local GREEN RED YELLOW WHITE GREY NC
71
+ set_palette 2
72
+ echo -e "${GREY}│${NC}\n${GREY}├${NC} ${WHITE}$1${NC}" >&2
73
+ }
74
+ log_add() {
75
+ local GREEN RED YELLOW WHITE GREY NC
76
+ set_palette 2
77
+ echo -e "${GREY}│${NC} ${GREEN}+${NC} $1" >&2
78
+ }
79
+ log_rem() {
80
+ local GREEN RED YELLOW WHITE GREY NC
81
+ set_palette 2
82
+ echo -e "${GREY}│${NC} ${RED}-${NC} $1" >&2
83
+ }
84
+
85
+ pipe_output() {
86
+ local GREEN RED YELLOW WHITE GREY NC
87
+ set_palette 2
88
+ while IFS= read -r line; do echo -e "${GREY}│${NC} $line" >&2; done
89
+ }
90
+
91
+ open_timeline() {
92
+ local GREEN RED YELLOW WHITE GREY NC
93
+ set_palette 2
94
+ echo -e "${GREY}┌${NC}" >&2
95
+ if [ -n "${1:-}" ]; then
96
+ echo -e "${GREY}│${NC} ${WHITE}$1${NC}" >&2
97
+ fi
98
+ }
99
+
100
+ close_timeline() {
101
+ local GREEN RED YELLOW WHITE GREY NC
102
+ set_palette 2
103
+ echo -e "${GREY}└${NC}" >&2
104
+ }
105
+
106
+ guard_root() {
107
+ local target="$1"
108
+ local target_abs
109
+ target_abs=$(cd "$target" && pwd)
110
+ if [ "$target_abs" = "$PROJECT_ROOT" ]; then
111
+ log_error "Cannot run against toolkit root. Files here are the source of truth."
112
+ fi
113
+ }
114
+
115
+ require_project_root() {
116
+ local GREEN RED YELLOW WHITE GREY NC
117
+ set_palette 2
118
+ local sandbox in_sandbox=0
119
+ if [ -n "${CANON_SANDBOX_DIR:-}" ]; then
120
+ sandbox="$CANON_SANDBOX_DIR"
121
+ [[ "$PWD" == "$sandbox" || "$PWD" == "$sandbox"/* ]] && in_sandbox=1
122
+ else
123
+ sandbox="$(sandbox_dir_prefix)"
124
+ [[ "$PWD" == "$sandbox" || "$PWD" == "$sandbox"/* || "$PWD" == "$sandbox"-* ]] && in_sandbox=1
125
+ fi
126
+ if [ "$in_sandbox" -eq 1 ]; then
127
+ echo -e "${GREY}┌${NC}" >&2
128
+ log_error "Execution restricted: Command cannot be run from inside the sandbox environment."
129
+ fi
130
+ if [[ "$PWD" != "$PROJECT_ROOT"* ]]; then
131
+ echo -e "${GREY}┌${NC}" >&2
132
+ log_error "Context Error: You must run this command from inside the repository."
133
+ fi
134
+ }
135
+
136
+ # The retired spelling stays honored, and permanently. This variable is the
137
+ # documented way to drive any command headlessly, so every skill body, CI job,
138
+ # and operator script already written sets the old name, and those callers live
139
+ # in repositories and plugin caches this release cannot reach. Dropping it
140
+ # leaves them waiting on a TTY nobody is watching.
141
+ is_non_interactive() {
142
+ # canon-keep-retired
143
+ [[ "${CANON_NON_INTERACTIVE:-}" == "1" || "${AITK_NON_INTERACTIVE:-}" == "1" ]]
144
+ }
145
+
146
+ ask() {
147
+ local GREEN RED YELLOW WHITE GREY NC
148
+ set_palette 2
149
+ local prompt_text=$1
150
+ local var_name=$2
151
+ local default_val=$3
152
+ local input=""
153
+ local char
154
+ local display_default=""
155
+ if [ -n "$default_val" ]; then
156
+ display_default=" (${default_val})"
157
+ fi
158
+ if is_non_interactive; then
159
+ echo -e "${GREY}│${NC}" >&2
160
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${default_val}${NC}" >&2
161
+ export "$var_name"="$default_val"
162
+ return
163
+ fi
164
+ echo -e "${GREY}│${NC}" >&2
165
+ echo -ne "${GREEN}◆${NC} ${prompt_text}${display_default} " >&2
166
+ while IFS= read -r -s -n1 char; do
167
+ if [[ $char == $'\x1b' ]]; then
168
+ read -rsn2 -t 0.001 _ || true
169
+ echo -ne "\r\033[K" >&2
170
+ echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
171
+ exit 1
172
+ elif [[ $char == $'\x7f' || $char == $'\x08' ]]; then
173
+ if [ -n "$input" ]; then
174
+ input="${input%?}"
175
+ echo -ne "\b \b" >&2
176
+ fi
177
+ elif [[ -z "$char" ]]; then
178
+ break
179
+ else
180
+ input+="$char"
181
+ echo -n "$char" >&2
182
+ fi
183
+ done
184
+ [ -z "$input" ] && input="$default_val"
185
+ echo -ne "\r\033[K" >&2
186
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${input}${NC}" >&2
187
+ export "$var_name"="$input"
188
+ }
189
+
190
+ select_or_route_scenario() {
191
+ local GREEN RED YELLOW WHITE GREY NC
192
+ set_palette 2
193
+ local prompt_text=$1
194
+ shift
195
+ local options=("$@")
196
+
197
+ if [ -n "${SANDBOX_SCENARIO:-}" ]; then
198
+ echo -e "${GREY}│${NC}" >&2
199
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${SANDBOX_SCENARIO}${NC}" >&2
200
+ export SELECTED_OPTION="$SANDBOX_SCENARIO"
201
+ return
202
+ fi
203
+
204
+ select_option "$prompt_text" "${options[@]}"
205
+ }
206
+
207
+ select_option() {
208
+ local GREEN RED YELLOW WHITE GREY NC
209
+ set_palette 2
210
+ local prompt_text=$1
211
+ shift
212
+ local options=("$@")
213
+ local cur=0
214
+ local count=${#options[@]}
215
+
216
+ if is_non_interactive; then
217
+ echo -e "${GREY}│${NC}" >&2
218
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${options[0]}${NC}" >&2
219
+ export SELECTED_OPTION="${options[0]}"
220
+ return
221
+ fi
222
+
223
+ if [ ! -t 0 ]; then
224
+ log_error "${prompt_text} requires a TTY. Pass an argument or set CANON_NON_INTERACTIVE=1."
225
+ fi
226
+
227
+ echo -e "${GREY}│${NC}" >&2
228
+ echo -ne "${GREEN}◆${NC} ${prompt_text}\n" >&2
229
+
230
+ while true; do
231
+ for i in "${!options[@]}"; do
232
+ if [ "$i" -eq "$cur" ]; then
233
+ echo -e "${GREY}│${NC} ${GREEN}❯ ${options[$i]}${NC}" >&2
234
+ else
235
+ echo -e "${GREY}│${NC} ${GREY}${options[$i]}${NC}" >&2
236
+ fi
237
+ done
238
+
239
+ read -rsn1 key
240
+ case "$key" in
241
+ $'\x1b')
242
+ if read -rsn2 -t 0.001 key_seq; then
243
+ if [[ "$key_seq" == "[A" ]]; then cur=$(((cur - 1 + count) % count)); fi
244
+ if [[ "$key_seq" == "[B" ]]; then cur=$(((cur + 1) % count)); fi
245
+ else
246
+ echo -ne "\033[$((count + 1))A\033[J" >&2
247
+ echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
248
+ exit 1
249
+ fi
250
+ ;;
251
+ "k") cur=$(((cur - 1 + count) % count)) ;;
252
+ "j") cur=$(((cur + 1) % count)) ;;
253
+ "q")
254
+ echo -ne "\033[$((count + 1))A\033[J" >&2
255
+ echo -e "${GREY}◇${NC} ${prompt_text} ${RED}Cancelled${NC}" >&2
256
+ exit 1
257
+ ;;
258
+ "") break ;;
259
+ esac
260
+ echo -ne "\033[${count}A" >&2
261
+ done
262
+
263
+ echo -ne "\033[$((count + 1))A\033[J" >&2
264
+ echo -e "${GREY}◇${NC} ${prompt_text} ${WHITE}${options[$cur]}${NC}" >&2
265
+ export SELECTED_OPTION="${options[$cur]}"
266
+ }
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Claude Code's worktree entry writes core.bare into the parent repository's
4
+ # shared config and its exit never restores it, stranding every later command in
5
+ # the main worktree. Sourced by verify.sh, which runs the repair before any stage
6
+ # because the flag breaks the git reads that scope the run.
7
+
8
+ repair_bare_flag() {
9
+ local root="${1:-$PROJECT_ROOT}"
10
+ local common_dir
11
+ [ "$(git -C "$root" config --get core.bare 2>/dev/null || echo false)" = true ] || return 0
12
+
13
+ common_dir=$(git -C "$root" rev-parse --path-format=absolute --git-common-dir 2>/dev/null) || return 0
14
+ # A genuinely bare repository keeps its objects at the root and has no .git
15
+ # directory, so it fails this test and keeps its flag.
16
+ [ "$(basename "$common_dir")" = ".git" ] || return 0
17
+
18
+ git -C "$root" config core.bare false
19
+ log_warn "Repaired core.bare, which worktree entry left set. Recovery is 'git config core.bare false'."
20
+ }