@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
package/package.json CHANGED
@@ -1,48 +1,48 @@
1
- {
2
- "name": "@phuc1403/musketeer",
3
- "version": "0.8.0",
4
- "description": "Distributable custom Claude Code harness — one declarative command scaffolds a curated company of musketeers (skills/agents/hooks) into any project's .claude/.",
5
- "type": "commonjs",
6
- "bin": {
7
- "musketeer": "bin/musketeer.js"
8
- },
9
- "engines": {
10
- "node": ">=18"
11
- },
12
- "scripts": {
13
- "test": "node --test"
14
- },
15
- "files": [
16
- "bin",
17
- "src",
18
- "manifest.json",
19
- "template",
20
- "README.md",
21
- "INSTALLATION.md",
22
- "LICENSE",
23
- "!template/**/bin",
24
- "!template/**/obj"
25
- ],
26
- "keywords": [
27
- "claude",
28
- "claude-code",
29
- "harness",
30
- "scaffolder",
31
- "cli",
32
- "skills",
33
- "agents",
34
- "hooks"
35
- ],
36
- "license": "MIT",
37
- "repository": {
38
- "type": "git",
39
- "url": "git+https://github.com/phamhongphuc1403/musketeer.git"
40
- },
41
- "bugs": {
42
- "url": "https://github.com/phamhongphuc1403/musketeer/issues"
43
- },
44
- "homepage": "https://github.com/phamhongphuc1403/musketeer#readme",
45
- "dependencies": {
46
- "@clack/prompts": "^0.7.0"
47
- }
48
- }
1
+ {
2
+ "name": "@phuc1403/musketeer",
3
+ "version": "0.10.0",
4
+ "description": "Distributable custom Claude Code harness — one declarative command scaffolds a curated company of musketeers (skills/agents/hooks) into any project's .claude/.",
5
+ "type": "commonjs",
6
+ "bin": {
7
+ "musketeer": "bin/musketeer.js"
8
+ },
9
+ "engines": {
10
+ "node": ">=18"
11
+ },
12
+ "scripts": {
13
+ "test": "node --test"
14
+ },
15
+ "files": [
16
+ "bin",
17
+ "src",
18
+ "manifest.json",
19
+ "template",
20
+ "README.md",
21
+ "INSTALLATION.md",
22
+ "LICENSE",
23
+ "!template/**/bin",
24
+ "!template/**/obj"
25
+ ],
26
+ "keywords": [
27
+ "claude",
28
+ "claude-code",
29
+ "harness",
30
+ "scaffolder",
31
+ "cli",
32
+ "skills",
33
+ "agents",
34
+ "hooks"
35
+ ],
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/phamhongphuc1403/musketeer.git"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/phamhongphuc1403/musketeer/issues"
43
+ },
44
+ "homepage": "https://github.com/phamhongphuc1403/musketeer#readme",
45
+ "dependencies": {
46
+ "@clack/prompts": "^0.7.0"
47
+ }
48
+ }
@@ -1,79 +1,79 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
-
6
- function containedPath(root, candidate) {
7
- const resolvedRoot = path.resolve(root);
8
- const resolved = path.resolve(candidate);
9
- if (resolved !== resolvedRoot && !resolved.startsWith(resolvedRoot + path.sep)) return null;
10
- return resolved;
11
- }
12
-
13
- // Build output directories. These are regenerated by `dotnet build` and must
14
- // never reach a generated project: they embed absolute paths from whichever
15
- // machine built the template, and their binaries would be mangled by the
16
- // UTF-8 read + token substitution below.
17
- const EXCLUDED_DIRS = new Set(["bin", "obj"]);
18
-
19
- function substitute(text, token, replacement) {
20
- return text.split(token).join(replacement);
21
- }
22
-
23
- /**
24
- * Recursively copy every file under srcDir into stagingDir, substituting
25
- * `token` with `replacement` in both path segments and file contents. Every
26
- * computed destination path is validated to stay under `stagingDir` — rejects
27
- * (throws) rather than writing outside it.
28
- * @param {string} srcDir
29
- * @param {string} stagingDir
30
- * @param {string} token
31
- * @param {string} replacement
32
- */
33
- function copyTemplateWithTokenSubstitution(srcDir, stagingDir, token, replacement) {
34
- walk(srcDir, stagingDir, stagingDir, token, replacement);
35
- }
36
-
37
- function walk(currentSrc, currentDest, stagingRoot, token, replacement) {
38
- const entries = fs.readdirSync(currentSrc, { withFileTypes: true });
39
- for (const entry of entries) {
40
- if (entry.isDirectory() && EXCLUDED_DIRS.has(entry.name)) continue;
41
- const substitutedName = substitute(entry.name, token, replacement);
42
- const srcPath = path.join(currentSrc, entry.name);
43
- const destPath = containedPath(stagingRoot, path.join(currentDest, substitutedName));
44
- if (!destPath) {
45
- throw new Error(`copyTemplateWithTokenSubstitution: computed path escapes staging dir: "${substitutedName}"`);
46
- }
47
-
48
- if (entry.isDirectory()) {
49
- fs.mkdirSync(destPath, { recursive: true });
50
- walk(srcPath, destPath, stagingRoot, token, replacement);
51
- } else if (entry.isFile()) {
52
- fs.mkdirSync(path.dirname(destPath), { recursive: true });
53
- const content = fs.readFileSync(srcPath, 'utf8');
54
- fs.writeFileSync(destPath, substitute(content, token, replacement), 'utf8');
55
- }
56
- }
57
- }
58
-
59
- /**
60
- * Move every top-level entry from stagingDir into projectDir. Pre-checks all
61
- * names for collisions before moving any of them, then moves each via
62
- * fs.renameSync (atomic per entry on the same filesystem). Throws instead of
63
- * silently overwriting if a destination name already exists.
64
- * @param {string} stagingDir
65
- * @param {string} projectDir
66
- */
67
- function promoteStagedScaffold(stagingDir, projectDir) {
68
- const entries = fs.readdirSync(stagingDir, { withFileTypes: true });
69
- for (const entry of entries) {
70
- if (fs.existsSync(path.join(projectDir, entry.name))) {
71
- throw new Error(`promoteStagedScaffold: "${entry.name}" already exists at destination`);
72
- }
73
- }
74
- for (const entry of entries) {
75
- fs.renameSync(path.join(stagingDir, entry.name), path.join(projectDir, entry.name));
76
- }
77
- }
78
-
79
- module.exports = { copyTemplateWithTokenSubstitution, promoteStagedScaffold };
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ function containedPath(root, candidate) {
7
+ const resolvedRoot = path.resolve(root);
8
+ const resolved = path.resolve(candidate);
9
+ if (resolved !== resolvedRoot && !resolved.startsWith(resolvedRoot + path.sep)) return null;
10
+ return resolved;
11
+ }
12
+
13
+ // Build output directories. These are regenerated by `dotnet build` and must
14
+ // never reach a generated project: they embed absolute paths from whichever
15
+ // machine built the template, and their binaries would be mangled by the
16
+ // UTF-8 read + token substitution below.
17
+ const EXCLUDED_DIRS = new Set(["bin", "obj"]);
18
+
19
+ function substitute(text, token, replacement) {
20
+ return text.split(token).join(replacement);
21
+ }
22
+
23
+ /**
24
+ * Recursively copy every file under srcDir into stagingDir, substituting
25
+ * `token` with `replacement` in both path segments and file contents. Every
26
+ * computed destination path is validated to stay under `stagingDir` — rejects
27
+ * (throws) rather than writing outside it.
28
+ * @param {string} srcDir
29
+ * @param {string} stagingDir
30
+ * @param {string} token
31
+ * @param {string} replacement
32
+ */
33
+ function copyTemplateWithTokenSubstitution(srcDir, stagingDir, token, replacement) {
34
+ walk(srcDir, stagingDir, stagingDir, token, replacement);
35
+ }
36
+
37
+ function walk(currentSrc, currentDest, stagingRoot, token, replacement) {
38
+ const entries = fs.readdirSync(currentSrc, { withFileTypes: true });
39
+ for (const entry of entries) {
40
+ if (entry.isDirectory() && EXCLUDED_DIRS.has(entry.name)) continue;
41
+ const substitutedName = substitute(entry.name, token, replacement);
42
+ const srcPath = path.join(currentSrc, entry.name);
43
+ const destPath = containedPath(stagingRoot, path.join(currentDest, substitutedName));
44
+ if (!destPath) {
45
+ throw new Error(`copyTemplateWithTokenSubstitution: computed path escapes staging dir: "${substitutedName}"`);
46
+ }
47
+
48
+ if (entry.isDirectory()) {
49
+ fs.mkdirSync(destPath, { recursive: true });
50
+ walk(srcPath, destPath, stagingRoot, token, replacement);
51
+ } else if (entry.isFile()) {
52
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
53
+ const content = fs.readFileSync(srcPath, 'utf8');
54
+ fs.writeFileSync(destPath, substitute(content, token, replacement), 'utf8');
55
+ }
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Move every top-level entry from stagingDir into projectDir. Pre-checks all
61
+ * names for collisions before moving any of them, then moves each via
62
+ * fs.renameSync (atomic per entry on the same filesystem). Throws instead of
63
+ * silently overwriting if a destination name already exists.
64
+ * @param {string} stagingDir
65
+ * @param {string} projectDir
66
+ */
67
+ function promoteStagedScaffold(stagingDir, projectDir) {
68
+ const entries = fs.readdirSync(stagingDir, { withFileTypes: true });
69
+ for (const entry of entries) {
70
+ if (fs.existsSync(path.join(projectDir, entry.name))) {
71
+ throw new Error(`promoteStagedScaffold: "${entry.name}" already exists at destination`);
72
+ }
73
+ }
74
+ for (const entry of entries) {
75
+ fs.renameSync(path.join(stagingDir, entry.name), path.join(projectDir, entry.name));
76
+ }
77
+ }
78
+
79
+ module.exports = { copyTemplateWithTokenSubstitution, promoteStagedScaffold };
@@ -1,93 +1,93 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { spawnSync } = require('child_process');
6
-
7
- // Map of secret prereq name → environment variable that satisfies it.
8
- const SECRET_ENV = { 'anthropic-api-key': 'ANTHROPIC_API_KEY' };
9
-
10
- /**
11
- * Default command runner. Captures stdout+stderr (java prints version to stderr)
12
- * and never throws. Tests inject their own `ctx.run` to avoid touching the host.
13
- * @param {string} cmd
14
- * @returns {{code:number, stdout:string, stderr:string}}
15
- */
16
- function defaultRun(cmd) {
17
- const r = spawnSync(cmd, { shell: true, encoding: 'utf8', windowsHide: true });
18
- return {
19
- code: typeof r.status === 'number' ? r.status : 1,
20
- stdout: r.stdout || '',
21
- stderr: r.stderr || '',
22
- };
23
- }
24
-
25
- /** Extract a numeric version tuple from arbitrary command output. */
26
- function parseVersion(text) {
27
- const m = String(text).match(/(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
28
- if (!m) return null;
29
- return [Number(m[1] || 0), Number(m[2] || 0), Number(m[3] || 0)];
30
- }
31
-
32
- /** found >= min ? (min may be "18" or "3.8") */
33
- function versionGte(found, min) {
34
- if (!found) return false;
35
- const want = parseVersion(min) || [0, 0, 0];
36
- for (let i = 0; i < 3; i++) {
37
- if (found[i] > want[i]) return true;
38
- if (found[i] < want[i]) return false;
39
- }
40
- return true;
41
- }
42
-
43
- /**
44
- * Detect whether a single prereq is satisfied. Detection NEVER mutates the host.
45
- * @param {string} name prereq id
46
- * @param {object} prereq manifest prereq entry
47
- * @param {object} ctx { run, platform, projectDir }
48
- * @returns {{name:string, present:boolean, version:?string, reason:string}}
49
- */
50
- function detectPrereq(name, prereq, ctx) {
51
- const run = ctx.run || defaultRun;
52
-
53
- switch (prereq.kind) {
54
- case 'secret': {
55
- const envVar = SECRET_ENV[name];
56
- const present = !!(envVar && process.env[envVar]);
57
- return { name, present, version: null, reason: present ? `${envVar} set` : `${envVar} unset` };
58
- }
59
- case 'venv': {
60
- const dir = path.join(ctx.projectDir, '.claude', 'skills', '.venv');
61
- const present = fs.existsSync(dir);
62
- return { name, present, version: null, reason: present ? 'venv exists' : 'venv missing' };
63
- }
64
- case 'mcp': {
65
- const r = run('claude mcp list');
66
- const present = r.code === 0 && /playwright/i.test(r.stdout + r.stderr);
67
- return { name, present, version: null, reason: present ? 'mcp registered' : 'mcp not registered' };
68
- }
69
- case 'note':
70
- // Nothing to probe directly; satisfied iff its `needs` are (handled by caller).
71
- return { name, present: false, version: null, reason: 'note (self-bootstrap)' };
72
- default: {
73
- // package
74
- if (!prereq.detect) return { name, present: false, version: null, reason: 'no detect command' };
75
- let r = run(prereq.detect);
76
- if (r.code !== 0 && name === 'python') r = run('python3 --version'); // unix fallback
77
- const out = r.stdout + r.stderr;
78
- const ver = parseVersion(out);
79
- if (r.code !== 0) return { name, present: false, version: null, reason: 'not found' };
80
- if (prereq.minVersion && !versionGte(ver, prereq.minVersion)) {
81
- return {
82
- name,
83
- present: false,
84
- version: ver ? ver.join('.') : null,
85
- reason: `version ${ver ? ver.join('.') : '?'} < required ${prereq.minVersion}`,
86
- };
87
- }
88
- return { name, present: true, version: ver ? ver.join('.') : null, reason: 'present' };
89
- }
90
- }
91
- }
92
-
93
- module.exports = { detectPrereq, parseVersion, versionGte, defaultRun, SECRET_ENV };
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { spawnSync } = require('child_process');
6
+
7
+ // Map of secret prereq name → environment variable that satisfies it.
8
+ const SECRET_ENV = { 'anthropic-api-key': 'ANTHROPIC_API_KEY' };
9
+
10
+ /**
11
+ * Default command runner. Captures stdout+stderr (java prints version to stderr)
12
+ * and never throws. Tests inject their own `ctx.run` to avoid touching the host.
13
+ * @param {string} cmd
14
+ * @returns {{code:number, stdout:string, stderr:string}}
15
+ */
16
+ function defaultRun(cmd) {
17
+ const r = spawnSync(cmd, { shell: true, encoding: 'utf8', windowsHide: true });
18
+ return {
19
+ code: typeof r.status === 'number' ? r.status : 1,
20
+ stdout: r.stdout || '',
21
+ stderr: r.stderr || '',
22
+ };
23
+ }
24
+
25
+ /** Extract a numeric version tuple from arbitrary command output. */
26
+ function parseVersion(text) {
27
+ const m = String(text).match(/(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
28
+ if (!m) return null;
29
+ return [Number(m[1] || 0), Number(m[2] || 0), Number(m[3] || 0)];
30
+ }
31
+
32
+ /** found >= min ? (min may be "18" or "3.8") */
33
+ function versionGte(found, min) {
34
+ if (!found) return false;
35
+ const want = parseVersion(min) || [0, 0, 0];
36
+ for (let i = 0; i < 3; i++) {
37
+ if (found[i] > want[i]) return true;
38
+ if (found[i] < want[i]) return false;
39
+ }
40
+ return true;
41
+ }
42
+
43
+ /**
44
+ * Detect whether a single prereq is satisfied. Detection NEVER mutates the host.
45
+ * @param {string} name prereq id
46
+ * @param {object} prereq manifest prereq entry
47
+ * @param {object} ctx { run, platform, projectDir }
48
+ * @returns {{name:string, present:boolean, version:?string, reason:string}}
49
+ */
50
+ function detectPrereq(name, prereq, ctx) {
51
+ const run = ctx.run || defaultRun;
52
+
53
+ switch (prereq.kind) {
54
+ case 'secret': {
55
+ const envVar = SECRET_ENV[name];
56
+ const present = !!(envVar && process.env[envVar]);
57
+ return { name, present, version: null, reason: present ? `${envVar} set` : `${envVar} unset` };
58
+ }
59
+ case 'venv': {
60
+ const dir = path.join(ctx.projectDir, '.claude', 'skills', '.venv');
61
+ const present = fs.existsSync(dir);
62
+ return { name, present, version: null, reason: present ? 'venv exists' : 'venv missing' };
63
+ }
64
+ case 'mcp': {
65
+ const r = run('claude mcp list');
66
+ const present = r.code === 0 && /playwright/i.test(r.stdout + r.stderr);
67
+ return { name, present, version: null, reason: present ? 'mcp registered' : 'mcp not registered' };
68
+ }
69
+ case 'note':
70
+ // Nothing to probe directly; satisfied iff its `needs` are (handled by caller).
71
+ return { name, present: false, version: null, reason: 'note (self-bootstrap)' };
72
+ default: {
73
+ // package
74
+ if (!prereq.detect) return { name, present: false, version: null, reason: 'no detect command' };
75
+ let r = run(prereq.detect);
76
+ if (r.code !== 0 && name === 'python') r = run('python3 --version'); // unix fallback
77
+ const out = r.stdout + r.stderr;
78
+ const ver = parseVersion(out);
79
+ if (r.code !== 0) return { name, present: false, version: null, reason: 'not found' };
80
+ if (prereq.minVersion && !versionGte(ver, prereq.minVersion)) {
81
+ return {
82
+ name,
83
+ present: false,
84
+ version: ver ? ver.join('.') : null,
85
+ reason: `version ${ver ? ver.join('.') : '?'} < required ${prereq.minVersion}`,
86
+ };
87
+ }
88
+ return { name, present: true, version: ver ? ver.join('.') : null, reason: 'present' };
89
+ }
90
+ }
91
+ }
92
+
93
+ module.exports = { detectPrereq, parseVersion, versionGte, defaultRun, SECRET_ENV };
@@ -1,77 +1,77 @@
1
- 'use strict';
2
-
3
- // Self-update gate for `musketeer muster`. Before the picker applies the bundled
4
- // template, make sure the CLI is at the latest PUBLISHED version — otherwise
5
- // "muster" would refresh installed skills to a stale package's template.
6
- //
7
- // When behind: promote (npm i -g @latest), then re-exec `musketeer muster` so the
8
- // picker runs under the freshly-installed template. A running Node process can't
9
- // reliably hot-swap its own package files mid-run, so re-exec is the safe path.
10
- //
11
- // Guards:
12
- // MUSKETEER_REEXEC=1 set on the child so it never re-checks (no loop)
13
- // MUSKETEER_NO_SELF_UPDATE=1 user opt-out (offline / pinned version)
14
-
15
- const { spawnSync } = require('child_process');
16
- const { fetchLatest, compareVersions, defaultRun } = require('./promote');
17
- const pkg = require('../package.json');
18
-
19
- /**
20
- * Decide whether muster should self-update first. Pure — injectable exec/env.
21
- * @param {{exec?:Function, current?:string, name?:string, env?:object}} [o]
22
- * @returns {{action:'proceed'|'update', latest:?string}}
23
- */
24
- function decide(o = {}) {
25
- const exec = o.exec || defaultRun;
26
- const current = o.current || pkg.version;
27
- const name = o.name || pkg.name;
28
- const env = o.env || process.env;
29
-
30
- if (env.MUSKETEER_REEXEC === '1' || env.MUSKETEER_NO_SELF_UPDATE === '1') {
31
- return { action: 'proceed', latest: null };
32
- }
33
- const latest = fetchLatest(exec, name);
34
- if (!latest) return { action: 'proceed', latest: null }; // offline / unknown — proceed as-is
35
- if (compareVersions(latest, current) <= 0) return { action: 'proceed', latest }; // already latest
36
- return { action: 'update', latest };
37
- }
38
-
39
- /**
40
- * Ensure the CLI is latest before muster applies the template.
41
- * @param {object} [io] injectable { log, exec, spawn, env, name, current } for tests
42
- * @returns {?number} an exit code if it re-exec'd a fresh muster (caller should
43
- * exit with it); null to mean "proceed in-process".
44
- */
45
- function ensureLatest(io = {}) {
46
- const log = io.log || ((m) => process.stdout.write(m + '\n'));
47
- const exec = io.exec || defaultRun;
48
- const spawn = io.spawn || spawnSync;
49
- const env = io.env || process.env;
50
- const name = io.name || pkg.name;
51
- const current = io.current || pkg.version;
52
-
53
- const d = decide({ exec, current, name, env });
54
- if (d.action === 'proceed') return null;
55
-
56
- log(`Updating musketeer ${current} → ${d.latest} before muster…`);
57
- const ins = exec(`npm i -g ${name}@latest`);
58
- if (ins.code !== 0) {
59
- log('Self-update failed — continuing with the current version.');
60
- if (ins.stderr) log(ins.stderr.trim());
61
- return null;
62
- }
63
-
64
- // Re-exec the now-latest binary's muster, inheriting the TTY for the picker.
65
- // The caller's flags come along: dropping them here would send a scripted
66
- // `muster --keep` back to the interactive picker, which is the one place it
67
- // cannot run.
68
- const args = io.args || [];
69
- const r = spawn('musketeer', ['muster', ...args], {
70
- stdio: 'inherit',
71
- shell: true,
72
- env: { ...env, MUSKETEER_REEXEC: '1' },
73
- });
74
- return typeof r.status === 'number' ? r.status : 0;
75
- }
76
-
77
- module.exports = { decide, ensureLatest };
1
+ 'use strict';
2
+
3
+ // Self-update gate for `musketeer muster`. Before the picker applies the bundled
4
+ // template, make sure the CLI is at the latest PUBLISHED version — otherwise
5
+ // "muster" would refresh installed skills to a stale package's template.
6
+ //
7
+ // When behind: promote (npm i -g @latest), then re-exec `musketeer muster` so the
8
+ // picker runs under the freshly-installed template. A running Node process can't
9
+ // reliably hot-swap its own package files mid-run, so re-exec is the safe path.
10
+ //
11
+ // Guards:
12
+ // MUSKETEER_REEXEC=1 set on the child so it never re-checks (no loop)
13
+ // MUSKETEER_NO_SELF_UPDATE=1 user opt-out (offline / pinned version)
14
+
15
+ const { spawnSync } = require('child_process');
16
+ const { fetchLatest, compareVersions, defaultRun } = require('./promote');
17
+ const pkg = require('../package.json');
18
+
19
+ /**
20
+ * Decide whether muster should self-update first. Pure — injectable exec/env.
21
+ * @param {{exec?:Function, current?:string, name?:string, env?:object}} [o]
22
+ * @returns {{action:'proceed'|'update', latest:?string}}
23
+ */
24
+ function decide(o = {}) {
25
+ const exec = o.exec || defaultRun;
26
+ const current = o.current || pkg.version;
27
+ const name = o.name || pkg.name;
28
+ const env = o.env || process.env;
29
+
30
+ if (env.MUSKETEER_REEXEC === '1' || env.MUSKETEER_NO_SELF_UPDATE === '1') {
31
+ return { action: 'proceed', latest: null };
32
+ }
33
+ const latest = fetchLatest(exec, name);
34
+ if (!latest) return { action: 'proceed', latest: null }; // offline / unknown — proceed as-is
35
+ if (compareVersions(latest, current) <= 0) return { action: 'proceed', latest }; // already latest
36
+ return { action: 'update', latest };
37
+ }
38
+
39
+ /**
40
+ * Ensure the CLI is latest before muster applies the template.
41
+ * @param {object} [io] injectable { log, exec, spawn, env, name, current } for tests
42
+ * @returns {?number} an exit code if it re-exec'd a fresh muster (caller should
43
+ * exit with it); null to mean "proceed in-process".
44
+ */
45
+ function ensureLatest(io = {}) {
46
+ const log = io.log || ((m) => process.stdout.write(m + '\n'));
47
+ const exec = io.exec || defaultRun;
48
+ const spawn = io.spawn || spawnSync;
49
+ const env = io.env || process.env;
50
+ const name = io.name || pkg.name;
51
+ const current = io.current || pkg.version;
52
+
53
+ const d = decide({ exec, current, name, env });
54
+ if (d.action === 'proceed') return null;
55
+
56
+ log(`Updating musketeer ${current} → ${d.latest} before muster…`);
57
+ const ins = exec(`npm i -g ${name}@latest`);
58
+ if (ins.code !== 0) {
59
+ log('Self-update failed — continuing with the current version.');
60
+ if (ins.stderr) log(ins.stderr.trim());
61
+ return null;
62
+ }
63
+
64
+ // Re-exec the now-latest binary's muster, inheriting the TTY for the picker.
65
+ // The caller's flags come along: dropping them here would send a scripted
66
+ // `muster --keep` back to the interactive picker, which is the one place it
67
+ // cannot run.
68
+ const args = io.args || [];
69
+ const r = spawn('musketeer', ['muster', ...args], {
70
+ stdio: 'inherit',
71
+ shell: true,
72
+ env: { ...env, MUSKETEER_REEXEC: '1' },
73
+ });
74
+ return typeof r.status === 'number' ? r.status : 0;
75
+ }
76
+
77
+ module.exports = { decide, ensureLatest };