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,197 @@
|
|
|
1
|
+
const path = require('node:path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const yaml = require('yaml');
|
|
4
|
+
const { CustomHandler } = require('../custom-handler');
|
|
5
|
+
const { Manifest } = require('../core/manifest');
|
|
6
|
+
const prompts = require('../prompts');
|
|
7
|
+
|
|
8
|
+
class CustomModules {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.paths = new Map();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
has(moduleCode) {
|
|
14
|
+
return this.paths.has(moduleCode);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get(moduleCode) {
|
|
18
|
+
return this.paths.get(moduleCode);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
set(moduleId, sourcePath) {
|
|
22
|
+
this.paths.set(moduleId, sourcePath);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Install a custom module from its source path.
|
|
27
|
+
* @param {string} moduleName - Module identifier
|
|
28
|
+
* @param {string} scmDir - Target scm directory
|
|
29
|
+
* @param {Function} fileTrackingCallback - Optional callback to track installed files
|
|
30
|
+
* @param {Object} options - Install options
|
|
31
|
+
* @param {Object} options.moduleConfig - Pre-collected module configuration
|
|
32
|
+
* @returns {Object} Install result
|
|
33
|
+
*/
|
|
34
|
+
async install(moduleName, scmDir, fileTrackingCallback = null, options = {}) {
|
|
35
|
+
const sourcePath = this.paths.get(moduleName);
|
|
36
|
+
if (!sourcePath) {
|
|
37
|
+
throw new Error(`No source path for custom module '${moduleName}'`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!(await fs.pathExists(sourcePath))) {
|
|
41
|
+
throw new Error(`Source for custom module '${moduleName}' not found at: ${sourcePath}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const targetPath = path.join(scmDir, moduleName);
|
|
45
|
+
|
|
46
|
+
// Read custom.yaml and merge into module config
|
|
47
|
+
let moduleConfig = options.moduleConfig ? { ...options.moduleConfig } : {};
|
|
48
|
+
const customConfigPath = path.join(sourcePath, 'custom.yaml');
|
|
49
|
+
if (await fs.pathExists(customConfigPath)) {
|
|
50
|
+
try {
|
|
51
|
+
const content = await fs.readFile(customConfigPath, 'utf8');
|
|
52
|
+
const customConfig = yaml.parse(content);
|
|
53
|
+
if (customConfig) {
|
|
54
|
+
moduleConfig = { ...moduleConfig, ...customConfig };
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
await prompts.log.warn(`Failed to read custom.yaml for ${moduleName}: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Remove existing installation
|
|
62
|
+
if (await fs.pathExists(targetPath)) {
|
|
63
|
+
await fs.remove(targetPath);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Copy files with filtering
|
|
67
|
+
await this._copyWithFiltering(sourcePath, targetPath, fileTrackingCallback);
|
|
68
|
+
|
|
69
|
+
// Add to manifest
|
|
70
|
+
const manifest = new Manifest();
|
|
71
|
+
const versionInfo = await manifest.getModuleVersionInfo(moduleName, scmDir, sourcePath);
|
|
72
|
+
await manifest.addModule(scmDir, moduleName, {
|
|
73
|
+
version: versionInfo.version,
|
|
74
|
+
source: versionInfo.source,
|
|
75
|
+
npmPackage: versionInfo.npmPackage,
|
|
76
|
+
repoUrl: versionInfo.repoUrl,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return { success: true, module: moduleName, path: targetPath, moduleConfig };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Copy module files, filtering out install-time-only artifacts.
|
|
84
|
+
* @param {string} sourcePath - Source module directory
|
|
85
|
+
* @param {string} targetPath - Target module directory
|
|
86
|
+
* @param {Function} fileTrackingCallback - Optional callback to track installed files
|
|
87
|
+
*/
|
|
88
|
+
async _copyWithFiltering(sourcePath, targetPath, fileTrackingCallback = null) {
|
|
89
|
+
const files = await this._getFileList(sourcePath);
|
|
90
|
+
|
|
91
|
+
for (const file of files) {
|
|
92
|
+
if (file.startsWith('sub-modules/')) continue;
|
|
93
|
+
|
|
94
|
+
const isInSidecar = path
|
|
95
|
+
.dirname(file)
|
|
96
|
+
.split('/')
|
|
97
|
+
.some((dir) => dir.toLowerCase().endsWith('-sidecar'));
|
|
98
|
+
if (isInSidecar) continue;
|
|
99
|
+
|
|
100
|
+
if (file === 'module.yaml') continue;
|
|
101
|
+
if (file === 'config.yaml') continue;
|
|
102
|
+
|
|
103
|
+
const sourceFile = path.join(sourcePath, file);
|
|
104
|
+
const targetFile = path.join(targetPath, file);
|
|
105
|
+
|
|
106
|
+
// Skip web-only agents
|
|
107
|
+
if (file.startsWith('agents/') && file.endsWith('.md')) {
|
|
108
|
+
const content = await fs.readFile(sourceFile, 'utf8');
|
|
109
|
+
if (/<agent[^>]*\slocalskip="true"[^>]*>/.test(content)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
await fs.ensureDir(path.dirname(targetFile));
|
|
115
|
+
await fs.copy(sourceFile, targetFile, { overwrite: true });
|
|
116
|
+
|
|
117
|
+
if (fileTrackingCallback) {
|
|
118
|
+
fileTrackingCallback(targetFile);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Recursively list all files in a directory.
|
|
125
|
+
* @param {string} dir - Directory to scan
|
|
126
|
+
* @param {string} baseDir - Base directory for relative paths
|
|
127
|
+
* @returns {string[]} Relative file paths
|
|
128
|
+
*/
|
|
129
|
+
async _getFileList(dir, baseDir = dir) {
|
|
130
|
+
const files = [];
|
|
131
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
132
|
+
|
|
133
|
+
for (const entry of entries) {
|
|
134
|
+
const fullPath = path.join(dir, entry.name);
|
|
135
|
+
if (entry.isDirectory()) {
|
|
136
|
+
files.push(...(await this._getFileList(fullPath, baseDir)));
|
|
137
|
+
} else {
|
|
138
|
+
files.push(path.relative(baseDir, fullPath));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return files;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Discover custom module source paths from all available sources.
|
|
147
|
+
* @param {Object} config - Installation configuration
|
|
148
|
+
* @param {Object} paths - InstallPaths instance
|
|
149
|
+
* @returns {Map<string, string>} Map of module ID to source path
|
|
150
|
+
*/
|
|
151
|
+
async discoverPaths(config, paths) {
|
|
152
|
+
this.paths = new Map();
|
|
153
|
+
|
|
154
|
+
if (config._quickUpdate) {
|
|
155
|
+
if (config._customModuleSources) {
|
|
156
|
+
for (const [moduleId, customInfo] of config._customModuleSources) {
|
|
157
|
+
this.paths.set(moduleId, customInfo.sourcePath);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return this.paths;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// From UI: selectedFiles
|
|
164
|
+
if (config.customContent && config.customContent.selected && config.customContent.selectedFiles) {
|
|
165
|
+
const customHandler = new CustomHandler();
|
|
166
|
+
for (const customFile of config.customContent.selectedFiles) {
|
|
167
|
+
const customInfo = await customHandler.getCustomInfo(customFile, paths.projectRoot);
|
|
168
|
+
if (customInfo && customInfo.id) {
|
|
169
|
+
this.paths.set(customInfo.id, customInfo.path);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// From UI: sources
|
|
175
|
+
if (config.customContent && config.customContent.sources) {
|
|
176
|
+
for (const source of config.customContent.sources) {
|
|
177
|
+
this.paths.set(source.id, source.path);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// From UI: cachedModules
|
|
182
|
+
if (config.customContent && config.customContent.cachedModules) {
|
|
183
|
+
const selectedCachedIds = config.customContent.selectedCachedModules || [];
|
|
184
|
+
const shouldIncludeAll = selectedCachedIds.length === 0 && config.customContent.selected;
|
|
185
|
+
|
|
186
|
+
for (const cachedModule of config.customContent.cachedModules) {
|
|
187
|
+
if (cachedModule.id && cachedModule.cachePath && (shouldIncludeAll || selectedCachedIds.includes(cachedModule.id))) {
|
|
188
|
+
this.paths.set(cachedModule.id, cachedModule.cachePath);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return this.paths;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
module.exports = { CustomModules };
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const os = require('node:os');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { execSync } = require('node:child_process');
|
|
5
|
+
const yaml = require('yaml');
|
|
6
|
+
const prompts = require('../prompts');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Manages external official modules defined in external-official-modules.yaml
|
|
10
|
+
* These are modules hosted in external repositories that can be installed
|
|
11
|
+
*
|
|
12
|
+
* @class ExternalModuleManager
|
|
13
|
+
*/
|
|
14
|
+
class ExternalModuleManager {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.externalModulesConfigPath = path.join(__dirname, '../external-official-modules.yaml');
|
|
17
|
+
this.cachedModules = null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load and parse the external-official-modules.yaml file
|
|
22
|
+
* @returns {Object} Parsed YAML content with modules object
|
|
23
|
+
*/
|
|
24
|
+
async loadExternalModulesConfig() {
|
|
25
|
+
if (this.cachedModules) {
|
|
26
|
+
return this.cachedModules;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const content = await fs.readFile(this.externalModulesConfigPath, 'utf8');
|
|
31
|
+
const config = yaml.parse(content);
|
|
32
|
+
this.cachedModules = config;
|
|
33
|
+
return config;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
await prompts.log.warn(`Failed to load external modules config: ${error.message}`);
|
|
36
|
+
return { modules: {} };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get list of available external modules
|
|
42
|
+
* @returns {Array<Object>} Array of module info objects
|
|
43
|
+
*/
|
|
44
|
+
async listAvailable() {
|
|
45
|
+
const config = await this.loadExternalModulesConfig();
|
|
46
|
+
const modules = [];
|
|
47
|
+
|
|
48
|
+
for (const [key, moduleConfig] of Object.entries(config.modules || {})) {
|
|
49
|
+
modules.push({
|
|
50
|
+
key,
|
|
51
|
+
url: moduleConfig.url,
|
|
52
|
+
moduleDefinition: moduleConfig['module-definition'],
|
|
53
|
+
code: moduleConfig.code,
|
|
54
|
+
name: moduleConfig.name,
|
|
55
|
+
header: moduleConfig.header,
|
|
56
|
+
subheader: moduleConfig.subheader,
|
|
57
|
+
description: moduleConfig.description || '',
|
|
58
|
+
defaultSelected: moduleConfig.defaultSelected === true,
|
|
59
|
+
type: moduleConfig.type || 'community', // scm-org or community
|
|
60
|
+
npmPackage: moduleConfig.npmPackage || null, // Include npm package name
|
|
61
|
+
isExternal: true,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return modules;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get module info by code
|
|
70
|
+
* @param {string} code - The module code (e.g., 'cis')
|
|
71
|
+
* @returns {Object|null} Module info or null if not found
|
|
72
|
+
*/
|
|
73
|
+
async getModuleByCode(code) {
|
|
74
|
+
const modules = await this.listAvailable();
|
|
75
|
+
return modules.find((m) => m.code === code) || null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get module info by key
|
|
80
|
+
* @param {string} key - The module key (e.g., 'scm-creative-intelligence-suite')
|
|
81
|
+
* @returns {Object|null} Module info or null if not found
|
|
82
|
+
*/
|
|
83
|
+
async getModuleByKey(key) {
|
|
84
|
+
const config = await this.loadExternalModulesConfig();
|
|
85
|
+
const moduleConfig = config.modules?.[key];
|
|
86
|
+
|
|
87
|
+
if (!moduleConfig) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
key,
|
|
93
|
+
url: moduleConfig.url,
|
|
94
|
+
moduleDefinition: moduleConfig['module-definition'],
|
|
95
|
+
code: moduleConfig.code,
|
|
96
|
+
name: moduleConfig.name,
|
|
97
|
+
header: moduleConfig.header,
|
|
98
|
+
subheader: moduleConfig.subheader,
|
|
99
|
+
description: moduleConfig.description || '',
|
|
100
|
+
defaultSelected: moduleConfig.defaultSelected === true,
|
|
101
|
+
type: moduleConfig.type || 'community', // scm-org or community
|
|
102
|
+
npmPackage: moduleConfig.npmPackage || null, // Include npm package name
|
|
103
|
+
isExternal: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Check if a module code exists in external modules
|
|
109
|
+
* @param {string} code - The module code to check
|
|
110
|
+
* @returns {boolean} True if the module exists
|
|
111
|
+
*/
|
|
112
|
+
async hasModule(code) {
|
|
113
|
+
const module = await this.getModuleByCode(code);
|
|
114
|
+
return module !== null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get the URL for a module by code
|
|
119
|
+
* @param {string} code - The module code
|
|
120
|
+
* @returns {string|null} The URL or null if not found
|
|
121
|
+
*/
|
|
122
|
+
async getModuleUrl(code) {
|
|
123
|
+
const module = await this.getModuleByCode(code);
|
|
124
|
+
return module ? module.url : null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get the module definition path for a module by code
|
|
129
|
+
* @param {string} code - The module code
|
|
130
|
+
* @returns {string|null} The module definition path or null if not found
|
|
131
|
+
*/
|
|
132
|
+
async getModuleDefinition(code) {
|
|
133
|
+
const module = await this.getModuleByCode(code);
|
|
134
|
+
return module ? module.moduleDefinition : null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get the cache directory for external modules
|
|
139
|
+
* @returns {string} Path to the external modules cache directory
|
|
140
|
+
*/
|
|
141
|
+
getExternalCacheDir() {
|
|
142
|
+
const cacheDir = path.join(os.homedir(), '.scm', 'cache', 'external-modules');
|
|
143
|
+
return cacheDir;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Clone an external module repository to cache
|
|
148
|
+
* @param {string} moduleCode - Code of the external module
|
|
149
|
+
* @param {Object} options - Clone options
|
|
150
|
+
* @param {boolean} options.silent - Suppress spinner output
|
|
151
|
+
* @returns {string} Path to the cloned repository
|
|
152
|
+
*/
|
|
153
|
+
async cloneExternalModule(moduleCode, options = {}) {
|
|
154
|
+
const moduleInfo = await this.getModuleByCode(moduleCode);
|
|
155
|
+
|
|
156
|
+
if (!moduleInfo) {
|
|
157
|
+
throw new Error(`External module '${moduleCode}' not found in external-official-modules.yaml`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const cacheDir = this.getExternalCacheDir();
|
|
161
|
+
const moduleCacheDir = path.join(cacheDir, moduleCode);
|
|
162
|
+
const silent = options.silent || false;
|
|
163
|
+
|
|
164
|
+
// Create cache directory if it doesn't exist
|
|
165
|
+
await fs.ensureDir(cacheDir);
|
|
166
|
+
|
|
167
|
+
// Helper to create a spinner or a no-op when silent
|
|
168
|
+
const createSpinner = async () => {
|
|
169
|
+
if (silent) {
|
|
170
|
+
return {
|
|
171
|
+
start() {},
|
|
172
|
+
stop() {},
|
|
173
|
+
error() {},
|
|
174
|
+
message() {},
|
|
175
|
+
cancel() {},
|
|
176
|
+
clear() {},
|
|
177
|
+
get isSpinning() {
|
|
178
|
+
return false;
|
|
179
|
+
},
|
|
180
|
+
get isCancelled() {
|
|
181
|
+
return false;
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return await prompts.spinner();
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// Track if we need to install dependencies
|
|
189
|
+
let needsDependencyInstall = false;
|
|
190
|
+
let wasNewClone = false;
|
|
191
|
+
|
|
192
|
+
// Check if already cloned
|
|
193
|
+
if (await fs.pathExists(moduleCacheDir)) {
|
|
194
|
+
// Try to update if it's a git repo
|
|
195
|
+
const fetchSpinner = await createSpinner();
|
|
196
|
+
fetchSpinner.start(`Fetching ${moduleInfo.name}...`);
|
|
197
|
+
try {
|
|
198
|
+
const currentRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
|
|
199
|
+
// Fetch and reset to remote - works better with shallow clones than pull
|
|
200
|
+
execSync('git fetch origin --depth 1', {
|
|
201
|
+
cwd: moduleCacheDir,
|
|
202
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
203
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
|
|
204
|
+
});
|
|
205
|
+
execSync('git reset --hard origin/HEAD', {
|
|
206
|
+
cwd: moduleCacheDir,
|
|
207
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
208
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
|
|
209
|
+
});
|
|
210
|
+
const newRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
|
|
211
|
+
|
|
212
|
+
fetchSpinner.stop(`Fetched ${moduleInfo.name}`);
|
|
213
|
+
// Force dependency install if we got new code
|
|
214
|
+
if (currentRef !== newRef) {
|
|
215
|
+
needsDependencyInstall = true;
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
fetchSpinner.error(`Fetch failed, re-downloading ${moduleInfo.name}`);
|
|
219
|
+
// If update fails, remove and re-clone
|
|
220
|
+
await fs.remove(moduleCacheDir);
|
|
221
|
+
wasNewClone = true;
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
wasNewClone = true;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Clone if not exists or was removed
|
|
228
|
+
if (wasNewClone) {
|
|
229
|
+
const fetchSpinner = await createSpinner();
|
|
230
|
+
fetchSpinner.start(`Fetching ${moduleInfo.name}...`);
|
|
231
|
+
try {
|
|
232
|
+
execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, {
|
|
233
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
234
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
|
|
235
|
+
});
|
|
236
|
+
fetchSpinner.stop(`Fetched ${moduleInfo.name}`);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
fetchSpinner.error(`Failed to fetch ${moduleInfo.name}`);
|
|
239
|
+
throw new Error(`Failed to clone external module '${moduleCode}': ${error.message}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Install dependencies if package.json exists
|
|
244
|
+
const packageJsonPath = path.join(moduleCacheDir, 'package.json');
|
|
245
|
+
const nodeModulesPath = path.join(moduleCacheDir, 'node_modules');
|
|
246
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
247
|
+
// Install if node_modules doesn't exist, or if package.json is newer (dependencies changed)
|
|
248
|
+
const nodeModulesMissing = !(await fs.pathExists(nodeModulesPath));
|
|
249
|
+
|
|
250
|
+
// Force install if we updated or cloned new
|
|
251
|
+
if (needsDependencyInstall || wasNewClone || nodeModulesMissing) {
|
|
252
|
+
const installSpinner = await createSpinner();
|
|
253
|
+
installSpinner.start(`Installing dependencies for ${moduleInfo.name}...`);
|
|
254
|
+
try {
|
|
255
|
+
execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', {
|
|
256
|
+
cwd: moduleCacheDir,
|
|
257
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
258
|
+
timeout: 120_000, // 2 minute timeout
|
|
259
|
+
});
|
|
260
|
+
installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
installSpinner.error(`Failed to install dependencies for ${moduleInfo.name}`);
|
|
263
|
+
if (!silent) await prompts.log.warn(` ${error.message}`);
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
// Check if package.json is newer than node_modules
|
|
267
|
+
let packageJsonNewer = false;
|
|
268
|
+
try {
|
|
269
|
+
const packageStats = await fs.stat(packageJsonPath);
|
|
270
|
+
const nodeModulesStats = await fs.stat(nodeModulesPath);
|
|
271
|
+
packageJsonNewer = packageStats.mtime > nodeModulesStats.mtime;
|
|
272
|
+
} catch {
|
|
273
|
+
// If stat fails, assume we need to install
|
|
274
|
+
packageJsonNewer = true;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (packageJsonNewer) {
|
|
278
|
+
const installSpinner = await createSpinner();
|
|
279
|
+
installSpinner.start(`Installing dependencies for ${moduleInfo.name}...`);
|
|
280
|
+
try {
|
|
281
|
+
execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', {
|
|
282
|
+
cwd: moduleCacheDir,
|
|
283
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
284
|
+
timeout: 120_000, // 2 minute timeout
|
|
285
|
+
});
|
|
286
|
+
installSpinner.stop(`Installed dependencies for ${moduleInfo.name}`);
|
|
287
|
+
} catch (error) {
|
|
288
|
+
installSpinner.error(`Failed to install dependencies for ${moduleInfo.name}`);
|
|
289
|
+
if (!silent) await prompts.log.warn(` ${error.message}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return moduleCacheDir;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Find the source path for an external module
|
|
300
|
+
* @param {string} moduleCode - Code of the external module
|
|
301
|
+
* @param {Object} options - Options passed to cloneExternalModule
|
|
302
|
+
* @returns {string|null} Path to the module source or null if not found
|
|
303
|
+
*/
|
|
304
|
+
async findExternalModuleSource(moduleCode, options = {}) {
|
|
305
|
+
const moduleInfo = await this.getModuleByCode(moduleCode);
|
|
306
|
+
|
|
307
|
+
if (!moduleInfo) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Clone the external module repo
|
|
312
|
+
const cloneDir = await this.cloneExternalModule(moduleCode, options);
|
|
313
|
+
|
|
314
|
+
// The module-definition specifies the path to module.yaml relative to repo root
|
|
315
|
+
// We need to return the directory containing module.yaml
|
|
316
|
+
const moduleDefinitionPath = moduleInfo.moduleDefinition; // e.g., 'skills/module.yaml'
|
|
317
|
+
const configuredPath = path.join(cloneDir, moduleDefinitionPath);
|
|
318
|
+
|
|
319
|
+
if (await fs.pathExists(configuredPath)) {
|
|
320
|
+
return path.dirname(configuredPath);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Fallback: search skills/ and src/ (root level and one level deep for subfolders)
|
|
324
|
+
for (const dir of ['skills', 'src']) {
|
|
325
|
+
const rootCandidate = path.join(cloneDir, dir, 'module.yaml');
|
|
326
|
+
if (await fs.pathExists(rootCandidate)) {
|
|
327
|
+
return path.dirname(rootCandidate);
|
|
328
|
+
}
|
|
329
|
+
const dirPath = path.join(cloneDir, dir);
|
|
330
|
+
if (await fs.pathExists(dirPath)) {
|
|
331
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
332
|
+
for (const entry of entries) {
|
|
333
|
+
if (entry.isDirectory()) {
|
|
334
|
+
const subCandidate = path.join(dirPath, entry.name, 'module.yaml');
|
|
335
|
+
if (await fs.pathExists(subCandidate)) {
|
|
336
|
+
return path.dirname(subCandidate);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Check repo root as last fallback
|
|
344
|
+
const rootCandidate = path.join(cloneDir, 'module.yaml');
|
|
345
|
+
if (await fs.pathExists(rootCandidate)) {
|
|
346
|
+
return path.dirname(rootCandidate);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Nothing found: return configured path (preserves old behavior for error messaging)
|
|
350
|
+
return path.dirname(configuredPath);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
module.exports = { ExternalModuleManager };
|