@phuc1403/musketeer 0.8.0 → 0.10.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 (236) hide show
  1. package/INSTALLATION.md +52 -52
  2. package/README.md +49 -49
  3. package/bin/musketeer.js +168 -168
  4. package/manifest.json +333 -301
  5. package/package.json +48 -48
  6. package/src/dotnet-scaffold-copier.js +79 -79
  7. package/src/provisioner/detect.js +93 -93
  8. package/src/self-update.js +77 -77
  9. package/template/.claude/agents/code-reviewer.md +182 -166
  10. package/template/.claude/agents/git-manager.md +18 -18
  11. package/template/.claude/agents/hallmark-auditor.md +78 -78
  12. package/template/.claude/agents/researcher.md +33 -33
  13. package/template/.claude/hooks/block-unsafe-adr-title.cjs +85 -85
  14. package/template/.claude/hooks/git-skill-reminder.cjs +53 -0
  15. package/template/.claude/hooks/init-adr-dir.cjs +173 -173
  16. package/template/.claude/hooks/inject-adr-flags.cjs +94 -94
  17. package/template/.claude/hooks/lib/adr/command-scan.cjs +115 -115
  18. package/template/.claude/hooks/lib/characteristics/checker.cjs +357 -357
  19. package/template/.claude/hooks/lib/colors.cjs +180 -122
  20. package/template/.claude/hooks/lib/git-info-cache.cjs +191 -191
  21. package/template/.claude/hooks/lib/transcript-parser.cjs +300 -277
  22. package/template/.claude/hooks/sync-adr-toc.cjs +146 -146
  23. package/template/.claude/hooks/{usage-context-awareness.cjs → usage-quota-cache-refresh.cjs} +166 -166
  24. package/template/.claude/hooks/validate-characteristics-hook.cjs +66 -66
  25. package/template/.claude/hooks/validate-cml-hook.js +145 -145
  26. package/template/.claude/skills/adr-writer/SKILL.md +48 -48
  27. package/template/.claude/skills/adr-writer/references/adr-example.md +35 -35
  28. package/template/.claude/skills/architecture-characteristic-writer/SKILL.md +215 -215
  29. package/template/.claude/skills/architecture-characteristic-writer/assets/worksheet-template.md +29 -29
  30. package/template/.claude/skills/architecture-characteristic-writer/references/characteristics-catalog.md +40 -40
  31. package/template/.claude/skills/architecture-characteristic-writer/scripts/ranking-table.cjs +171 -171
  32. package/template/.claude/skills/code-review/SKILL.md +201 -54
  33. package/template/.claude/skills/code-review/references/checklist-workflow.md +96 -0
  34. package/template/.claude/skills/code-review/references/checklists/api.md +52 -52
  35. package/template/.claude/skills/code-review/references/checklists/base.md +100 -100
  36. package/template/.claude/skills/code-review/references/checklists/web-app.md +54 -54
  37. package/template/.claude/skills/code-review/references/code-review-reception.md +113 -0
  38. package/template/.claude/skills/code-review/references/codebase-scan-workflow.md +30 -0
  39. package/template/.claude/skills/code-review/references/edge-case-scouting.md +119 -0
  40. package/template/.claude/skills/code-review/references/input-mode-resolution.md +135 -0
  41. package/template/.claude/skills/code-review/references/parallel-review-workflow.md +76 -0
  42. package/template/.claude/skills/code-review/references/requesting-code-review.md +116 -0
  43. package/template/.claude/skills/code-review/references/spec-compliance-review.md +43 -0
  44. package/template/.claude/skills/code-review/references/task-management-reviews.md +140 -0
  45. package/template/.claude/skills/code-review/references/verification-before-completion.md +139 -0
  46. package/template/.claude/skills/context-map/SKILL.md +80 -80
  47. package/template/.claude/skills/context-map/example.cml +106 -106
  48. package/template/.claude/skills/context-map/reference/Bounded Context/Bounded Context.md +40 -40
  49. package/template/.claude/skills/context-map/reference/Bounded Context/businessModel.md +5 -5
  50. package/template/.claude/skills/context-map/reference/Bounded Context/domainVisionStatement.md +2 -2
  51. package/template/.claude/skills/context-map/reference/Bounded Context/evolution.md +5 -5
  52. package/template/.claude/skills/context-map/reference/Bounded Context/implementationTechnology.md +1 -1
  53. package/template/.claude/skills/context-map/reference/Bounded Context/implements.md +1 -1
  54. package/template/.claude/skills/context-map/reference/Bounded Context/knowledgeLevel.md +4 -4
  55. package/template/.claude/skills/context-map/reference/Bounded Context/realizes.md +9 -9
  56. package/template/.claude/skills/context-map/reference/Bounded Context/refines.md +10 -10
  57. package/template/.claude/skills/context-map/reference/Bounded Context/responsibilities.md +26 -26
  58. package/template/.claude/skills/context-map/reference/Bounded Context/type.md +23 -23
  59. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Anticorruption Layer.md +5 -5
  60. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Bounded Context Relationship.md +12 -12
  61. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Conformist.md +5 -5
  62. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Customer-Supplier (C-S).md +22 -22
  63. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Open Host Service.md +4 -4
  64. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Partnership (P).md +13 -13
  65. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Published Language.md +4 -4
  66. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Shared Kernel (SK).md +12 -12
  67. package/template/.claude/skills/context-map/reference/Context Map.md +62 -62
  68. package/template/.claude/skills/context-map/reference/Domain/Domain.md +30 -30
  69. package/template/.claude/skills/context-map/reference/Domain/supports.md +33 -33
  70. package/template/.claude/skills/context-map/reference/Domain/type.md +3 -3
  71. package/template/.claude/skills/context-map/reference/Semantic Rules.md +32 -32
  72. package/template/.claude/skills/git/SKILL.md +131 -115
  73. package/template/.claude/skills/git/references/branch-management.md +88 -88
  74. package/template/.claude/skills/git/references/commit-standards.md +46 -46
  75. package/template/.claude/skills/git/references/context-efficiency.md +54 -0
  76. package/template/.claude/skills/git/references/gh-cli-guide.md +109 -109
  77. package/template/.claude/skills/git/references/safety-protocols.md +69 -69
  78. package/template/.claude/skills/git/references/workflow-commit.md +58 -58
  79. package/template/.claude/skills/git/references/workflow-merge-pr.md +136 -0
  80. package/template/.claude/skills/git/references/workflow-merge.md +48 -48
  81. package/template/.claude/skills/git/references/workflow-pr.md +58 -58
  82. package/template/.claude/skills/git/references/workflow-push.md +52 -52
  83. package/template/.claude/skills/hallmark/SKILL.md +552 -552
  84. package/template/.claude/skills/hallmark/references/anti-patterns.md +412 -412
  85. package/template/.claude/skills/hallmark/references/assets.md +406 -406
  86. package/template/.claude/skills/hallmark/references/color.md +95 -95
  87. package/template/.claude/skills/hallmark/references/component-cookbook.md +256 -256
  88. package/template/.claude/skills/hallmark/references/components/c1-outlined-chip.md +12 -12
  89. package/template/.claude/skills/hallmark/references/components/c2-inline-form-as-cta.md +16 -16
  90. package/template/.claude/skills/hallmark/references/components/c3-typographic-link.md +8 -8
  91. package/template/.claude/skills/hallmark/references/components/c4-sticky-bottom-bar.md +16 -16
  92. package/template/.claude/skills/hallmark/references/components/f1-bento-grid.md +20 -20
  93. package/template/.claude/skills/hallmark/references/components/f2-sticky-scroll-stack.md +20 -20
  94. package/template/.claude/skills/hallmark/references/components/f3-tabular-spec-sheet.md +11 -11
  95. package/template/.claude/skills/hallmark/references/components/f4-step-sequence.md +11 -11
  96. package/template/.claude/skills/hallmark/references/components/f5-annotated-screenshot.md +11 -11
  97. package/template/.claude/skills/hallmark/references/components/f6-product-card-grid.md +41 -41
  98. package/template/.claude/skills/hallmark/references/components/ft1-mast-headed.md +13 -13
  99. package/template/.claude/skills/hallmark/references/components/ft2-inline-rule-single-line.md +10 -10
  100. package/template/.claude/skills/hallmark/references/components/ft3-index-style-category-list.md +12 -12
  101. package/template/.claude/skills/hallmark/references/components/ft4-dense-typographic.md +10 -10
  102. package/template/.claude/skills/hallmark/references/components/ft5-statement.md +21 -21
  103. package/template/.claude/skills/hallmark/references/components/ft6-letter-close.md +19 -19
  104. package/template/.claude/skills/hallmark/references/components/ft7-newsletter-first.md +27 -27
  105. package/template/.claude/skills/hallmark/references/components/ft8-marquee-scroll.md +25 -25
  106. package/template/.claude/skills/hallmark/references/components/h1-marquee.md +15 -15
  107. package/template/.claude/skills/hallmark/references/components/h2-split-diptych.md +15 -15
  108. package/template/.claude/skills/hallmark/references/components/h3-quote-led.md +11 -11
  109. package/template/.claude/skills/hallmark/references/components/h4-stat-led.md +14 -14
  110. package/template/.claude/skills/hallmark/references/components/h5-letter-hero.md +11 -11
  111. package/template/.claude/skills/hallmark/references/components/h6-photographic-fold.md +16 -16
  112. package/template/.claude/skills/hallmark/references/components/h7-demo-video-clipped-by-viewport-edge.md +27 -27
  113. package/template/.claude/skills/hallmark/references/components/h8-mockup-split-browser-framed.md +23 -23
  114. package/template/.claude/skills/hallmark/references/components/h9-custom-illustration-centerpiece.md +27 -27
  115. package/template/.claude/skills/hallmark/references/components/n1-wordmark-2-links.md +12 -12
  116. package/template/.claude/skills/hallmark/references/components/n10-floating-on-scroll-morph.md +19 -19
  117. package/template/.claude/skills/hallmark/references/components/n2-floating-chip.md +14 -14
  118. package/template/.claude/skills/hallmark/references/components/n3-side-rail.md +14 -14
  119. package/template/.claude/skills/hallmark/references/components/n4-hidden-behind-k.md +9 -9
  120. package/template/.claude/skills/hallmark/references/components/n5-floating-pill.md +28 -28
  121. package/template/.claude/skills/hallmark/references/components/n6-newspaper-masthead.md +24 -24
  122. package/template/.claude/skills/hallmark/references/components/n7-brutal-slab.md +22 -22
  123. package/template/.claude/skills/hallmark/references/components/n8-terminal-command.md +21 -21
  124. package/template/.claude/skills/hallmark/references/components/n9-edge-aligned-minimal.md +17 -17
  125. package/template/.claude/skills/hallmark/references/components/s1-left-margin-numbered.md +15 -15
  126. package/template/.claude/skills/hallmark/references/components/s2-hanging.md +13 -13
  127. package/template/.claude/skills/hallmark/references/components/s3-sticky-pinned.md +19 -19
  128. package/template/.claude/skills/hallmark/references/components/s4-inline-no-break.md +11 -11
  129. package/template/.claude/skills/hallmark/references/components/s5-bottom-anchored.md +13 -13
  130. package/template/.claude/skills/hallmark/references/components/t1-pull-quote-with-marginalia.md +12 -12
  131. package/template/.claude/skills/hallmark/references/components/t2-logo-wall-hairline.md +19 -19
  132. package/template/.claude/skills/hallmark/references/components/t3-single-huge-quote.md +11 -11
  133. package/template/.claude/skills/hallmark/references/components/t4-numbered-stat-strip.md +14 -14
  134. package/template/.claude/skills/hallmark/references/contract.md +24 -24
  135. package/template/.claude/skills/hallmark/references/copy.md +182 -182
  136. package/template/.claude/skills/hallmark/references/custom-craft.md +626 -626
  137. package/template/.claude/skills/hallmark/references/custom-theme.md +329 -329
  138. package/template/.claude/skills/hallmark/references/design-md.md +116 -116
  139. package/template/.claude/skills/hallmark/references/export-formats.md +328 -328
  140. package/template/.claude/skills/hallmark/references/floating-nav.md +89 -89
  141. package/template/.claude/skills/hallmark/references/genres/atmospheric.md +65 -65
  142. package/template/.claude/skills/hallmark/references/genres/editorial.md +70 -70
  143. package/template/.claude/skills/hallmark/references/genres/modern-minimal.md +67 -67
  144. package/template/.claude/skills/hallmark/references/genres/playful.md +65 -65
  145. package/template/.claude/skills/hallmark/references/hero-enrichment.md +474 -474
  146. package/template/.claude/skills/hallmark/references/imagery-kit.md +170 -170
  147. package/template/.claude/skills/hallmark/references/interaction-and-states.md +207 -207
  148. package/template/.claude/skills/hallmark/references/layout-and-space.md +111 -111
  149. package/template/.claude/skills/hallmark/references/macrostructures/01-bento-grid.md +35 -35
  150. package/template/.claude/skills/hallmark/references/macrostructures/02-long-document.md +34 -34
  151. package/template/.claude/skills/hallmark/references/macrostructures/03-marquee-hero.md +31 -31
  152. package/template/.claude/skills/hallmark/references/macrostructures/04-stat-led.md +32 -32
  153. package/template/.claude/skills/hallmark/references/macrostructures/05-workbench.md +32 -32
  154. package/template/.claude/skills/hallmark/references/macrostructures/06-conversational-faq.md +33 -33
  155. package/template/.claude/skills/hallmark/references/macrostructures/07-manifesto.md +32 -32
  156. package/template/.claude/skills/hallmark/references/macrostructures/08-photographic.md +34 -34
  157. package/template/.claude/skills/hallmark/references/macrostructures/09-quote-led.md +32 -32
  158. package/template/.claude/skills/hallmark/references/macrostructures/10-specimen.md +32 -32
  159. package/template/.claude/skills/hallmark/references/macrostructures/11-catalogue.md +23 -23
  160. package/template/.claude/skills/hallmark/references/macrostructures/12-letter.md +23 -23
  161. package/template/.claude/skills/hallmark/references/macrostructures/13-index-first.md +23 -23
  162. package/template/.claude/skills/hallmark/references/macrostructures/14-narrative-workflow.md +23 -23
  163. package/template/.claude/skills/hallmark/references/macrostructures/15-split-studio.md +23 -23
  164. package/template/.claude/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -23
  165. package/template/.claude/skills/hallmark/references/macrostructures/17-type-specimen.md +23 -23
  166. package/template/.claude/skills/hallmark/references/macrostructures/18-portfolio-grid.md +23 -23
  167. package/template/.claude/skills/hallmark/references/macrostructures/19-map-diagram.md +23 -23
  168. package/template/.claude/skills/hallmark/references/macrostructures/20-ecosystem-index.md +23 -23
  169. package/template/.claude/skills/hallmark/references/macrostructures/21-component-playground.md +23 -23
  170. package/template/.claude/skills/hallmark/references/macrostructures.md +89 -89
  171. package/template/.claude/skills/hallmark/references/microinteractions.md +260 -260
  172. package/template/.claude/skills/hallmark/references/motion.md +109 -109
  173. package/template/.claude/skills/hallmark/references/preview-examples.md +49 -49
  174. package/template/.claude/skills/hallmark/references/responsive.md +138 -138
  175. package/template/.claude/skills/hallmark/references/slop-test.md +205 -205
  176. package/template/.claude/skills/hallmark/references/structure.md +164 -164
  177. package/template/.claude/skills/hallmark/references/study.md +511 -511
  178. package/template/.claude/skills/hallmark/references/typography.md +243 -243
  179. package/template/.claude/skills/hallmark/references/verbs/audit.md +25 -25
  180. package/template/.claude/skills/hallmark/references/verbs/redesign.md +269 -269
  181. package/template/.claude/skills/hallmark-loop/SKILL.md +105 -105
  182. package/template/.claude/skills/hallmark-loop/references/auditor-call.md +60 -60
  183. package/template/.claude/skills/hallmark-loop/references/capture.md +78 -78
  184. package/template/.claude/skills/hallmark-loop/references/loop-control.md +79 -79
  185. package/template/.claude/skills/handoff/SKILL.md +15 -15
  186. package/template/.claude/skills/knowledge-crunching/SKILL.md +94 -94
  187. package/template/.claude/skills/research/SKILL.md +69 -69
  188. package/template/.claude/skills/skill-creator/LICENSE.txt +201 -201
  189. package/template/.claude/skills/skill-creator/SKILL.md +154 -149
  190. package/template/.claude/skills/skill-creator/agents/analyzer.md +274 -274
  191. package/template/.claude/skills/skill-creator/agents/comparator.md +202 -202
  192. package/template/.claude/skills/skill-creator/agents/grader.md +223 -223
  193. package/template/.claude/skills/skill-creator/assets/eval_review.html +146 -146
  194. package/template/.claude/skills/skill-creator/eval-viewer/generate_review.py +471 -471
  195. package/template/.claude/skills/skill-creator/eval-viewer/viewer.html +1325 -1325
  196. package/template/.claude/skills/skill-creator/references/benchmark-optimization-guide.md +86 -86
  197. package/template/.claude/skills/skill-creator/references/distribution-guide.md +79 -79
  198. package/template/.claude/skills/skill-creator/references/eval-infrastructure-guide.md +129 -129
  199. package/template/.claude/skills/skill-creator/references/eval-schemas.md +121 -121
  200. package/template/.claude/skills/skill-creator/references/mcp-skills-integration.md +71 -71
  201. package/template/.claude/skills/skill-creator/references/metadata-quality-criteria.md +94 -94
  202. package/template/.claude/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -104
  203. package/template/.claude/skills/skill-creator/references/plugin-marketplace-overview.md +89 -89
  204. package/template/.claude/skills/skill-creator/references/plugin-marketplace-schema.md +93 -93
  205. package/template/.claude/skills/skill-creator/references/plugin-marketplace-sources.md +103 -103
  206. package/template/.claude/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -76
  207. package/template/.claude/skills/skill-creator/references/script-quality-criteria.md +106 -106
  208. package/template/.claude/skills/skill-creator/references/skill-anatomy-and-requirements.md +77 -77
  209. package/template/.claude/skills/skill-creator/references/skill-creation-workflow.md +152 -151
  210. package/template/.claude/skills/skill-creator/references/skill-design-patterns.md +75 -75
  211. package/template/.claude/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -102
  212. package/template/.claude/skills/skill-creator/references/structure-organization-criteria.md +114 -114
  213. package/template/.claude/skills/skill-creator/references/testing-and-iteration.md +78 -78
  214. package/template/.claude/skills/skill-creator/references/token-efficiency-criteria.md +74 -74
  215. package/template/.claude/skills/skill-creator/references/troubleshooting-guide.md +81 -81
  216. package/template/.claude/skills/skill-creator/references/validation-checklist.md +83 -83
  217. package/template/.claude/skills/skill-creator/references/writing-effective-instructions.md +88 -88
  218. package/template/.claude/skills/skill-creator/references/yaml-frontmatter-reference.md +92 -92
  219. package/template/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +401 -401
  220. package/template/.claude/skills/skill-creator/scripts/encoding_utils.py +36 -36
  221. package/template/.claude/skills/skill-creator/scripts/generate_report.py +326 -326
  222. package/template/.claude/skills/skill-creator/scripts/improve_description.py +248 -248
  223. package/template/.claude/skills/skill-creator/scripts/init_skill.py +360 -360
  224. package/template/.claude/skills/skill-creator/scripts/package_skill.py +143 -143
  225. package/template/.claude/skills/skill-creator/scripts/quick_validate.py +110 -110
  226. package/template/.claude/skills/skill-creator/scripts/run_eval.py +310 -310
  227. package/template/.claude/skills/skill-creator/scripts/run_loop.py +332 -332
  228. package/template/.claude/skills/skill-creator/scripts/utils.py +47 -47
  229. package/template/.claude/skills/tdd/SKILL.md +142 -142
  230. package/template/.claude/skills/tdd/deep-modules.md +15 -15
  231. package/template/.claude/skills/tdd/interface-design.md +31 -31
  232. package/template/.claude/skills/tdd/mocking.md +59 -59
  233. package/template/.claude/skills/tdd/refactoring.md +10 -10
  234. package/template/.claude/skills/tdd/tests.md +61 -61
  235. package/template/.claude/statusline.cjs +0 -0
  236. package/template/.claude/skills/code-review/references/adversarial-review.md +0 -223
@@ -1,85 +1,85 @@
1
- #!/usr/bin/env node
2
- // PreToolUse guard: block an `adr new` title the tool cannot render safely.
3
- //
4
- // The tool builds the ADR by running plain JS string replacements over the
5
- // template, in a fixed order: DATE, TITLE, NUMBER, STATUS. `String.replace`
6
- // with a string pattern rewrites the FIRST occurrence, and by the time STATUS
7
- // is substituted the title is already sitting in the document — on line 1,
8
- // ahead of the real `STATUS` placeholder in the `## Status` section.
9
- //
10
- // So an uppercase STATUS inside the title captures the substitution meant for
11
- // the status line. Verified against @meza/adr-tools 2.0.4:
12
- // adr new -q -- "Use STATUS codes for errors"
13
- // writes `# 1: Use Accepted codes for errors` and leaves the real status as the
14
- // literal word STATUS — exit 0, no warning, wrong data in the index.
15
- //
16
- // Only STATUS is blocked, and only in uppercase:
17
- // - the replacement is case-sensitive, so "Use status codes" is fine;
18
- // - DATE is substituted before the title is inserted, so it cannot be caught;
19
- // - NUMBER and TITLE are substituted at points that precede the title text in
20
- // the template shipped with this skill, so the real placeholder always wins.
21
- // That last one holds because of where the tokens sit in
22
- // `references/adr-template.md` — revisit this guard if that file is ever
23
- // reordered so `## Status` precedes the heading.
24
- //
25
- // A title starting with `-` is the second case: the tool parses its own flags
26
- // with commander, so without a `--` separator the title is read as an unknown
27
- // option. That one fails cleanly (exit 1, no file created), but it is still
28
- // worth catching early with a clearer reason than "unknown option".
29
- //
30
- // Blocking, not warning: the STATUS case corrupts data with no error at all, so
31
- // there is nothing later in the pipeline that will catch it.
32
- //
33
- // The `|` and `&` characters used to be blocked here too. Those were hazards of
34
- // the old bash implementation, which substituted the title into
35
- // `sed -e "s|TITLE|$title|"`. Substitution is JS now, and both characters were
36
- // re-verified as harmless, so blocking them would only refuse valid titles.
37
-
38
- const { invokesAdr } = require("./lib/adr/command-scan.cjs");
39
-
40
- let raw = "";
41
- process.stdin.on("data", (chunk) => (raw += chunk));
42
- process.stdin.on("end", () => {
43
- let input;
44
- try {
45
- input = JSON.parse(raw || "{}");
46
- } catch {
47
- process.exit(0); // unparseable payload — fail open, don't block legit work
48
- }
49
-
50
- const command = (input && input.tool_input && input.tool_input.command) || "";
51
- if (!invokesAdr(command, "new")) process.exit(0);
52
-
53
- // The skill always places `--` immediately before a quoted title. Extract
54
- // that argument; anything else about the command's shape is not this hook's
55
- // concern.
56
- const afterDashDash = command.match(/--\s+(["'])((?:(?!\1).)*)\1/);
57
- const title = afterDashDash ? afterDashDash[2] : null;
58
-
59
- let reason = null;
60
- if (!afterDashDash) {
61
- reason =
62
- "no `--` before the title (or no quoted title found after it). Without `--`, " +
63
- "a title starting with `-` is parsed as an unknown option and no ADR is " +
64
- 'created. Always: adr new -q [-s STEM]... -- "Title".';
65
- } else if (title.includes("STATUS")) {
66
- reason =
67
- "the title contains `STATUS` in uppercase. The tool substitutes STATUS into the " +
68
- 'template after the title is already in the document, so "Use STATUS codes" ' +
69
- 'becomes "Use Accepted codes" and the real Status section is left as the literal ' +
70
- "word STATUS — it exits 0, so nothing else will catch this. Lowercase `status` is fine.";
71
- }
72
-
73
- if (reason) {
74
- process.stdout.write(
75
- JSON.stringify({
76
- hookSpecificOutput: {
77
- hookEventName: "PreToolUse",
78
- permissionDecision: "deny",
79
- permissionDecisionReason: `Refusing this \`adr new\` call: ${reason} Rename the title and retry.`,
80
- },
81
- })
82
- );
83
- }
84
- process.exit(0);
85
- });
1
+ #!/usr/bin/env node
2
+ // PreToolUse guard: block an `adr new` title the tool cannot render safely.
3
+ //
4
+ // The tool builds the ADR by running plain JS string replacements over the
5
+ // template, in a fixed order: DATE, TITLE, NUMBER, STATUS. `String.replace`
6
+ // with a string pattern rewrites the FIRST occurrence, and by the time STATUS
7
+ // is substituted the title is already sitting in the document — on line 1,
8
+ // ahead of the real `STATUS` placeholder in the `## Status` section.
9
+ //
10
+ // So an uppercase STATUS inside the title captures the substitution meant for
11
+ // the status line. Verified against @meza/adr-tools 2.0.4:
12
+ // adr new -q -- "Use STATUS codes for errors"
13
+ // writes `# 1: Use Accepted codes for errors` and leaves the real status as the
14
+ // literal word STATUS — exit 0, no warning, wrong data in the index.
15
+ //
16
+ // Only STATUS is blocked, and only in uppercase:
17
+ // - the replacement is case-sensitive, so "Use status codes" is fine;
18
+ // - DATE is substituted before the title is inserted, so it cannot be caught;
19
+ // - NUMBER and TITLE are substituted at points that precede the title text in
20
+ // the template shipped with this skill, so the real placeholder always wins.
21
+ // That last one holds because of where the tokens sit in
22
+ // `references/adr-template.md` — revisit this guard if that file is ever
23
+ // reordered so `## Status` precedes the heading.
24
+ //
25
+ // A title starting with `-` is the second case: the tool parses its own flags
26
+ // with commander, so without a `--` separator the title is read as an unknown
27
+ // option. That one fails cleanly (exit 1, no file created), but it is still
28
+ // worth catching early with a clearer reason than "unknown option".
29
+ //
30
+ // Blocking, not warning: the STATUS case corrupts data with no error at all, so
31
+ // there is nothing later in the pipeline that will catch it.
32
+ //
33
+ // The `|` and `&` characters used to be blocked here too. Those were hazards of
34
+ // the old bash implementation, which substituted the title into
35
+ // `sed -e "s|TITLE|$title|"`. Substitution is JS now, and both characters were
36
+ // re-verified as harmless, so blocking them would only refuse valid titles.
37
+
38
+ const { invokesAdr } = require("./lib/adr/command-scan.cjs");
39
+
40
+ let raw = "";
41
+ process.stdin.on("data", (chunk) => (raw += chunk));
42
+ process.stdin.on("end", () => {
43
+ let input;
44
+ try {
45
+ input = JSON.parse(raw || "{}");
46
+ } catch {
47
+ process.exit(0); // unparseable payload — fail open, don't block legit work
48
+ }
49
+
50
+ const command = (input && input.tool_input && input.tool_input.command) || "";
51
+ if (!invokesAdr(command, "new")) process.exit(0);
52
+
53
+ // The skill always places `--` immediately before a quoted title. Extract
54
+ // that argument; anything else about the command's shape is not this hook's
55
+ // concern.
56
+ const afterDashDash = command.match(/--\s+(["'])((?:(?!\1).)*)\1/);
57
+ const title = afterDashDash ? afterDashDash[2] : null;
58
+
59
+ let reason = null;
60
+ if (!afterDashDash) {
61
+ reason =
62
+ "no `--` before the title (or no quoted title found after it). Without `--`, " +
63
+ "a title starting with `-` is parsed as an unknown option and no ADR is " +
64
+ 'created. Always: adr new -q [-s STEM]... -- "Title".';
65
+ } else if (title.includes("STATUS")) {
66
+ reason =
67
+ "the title contains `STATUS` in uppercase. The tool substitutes STATUS into the " +
68
+ 'template after the title is already in the document, so "Use STATUS codes" ' +
69
+ 'becomes "Use Accepted codes" and the real Status section is left as the literal ' +
70
+ "word STATUS — it exits 0, so nothing else will catch this. Lowercase `status` is fine.";
71
+ }
72
+
73
+ if (reason) {
74
+ process.stdout.write(
75
+ JSON.stringify({
76
+ hookSpecificOutput: {
77
+ hookEventName: "PreToolUse",
78
+ permissionDecision: "deny",
79
+ permissionDecisionReason: `Refusing this \`adr new\` call: ${reason} Rename the title and retry.`,
80
+ },
81
+ })
82
+ );
83
+ }
84
+ process.exit(0);
85
+ });
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ // PreToolUse hook (core company): make the ck:git skill load on git work.
3
+ //
4
+ // Skill auto-activation is a model judgement, not enforcement — the agent
5
+ // routinely runs `git commit` / `git push` straight through Bash without ever
6
+ // opening the skill, so its conventional-commit format, split rules and secret
7
+ // scan are silently skipped. A description alone cannot fix that; only a hook
8
+ // runs every time.
9
+ //
10
+ // Fires on state-changing git/gh operations only. Read-only commands (status,
11
+ // log, diff, show) are skipped so the reminder does not burn context on every
12
+ // incidental `git status`.
13
+ //
14
+ // Matches mid-command too (`cd repo && git push`), since the operation is
15
+ // often not the first word.
16
+ //
17
+ // Always exits 0: this advises, it never blocks.
18
+
19
+ const fs = require("fs");
20
+
21
+ const SKILL = ".claude/skills/git/SKILL.md";
22
+
23
+ // Mutating git verbs, plus the gh surfaces the skill covers.
24
+ const GIT_OPS =
25
+ /(^|[\s;&|(])(git\s+(commit|push|merge|rebase|tag|revert|reset|cherry-pick|switch|checkout|branch|remote|stash)|gh\s+(pr|release|repo))\b/;
26
+
27
+ function isGitOperation(command) {
28
+ if (!command || typeof command !== "string") return false;
29
+ return GIT_OPS.test(command);
30
+ }
31
+
32
+ try {
33
+ const payload = JSON.parse(fs.readFileSync(0, "utf-8"));
34
+ const command = payload?.tool_input?.command || "";
35
+
36
+ if (!isGitOperation(command)) process.exit(0);
37
+
38
+ process.stdout.write(
39
+ JSON.stringify({
40
+ hookSpecificOutput: {
41
+ hookEventName: "PreToolUse",
42
+ additionalContext:
43
+ `This is a git operation. Read ${SKILL} (the ck:git skill) and follow it — its ` +
44
+ "conventional-commit format, commit-splitting rules, secret scan and branch " +
45
+ "protections are project policy, not suggestions. Do that before running the " +
46
+ "command; if you have already read it this session, carry on.",
47
+ },
48
+ })
49
+ );
50
+ process.exit(0);
51
+ } catch {
52
+ process.exit(0); // fail open — never block a command over a reminder
53
+ }
@@ -1,173 +1,173 @@
1
- #!/usr/bin/env node
2
- // PreToolUse guard: set up `.adr-dir` before the first `adr new` in a project,
3
- // so the agent never has to pick between `adr init` and a hand-written file.
4
- //
5
- // Two setup paths, and picking the wrong one is destructive:
6
- // - fresh (no `.adr-dir`, no numbered ADRs yet): `adr init docs/adr` is safe —
7
- // it creates docs/adr/, writes `.adr-dir`, and adds a baseline ADR.
8
- // - migration (numbered ADRs already exist, but no `.adr-dir`): `adr init`
9
- // would ALSO add that baseline ADR, burning the next real number. The fix
10
- // is a plain `.adr-dir` file with no tool call.
11
- // Already initialized: nothing to do, both paths are a no-op.
12
- //
13
- // Also makes sure this skill's ADR template is the one `adr new` picks up, by
14
- // placing it at `<adr-dir>/templates/template.md` — the third step of the tool's
15
- // own template resolution, and the reason no env var has to be injected.
16
- //
17
- // Runs the setup itself (as a side effect) before allowing `adr new` through,
18
- // and denies a *direct* `adr init` call whenever running it would be wrong —
19
- // already initialized, or migration state — since either would burn a number.
20
- // Anything it does is echoed to stdout so it stays visible in the transcript.
21
-
22
- const fs = require('fs');
23
- const path = require('path');
24
- const { spawnSync } = require('child_process');
25
- const { invokesAdr } = require('./lib/adr/command-scan.cjs');
26
-
27
- const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
28
- const ADR_DIR = 'docs/adr';
29
- const ADR_DIR_FILE = path.join(root, '.adr-dir');
30
- const ADR_FILE = /^\d+-.*\.md$/;
31
- const SKILL_TEMPLATE = path.join(
32
- root,
33
- '.claude',
34
- 'skills',
35
- 'adr-writer',
36
- 'references',
37
- 'adr-template.md'
38
- );
39
-
40
- function allow(message) {
41
- if (message) process.stdout.write(message + '\n');
42
- process.exit(0);
43
- }
44
-
45
- function deny(reason) {
46
- process.stdout.write(
47
- JSON.stringify({
48
- hookSpecificOutput: {
49
- hookEventName: 'PreToolUse',
50
- permissionDecision: 'deny',
51
- permissionDecisionReason: reason,
52
- },
53
- })
54
- );
55
- process.exit(0);
56
- }
57
-
58
- function readAdrDir() {
59
- try {
60
- return fs.readFileSync(ADR_DIR_FILE, 'utf8').trim() || null;
61
- } catch {
62
- return null;
63
- }
64
- }
65
-
66
- function isInitialized() {
67
- return readAdrDir() !== null;
68
- }
69
-
70
- function hasNumberedAdrs() {
71
- try {
72
- return fs.readdirSync(path.join(root, ADR_DIR)).some((f) => ADR_FILE.test(f));
73
- } catch {
74
- return false; // directory doesn't exist yet -> nothing to migrate
75
- }
76
- }
77
-
78
- function runAdrInit() {
79
- // `adr` is an npm bin — a real executable on every platform, so it is called
80
- // directly rather than through a shell script interpreter. `shell: true` is
81
- // here only because npm installs it as `adr.cmd` on Windows, which
82
- // CreateProcess cannot launch on its own; every argument is a constant, so
83
- // there is nothing for a shell to interpolate.
84
- return spawnSync('adr', ['init', ADR_DIR], { cwd: root, shell: true, encoding: 'utf8' });
85
- }
86
-
87
- // `adr init` writes `.adr-dir` with `path.relative`, so on Windows it lands as
88
- // `docs\adr` with no trailing newline. That file is committed and read on every
89
- // other machine, where a backslash is an ordinary filename character and not a
90
- // separator. Rewrite it in the portable form the rest of this toolchain emits.
91
- function normalizeAdrDirFile() {
92
- const declared = readAdrDir();
93
- if (!declared) return;
94
- fs.writeFileSync(ADR_DIR_FILE, `${declared.split(path.sep).join('/')}\n`);
95
- }
96
-
97
- // The tool resolves its template as: explicit argument, then $ADR_TEMPLATE, then
98
- // `<adr-dir>/templates/template.md`, then its own bundled default. Copying this
99
- // skill's template into the third slot means a bare `adr new` produces a
100
- // musketeer ADR with no environment set up for it.
101
- //
102
- // Only ever writes when the file is absent, so a project that has customised its
103
- // own template keeps it.
104
- function ensureTemplate() {
105
- try {
106
- const dir = readAdrDir() || ADR_DIR;
107
- const target = path.join(root, dir, 'templates', 'template.md');
108
- if (fs.existsSync(target) || !fs.existsSync(SKILL_TEMPLATE)) return null;
109
- fs.mkdirSync(path.dirname(target), { recursive: true });
110
- fs.copyFileSync(SKILL_TEMPLATE, target);
111
- return `Installed the adr-writer template at ${dir}/templates/template.md.`;
112
- } catch {
113
- return null; // never block an ADR over the template copy
114
- }
115
- }
116
-
117
- function main() {
118
- const payload = JSON.parse(fs.readFileSync(0, 'utf8'));
119
- const command = payload?.tool_input?.command || '';
120
- const isInit = invokesAdr(command, 'init');
121
- const isNew = invokesAdr(command, 'new');
122
- if (!isInit && !isNew) return allow();
123
-
124
- if (isInitialized()) {
125
- if (isInit) {
126
- return deny(
127
- '.adr-dir already exists — do not run `adr init` again, it would add a duplicate ' +
128
- 'baseline ADR and burn the next number. Run `adr new` directly.'
129
- );
130
- }
131
- return allow(ensureTemplate()); // adr new, already set up: nothing else to do
132
- }
133
-
134
- if (hasNumberedAdrs()) {
135
- // Migration: numbered ADRs exist but `.adr-dir` does not. `adr init` would
136
- // still add a baseline ADR here, so it is never the right command.
137
- if (isInit) {
138
- return deny(
139
- 'Numbered ADRs already exist without `.adr-dir` — this is a migration, not a fresh ' +
140
- 'project. `adr init` would add a duplicate baseline ADR and burn the next number. ' +
141
- 'Run `adr new` directly; `.adr-dir` is set up automatically.'
142
- );
143
- }
144
- fs.writeFileSync(ADR_DIR_FILE, `${ADR_DIR}\n`);
145
- const note = ensureTemplate();
146
- return allow(
147
- `Migration detected: wrote .adr-dir (${ADR_DIR}) by hand, no baseline ADR added.` +
148
- (note ? `\n${note}` : '')
149
- );
150
- }
151
-
152
- // Fresh project.
153
- if (isInit) return allow(); // the agent's own `adr init` call is correct here — let it run
154
- const res = runAdrInit();
155
- if (res.error || res.status !== 0) {
156
- return allow(
157
- `Could not run \`adr init ${ADR_DIR}\` (${res.error?.message || res.stderr}); ` +
158
- 'letting the original command run and fail with its own error.'
159
- );
160
- }
161
- normalizeAdrDirFile();
162
- const note = ensureTemplate();
163
- return allow(
164
- `Fresh project: ran \`adr init ${ADR_DIR}\` (creates the baseline ADR).` +
165
- (note ? `\n${note}` : '')
166
- );
167
- }
168
-
169
- try {
170
- main();
171
- } catch {
172
- allow(); // fail open
173
- }
1
+ #!/usr/bin/env node
2
+ // PreToolUse guard: set up `.adr-dir` before the first `adr new` in a project,
3
+ // so the agent never has to pick between `adr init` and a hand-written file.
4
+ //
5
+ // Two setup paths, and picking the wrong one is destructive:
6
+ // - fresh (no `.adr-dir`, no numbered ADRs yet): `adr init docs/adr` is safe —
7
+ // it creates docs/adr/, writes `.adr-dir`, and adds a baseline ADR.
8
+ // - migration (numbered ADRs already exist, but no `.adr-dir`): `adr init`
9
+ // would ALSO add that baseline ADR, burning the next real number. The fix
10
+ // is a plain `.adr-dir` file with no tool call.
11
+ // Already initialized: nothing to do, both paths are a no-op.
12
+ //
13
+ // Also makes sure this skill's ADR template is the one `adr new` picks up, by
14
+ // placing it at `<adr-dir>/templates/template.md` — the third step of the tool's
15
+ // own template resolution, and the reason no env var has to be injected.
16
+ //
17
+ // Runs the setup itself (as a side effect) before allowing `adr new` through,
18
+ // and denies a *direct* `adr init` call whenever running it would be wrong —
19
+ // already initialized, or migration state — since either would burn a number.
20
+ // Anything it does is echoed to stdout so it stays visible in the transcript.
21
+
22
+ const fs = require('fs');
23
+ const path = require('path');
24
+ const { spawnSync } = require('child_process');
25
+ const { invokesAdr } = require('./lib/adr/command-scan.cjs');
26
+
27
+ const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
28
+ const ADR_DIR = 'docs/adr';
29
+ const ADR_DIR_FILE = path.join(root, '.adr-dir');
30
+ const ADR_FILE = /^\d+-.*\.md$/;
31
+ const SKILL_TEMPLATE = path.join(
32
+ root,
33
+ '.claude',
34
+ 'skills',
35
+ 'adr-writer',
36
+ 'references',
37
+ 'adr-template.md'
38
+ );
39
+
40
+ function allow(message) {
41
+ if (message) process.stdout.write(message + '\n');
42
+ process.exit(0);
43
+ }
44
+
45
+ function deny(reason) {
46
+ process.stdout.write(
47
+ JSON.stringify({
48
+ hookSpecificOutput: {
49
+ hookEventName: 'PreToolUse',
50
+ permissionDecision: 'deny',
51
+ permissionDecisionReason: reason,
52
+ },
53
+ })
54
+ );
55
+ process.exit(0);
56
+ }
57
+
58
+ function readAdrDir() {
59
+ try {
60
+ return fs.readFileSync(ADR_DIR_FILE, 'utf8').trim() || null;
61
+ } catch {
62
+ return null;
63
+ }
64
+ }
65
+
66
+ function isInitialized() {
67
+ return readAdrDir() !== null;
68
+ }
69
+
70
+ function hasNumberedAdrs() {
71
+ try {
72
+ return fs.readdirSync(path.join(root, ADR_DIR)).some((f) => ADR_FILE.test(f));
73
+ } catch {
74
+ return false; // directory doesn't exist yet -> nothing to migrate
75
+ }
76
+ }
77
+
78
+ function runAdrInit() {
79
+ // `adr` is an npm bin — a real executable on every platform, so it is called
80
+ // directly rather than through a shell script interpreter. `shell: true` is
81
+ // here only because npm installs it as `adr.cmd` on Windows, which
82
+ // CreateProcess cannot launch on its own; every argument is a constant, so
83
+ // there is nothing for a shell to interpolate.
84
+ return spawnSync('adr', ['init', ADR_DIR], { cwd: root, shell: true, encoding: 'utf8' });
85
+ }
86
+
87
+ // `adr init` writes `.adr-dir` with `path.relative`, so on Windows it lands as
88
+ // `docs\adr` with no trailing newline. That file is committed and read on every
89
+ // other machine, where a backslash is an ordinary filename character and not a
90
+ // separator. Rewrite it in the portable form the rest of this toolchain emits.
91
+ function normalizeAdrDirFile() {
92
+ const declared = readAdrDir();
93
+ if (!declared) return;
94
+ fs.writeFileSync(ADR_DIR_FILE, `${declared.split(path.sep).join('/')}\n`);
95
+ }
96
+
97
+ // The tool resolves its template as: explicit argument, then $ADR_TEMPLATE, then
98
+ // `<adr-dir>/templates/template.md`, then its own bundled default. Copying this
99
+ // skill's template into the third slot means a bare `adr new` produces a
100
+ // musketeer ADR with no environment set up for it.
101
+ //
102
+ // Only ever writes when the file is absent, so a project that has customised its
103
+ // own template keeps it.
104
+ function ensureTemplate() {
105
+ try {
106
+ const dir = readAdrDir() || ADR_DIR;
107
+ const target = path.join(root, dir, 'templates', 'template.md');
108
+ if (fs.existsSync(target) || !fs.existsSync(SKILL_TEMPLATE)) return null;
109
+ fs.mkdirSync(path.dirname(target), { recursive: true });
110
+ fs.copyFileSync(SKILL_TEMPLATE, target);
111
+ return `Installed the adr-writer template at ${dir}/templates/template.md.`;
112
+ } catch {
113
+ return null; // never block an ADR over the template copy
114
+ }
115
+ }
116
+
117
+ function main() {
118
+ const payload = JSON.parse(fs.readFileSync(0, 'utf8'));
119
+ const command = payload?.tool_input?.command || '';
120
+ const isInit = invokesAdr(command, 'init');
121
+ const isNew = invokesAdr(command, 'new');
122
+ if (!isInit && !isNew) return allow();
123
+
124
+ if (isInitialized()) {
125
+ if (isInit) {
126
+ return deny(
127
+ '.adr-dir already exists — do not run `adr init` again, it would add a duplicate ' +
128
+ 'baseline ADR and burn the next number. Run `adr new` directly.'
129
+ );
130
+ }
131
+ return allow(ensureTemplate()); // adr new, already set up: nothing else to do
132
+ }
133
+
134
+ if (hasNumberedAdrs()) {
135
+ // Migration: numbered ADRs exist but `.adr-dir` does not. `adr init` would
136
+ // still add a baseline ADR here, so it is never the right command.
137
+ if (isInit) {
138
+ return deny(
139
+ 'Numbered ADRs already exist without `.adr-dir` — this is a migration, not a fresh ' +
140
+ 'project. `adr init` would add a duplicate baseline ADR and burn the next number. ' +
141
+ 'Run `adr new` directly; `.adr-dir` is set up automatically.'
142
+ );
143
+ }
144
+ fs.writeFileSync(ADR_DIR_FILE, `${ADR_DIR}\n`);
145
+ const note = ensureTemplate();
146
+ return allow(
147
+ `Migration detected: wrote .adr-dir (${ADR_DIR}) by hand, no baseline ADR added.` +
148
+ (note ? `\n${note}` : '')
149
+ );
150
+ }
151
+
152
+ // Fresh project.
153
+ if (isInit) return allow(); // the agent's own `adr init` call is correct here — let it run
154
+ const res = runAdrInit();
155
+ if (res.error || res.status !== 0) {
156
+ return allow(
157
+ `Could not run \`adr init ${ADR_DIR}\` (${res.error?.message || res.stderr}); ` +
158
+ 'letting the original command run and fail with its own error.'
159
+ );
160
+ }
161
+ normalizeAdrDirFile();
162
+ const note = ensureTemplate();
163
+ return allow(
164
+ `Fresh project: ran \`adr init ${ADR_DIR}\` (creates the baseline ADR).` +
165
+ (note ? `\n${note}` : '')
166
+ );
167
+ }
168
+
169
+ try {
170
+ main();
171
+ } catch {
172
+ allow(); // fail open
173
+ }