@phuc1403/musketeer 0.1.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.
- package/INSTALLATION.md +22 -0
- package/LICENSE +21 -0
- package/README.md +38 -0
- package/bin/musketeer.js +72 -0
- package/manifest.json +238 -0
- package/package.json +46 -0
- package/src/copier.js +119 -0
- package/src/lockfile.js +61 -0
- package/src/manifest-loader.js +46 -0
- package/src/muster.js +48 -0
- package/src/provisioner/detect.js +93 -0
- package/src/provisioner/guide.js +32 -0
- package/src/provisioner/index.js +113 -0
- package/src/provisioner/mcp.js +26 -0
- package/src/provisioner/os-package-manager.js +71 -0
- package/src/provisioner/venv.js +44 -0
- package/src/reconcile.js +94 -0
- package/src/resolver.js +130 -0
- package/src/schema.js +152 -0
- package/src/settings-merger.js +0 -0
- package/template/.claude/agents/code-reviewer.md +166 -0
- package/template/.claude/agents/hallmark-auditor.md +78 -0
- package/template/.claude/agents/hallmark-explorer.md +81 -0
- package/template/.claude/agents/researcher.md +33 -0
- package/template/.claude/hooks/block-migration-edits.cjs +31 -0
- package/template/.claude/hooks/format-json-hook.js +91 -0
- package/template/.claude/hooks/inject-design-docs.cjs +86 -0
- package/template/.claude/hooks/lib/colors.cjs +122 -0
- package/template/.claude/hooks/lib/git-info-cache.cjs +191 -0
- package/template/.claude/hooks/lib/transcript-parser.cjs +277 -0
- package/template/.claude/hooks/usage-context-awareness.cjs +166 -0
- package/template/.claude/hooks/validate-cml-hook.js +145 -0
- package/template/.claude/skills/adr-writer/SKILL.md +78 -0
- package/template/.claude/skills/adr-writer/references/adr-example.md +38 -0
- package/template/.claude/skills/adr-writer/references/adr-template.md +46 -0
- package/template/.claude/skills/architecture-characteristic-writer/SKILL.md +117 -0
- package/template/.claude/skills/architecture-characteristic-writer/assets/worksheet-template.md +40 -0
- package/template/.claude/skills/architecture-characteristic-writer/references/characteristics-catalog.md +106 -0
- package/template/.claude/skills/code-review/SKILL.md +54 -0
- package/template/.claude/skills/code-review/references/adversarial-review.md +223 -0
- package/template/.claude/skills/code-review/references/checklists/api.md +52 -0
- package/template/.claude/skills/code-review/references/checklists/base.md +100 -0
- package/template/.claude/skills/code-review/references/checklists/web-app.md +54 -0
- package/template/.claude/skills/context-map/SKILL.md +80 -0
- package/template/.claude/skills/context-map/example.cml +106 -0
- package/template/.claude/skills/context-map/reference/Aggregate/Aggregate.md +1 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/Bounded Context.md +41 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/businessModel.md +6 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/domainVisionStatement.md +3 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/evolution.md +6 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/implementationTechnology.md +1 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/implements.md +1 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/knowledgeLevel.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/realizes.md +9 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/refines.md +10 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/responsibilities.md +26 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/type.md +23 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Anticorruption Layer.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Bounded Context Relationship.md +13 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Conformist.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Customer-Supplier (C-S).md +23 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Open Host Service.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Partnership (P).md +14 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Published Language.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Shared Kernel (SK).md +13 -0
- package/template/.claude/skills/context-map/reference/Context Map.md +63 -0
- package/template/.claude/skills/context-map/reference/Domain/Domain.md +30 -0
- package/template/.claude/skills/context-map/reference/Domain/supports.md +34 -0
- package/template/.claude/skills/context-map/reference/Domain/type.md +3 -0
- package/template/.claude/skills/context-map/reference/Semantic Rules.md +33 -0
- package/template/.claude/skills/hallmark/SKILL.md +552 -0
- package/template/.claude/skills/hallmark/references/anti-patterns.md +412 -0
- package/template/.claude/skills/hallmark/references/assets.md +406 -0
- package/template/.claude/skills/hallmark/references/color.md +95 -0
- package/template/.claude/skills/hallmark/references/component-cookbook.md +256 -0
- package/template/.claude/skills/hallmark/references/components/c1-outlined-chip.md +12 -0
- package/template/.claude/skills/hallmark/references/components/c2-inline-form-as-cta.md +16 -0
- package/template/.claude/skills/hallmark/references/components/c3-typographic-link.md +8 -0
- package/template/.claude/skills/hallmark/references/components/c4-sticky-bottom-bar.md +16 -0
- package/template/.claude/skills/hallmark/references/components/f1-bento-grid.md +20 -0
- package/template/.claude/skills/hallmark/references/components/f2-sticky-scroll-stack.md +20 -0
- package/template/.claude/skills/hallmark/references/components/f3-tabular-spec-sheet.md +11 -0
- package/template/.claude/skills/hallmark/references/components/f4-step-sequence.md +11 -0
- package/template/.claude/skills/hallmark/references/components/f5-annotated-screenshot.md +11 -0
- package/template/.claude/skills/hallmark/references/components/f6-product-card-grid.md +41 -0
- package/template/.claude/skills/hallmark/references/components/ft1-mast-headed.md +13 -0
- package/template/.claude/skills/hallmark/references/components/ft2-inline-rule-single-line.md +10 -0
- package/template/.claude/skills/hallmark/references/components/ft3-index-style-category-list.md +12 -0
- package/template/.claude/skills/hallmark/references/components/ft4-dense-typographic.md +10 -0
- package/template/.claude/skills/hallmark/references/components/ft5-statement.md +21 -0
- package/template/.claude/skills/hallmark/references/components/ft6-letter-close.md +19 -0
- package/template/.claude/skills/hallmark/references/components/ft7-newsletter-first.md +27 -0
- package/template/.claude/skills/hallmark/references/components/ft8-marquee-scroll.md +25 -0
- package/template/.claude/skills/hallmark/references/components/h1-marquee.md +15 -0
- package/template/.claude/skills/hallmark/references/components/h2-split-diptych.md +15 -0
- package/template/.claude/skills/hallmark/references/components/h3-quote-led.md +11 -0
- package/template/.claude/skills/hallmark/references/components/h4-stat-led.md +14 -0
- package/template/.claude/skills/hallmark/references/components/h5-letter-hero.md +11 -0
- package/template/.claude/skills/hallmark/references/components/h6-photographic-fold.md +16 -0
- package/template/.claude/skills/hallmark/references/components/h7-demo-video-clipped-by-viewport-edge.md +27 -0
- package/template/.claude/skills/hallmark/references/components/h8-mockup-split-browser-framed.md +23 -0
- package/template/.claude/skills/hallmark/references/components/h9-custom-illustration-centerpiece.md +27 -0
- package/template/.claude/skills/hallmark/references/components/n1-wordmark-2-links.md +12 -0
- package/template/.claude/skills/hallmark/references/components/n10-floating-on-scroll-morph.md +19 -0
- package/template/.claude/skills/hallmark/references/components/n2-floating-chip.md +14 -0
- package/template/.claude/skills/hallmark/references/components/n3-side-rail.md +14 -0
- package/template/.claude/skills/hallmark/references/components/n4-hidden-behind-k.md +9 -0
- package/template/.claude/skills/hallmark/references/components/n5-floating-pill.md +28 -0
- package/template/.claude/skills/hallmark/references/components/n6-newspaper-masthead.md +24 -0
- package/template/.claude/skills/hallmark/references/components/n7-brutal-slab.md +22 -0
- package/template/.claude/skills/hallmark/references/components/n8-terminal-command.md +21 -0
- package/template/.claude/skills/hallmark/references/components/n9-edge-aligned-minimal.md +17 -0
- package/template/.claude/skills/hallmark/references/components/s1-left-margin-numbered.md +15 -0
- package/template/.claude/skills/hallmark/references/components/s2-hanging.md +13 -0
- package/template/.claude/skills/hallmark/references/components/s3-sticky-pinned.md +19 -0
- package/template/.claude/skills/hallmark/references/components/s4-inline-no-break.md +11 -0
- package/template/.claude/skills/hallmark/references/components/s5-bottom-anchored.md +13 -0
- package/template/.claude/skills/hallmark/references/components/t1-pull-quote-with-marginalia.md +12 -0
- package/template/.claude/skills/hallmark/references/components/t2-logo-wall-hairline.md +19 -0
- package/template/.claude/skills/hallmark/references/components/t3-single-huge-quote.md +11 -0
- package/template/.claude/skills/hallmark/references/components/t4-numbered-stat-strip.md +14 -0
- package/template/.claude/skills/hallmark/references/contract.md +24 -0
- package/template/.claude/skills/hallmark/references/copy.md +182 -0
- package/template/.claude/skills/hallmark/references/custom-craft.md +626 -0
- package/template/.claude/skills/hallmark/references/custom-theme.md +329 -0
- package/template/.claude/skills/hallmark/references/design-md.md +116 -0
- package/template/.claude/skills/hallmark/references/export-formats.md +328 -0
- package/template/.claude/skills/hallmark/references/floating-nav.md +89 -0
- package/template/.claude/skills/hallmark/references/genres/atmospheric.md +65 -0
- package/template/.claude/skills/hallmark/references/genres/editorial.md +70 -0
- package/template/.claude/skills/hallmark/references/genres/modern-minimal.md +67 -0
- package/template/.claude/skills/hallmark/references/genres/playful.md +65 -0
- package/template/.claude/skills/hallmark/references/hero-enrichment.md +474 -0
- package/template/.claude/skills/hallmark/references/imagery-kit.md +170 -0
- package/template/.claude/skills/hallmark/references/interaction-and-states.md +207 -0
- package/template/.claude/skills/hallmark/references/layout-and-space.md +111 -0
- package/template/.claude/skills/hallmark/references/macrostructures/01-bento-grid.md +35 -0
- package/template/.claude/skills/hallmark/references/macrostructures/02-long-document.md +34 -0
- package/template/.claude/skills/hallmark/references/macrostructures/03-marquee-hero.md +31 -0
- package/template/.claude/skills/hallmark/references/macrostructures/04-stat-led.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/05-workbench.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/06-conversational-faq.md +33 -0
- package/template/.claude/skills/hallmark/references/macrostructures/07-manifesto.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/08-photographic.md +34 -0
- package/template/.claude/skills/hallmark/references/macrostructures/09-quote-led.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/10-specimen.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/11-catalogue.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/12-letter.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/13-index-first.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/14-narrative-workflow.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/15-split-studio.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/17-type-specimen.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/18-portfolio-grid.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/19-map-diagram.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/20-ecosystem-index.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/21-component-playground.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures.md +89 -0
- package/template/.claude/skills/hallmark/references/microinteractions.md +260 -0
- package/template/.claude/skills/hallmark/references/motion.md +109 -0
- package/template/.claude/skills/hallmark/references/preview-examples.md +49 -0
- package/template/.claude/skills/hallmark/references/responsive.md +138 -0
- package/template/.claude/skills/hallmark/references/slop-test.md +205 -0
- package/template/.claude/skills/hallmark/references/structure.md +164 -0
- package/template/.claude/skills/hallmark/references/study.md +511 -0
- package/template/.claude/skills/hallmark/references/typography.md +243 -0
- package/template/.claude/skills/hallmark/references/verbs/audit.md +25 -0
- package/template/.claude/skills/hallmark/references/verbs/redesign.md +269 -0
- package/template/.claude/skills/hallmark-explore/SKILL.md +137 -0
- package/template/.claude/skills/hallmark-explore/references/direction-matrix.md +124 -0
- package/template/.claude/skills/hallmark-explore/references/explorer-call.md +68 -0
- package/template/.claude/skills/hallmark-explore/scripts/build_compare.py +174 -0
- package/template/.claude/skills/hallmark-explore/scripts/scaffold_exploration.py +122 -0
- package/template/.claude/skills/hallmark-loop/SKILL.md +105 -0
- package/template/.claude/skills/hallmark-loop/references/auditor-call.md +60 -0
- package/template/.claude/skills/hallmark-loop/references/capture.md +78 -0
- package/template/.claude/skills/hallmark-loop/references/loop-control.md +79 -0
- package/template/.claude/skills/handoff/SKILL.md +15 -0
- package/template/.claude/skills/install.ps1 +42 -0
- package/template/.claude/skills/install.sh +54 -0
- package/template/.claude/skills/knowledge-crunching/SKILL.md +130 -0
- package/template/.claude/skills/knowledge-crunching/assets/context.template.md +59 -0
- package/template/.claude/skills/knowledge-crunching/references/crunching-dialogue.md +113 -0
- package/template/.claude/skills/research/SKILL.md +69 -0
- package/template/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.claude/skills/skill-creator/SKILL.md +149 -0
- package/template/.claude/skills/skill-creator/agents/analyzer.md +274 -0
- package/template/.claude/skills/skill-creator/agents/comparator.md +202 -0
- package/template/.claude/skills/skill-creator/agents/grader.md +223 -0
- package/template/.claude/skills/skill-creator/assets/eval_review.html +146 -0
- package/template/.claude/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/template/.claude/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/template/.claude/skills/skill-creator/references/benchmark-optimization-guide.md +86 -0
- package/template/.claude/skills/skill-creator/references/distribution-guide.md +79 -0
- package/template/.claude/skills/skill-creator/references/eval-infrastructure-guide.md +129 -0
- package/template/.claude/skills/skill-creator/references/eval-schemas.md +121 -0
- package/template/.claude/skills/skill-creator/references/mcp-skills-integration.md +71 -0
- package/template/.claude/skills/skill-creator/references/metadata-quality-criteria.md +94 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-overview.md +89 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-schema.md +93 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-sources.md +103 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -0
- package/template/.claude/skills/skill-creator/references/script-quality-criteria.md +106 -0
- package/template/.claude/skills/skill-creator/references/skill-anatomy-and-requirements.md +77 -0
- package/template/.claude/skills/skill-creator/references/skill-creation-workflow.md +151 -0
- package/template/.claude/skills/skill-creator/references/skill-design-patterns.md +75 -0
- package/template/.claude/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -0
- package/template/.claude/skills/skill-creator/references/structure-organization-criteria.md +114 -0
- package/template/.claude/skills/skill-creator/references/testing-and-iteration.md +78 -0
- package/template/.claude/skills/skill-creator/references/token-efficiency-criteria.md +74 -0
- package/template/.claude/skills/skill-creator/references/troubleshooting-guide.md +81 -0
- package/template/.claude/skills/skill-creator/references/validation-checklist.md +83 -0
- package/template/.claude/skills/skill-creator/references/writing-effective-instructions.md +88 -0
- package/template/.claude/skills/skill-creator/references/yaml-frontmatter-reference.md +92 -0
- package/template/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/template/.claude/skills/skill-creator/scripts/encoding_utils.py +36 -0
- package/template/.claude/skills/skill-creator/scripts/generate_report.py +326 -0
- package/template/.claude/skills/skill-creator/scripts/improve_description.py +248 -0
- package/template/.claude/skills/skill-creator/scripts/init_skill.py +360 -0
- package/template/.claude/skills/skill-creator/scripts/package_skill.py +143 -0
- package/template/.claude/skills/skill-creator/scripts/quick_validate.py +110 -0
- package/template/.claude/skills/skill-creator/scripts/run_eval.py +310 -0
- package/template/.claude/skills/skill-creator/scripts/run_loop.py +332 -0
- package/template/.claude/skills/skill-creator/scripts/utils.py +47 -0
- package/template/.claude/skills/tdd/SKILL.md +142 -0
- package/template/.claude/skills/tdd/assets/Directory.Build.props +26 -0
- package/template/.claude/skills/tdd/deep-modules.md +15 -0
- package/template/.claude/skills/tdd/dotnet-build-config.md +21 -0
- package/template/.claude/skills/tdd/interface-design.md +31 -0
- package/template/.claude/skills/tdd/mocking.md +59 -0
- package/template/.claude/skills/tdd/refactoring.md +10 -0
- package/template/.claude/skills/tdd/test-per-layer.md +69 -0
- package/template/.claude/skills/tdd/tests.md +61 -0
- package/template/.claude/statusline.cjs +0 -0
package/INSTALLATION.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Prerequisites & Auto-Install
|
|
2
|
+
|
|
3
|
+
`musketeer` auto-installs the external prerequisites required by your selected company
|
|
4
|
+
(announced before each install, never silent). When no OS package manager is available — or
|
|
5
|
+
an elevation prompt is refused — it falls back to printing the exact manual command below.
|
|
6
|
+
|
|
7
|
+
> Filled in detail during Phase 06 (provisioner) / Phase 08 (publish).
|
|
8
|
+
|
|
9
|
+
## Per-prerequisite matrix
|
|
10
|
+
|
|
11
|
+
| Prereq | Needed by | Windows | macOS | Linux |
|
|
12
|
+
|--------|-----------|---------|-------|-------|
|
|
13
|
+
| Node 18+ | core | `winget install OpenJS.NodeJS.LTS` | `brew install node` | NodeSource / distro |
|
|
14
|
+
| git | core, code-review | `winget install Git.Git` | `brew install git` | `apt/dnf/pacman install git` |
|
|
15
|
+
| Python 3.8+ | core (skill-creator) | `winget install Python.Python.3.12` | `brew install python@3.12` | `apt install python3 python3-pip` |
|
|
16
|
+
| Java 8+ | architecture (context-map) | `winget install Microsoft.OpenJDK` | `brew install --cask temurin` | `apt install openjdk-17-jdk` |
|
|
17
|
+
| gh | code-review (PR mode) | `winget install GitHub.cli` | `brew install gh` | `apt install gh` |
|
|
18
|
+
|
|
19
|
+
## Secrets (never auto-installed)
|
|
20
|
+
|
|
21
|
+
- `ANTHROPIC_API_KEY` — needed only by skill-creator's improve/loop scripts. You will be
|
|
22
|
+
prompted / shown how to set it; musketeer never writes it to the repo.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Phuc Pham (phamhongphuc1403)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# musketeer
|
|
2
|
+
|
|
3
|
+
> Distributable custom Claude Code harness. One declarative command scaffolds a curated
|
|
4
|
+
> **company** of **musketeers** (skills + agents + hooks) into any project's `./.claude/`.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm i -g @phuc1403/musketeer
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Use
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
musketeer # open the muster (interactive picker) → reconcile your company
|
|
16
|
+
musketeer --with a,b,c # non-interactive: set company to EXACTLY {core,a,b,c}
|
|
17
|
+
musketeer --list # print current company + available musketeers
|
|
18
|
+
musketeer --help # usage
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`musketeer` is **idempotent**: the picker pre-checks your current company (from `.musketeer.json`),
|
|
22
|
+
and confirming applies the diff — install newly-checked, remove newly-unchecked, regenerate
|
|
23
|
+
`settings.json`, and auto-install any missing prerequisites.
|
|
24
|
+
|
|
25
|
+
## Musketeers (v1)
|
|
26
|
+
|
|
27
|
+
| Musketeer | Default | What it adds |
|
|
28
|
+
|-----------|---------|--------------|
|
|
29
|
+
| **core** | always (locked) | research, handoff, skill-creator · statusline, usage-context, format-json hooks |
|
|
30
|
+
| **architecture** | checked | adr-writer, architecture-characteristic-writer, context-map · CML validation hook |
|
|
31
|
+
| **hallmark** | checked | hallmark, hallmark-explore, hallmark-loop · auditor/explorer agents |
|
|
32
|
+
| **code-review** | checked | code-review skill + code-reviewer agent |
|
|
33
|
+
| **dotnet** | opt-in | tdd, knowledge-crunching · EF migration guard hook |
|
|
34
|
+
| **design-docs** | opt-in | inject-design-docs SessionStart hook |
|
|
35
|
+
|
|
36
|
+
Vocabulary: **musketeer** = a selectable unit · **muster** = the picker · **company** = your recruited set.
|
|
37
|
+
|
|
38
|
+
See [INSTALLATION.md](INSTALLATION.md) for prerequisites and auto-install behavior.
|
package/bin/musketeer.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { parseArgs } = require('node:util');
|
|
5
|
+
|
|
6
|
+
const USAGE = `musketeer — scaffold a curated company of Claude Code musketeers into ./.claude
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
musketeer Open the muster (interactive picker), reconcile your company
|
|
10
|
+
musketeer --with a,b,c Non-interactive: set company to EXACTLY {core,a,b,c} (CI/scriptable)
|
|
11
|
+
musketeer --list Print current company + all available musketeers
|
|
12
|
+
musketeer --help Show this help
|
|
13
|
+
|
|
14
|
+
Notes:
|
|
15
|
+
* "core" is always installed and locked — it cannot be removed.
|
|
16
|
+
* Re-running is idempotent: the picker shows your current state, confirm applies the diff.
|
|
17
|
+
* settings.json is GENERATED per-selection; missing prereqs are auto-installed (announced).`;
|
|
18
|
+
|
|
19
|
+
function parse(argv) {
|
|
20
|
+
return parseArgs({
|
|
21
|
+
args: argv,
|
|
22
|
+
options: {
|
|
23
|
+
with: { type: 'string' },
|
|
24
|
+
list: { type: 'boolean', default: false },
|
|
25
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
26
|
+
},
|
|
27
|
+
allowPositionals: false,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function main(argv = process.argv.slice(2)) {
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = parse(argv);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
process.stderr.write(`${err.message}\n\n${USAGE}\n`);
|
|
37
|
+
process.exitCode = 2;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { values } = parsed;
|
|
42
|
+
|
|
43
|
+
if (values.help) {
|
|
44
|
+
process.stdout.write(`${USAGE}\n`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Lazy-require so --help never pays the cost of loading the engine/manifest.
|
|
49
|
+
const reconcile = require('../src/reconcile');
|
|
50
|
+
|
|
51
|
+
if (values.list) {
|
|
52
|
+
await reconcile.list();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (typeof values.with === 'string') {
|
|
57
|
+
const ids = values.with
|
|
58
|
+
.split(',')
|
|
59
|
+
.map((s) => s.trim())
|
|
60
|
+
.filter(Boolean);
|
|
61
|
+
await reconcile.run({ desiredIds: ids, interactive: false });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// No flags → open the muster (interactive).
|
|
66
|
+
await reconcile.run({ desiredIds: null, interactive: true });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
main().catch((err) => {
|
|
70
|
+
process.stderr.write(`musketeer: ${err && err.message ? err.message : err}\n`);
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
});
|
package/manifest.json
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"musketeers": {
|
|
4
|
+
"core": {
|
|
5
|
+
"label": "core",
|
|
6
|
+
"description": "Always-on foundation: research, handoff, skill-creator + statusline, usage-context & format-json hooks.",
|
|
7
|
+
"locked": true,
|
|
8
|
+
"defaultChecked": true,
|
|
9
|
+
"deps": [],
|
|
10
|
+
"files": [
|
|
11
|
+
"skills/research/**",
|
|
12
|
+
"skills/handoff/**",
|
|
13
|
+
"skills/skill-creator/**",
|
|
14
|
+
"skills/install.ps1",
|
|
15
|
+
"skills/install.sh",
|
|
16
|
+
"agents/researcher.md",
|
|
17
|
+
"statusline.cjs",
|
|
18
|
+
"hooks/usage-context-awareness.cjs",
|
|
19
|
+
"hooks/lib/**",
|
|
20
|
+
"hooks/format-json-hook.js"
|
|
21
|
+
],
|
|
22
|
+
"settings": [
|
|
23
|
+
{
|
|
24
|
+
"event": "statusLine",
|
|
25
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/statusline.cjs\"",
|
|
26
|
+
"padding": 0
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"event": "UserPromptSubmit",
|
|
30
|
+
"matcher": null,
|
|
31
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/usage-context-awareness.cjs\"",
|
|
32
|
+
"order": 1
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"event": "PostToolUse",
|
|
36
|
+
"matcher": null,
|
|
37
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/usage-context-awareness.cjs\"",
|
|
38
|
+
"order": 1
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"event": "PostToolUse",
|
|
42
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
43
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/format-json-hook.js\"",
|
|
44
|
+
"order": 2
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"prereqs": ["node", "git", "python", "venv-anthropic", "claude-cli"]
|
|
48
|
+
},
|
|
49
|
+
"architecture": {
|
|
50
|
+
"label": "architecture",
|
|
51
|
+
"description": "DDD architecture authoring: adr-writer, architecture-characteristic-writer, context-map (CML) + validation hook.",
|
|
52
|
+
"locked": false,
|
|
53
|
+
"defaultChecked": true,
|
|
54
|
+
"deps": [],
|
|
55
|
+
"files": [
|
|
56
|
+
"skills/adr-writer/**",
|
|
57
|
+
"skills/architecture-characteristic-writer/**",
|
|
58
|
+
"skills/context-map/**",
|
|
59
|
+
"hooks/validate-cml-hook.js"
|
|
60
|
+
],
|
|
61
|
+
"settings": [
|
|
62
|
+
{
|
|
63
|
+
"event": "PostToolUse",
|
|
64
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
65
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/validate-cml-hook.js\"",
|
|
66
|
+
"order": 1
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"prereqs": ["java", "cm-cli"]
|
|
70
|
+
},
|
|
71
|
+
"hallmark": {
|
|
72
|
+
"label": "hallmark",
|
|
73
|
+
"description": "Hallmark design system: hallmark rubric, hallmark-explore, hallmark-loop + auditor/explorer agents.",
|
|
74
|
+
"locked": false,
|
|
75
|
+
"defaultChecked": true,
|
|
76
|
+
"deps": [],
|
|
77
|
+
"files": [
|
|
78
|
+
"skills/hallmark/**",
|
|
79
|
+
"skills/hallmark-explore/**",
|
|
80
|
+
"skills/hallmark-loop/**",
|
|
81
|
+
"agents/hallmark-auditor.md",
|
|
82
|
+
"agents/hallmark-explorer.md"
|
|
83
|
+
],
|
|
84
|
+
"settings": [],
|
|
85
|
+
"prereqs": ["python", "playwright-mcp"]
|
|
86
|
+
},
|
|
87
|
+
"code-review": {
|
|
88
|
+
"label": "code-review",
|
|
89
|
+
"description": "Adversarial code review skill + code-reviewer agent (commit / pending / PR modes).",
|
|
90
|
+
"locked": false,
|
|
91
|
+
"defaultChecked": true,
|
|
92
|
+
"deps": [],
|
|
93
|
+
"files": [
|
|
94
|
+
"skills/code-review/**",
|
|
95
|
+
"agents/code-reviewer.md"
|
|
96
|
+
],
|
|
97
|
+
"settings": [],
|
|
98
|
+
"prereqs": ["git", "gh"]
|
|
99
|
+
},
|
|
100
|
+
"dotnet": {
|
|
101
|
+
"label": "dotnet",
|
|
102
|
+
"description": "Opt-in .NET extras: tdd, knowledge-crunching + EF migration-guard hook.",
|
|
103
|
+
"locked": false,
|
|
104
|
+
"defaultChecked": false,
|
|
105
|
+
"deps": [],
|
|
106
|
+
"files": [
|
|
107
|
+
"skills/tdd/**",
|
|
108
|
+
"skills/knowledge-crunching/**",
|
|
109
|
+
"hooks/block-migration-edits.cjs"
|
|
110
|
+
],
|
|
111
|
+
"settings": [
|
|
112
|
+
{
|
|
113
|
+
"event": "PreToolUse",
|
|
114
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
115
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/block-migration-edits.cjs\"",
|
|
116
|
+
"order": 1,
|
|
117
|
+
"statusMessage": "Checking for EF migration edits"
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"prereqs": []
|
|
121
|
+
},
|
|
122
|
+
"design-docs": {
|
|
123
|
+
"label": "design-docs",
|
|
124
|
+
"description": "Opt-in SessionStart hook that injects architecture/context-map/adr docs/ outputs into context.",
|
|
125
|
+
"locked": false,
|
|
126
|
+
"defaultChecked": false,
|
|
127
|
+
"deps": [],
|
|
128
|
+
"files": [
|
|
129
|
+
"hooks/inject-design-docs.cjs"
|
|
130
|
+
],
|
|
131
|
+
"settings": [
|
|
132
|
+
{
|
|
133
|
+
"event": "SessionStart",
|
|
134
|
+
"matcher": "startup|resume|clear|compact",
|
|
135
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/inject-design-docs.cjs\"",
|
|
136
|
+
"order": 1,
|
|
137
|
+
"statusMessage": "Injecting design artifacts"
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
"prereqs": []
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"prereqs": {
|
|
144
|
+
"node": {
|
|
145
|
+
"detect": "node --version",
|
|
146
|
+
"minVersion": "18",
|
|
147
|
+
"kind": "package",
|
|
148
|
+
"install": {
|
|
149
|
+
"win": "winget install -e --id OpenJS.NodeJS.LTS",
|
|
150
|
+
"mac": "brew install node",
|
|
151
|
+
"linux": {
|
|
152
|
+
"apt": "sudo apt-get install -y nodejs npm",
|
|
153
|
+
"dnf": "sudo dnf install -y nodejs",
|
|
154
|
+
"pacman": "sudo pacman -S --noconfirm nodejs npm"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"git": {
|
|
159
|
+
"detect": "git --version",
|
|
160
|
+
"kind": "package",
|
|
161
|
+
"install": {
|
|
162
|
+
"win": "winget install -e --id Git.Git",
|
|
163
|
+
"mac": "brew install git",
|
|
164
|
+
"linux": {
|
|
165
|
+
"apt": "sudo apt-get install -y git",
|
|
166
|
+
"dnf": "sudo dnf install -y git",
|
|
167
|
+
"pacman": "sudo pacman -S --noconfirm git"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"python": {
|
|
172
|
+
"detect": "python --version",
|
|
173
|
+
"minVersion": "3.8",
|
|
174
|
+
"kind": "package",
|
|
175
|
+
"install": {
|
|
176
|
+
"win": "winget install -e --id Python.Python.3.12",
|
|
177
|
+
"mac": "brew install python@3.12",
|
|
178
|
+
"linux": {
|
|
179
|
+
"apt": "sudo apt-get install -y python3 python3-pip python3-venv",
|
|
180
|
+
"dnf": "sudo dnf install -y python3 python3-pip",
|
|
181
|
+
"pacman": "sudo pacman -S --noconfirm python python-pip"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"venv-anthropic": {
|
|
186
|
+
"kind": "venv",
|
|
187
|
+
"needs": ["python"]
|
|
188
|
+
},
|
|
189
|
+
"claude-cli": {
|
|
190
|
+
"detect": "claude --version",
|
|
191
|
+
"kind": "package",
|
|
192
|
+
"install": {
|
|
193
|
+
"win": "powershell -NoProfile -Command \"irm https://claude.ai/install.ps1 | iex\"",
|
|
194
|
+
"mac": "brew install --cask claude-code",
|
|
195
|
+
"linux": "curl -fsSL https://claude.ai/install.sh | bash"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"java": {
|
|
199
|
+
"detect": "java -version",
|
|
200
|
+
"minVersion": "8",
|
|
201
|
+
"kind": "package",
|
|
202
|
+
"install": {
|
|
203
|
+
"win": "winget install -e --id Microsoft.OpenJDK.17",
|
|
204
|
+
"mac": "brew install --cask temurin",
|
|
205
|
+
"linux": {
|
|
206
|
+
"apt": "sudo apt-get install -y openjdk-17-jdk",
|
|
207
|
+
"dnf": "sudo dnf install -y java-17-openjdk",
|
|
208
|
+
"pacman": "sudo pacman -S --noconfirm jdk-openjdk"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"cm-cli": {
|
|
213
|
+
"kind": "note",
|
|
214
|
+
"needs": ["java"]
|
|
215
|
+
},
|
|
216
|
+
"gh": {
|
|
217
|
+
"detect": "gh --version",
|
|
218
|
+
"kind": "package",
|
|
219
|
+
"install": {
|
|
220
|
+
"win": "winget install -e --id GitHub.cli",
|
|
221
|
+
"mac": "brew install gh",
|
|
222
|
+
"linux": {
|
|
223
|
+
"apt": "sudo apt-get install -y gh",
|
|
224
|
+
"dnf": "sudo dnf install -y gh",
|
|
225
|
+
"pacman": "sudo pacman -S --noconfirm github-cli"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"playwright-mcp": {
|
|
230
|
+
"kind": "mcp",
|
|
231
|
+
"needs": ["node", "claude-cli"]
|
|
232
|
+
},
|
|
233
|
+
"anthropic-api-key": {
|
|
234
|
+
"kind": "secret",
|
|
235
|
+
"guideOnly": true
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@phuc1403/musketeer",
|
|
3
|
+
"version": "0.1.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
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"claude",
|
|
26
|
+
"claude-code",
|
|
27
|
+
"harness",
|
|
28
|
+
"scaffolder",
|
|
29
|
+
"cli",
|
|
30
|
+
"skills",
|
|
31
|
+
"agents",
|
|
32
|
+
"hooks"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/phamhongphuc1403/musketeer.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/phamhongphuc1403/musketeer/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/phamhongphuc1403/musketeer#readme",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@clack/prompts": "^0.7.0"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/copier.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Guard against operating on a `.claude` that is a symlink pointing outside the
|
|
8
|
+
* project (would let copy/remove escape the project tree).
|
|
9
|
+
* @param {string} projectClaudeDir
|
|
10
|
+
* @param {string} projectDir
|
|
11
|
+
*/
|
|
12
|
+
function guardClaudeDir(projectClaudeDir, projectDir) {
|
|
13
|
+
let st;
|
|
14
|
+
try {
|
|
15
|
+
st = fs.lstatSync(projectClaudeDir);
|
|
16
|
+
} catch {
|
|
17
|
+
return; // doesn't exist yet — fine
|
|
18
|
+
}
|
|
19
|
+
if (st.isSymbolicLink()) {
|
|
20
|
+
const real = fs.realpathSync(projectClaudeDir);
|
|
21
|
+
const realProject = fs.realpathSync(projectDir);
|
|
22
|
+
if (!real.startsWith(realProject + path.sep) && real !== realProject) {
|
|
23
|
+
throw new Error(`.claude is a symlink pointing outside the project (${real}); refusing to operate.`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Compute the reconcile file plan.
|
|
30
|
+
* Force-update model: every desired file is (re)copied; only files the lockfile
|
|
31
|
+
* recorded that are no longer desired get removed.
|
|
32
|
+
* @param {string[]} prevFiles
|
|
33
|
+
* @param {string[]} desiredFiles
|
|
34
|
+
* @returns {{copy:string[], remove:string[]}}
|
|
35
|
+
*/
|
|
36
|
+
function planFiles(prevFiles, desiredFiles) {
|
|
37
|
+
const desiredSet = new Set(desiredFiles);
|
|
38
|
+
const remove = prevFiles.filter((f) => !desiredSet.has(f));
|
|
39
|
+
return { copy: [...desiredFiles], remove };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resolve `rel` under `base`, returning an absolute path ONLY if it stays
|
|
44
|
+
* contained within `base`. Defends against traversal (`../../x`) from
|
|
45
|
+
* lockfile-supplied paths — upholds "never touch files outside .claude/".
|
|
46
|
+
* @returns {?string} contained absolute path, or null if it would escape
|
|
47
|
+
*/
|
|
48
|
+
function containedPath(base, rel) {
|
|
49
|
+
const root = path.resolve(base);
|
|
50
|
+
const abs = path.resolve(root, rel);
|
|
51
|
+
if (abs !== root && !abs.startsWith(root + path.sep)) return null;
|
|
52
|
+
return abs;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function copyOne(rel, templateClaudeDir, projectClaudeDir) {
|
|
56
|
+
const dest = containedPath(projectClaudeDir, rel);
|
|
57
|
+
const src = containedPath(templateClaudeDir, rel);
|
|
58
|
+
if (!dest || !src) {
|
|
59
|
+
process.stderr.write(`musketeer: skipping out-of-tree path "${rel}"\n`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
63
|
+
fs.copyFileSync(src, dest);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function removeOne(rel, projectClaudeDir) {
|
|
67
|
+
const dest = containedPath(projectClaudeDir, rel);
|
|
68
|
+
if (!dest) {
|
|
69
|
+
process.stderr.write(`musketeer: refusing to remove out-of-tree path "${rel}"\n`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
fs.rmSync(dest, { force: true });
|
|
74
|
+
} catch {
|
|
75
|
+
/* already gone */
|
|
76
|
+
}
|
|
77
|
+
pruneEmptyParents(path.dirname(dest), projectClaudeDir);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Remove now-empty directories walking up from `dir` to (but not including)
|
|
82
|
+
* `stopAt`. Never deletes a non-empty directory (preserves user files).
|
|
83
|
+
*/
|
|
84
|
+
function pruneEmptyParents(dir, stopAt) {
|
|
85
|
+
let cur = dir;
|
|
86
|
+
const stop = path.resolve(stopAt);
|
|
87
|
+
while (path.resolve(cur) !== stop && path.resolve(cur).startsWith(stop + path.sep)) {
|
|
88
|
+
let entries;
|
|
89
|
+
try {
|
|
90
|
+
entries = fs.readdirSync(cur);
|
|
91
|
+
} catch {
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
if (entries.length > 0) break;
|
|
95
|
+
try {
|
|
96
|
+
fs.rmdirSync(cur);
|
|
97
|
+
} catch {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
cur = path.dirname(cur);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Apply a file plan to the project's `.claude` directory.
|
|
106
|
+
* @param {{copy:string[], remove:string[]}} plan
|
|
107
|
+
* @param {string} templateClaudeDir absolute path to packaged template/.claude
|
|
108
|
+
* @param {string} projectDir absolute path to the target project
|
|
109
|
+
*/
|
|
110
|
+
function apply(plan, templateClaudeDir, projectDir) {
|
|
111
|
+
const projectClaudeDir = path.join(projectDir, '.claude');
|
|
112
|
+
guardClaudeDir(projectClaudeDir, projectDir);
|
|
113
|
+
fs.mkdirSync(projectClaudeDir, { recursive: true });
|
|
114
|
+
|
|
115
|
+
for (const rel of plan.remove) removeOne(rel, projectClaudeDir);
|
|
116
|
+
for (const rel of plan.copy) copyOne(rel, templateClaudeDir, projectClaudeDir);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = { apply, planFiles, guardClaudeDir, pruneEmptyParents, containedPath };
|
package/src/lockfile.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const LOCKFILE_NAME = '.musketeer.json';
|
|
7
|
+
const LOCKFILE_VERSION = 1;
|
|
8
|
+
|
|
9
|
+
function lockfilePath(projectDir) {
|
|
10
|
+
return path.join(projectDir, LOCKFILE_NAME);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Read the current company from `.musketeer.json`.
|
|
15
|
+
* Missing / unreadable / malformed → empty company (first-run semantics).
|
|
16
|
+
* @param {string} projectDir
|
|
17
|
+
* @returns {{version:number, musketeers:string[], files:string[], updatedAt?:string}}
|
|
18
|
+
*/
|
|
19
|
+
function readLockfile(projectDir) {
|
|
20
|
+
const file = lockfilePath(projectDir);
|
|
21
|
+
let raw;
|
|
22
|
+
try {
|
|
23
|
+
raw = fs.readFileSync(file, 'utf8');
|
|
24
|
+
} catch {
|
|
25
|
+
return { version: LOCKFILE_VERSION, musketeers: [], files: [] };
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const obj = JSON.parse(raw);
|
|
29
|
+
return {
|
|
30
|
+
version: typeof obj.version === 'number' ? obj.version : LOCKFILE_VERSION,
|
|
31
|
+
musketeers: Array.isArray(obj.musketeers) ? obj.musketeers : [],
|
|
32
|
+
files: Array.isArray(obj.files) ? obj.files : [],
|
|
33
|
+
updatedAt: obj.updatedAt,
|
|
34
|
+
};
|
|
35
|
+
} catch {
|
|
36
|
+
return { version: LOCKFILE_VERSION, musketeers: [], files: [] };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Atomically write the lockfile. `updatedAt` is provided by the caller
|
|
42
|
+
* (kept out of the pure core so output is deterministic in tests).
|
|
43
|
+
* @param {string} projectDir
|
|
44
|
+
* @param {{musketeers:string[], files:string[], updatedAt?:string}} data
|
|
45
|
+
*/
|
|
46
|
+
function writeLockfile(projectDir, data) {
|
|
47
|
+
const out = {
|
|
48
|
+
version: LOCKFILE_VERSION,
|
|
49
|
+
musketeers: [...(data.musketeers || [])].sort(),
|
|
50
|
+
files: [...(data.files || [])].sort(),
|
|
51
|
+
};
|
|
52
|
+
if (data.updatedAt) out.updatedAt = data.updatedAt;
|
|
53
|
+
|
|
54
|
+
const file = lockfilePath(projectDir);
|
|
55
|
+
const tmp = `${file}.tmp`;
|
|
56
|
+
fs.writeFileSync(tmp, JSON.stringify(out, null, 2) + '\n', 'utf8');
|
|
57
|
+
fs.renameSync(tmp, file);
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = { readLockfile, writeLockfile, lockfilePath, LOCKFILE_NAME, LOCKFILE_VERSION };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { validateManifest } = require('./schema');
|
|
6
|
+
|
|
7
|
+
const MANIFEST_FILENAME = 'manifest.json';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the path to the packaged manifest.json (sibling of src/).
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
function manifestPath() {
|
|
14
|
+
return path.join(__dirname, '..', MANIFEST_FILENAME);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Load + validate the packaged manifest.
|
|
19
|
+
* @param {string} [file] override path (tests)
|
|
20
|
+
* @returns {object} validated manifest
|
|
21
|
+
*/
|
|
22
|
+
function loadManifest(file = manifestPath()) {
|
|
23
|
+
let raw;
|
|
24
|
+
try {
|
|
25
|
+
raw = fs.readFileSync(file, 'utf8');
|
|
26
|
+
} catch (err) {
|
|
27
|
+
throw new Error(`Cannot read manifest at ${file}: ${err.message}`);
|
|
28
|
+
}
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = JSON.parse(raw);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
throw new Error(`manifest.json is not valid JSON: ${err.message}`);
|
|
34
|
+
}
|
|
35
|
+
return validateManifest(parsed);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Absolute path to the packaged template/.claude directory.
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
function templateClaudeDir() {
|
|
43
|
+
return path.join(__dirname, '..', 'template', '.claude');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = { loadManifest, manifestPath, templateClaudeDir, MANIFEST_FILENAME };
|