scm-method 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +77 -0
- package/AGENTS.md +12 -0
- package/LICENSE +30 -0
- package/README.md +109 -0
- package/README_CN.md +108 -0
- package/package.json +110 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/SKILL.md +6 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-01-init.md +137 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-02-domain-analysis.md +229 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-03-competitive-landscape.md +238 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-04-regulatory-focus.md +206 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-05-technical-trends.md +234 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-06-research-synthesis.md +444 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/research.template.md +29 -0
- package/src/bmm-skills/1-analysis/research/scm-domain-research/workflow.md +51 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/SKILL.md +6 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/research.template.md +29 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-01-init.md +184 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-02-customer-behavior.md +239 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-03-customer-pain-points.md +251 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-04-customer-decisions.md +261 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-05-competitive-analysis.md +173 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-06-research-completion.md +478 -0
- package/src/bmm-skills/1-analysis/research/scm-market-research/workflow.md +51 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/SKILL.md +6 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/research.template.md +29 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-01-init.md +137 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-02-technical-overview.md +239 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-03-integration-patterns.md +248 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-04-architectural-patterns.md +202 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-05-implementation-research.md +233 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-06-research-synthesis.md +487 -0
- package/src/bmm-skills/1-analysis/research/scm-technical-research/workflow.md +52 -0
- package/src/bmm-skills/1-analysis/scm-agent-analyst/SKILL.md +59 -0
- package/src/bmm-skills/1-analysis/scm-agent-analyst/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/1-analysis/scm-agent-tech-writer/SKILL.md +57 -0
- package/src/bmm-skills/1-analysis/scm-agent-tech-writer/explain-concept.md +20 -0
- package/src/bmm-skills/1-analysis/scm-agent-tech-writer/mermaid-gen.md +20 -0
- package/src/bmm-skills/1-analysis/scm-agent-tech-writer/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/1-analysis/scm-agent-tech-writer/validate-doc.md +19 -0
- package/src/bmm-skills/1-analysis/scm-agent-tech-writer/write-document.md +20 -0
- package/src/bmm-skills/1-analysis/scm-document-project/SKILL.md +6 -0
- package/src/bmm-skills/1-analysis/scm-document-project/checklist.md +245 -0
- package/src/bmm-skills/1-analysis/scm-document-project/documentation-requirements.csv +12 -0
- package/src/bmm-skills/1-analysis/scm-document-project/instructions.md +128 -0
- package/src/bmm-skills/1-analysis/scm-document-project/templates/deep-dive-template.md +345 -0
- package/src/bmm-skills/1-analysis/scm-document-project/templates/index-template.md +169 -0
- package/src/bmm-skills/1-analysis/scm-document-project/templates/project-overview-template.md +103 -0
- package/src/bmm-skills/1-analysis/scm-document-project/templates/project-scan-report-schema.json +160 -0
- package/src/bmm-skills/1-analysis/scm-document-project/templates/source-tree-template.md +135 -0
- package/src/bmm-skills/1-analysis/scm-document-project/workflow.md +25 -0
- package/src/bmm-skills/1-analysis/scm-document-project/workflows/deep-dive-instructions.md +299 -0
- package/src/bmm-skills/1-analysis/scm-document-project/workflows/deep-dive-workflow.md +34 -0
- package/src/bmm-skills/1-analysis/scm-document-project/workflows/full-scan-instructions.md +1107 -0
- package/src/bmm-skills/1-analysis/scm-document-project/workflows/full-scan-workflow.md +34 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/SKILL.md +96 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/agents/artifact-analyzer.md +60 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/agents/web-researcher.md +49 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/assets/prfaq-template.md +62 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/references/customer-faq.md +55 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/references/internal-faq.md +51 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/references/press-release.md +60 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/references/verdict.md +79 -0
- package/src/bmm-skills/1-analysis/scm-prfaq/scm-manifest.json +16 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/SKILL.md +82 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/agents/artifact-analyzer.md +60 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/agents/opportunity-reviewer.md +44 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/agents/skeptic-reviewer.md +44 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/agents/web-researcher.md +49 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/prompts/contextual-discovery.md +57 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/prompts/draft-and-review.md +86 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/prompts/finalize.md +75 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/prompts/guided-elicitation.md +70 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/resources/brief-template.md +60 -0
- package/src/bmm-skills/1-analysis/scm-product-brief/scm-manifest.json +17 -0
- package/src/bmm-skills/2-plan-workflows/scm-agent-pm/SKILL.md +59 -0
- package/src/bmm-skills/2-plan-workflows/scm-agent-pm/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/2-plan-workflows/scm-agent-ux-designer/SKILL.md +55 -0
- package/src/bmm-skills/2-plan-workflows/scm-agent-ux-designer/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/SKILL.md +6 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/data/domain-complexity.csv +15 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/data/prd-purpose.md +197 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/data/project-types.csv +11 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-01-init.md +178 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-01b-continue.md +161 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-02-discovery.md +208 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-02b-vision.md +142 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-02c-executive-summary.md +158 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-03-success.md +214 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-04-journeys.md +201 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-05-domain.md +194 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-06-innovation.md +211 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-07-project-type.md +222 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-08-scoping.md +216 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-09-functional.md +219 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-10-nonfunctional.md +230 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-11-polish.md +221 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-12-complete.md +115 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/templates/prd-template.md +10 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-prd/workflow.md +61 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/SKILL.md +6 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-01-init.md +135 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-01b-continue.md +127 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-02-discovery.md +190 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-03-core-experience.md +217 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-04-emotional-response.md +220 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-05-inspiration.md +235 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-06-design-system.md +253 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-07-defining-experience.md +255 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-08-visual-foundation.md +225 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-09-design-directions.md +225 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-10-user-journeys.md +242 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-11-component-strategy.md +249 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-12-ux-patterns.md +238 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-13-responsive-accessibility.md +265 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-14-complete.md +171 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/ux-design-template.md +13 -0
- package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/workflow.md +35 -0
- package/src/bmm-skills/2-plan-workflows/scm-edit-prd/SKILL.md +6 -0
- package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-01-discovery.md +242 -0
- package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-01b-legacy-conversion.md +204 -0
- package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-02-review.md +245 -0
- package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-03-edit.md +250 -0
- package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-04-complete.md +165 -0
- package/src/bmm-skills/2-plan-workflows/scm-edit-prd/workflow.md +62 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/SKILL.md +6 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/data/domain-complexity.csv +15 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/data/prd-purpose.md +197 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/data/project-types.csv +11 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-01-discovery.md +221 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-02-format-detection.md +188 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-02b-parity-check.md +206 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-03-density-validation.md +171 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-04-brief-coverage-validation.md +211 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-05-measurability-validation.md +225 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-06-traceability-validation.md +214 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-07-implementation-leakage-validation.md +202 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-08-domain-compliance-validation.md +240 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-09-project-type-validation.md +260 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-10-smart-validation.md +206 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-11-holistic-quality-validation.md +261 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-12-completeness-validation.md +239 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-13-report-complete.md +229 -0
- package/src/bmm-skills/2-plan-workflows/scm-validate-prd/workflow.md +61 -0
- package/src/bmm-skills/3-solutioning/scm-agent-architect/SKILL.md +54 -0
- package/src/bmm-skills/3-solutioning/scm-agent-architect/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/SKILL.md +6 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-01-document-discovery.md +179 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-02-prd-analysis.md +168 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-03-epic-coverage-validation.md +169 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-04-ux-alignment.md +129 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-05-epic-quality-review.md +241 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-06-final-assessment.md +126 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/templates/readiness-report-template.md +4 -0
- package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/workflow.md +47 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/SKILL.md +6 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/architecture-decision-template.md +12 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/data/domain-complexity.csv +13 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/data/project-types.csv +7 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-01-init.md +153 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-01b-continue.md +173 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-02-context.md +224 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-03-starter.md +329 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-04-decisions.md +318 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-05-patterns.md +359 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-06-structure.md +379 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-07-validation.md +359 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-08-complete.md +76 -0
- package/src/bmm-skills/3-solutioning/scm-create-architecture/workflow.md +32 -0
- package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/SKILL.md +6 -0
- package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/steps/step-01-validate-prerequisites.md +255 -0
- package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/steps/step-02-design-epics.md +212 -0
- package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
- package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/steps/step-04-final-validation.md +131 -0
- package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/templates/epics-template.md +61 -0
- package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/workflow.md +51 -0
- package/src/bmm-skills/3-solutioning/scm-generate-project-context/SKILL.md +6 -0
- package/src/bmm-skills/3-solutioning/scm-generate-project-context/project-context-template.md +21 -0
- package/src/bmm-skills/3-solutioning/scm-generate-project-context/steps/step-01-discover.md +186 -0
- package/src/bmm-skills/3-solutioning/scm-generate-project-context/steps/step-02-generate.md +321 -0
- package/src/bmm-skills/3-solutioning/scm-generate-project-context/steps/step-03-complete.md +278 -0
- package/src/bmm-skills/3-solutioning/scm-generate-project-context/workflow.md +39 -0
- package/src/bmm-skills/4-implementation/scm-agent-dev/SKILL.md +64 -0
- package/src/bmm-skills/4-implementation/scm-agent-dev/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/4-implementation/scm-agent-qa/SKILL.md +61 -0
- package/src/bmm-skills/4-implementation/scm-agent-qa/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/4-implementation/scm-agent-quick-flow-solo-dev/SKILL.md +53 -0
- package/src/bmm-skills/4-implementation/scm-agent-quick-flow-solo-dev/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/4-implementation/scm-agent-sm/SKILL.md +55 -0
- package/src/bmm-skills/4-implementation/scm-agent-sm/scm-skill-manifest.yaml +11 -0
- package/src/bmm-skills/4-implementation/scm-code-review/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-code-review/steps/step-01-gather-context.md +62 -0
- package/src/bmm-skills/4-implementation/scm-code-review/steps/step-02-review.md +34 -0
- package/src/bmm-skills/4-implementation/scm-code-review/steps/step-03-triage.md +49 -0
- package/src/bmm-skills/4-implementation/scm-code-review/steps/step-04-present.md +129 -0
- package/src/bmm-skills/4-implementation/scm-code-review/workflow.md +55 -0
- package/src/bmm-skills/4-implementation/scm-correct-course/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-correct-course/checklist.md +288 -0
- package/src/bmm-skills/4-implementation/scm-correct-course/workflow.md +267 -0
- package/src/bmm-skills/4-implementation/scm-create-story/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-create-story/checklist.md +357 -0
- package/src/bmm-skills/4-implementation/scm-create-story/discover-inputs.md +88 -0
- package/src/bmm-skills/4-implementation/scm-create-story/template.md +49 -0
- package/src/bmm-skills/4-implementation/scm-create-story/workflow.md +380 -0
- package/src/bmm-skills/4-implementation/scm-dev-story/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-dev-story/checklist.md +80 -0
- package/src/bmm-skills/4-implementation/scm-dev-story/workflow.md +450 -0
- package/src/bmm-skills/4-implementation/scm-qa-generate-e2e-tests/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-qa-generate-e2e-tests/checklist.md +33 -0
- package/src/bmm-skills/4-implementation/scm-qa-generate-e2e-tests/workflow.md +136 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/spec-template.md +88 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/step-01-clarify-and-route.md +66 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/step-02-plan.md +35 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/step-03-implement.md +37 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/step-04-review.md +49 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/step-05-present.md +63 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/step-oneshot.md +62 -0
- package/src/bmm-skills/4-implementation/scm-quick-dev/workflow.md +79 -0
- package/src/bmm-skills/4-implementation/scm-retrospective/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-retrospective/workflow.md +1479 -0
- package/src/bmm-skills/4-implementation/scm-sprint-planning/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-sprint-planning/checklist.md +33 -0
- package/src/bmm-skills/4-implementation/scm-sprint-planning/sprint-status-template.yaml +56 -0
- package/src/bmm-skills/4-implementation/scm-sprint-planning/workflow.md +263 -0
- package/src/bmm-skills/4-implementation/scm-sprint-status/SKILL.md +6 -0
- package/src/bmm-skills/4-implementation/scm-sprint-status/workflow.md +261 -0
- package/src/bmm-skills/module-help.csv +31 -0
- package/src/bmm-skills/module.yaml +50 -0
- package/src/core-skills/module-help.csv +11 -0
- package/src/core-skills/module.yaml +25 -0
- package/src/core-skills/scm-advanced-elicitation/SKILL.md +136 -0
- package/src/core-skills/scm-advanced-elicitation/methods.csv +51 -0
- package/src/core-skills/scm-brainstorming/SKILL.md +6 -0
- package/src/core-skills/scm-brainstorming/brain-methods.csv +62 -0
- package/src/core-skills/scm-brainstorming/steps/step-01-session-setup.md +214 -0
- package/src/core-skills/scm-brainstorming/steps/step-01b-continue.md +124 -0
- package/src/core-skills/scm-brainstorming/steps/step-02a-user-selected.md +229 -0
- package/src/core-skills/scm-brainstorming/steps/step-02b-ai-recommended.md +239 -0
- package/src/core-skills/scm-brainstorming/steps/step-02c-random-selection.md +211 -0
- package/src/core-skills/scm-brainstorming/steps/step-02d-progressive-flow.md +266 -0
- package/src/core-skills/scm-brainstorming/steps/step-03-technique-execution.md +401 -0
- package/src/core-skills/scm-brainstorming/steps/step-04-idea-organization.md +305 -0
- package/src/core-skills/scm-brainstorming/template.md +15 -0
- package/src/core-skills/scm-brainstorming/workflow.md +53 -0
- package/src/core-skills/scm-distillator/SKILL.md +177 -0
- package/src/core-skills/scm-distillator/agents/distillate-compressor.md +116 -0
- package/src/core-skills/scm-distillator/agents/round-trip-reconstructor.md +68 -0
- package/src/core-skills/scm-distillator/resources/compression-rules.md +51 -0
- package/src/core-skills/scm-distillator/resources/distillate-format-reference.md +227 -0
- package/src/core-skills/scm-distillator/resources/splitting-strategy.md +78 -0
- package/src/core-skills/scm-distillator/scripts/analyze_sources.py +300 -0
- package/src/core-skills/scm-distillator/scripts/tests/test_analyze_sources.py +204 -0
- package/src/core-skills/scm-editorial-review-prose/SKILL.md +86 -0
- package/src/core-skills/scm-editorial-review-structure/SKILL.md +179 -0
- package/src/core-skills/scm-help/SKILL.md +73 -0
- package/src/core-skills/scm-index-docs/SKILL.md +66 -0
- package/src/core-skills/scm-party-mode/SKILL.md +125 -0
- package/src/core-skills/scm-review-adversarial-general/SKILL.md +37 -0
- package/src/core-skills/scm-review-edge-case-hunter/SKILL.md +67 -0
- package/src/core-skills/scm-shard-doc/SKILL.md +105 -0
- package/tools/format-workflow-md.js +263 -0
- package/tools/installer/README.md +60 -0
- package/tools/installer/cli-utils.js +181 -0
- package/tools/installer/commands/install.js +80 -0
- package/tools/installer/commands/status.js +65 -0
- package/tools/installer/commands/uninstall.js +167 -0
- package/tools/installer/core/config.js +52 -0
- package/tools/installer/core/custom-module-cache.js +260 -0
- package/tools/installer/core/existing-install.js +127 -0
- package/tools/installer/core/install-paths.js +129 -0
- package/tools/installer/core/installer.js +1790 -0
- package/tools/installer/core/manifest-generator.js +701 -0
- package/tools/installer/core/manifest.js +1040 -0
- package/tools/installer/custom-handler.js +112 -0
- package/tools/installer/external-official-modules.yaml +63 -0
- package/tools/installer/file-ops.js +204 -0
- package/tools/installer/ide/_config-driven.js +536 -0
- package/tools/installer/ide/manager.js +247 -0
- package/tools/installer/ide/platform-codes.js +37 -0
- package/tools/installer/ide/platform-codes.yaml +192 -0
- package/tools/installer/ide/shared/agent-command-generator.js +180 -0
- package/tools/installer/ide/shared/module-injections.js +136 -0
- package/tools/installer/ide/shared/path-utils.js +364 -0
- package/tools/installer/ide/shared/scm-artifacts.js +208 -0
- package/tools/installer/ide/shared/skill-manifest.js +72 -0
- package/tools/installer/ide/templates/agent-command-template.md +14 -0
- package/tools/installer/ide/templates/combined/antigravity.md +8 -0
- package/tools/installer/ide/templates/combined/default-agent.md +15 -0
- package/tools/installer/ide/templates/combined/default-task.md +10 -0
- package/tools/installer/ide/templates/combined/default-tool.md +10 -0
- package/tools/installer/ide/templates/combined/default-workflow.md +6 -0
- package/tools/installer/ide/templates/combined/gemini-agent.toml +14 -0
- package/tools/installer/ide/templates/combined/gemini-task.toml +11 -0
- package/tools/installer/ide/templates/combined/gemini-tool.toml +11 -0
- package/tools/installer/ide/templates/combined/gemini-workflow-yaml.toml +16 -0
- package/tools/installer/ide/templates/combined/gemini-workflow.toml +14 -0
- package/tools/installer/ide/templates/combined/kiro-agent.md +16 -0
- package/tools/installer/ide/templates/combined/kiro-task.md +9 -0
- package/tools/installer/ide/templates/combined/kiro-tool.md +9 -0
- package/tools/installer/ide/templates/combined/kiro-workflow.md +7 -0
- package/tools/installer/ide/templates/combined/opencode-agent.md +15 -0
- package/tools/installer/ide/templates/combined/opencode-task.md +13 -0
- package/tools/installer/ide/templates/combined/opencode-tool.md +13 -0
- package/tools/installer/ide/templates/combined/opencode-workflow-yaml.md +16 -0
- package/tools/installer/ide/templates/combined/opencode-workflow.md +16 -0
- package/tools/installer/ide/templates/combined/rovodev.md +9 -0
- package/tools/installer/ide/templates/combined/trae.md +9 -0
- package/tools/installer/ide/templates/combined/windsurf-workflow.md +10 -0
- package/tools/installer/ide/templates/split/.gitkeep +0 -0
- package/tools/installer/install-messages.yaml +35 -0
- package/tools/installer/message-loader.js +83 -0
- package/tools/installer/modules/custom-modules.js +197 -0
- package/tools/installer/modules/external-manager.js +354 -0
- package/tools/installer/modules/official-modules.js +2043 -0
- package/tools/installer/project-root.js +77 -0
- package/tools/installer/prompts.js +809 -0
- package/tools/installer/scm-cli.js +108 -0
- package/tools/installer/ui.js +1683 -0
- package/tools/installer/yaml-format.js +245 -0
- package/tools/javascript-conventions.md +5 -0
- package/tools/migrate-custom-module-paths.js +124 -0
- package/tools/platform-codes.yaml +169 -0
- package/tools/validate-skills.js +736 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
const path = require('node:path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const prompts = require('../prompts');
|
|
4
|
+
const { Installer } = require('../core/installer');
|
|
5
|
+
|
|
6
|
+
const installer = new Installer();
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
command: 'uninstall',
|
|
10
|
+
description: 'Remove SCM installation from the current project',
|
|
11
|
+
options: [
|
|
12
|
+
['-y, --yes', 'Remove all SCM components without prompting (preserves user artifacts)'],
|
|
13
|
+
['--directory <path>', 'Project directory (default: current directory)'],
|
|
14
|
+
],
|
|
15
|
+
action: async (options) => {
|
|
16
|
+
try {
|
|
17
|
+
let projectDir;
|
|
18
|
+
|
|
19
|
+
if (options.directory) {
|
|
20
|
+
// Explicit --directory flag takes precedence
|
|
21
|
+
projectDir = path.resolve(options.directory);
|
|
22
|
+
} else if (options.yes) {
|
|
23
|
+
// Non-interactive mode: use current directory
|
|
24
|
+
projectDir = process.cwd();
|
|
25
|
+
} else {
|
|
26
|
+
// Interactive: ask user which directory to uninstall from
|
|
27
|
+
// select() handles cancellation internally (exits process)
|
|
28
|
+
const dirChoice = await prompts.select({
|
|
29
|
+
message: 'Where do you want to uninstall SCM from?',
|
|
30
|
+
choices: [
|
|
31
|
+
{ value: 'cwd', name: `Current directory (${process.cwd()})` },
|
|
32
|
+
{ value: 'other', name: 'Another directory...' },
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (dirChoice === 'other') {
|
|
37
|
+
// text() handles cancellation internally (exits process)
|
|
38
|
+
const customDir = await prompts.text({
|
|
39
|
+
message: 'Enter the project directory path:',
|
|
40
|
+
placeholder: process.cwd(),
|
|
41
|
+
validate: (value) => {
|
|
42
|
+
if (!value || value.trim().length === 0) return 'Directory path is required';
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
projectDir = path.resolve(customDir.trim());
|
|
47
|
+
} else {
|
|
48
|
+
projectDir = process.cwd();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!(await fs.pathExists(projectDir))) {
|
|
53
|
+
await prompts.log.error(`Directory does not exist: ${projectDir}`);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { scmDir } = await installer.findBmadDir(projectDir);
|
|
58
|
+
|
|
59
|
+
if (!(await fs.pathExists(scmDir))) {
|
|
60
|
+
await prompts.log.warn('No SCM installation found.');
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const existingInstall = await installer.getStatus(projectDir);
|
|
65
|
+
const version = existingInstall.installed ? existingInstall.version : 'unknown';
|
|
66
|
+
const modules = existingInstall.moduleIds.join(', ');
|
|
67
|
+
const ides = existingInstall.ides.join(', ');
|
|
68
|
+
|
|
69
|
+
const outputFolder = await installer.getOutputFolder(projectDir);
|
|
70
|
+
|
|
71
|
+
await prompts.intro('SCM Uninstall');
|
|
72
|
+
await prompts.note(`Version: ${version}\nModules: ${modules}\nIDE integrations: ${ides}`, 'Current Installation');
|
|
73
|
+
|
|
74
|
+
let removeModules = true;
|
|
75
|
+
let removeIdeConfigs = true;
|
|
76
|
+
let removeOutputFolder = false;
|
|
77
|
+
|
|
78
|
+
if (!options.yes) {
|
|
79
|
+
// multiselect() handles cancellation internally (exits process)
|
|
80
|
+
const selected = await prompts.multiselect({
|
|
81
|
+
message: 'Select components to remove:',
|
|
82
|
+
options: [
|
|
83
|
+
{
|
|
84
|
+
value: 'modules',
|
|
85
|
+
label: `SCM Modules & data (${installer.scmFolderName}/)`,
|
|
86
|
+
hint: 'Core installation, agents, workflows, config',
|
|
87
|
+
},
|
|
88
|
+
{ value: 'ide', label: 'IDE integrations', hint: ides || 'No IDEs configured' },
|
|
89
|
+
{ value: 'output', label: `User artifacts (${outputFolder}/)`, hint: 'WARNING: Contains your work products' },
|
|
90
|
+
],
|
|
91
|
+
initialValues: ['modules', 'ide'],
|
|
92
|
+
required: true,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
removeModules = selected.includes('modules');
|
|
96
|
+
removeIdeConfigs = selected.includes('ide');
|
|
97
|
+
removeOutputFolder = selected.includes('output');
|
|
98
|
+
|
|
99
|
+
const red = (s) => `\u001B[31m${s}\u001B[0m`;
|
|
100
|
+
await prompts.note(
|
|
101
|
+
red('💀 This action is IRREVERSIBLE! Removed files cannot be recovered!') +
|
|
102
|
+
'\n' +
|
|
103
|
+
red('💀 IDE configurations and modules will need to be reinstalled.') +
|
|
104
|
+
'\n' +
|
|
105
|
+
red('💀 User artifacts are preserved unless explicitly selected.'),
|
|
106
|
+
'!! DESTRUCTIVE ACTION !!',
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const confirmed = await prompts.confirm({
|
|
110
|
+
message: 'Proceed with uninstall?',
|
|
111
|
+
default: false,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (!confirmed) {
|
|
115
|
+
await prompts.outro('Uninstall cancelled.');
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Phase 1: IDE integrations
|
|
121
|
+
if (removeIdeConfigs) {
|
|
122
|
+
const s = await prompts.spinner();
|
|
123
|
+
s.start('Removing IDE integrations...');
|
|
124
|
+
await installer.uninstallIdeConfigs(projectDir, existingInstall, { silent: true });
|
|
125
|
+
s.stop(`Removed IDE integrations (${ides || 'none'})`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Phase 2: User artifacts
|
|
129
|
+
if (removeOutputFolder) {
|
|
130
|
+
const s = await prompts.spinner();
|
|
131
|
+
s.start(`Removing user artifacts (${outputFolder}/)...`);
|
|
132
|
+
await installer.uninstallOutputFolder(projectDir, outputFolder);
|
|
133
|
+
s.stop('User artifacts removed');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Phase 3: SCM modules & data (last — other phases may need _scm/)
|
|
137
|
+
if (removeModules) {
|
|
138
|
+
const s = await prompts.spinner();
|
|
139
|
+
s.start(`Removing SCM modules & data (${installer.scmFolderName}/)...`);
|
|
140
|
+
await installer.uninstallModules(projectDir);
|
|
141
|
+
s.stop('Modules & data removed');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const summary = [];
|
|
145
|
+
if (removeIdeConfigs) summary.push('IDE integrations cleaned');
|
|
146
|
+
if (removeModules) summary.push('Modules & data removed');
|
|
147
|
+
if (removeOutputFolder) summary.push('User artifacts removed');
|
|
148
|
+
if (!removeOutputFolder) summary.push(`User artifacts preserved in ${outputFolder}/`);
|
|
149
|
+
|
|
150
|
+
await prompts.note(summary.join('\n'), 'Summary');
|
|
151
|
+
await prompts.outro('To reinstall, run: npx SCM-method install');
|
|
152
|
+
|
|
153
|
+
process.exit(0);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
try {
|
|
156
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
157
|
+
await prompts.log.error(`Uninstall failed: ${errorMessage}`);
|
|
158
|
+
if (error instanceof Error && error.stack) {
|
|
159
|
+
await prompts.log.message(error.stack);
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
console.error(error instanceof Error ? error.message : error);
|
|
163
|
+
}
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean install configuration built from user input.
|
|
3
|
+
* User input comes from either UI answers or headless CLI flags.
|
|
4
|
+
*/
|
|
5
|
+
class Config {
|
|
6
|
+
constructor({ directory, modules, ides, skipPrompts, verbose, actionType, coreConfig, moduleConfigs, quickUpdate }) {
|
|
7
|
+
this.directory = directory;
|
|
8
|
+
this.modules = Object.freeze([...modules]);
|
|
9
|
+
this.ides = Object.freeze([...ides]);
|
|
10
|
+
this.skipPrompts = skipPrompts;
|
|
11
|
+
this.verbose = verbose;
|
|
12
|
+
this.actionType = actionType;
|
|
13
|
+
this.coreConfig = coreConfig;
|
|
14
|
+
this.moduleConfigs = moduleConfigs;
|
|
15
|
+
this._quickUpdate = quickUpdate;
|
|
16
|
+
Object.freeze(this);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Build a clean install config from raw user input.
|
|
21
|
+
* @param {Object} userInput - UI answers or CLI flags
|
|
22
|
+
* @returns {Config}
|
|
23
|
+
*/
|
|
24
|
+
static build(userInput) {
|
|
25
|
+
const modules = [...(userInput.modules || [])];
|
|
26
|
+
if (userInput.installCore && !modules.includes('core')) {
|
|
27
|
+
modules.unshift('core');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return new Config({
|
|
31
|
+
directory: userInput.directory,
|
|
32
|
+
modules,
|
|
33
|
+
ides: userInput.skipIde ? [] : [...(userInput.ides || [])],
|
|
34
|
+
skipPrompts: userInput.skipPrompts || false,
|
|
35
|
+
verbose: userInput.verbose || false,
|
|
36
|
+
actionType: userInput.actionType,
|
|
37
|
+
coreConfig: userInput.coreConfig || {},
|
|
38
|
+
moduleConfigs: userInput.moduleConfigs || null,
|
|
39
|
+
quickUpdate: userInput._quickUpdate || false,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
hasCoreConfig() {
|
|
44
|
+
return this.coreConfig && Object.keys(this.coreConfig).length > 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
isQuickUpdate() {
|
|
48
|
+
return this._quickUpdate;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = { Config };
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Module Source Cache
|
|
3
|
+
* Caches custom module sources under _config/custom/ to ensure they're never lost
|
|
4
|
+
* and can be checked into source control
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const crypto = require('node:crypto');
|
|
10
|
+
const prompts = require('../prompts');
|
|
11
|
+
|
|
12
|
+
class CustomModuleCache {
|
|
13
|
+
constructor(scmDir) {
|
|
14
|
+
this.scmDir = scmDir;
|
|
15
|
+
this.customCacheDir = path.join(scmDir, '_config', 'custom');
|
|
16
|
+
this.manifestPath = path.join(this.customCacheDir, 'cache-manifest.yaml');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Ensure the custom cache directory exists
|
|
21
|
+
*/
|
|
22
|
+
async ensureCacheDir() {
|
|
23
|
+
await fs.ensureDir(this.customCacheDir);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get cache manifest
|
|
28
|
+
*/
|
|
29
|
+
async getCacheManifest() {
|
|
30
|
+
if (!(await fs.pathExists(this.manifestPath))) {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const content = await fs.readFile(this.manifestPath, 'utf8');
|
|
35
|
+
const yaml = require('yaml');
|
|
36
|
+
return yaml.parse(content) || {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Update cache manifest
|
|
41
|
+
*/
|
|
42
|
+
async updateCacheManifest(manifest) {
|
|
43
|
+
const yaml = require('yaml');
|
|
44
|
+
// Clean the manifest to remove any non-serializable values
|
|
45
|
+
const cleanManifest = structuredClone(manifest);
|
|
46
|
+
|
|
47
|
+
const content = yaml.stringify(cleanManifest, {
|
|
48
|
+
indent: 2,
|
|
49
|
+
lineWidth: 0,
|
|
50
|
+
sortKeys: false,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
await fs.writeFile(this.manifestPath, content);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Stream a file into the hash to avoid loading entire file into memory
|
|
58
|
+
*/
|
|
59
|
+
async hashFileStream(filePath, hash) {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
const stream = require('node:fs').createReadStream(filePath);
|
|
62
|
+
stream.on('data', (chunk) => hash.update(chunk));
|
|
63
|
+
stream.on('end', resolve);
|
|
64
|
+
stream.on('error', reject);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Calculate hash of a file or directory using streaming to minimize memory usage
|
|
70
|
+
*/
|
|
71
|
+
async calculateHash(sourcePath) {
|
|
72
|
+
const hash = crypto.createHash('sha256');
|
|
73
|
+
|
|
74
|
+
const isDir = (await fs.stat(sourcePath)).isDirectory();
|
|
75
|
+
|
|
76
|
+
if (isDir) {
|
|
77
|
+
// For directories, hash all files
|
|
78
|
+
const files = [];
|
|
79
|
+
async function collectFiles(dir) {
|
|
80
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (entry.isFile()) {
|
|
83
|
+
files.push(path.join(dir, entry.name));
|
|
84
|
+
} else if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
85
|
+
await collectFiles(path.join(dir, entry.name));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await collectFiles(sourcePath);
|
|
91
|
+
files.sort(); // Ensure consistent order
|
|
92
|
+
|
|
93
|
+
for (const file of files) {
|
|
94
|
+
const relativePath = path.relative(sourcePath, file);
|
|
95
|
+
// Hash the path first, then stream file contents
|
|
96
|
+
hash.update(relativePath + '|');
|
|
97
|
+
await this.hashFileStream(file, hash);
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
// For single files, stream directly into hash
|
|
101
|
+
await this.hashFileStream(sourcePath, hash);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return hash.digest('hex');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Cache a custom module source
|
|
109
|
+
* @param {string} moduleId - Module ID
|
|
110
|
+
* @param {string} sourcePath - Original source path
|
|
111
|
+
* @param {Object} metadata - Additional metadata to store
|
|
112
|
+
* @returns {Object} Cached module info
|
|
113
|
+
*/
|
|
114
|
+
async cacheModule(moduleId, sourcePath, metadata = {}) {
|
|
115
|
+
await this.ensureCacheDir();
|
|
116
|
+
|
|
117
|
+
const cacheDir = path.join(this.customCacheDir, moduleId);
|
|
118
|
+
const cacheManifest = await this.getCacheManifest();
|
|
119
|
+
|
|
120
|
+
// Check if already cached and unchanged
|
|
121
|
+
if (cacheManifest[moduleId]) {
|
|
122
|
+
const cached = cacheManifest[moduleId];
|
|
123
|
+
if (cached.originalHash && cached.originalHash === (await this.calculateHash(sourcePath))) {
|
|
124
|
+
// Source unchanged, return existing cache info
|
|
125
|
+
return {
|
|
126
|
+
moduleId,
|
|
127
|
+
cachePath: cacheDir,
|
|
128
|
+
...cached,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Remove existing cache if it exists
|
|
134
|
+
if (await fs.pathExists(cacheDir)) {
|
|
135
|
+
await fs.remove(cacheDir);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Copy module to cache
|
|
139
|
+
await fs.copy(sourcePath, cacheDir, {
|
|
140
|
+
filter: (src) => {
|
|
141
|
+
const relative = path.relative(sourcePath, src);
|
|
142
|
+
// Skip node_modules, .git, and other common ignore patterns
|
|
143
|
+
return !relative.includes('node_modules') && !relative.startsWith('.git') && !relative.startsWith('.DS_Store');
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Calculate hash of the source
|
|
148
|
+
const sourceHash = await this.calculateHash(sourcePath);
|
|
149
|
+
const cacheHash = await this.calculateHash(cacheDir);
|
|
150
|
+
|
|
151
|
+
// Update manifest - don't store absolute paths for portability
|
|
152
|
+
// Clean metadata to remove absolute paths
|
|
153
|
+
const cleanMetadata = { ...metadata };
|
|
154
|
+
if (cleanMetadata.sourcePath) {
|
|
155
|
+
delete cleanMetadata.sourcePath;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
cacheManifest[moduleId] = {
|
|
159
|
+
originalHash: sourceHash,
|
|
160
|
+
cacheHash: cacheHash,
|
|
161
|
+
cachedAt: new Date().toISOString(),
|
|
162
|
+
...cleanMetadata,
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
await this.updateCacheManifest(cacheManifest);
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
moduleId,
|
|
169
|
+
cachePath: cacheDir,
|
|
170
|
+
...cacheManifest[moduleId],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get cached module info
|
|
176
|
+
* @param {string} moduleId - Module ID
|
|
177
|
+
* @returns {Object|null} Cached module info or null
|
|
178
|
+
*/
|
|
179
|
+
async getCachedModule(moduleId) {
|
|
180
|
+
const cacheManifest = await this.getCacheManifest();
|
|
181
|
+
const cached = cacheManifest[moduleId];
|
|
182
|
+
|
|
183
|
+
if (!cached) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const cacheDir = path.join(this.customCacheDir, moduleId);
|
|
188
|
+
|
|
189
|
+
if (!(await fs.pathExists(cacheDir))) {
|
|
190
|
+
// Cache dir missing, remove from manifest
|
|
191
|
+
delete cacheManifest[moduleId];
|
|
192
|
+
await this.updateCacheManifest(cacheManifest);
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Verify cache integrity
|
|
197
|
+
const currentCacheHash = await this.calculateHash(cacheDir);
|
|
198
|
+
if (currentCacheHash !== cached.cacheHash) {
|
|
199
|
+
await prompts.log.warn(`Cache integrity check failed for ${moduleId}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
moduleId,
|
|
204
|
+
cachePath: cacheDir,
|
|
205
|
+
...cached,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get all cached modules
|
|
211
|
+
* @returns {Array} Array of cached module info
|
|
212
|
+
*/
|
|
213
|
+
async getAllCachedModules() {
|
|
214
|
+
const cacheManifest = await this.getCacheManifest();
|
|
215
|
+
const cached = [];
|
|
216
|
+
|
|
217
|
+
for (const [moduleId, info] of Object.entries(cacheManifest)) {
|
|
218
|
+
const cachedModule = await this.getCachedModule(moduleId);
|
|
219
|
+
if (cachedModule) {
|
|
220
|
+
cached.push(cachedModule);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return cached;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Remove a cached module
|
|
229
|
+
* @param {string} moduleId - Module ID to remove
|
|
230
|
+
*/
|
|
231
|
+
async removeCachedModule(moduleId) {
|
|
232
|
+
const cacheManifest = await this.getCacheManifest();
|
|
233
|
+
const cacheDir = path.join(this.customCacheDir, moduleId);
|
|
234
|
+
|
|
235
|
+
// Remove cache directory
|
|
236
|
+
if (await fs.pathExists(cacheDir)) {
|
|
237
|
+
await fs.remove(cacheDir);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Remove from manifest
|
|
241
|
+
delete cacheManifest[moduleId];
|
|
242
|
+
await this.updateCacheManifest(cacheManifest);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Sync cached modules with a list of module IDs
|
|
247
|
+
* @param {Array<string>} moduleIds - Module IDs to keep
|
|
248
|
+
*/
|
|
249
|
+
async syncCache(moduleIds) {
|
|
250
|
+
const cached = await this.getAllCachedModules();
|
|
251
|
+
|
|
252
|
+
for (const cachedModule of cached) {
|
|
253
|
+
if (!moduleIds.includes(cachedModule.moduleId)) {
|
|
254
|
+
await this.removeCachedModule(cachedModule.moduleId);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
module.exports = { CustomModuleCache };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const path = require('node:path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const yaml = require('yaml');
|
|
4
|
+
const { Manifest } = require('./manifest');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Immutable snapshot of an existing SCM installation.
|
|
8
|
+
* Pure query object — no filesystem operations after construction.
|
|
9
|
+
*/
|
|
10
|
+
class ExistingInstall {
|
|
11
|
+
#version;
|
|
12
|
+
|
|
13
|
+
constructor({ installed, version, hasCore, modules, ides, customModules }) {
|
|
14
|
+
this.installed = installed;
|
|
15
|
+
this.#version = version;
|
|
16
|
+
this.hasCore = hasCore;
|
|
17
|
+
this.modules = Object.freeze(modules.map((m) => Object.freeze({ ...m })));
|
|
18
|
+
this.moduleIds = Object.freeze(this.modules.map((m) => m.id));
|
|
19
|
+
this.ides = Object.freeze([...ides]);
|
|
20
|
+
this.customModules = Object.freeze([...customModules]);
|
|
21
|
+
Object.freeze(this);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get version() {
|
|
25
|
+
if (!this.installed) {
|
|
26
|
+
throw new Error('version is not available when nothing is installed');
|
|
27
|
+
}
|
|
28
|
+
return this.#version;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static empty() {
|
|
32
|
+
return new ExistingInstall({
|
|
33
|
+
installed: false,
|
|
34
|
+
version: null,
|
|
35
|
+
hasCore: false,
|
|
36
|
+
modules: [],
|
|
37
|
+
ides: [],
|
|
38
|
+
customModules: [],
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Scan a scm directory and return an immutable snapshot of what's installed.
|
|
44
|
+
* @param {string} scmDir - Path to scm directory
|
|
45
|
+
* @returns {Promise<ExistingInstall>}
|
|
46
|
+
*/
|
|
47
|
+
static async detect(scmDir) {
|
|
48
|
+
if (!(await fs.pathExists(scmDir))) {
|
|
49
|
+
return ExistingInstall.empty();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let version = null;
|
|
53
|
+
let hasCore = false;
|
|
54
|
+
const modules = [];
|
|
55
|
+
let ides = [];
|
|
56
|
+
let customModules = [];
|
|
57
|
+
|
|
58
|
+
const manifest = new Manifest();
|
|
59
|
+
const manifestData = await manifest.read(scmDir);
|
|
60
|
+
if (manifestData) {
|
|
61
|
+
version = manifestData.version;
|
|
62
|
+
if (manifestData.customModules) {
|
|
63
|
+
customModules = manifestData.customModules;
|
|
64
|
+
}
|
|
65
|
+
if (manifestData.ides) {
|
|
66
|
+
ides = manifestData.ides.filter((ide) => ide && typeof ide === 'string');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const corePath = path.join(scmDir, 'core');
|
|
71
|
+
if (await fs.pathExists(corePath)) {
|
|
72
|
+
hasCore = true;
|
|
73
|
+
|
|
74
|
+
if (!version) {
|
|
75
|
+
const coreConfigPath = path.join(corePath, 'config.yaml');
|
|
76
|
+
if (await fs.pathExists(coreConfigPath)) {
|
|
77
|
+
try {
|
|
78
|
+
const configContent = await fs.readFile(coreConfigPath, 'utf8');
|
|
79
|
+
const config = yaml.parse(configContent);
|
|
80
|
+
if (config.version) {
|
|
81
|
+
version = config.version;
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
// Ignore config read errors
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (manifestData && manifestData.modules && manifestData.modules.length > 0) {
|
|
91
|
+
for (const moduleId of manifestData.modules) {
|
|
92
|
+
const modulePath = path.join(scmDir, moduleId);
|
|
93
|
+
const moduleConfigPath = path.join(modulePath, 'config.yaml');
|
|
94
|
+
|
|
95
|
+
const moduleInfo = {
|
|
96
|
+
id: moduleId,
|
|
97
|
+
path: modulePath,
|
|
98
|
+
version: 'unknown',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
if (await fs.pathExists(moduleConfigPath)) {
|
|
102
|
+
try {
|
|
103
|
+
const configContent = await fs.readFile(moduleConfigPath, 'utf8');
|
|
104
|
+
const config = yaml.parse(configContent);
|
|
105
|
+
moduleInfo.version = config.version || 'unknown';
|
|
106
|
+
moduleInfo.name = config.name || moduleId;
|
|
107
|
+
moduleInfo.description = config.description;
|
|
108
|
+
} catch {
|
|
109
|
+
// Ignore config read errors
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
modules.push(moduleInfo);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const installed = hasCore || modules.length > 0 || !!manifestData;
|
|
118
|
+
|
|
119
|
+
if (!installed) {
|
|
120
|
+
return ExistingInstall.empty();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return new ExistingInstall({ installed, version, hasCore, modules, ides, customModules });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
module.exports = { ExistingInstall };
|