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.
Files changed (324) hide show
  1. package/.claude-plugin/marketplace.json +77 -0
  2. package/AGENTS.md +12 -0
  3. package/LICENSE +30 -0
  4. package/README.md +109 -0
  5. package/README_CN.md +108 -0
  6. package/package.json +110 -0
  7. package/src/bmm-skills/1-analysis/research/scm-domain-research/SKILL.md +6 -0
  8. package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-01-init.md +137 -0
  9. package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-02-domain-analysis.md +229 -0
  10. package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-03-competitive-landscape.md +238 -0
  11. package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-04-regulatory-focus.md +206 -0
  12. package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-05-technical-trends.md +234 -0
  13. package/src/bmm-skills/1-analysis/research/scm-domain-research/domain-steps/step-06-research-synthesis.md +444 -0
  14. package/src/bmm-skills/1-analysis/research/scm-domain-research/research.template.md +29 -0
  15. package/src/bmm-skills/1-analysis/research/scm-domain-research/workflow.md +51 -0
  16. package/src/bmm-skills/1-analysis/research/scm-market-research/SKILL.md +6 -0
  17. package/src/bmm-skills/1-analysis/research/scm-market-research/research.template.md +29 -0
  18. package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-01-init.md +184 -0
  19. package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-02-customer-behavior.md +239 -0
  20. package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-03-customer-pain-points.md +251 -0
  21. package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-04-customer-decisions.md +261 -0
  22. package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-05-competitive-analysis.md +173 -0
  23. package/src/bmm-skills/1-analysis/research/scm-market-research/steps/step-06-research-completion.md +478 -0
  24. package/src/bmm-skills/1-analysis/research/scm-market-research/workflow.md +51 -0
  25. package/src/bmm-skills/1-analysis/research/scm-technical-research/SKILL.md +6 -0
  26. package/src/bmm-skills/1-analysis/research/scm-technical-research/research.template.md +29 -0
  27. package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-01-init.md +137 -0
  28. package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-02-technical-overview.md +239 -0
  29. package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-03-integration-patterns.md +248 -0
  30. package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-04-architectural-patterns.md +202 -0
  31. package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-05-implementation-research.md +233 -0
  32. package/src/bmm-skills/1-analysis/research/scm-technical-research/technical-steps/step-06-research-synthesis.md +487 -0
  33. package/src/bmm-skills/1-analysis/research/scm-technical-research/workflow.md +52 -0
  34. package/src/bmm-skills/1-analysis/scm-agent-analyst/SKILL.md +59 -0
  35. package/src/bmm-skills/1-analysis/scm-agent-analyst/scm-skill-manifest.yaml +11 -0
  36. package/src/bmm-skills/1-analysis/scm-agent-tech-writer/SKILL.md +57 -0
  37. package/src/bmm-skills/1-analysis/scm-agent-tech-writer/explain-concept.md +20 -0
  38. package/src/bmm-skills/1-analysis/scm-agent-tech-writer/mermaid-gen.md +20 -0
  39. package/src/bmm-skills/1-analysis/scm-agent-tech-writer/scm-skill-manifest.yaml +11 -0
  40. package/src/bmm-skills/1-analysis/scm-agent-tech-writer/validate-doc.md +19 -0
  41. package/src/bmm-skills/1-analysis/scm-agent-tech-writer/write-document.md +20 -0
  42. package/src/bmm-skills/1-analysis/scm-document-project/SKILL.md +6 -0
  43. package/src/bmm-skills/1-analysis/scm-document-project/checklist.md +245 -0
  44. package/src/bmm-skills/1-analysis/scm-document-project/documentation-requirements.csv +12 -0
  45. package/src/bmm-skills/1-analysis/scm-document-project/instructions.md +128 -0
  46. package/src/bmm-skills/1-analysis/scm-document-project/templates/deep-dive-template.md +345 -0
  47. package/src/bmm-skills/1-analysis/scm-document-project/templates/index-template.md +169 -0
  48. package/src/bmm-skills/1-analysis/scm-document-project/templates/project-overview-template.md +103 -0
  49. package/src/bmm-skills/1-analysis/scm-document-project/templates/project-scan-report-schema.json +160 -0
  50. package/src/bmm-skills/1-analysis/scm-document-project/templates/source-tree-template.md +135 -0
  51. package/src/bmm-skills/1-analysis/scm-document-project/workflow.md +25 -0
  52. package/src/bmm-skills/1-analysis/scm-document-project/workflows/deep-dive-instructions.md +299 -0
  53. package/src/bmm-skills/1-analysis/scm-document-project/workflows/deep-dive-workflow.md +34 -0
  54. package/src/bmm-skills/1-analysis/scm-document-project/workflows/full-scan-instructions.md +1107 -0
  55. package/src/bmm-skills/1-analysis/scm-document-project/workflows/full-scan-workflow.md +34 -0
  56. package/src/bmm-skills/1-analysis/scm-prfaq/SKILL.md +96 -0
  57. package/src/bmm-skills/1-analysis/scm-prfaq/agents/artifact-analyzer.md +60 -0
  58. package/src/bmm-skills/1-analysis/scm-prfaq/agents/web-researcher.md +49 -0
  59. package/src/bmm-skills/1-analysis/scm-prfaq/assets/prfaq-template.md +62 -0
  60. package/src/bmm-skills/1-analysis/scm-prfaq/references/customer-faq.md +55 -0
  61. package/src/bmm-skills/1-analysis/scm-prfaq/references/internal-faq.md +51 -0
  62. package/src/bmm-skills/1-analysis/scm-prfaq/references/press-release.md +60 -0
  63. package/src/bmm-skills/1-analysis/scm-prfaq/references/verdict.md +79 -0
  64. package/src/bmm-skills/1-analysis/scm-prfaq/scm-manifest.json +16 -0
  65. package/src/bmm-skills/1-analysis/scm-product-brief/SKILL.md +82 -0
  66. package/src/bmm-skills/1-analysis/scm-product-brief/agents/artifact-analyzer.md +60 -0
  67. package/src/bmm-skills/1-analysis/scm-product-brief/agents/opportunity-reviewer.md +44 -0
  68. package/src/bmm-skills/1-analysis/scm-product-brief/agents/skeptic-reviewer.md +44 -0
  69. package/src/bmm-skills/1-analysis/scm-product-brief/agents/web-researcher.md +49 -0
  70. package/src/bmm-skills/1-analysis/scm-product-brief/prompts/contextual-discovery.md +57 -0
  71. package/src/bmm-skills/1-analysis/scm-product-brief/prompts/draft-and-review.md +86 -0
  72. package/src/bmm-skills/1-analysis/scm-product-brief/prompts/finalize.md +75 -0
  73. package/src/bmm-skills/1-analysis/scm-product-brief/prompts/guided-elicitation.md +70 -0
  74. package/src/bmm-skills/1-analysis/scm-product-brief/resources/brief-template.md +60 -0
  75. package/src/bmm-skills/1-analysis/scm-product-brief/scm-manifest.json +17 -0
  76. package/src/bmm-skills/2-plan-workflows/scm-agent-pm/SKILL.md +59 -0
  77. package/src/bmm-skills/2-plan-workflows/scm-agent-pm/scm-skill-manifest.yaml +11 -0
  78. package/src/bmm-skills/2-plan-workflows/scm-agent-ux-designer/SKILL.md +55 -0
  79. package/src/bmm-skills/2-plan-workflows/scm-agent-ux-designer/scm-skill-manifest.yaml +11 -0
  80. package/src/bmm-skills/2-plan-workflows/scm-create-prd/SKILL.md +6 -0
  81. package/src/bmm-skills/2-plan-workflows/scm-create-prd/data/domain-complexity.csv +15 -0
  82. package/src/bmm-skills/2-plan-workflows/scm-create-prd/data/prd-purpose.md +197 -0
  83. package/src/bmm-skills/2-plan-workflows/scm-create-prd/data/project-types.csv +11 -0
  84. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-01-init.md +178 -0
  85. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-01b-continue.md +161 -0
  86. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-02-discovery.md +208 -0
  87. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-02b-vision.md +142 -0
  88. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-02c-executive-summary.md +158 -0
  89. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-03-success.md +214 -0
  90. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-04-journeys.md +201 -0
  91. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-05-domain.md +194 -0
  92. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-06-innovation.md +211 -0
  93. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-07-project-type.md +222 -0
  94. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-08-scoping.md +216 -0
  95. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-09-functional.md +219 -0
  96. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-10-nonfunctional.md +230 -0
  97. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-11-polish.md +221 -0
  98. package/src/bmm-skills/2-plan-workflows/scm-create-prd/steps-c/step-12-complete.md +115 -0
  99. package/src/bmm-skills/2-plan-workflows/scm-create-prd/templates/prd-template.md +10 -0
  100. package/src/bmm-skills/2-plan-workflows/scm-create-prd/workflow.md +61 -0
  101. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/SKILL.md +6 -0
  102. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-01-init.md +135 -0
  103. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-01b-continue.md +127 -0
  104. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-02-discovery.md +190 -0
  105. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-03-core-experience.md +217 -0
  106. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-04-emotional-response.md +220 -0
  107. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-05-inspiration.md +235 -0
  108. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-06-design-system.md +253 -0
  109. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-07-defining-experience.md +255 -0
  110. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-08-visual-foundation.md +225 -0
  111. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-09-design-directions.md +225 -0
  112. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-10-user-journeys.md +242 -0
  113. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-11-component-strategy.md +249 -0
  114. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-12-ux-patterns.md +238 -0
  115. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-13-responsive-accessibility.md +265 -0
  116. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/steps/step-14-complete.md +171 -0
  117. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/ux-design-template.md +13 -0
  118. package/src/bmm-skills/2-plan-workflows/scm-create-ux-design/workflow.md +35 -0
  119. package/src/bmm-skills/2-plan-workflows/scm-edit-prd/SKILL.md +6 -0
  120. package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-01-discovery.md +242 -0
  121. package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-01b-legacy-conversion.md +204 -0
  122. package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-02-review.md +245 -0
  123. package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-03-edit.md +250 -0
  124. package/src/bmm-skills/2-plan-workflows/scm-edit-prd/steps-e/step-e-04-complete.md +165 -0
  125. package/src/bmm-skills/2-plan-workflows/scm-edit-prd/workflow.md +62 -0
  126. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/SKILL.md +6 -0
  127. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/data/domain-complexity.csv +15 -0
  128. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/data/prd-purpose.md +197 -0
  129. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/data/project-types.csv +11 -0
  130. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-01-discovery.md +221 -0
  131. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-02-format-detection.md +188 -0
  132. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-02b-parity-check.md +206 -0
  133. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-03-density-validation.md +171 -0
  134. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-04-brief-coverage-validation.md +211 -0
  135. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-05-measurability-validation.md +225 -0
  136. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-06-traceability-validation.md +214 -0
  137. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-07-implementation-leakage-validation.md +202 -0
  138. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-08-domain-compliance-validation.md +240 -0
  139. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-09-project-type-validation.md +260 -0
  140. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-10-smart-validation.md +206 -0
  141. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-11-holistic-quality-validation.md +261 -0
  142. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-12-completeness-validation.md +239 -0
  143. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/steps-v/step-v-13-report-complete.md +229 -0
  144. package/src/bmm-skills/2-plan-workflows/scm-validate-prd/workflow.md +61 -0
  145. package/src/bmm-skills/3-solutioning/scm-agent-architect/SKILL.md +54 -0
  146. package/src/bmm-skills/3-solutioning/scm-agent-architect/scm-skill-manifest.yaml +11 -0
  147. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/SKILL.md +6 -0
  148. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-01-document-discovery.md +179 -0
  149. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-02-prd-analysis.md +168 -0
  150. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-03-epic-coverage-validation.md +169 -0
  151. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-04-ux-alignment.md +129 -0
  152. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-05-epic-quality-review.md +241 -0
  153. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/steps/step-06-final-assessment.md +126 -0
  154. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/templates/readiness-report-template.md +4 -0
  155. package/src/bmm-skills/3-solutioning/scm-check-implementation-readiness/workflow.md +47 -0
  156. package/src/bmm-skills/3-solutioning/scm-create-architecture/SKILL.md +6 -0
  157. package/src/bmm-skills/3-solutioning/scm-create-architecture/architecture-decision-template.md +12 -0
  158. package/src/bmm-skills/3-solutioning/scm-create-architecture/data/domain-complexity.csv +13 -0
  159. package/src/bmm-skills/3-solutioning/scm-create-architecture/data/project-types.csv +7 -0
  160. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-01-init.md +153 -0
  161. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-01b-continue.md +173 -0
  162. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-02-context.md +224 -0
  163. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-03-starter.md +329 -0
  164. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-04-decisions.md +318 -0
  165. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-05-patterns.md +359 -0
  166. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-06-structure.md +379 -0
  167. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-07-validation.md +359 -0
  168. package/src/bmm-skills/3-solutioning/scm-create-architecture/steps/step-08-complete.md +76 -0
  169. package/src/bmm-skills/3-solutioning/scm-create-architecture/workflow.md +32 -0
  170. package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/SKILL.md +6 -0
  171. package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/steps/step-01-validate-prerequisites.md +255 -0
  172. package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/steps/step-02-design-epics.md +212 -0
  173. package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
  174. package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/steps/step-04-final-validation.md +131 -0
  175. package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/templates/epics-template.md +61 -0
  176. package/src/bmm-skills/3-solutioning/scm-create-epics-and-stories/workflow.md +51 -0
  177. package/src/bmm-skills/3-solutioning/scm-generate-project-context/SKILL.md +6 -0
  178. package/src/bmm-skills/3-solutioning/scm-generate-project-context/project-context-template.md +21 -0
  179. package/src/bmm-skills/3-solutioning/scm-generate-project-context/steps/step-01-discover.md +186 -0
  180. package/src/bmm-skills/3-solutioning/scm-generate-project-context/steps/step-02-generate.md +321 -0
  181. package/src/bmm-skills/3-solutioning/scm-generate-project-context/steps/step-03-complete.md +278 -0
  182. package/src/bmm-skills/3-solutioning/scm-generate-project-context/workflow.md +39 -0
  183. package/src/bmm-skills/4-implementation/scm-agent-dev/SKILL.md +64 -0
  184. package/src/bmm-skills/4-implementation/scm-agent-dev/scm-skill-manifest.yaml +11 -0
  185. package/src/bmm-skills/4-implementation/scm-agent-qa/SKILL.md +61 -0
  186. package/src/bmm-skills/4-implementation/scm-agent-qa/scm-skill-manifest.yaml +11 -0
  187. package/src/bmm-skills/4-implementation/scm-agent-quick-flow-solo-dev/SKILL.md +53 -0
  188. package/src/bmm-skills/4-implementation/scm-agent-quick-flow-solo-dev/scm-skill-manifest.yaml +11 -0
  189. package/src/bmm-skills/4-implementation/scm-agent-sm/SKILL.md +55 -0
  190. package/src/bmm-skills/4-implementation/scm-agent-sm/scm-skill-manifest.yaml +11 -0
  191. package/src/bmm-skills/4-implementation/scm-code-review/SKILL.md +6 -0
  192. package/src/bmm-skills/4-implementation/scm-code-review/steps/step-01-gather-context.md +62 -0
  193. package/src/bmm-skills/4-implementation/scm-code-review/steps/step-02-review.md +34 -0
  194. package/src/bmm-skills/4-implementation/scm-code-review/steps/step-03-triage.md +49 -0
  195. package/src/bmm-skills/4-implementation/scm-code-review/steps/step-04-present.md +129 -0
  196. package/src/bmm-skills/4-implementation/scm-code-review/workflow.md +55 -0
  197. package/src/bmm-skills/4-implementation/scm-correct-course/SKILL.md +6 -0
  198. package/src/bmm-skills/4-implementation/scm-correct-course/checklist.md +288 -0
  199. package/src/bmm-skills/4-implementation/scm-correct-course/workflow.md +267 -0
  200. package/src/bmm-skills/4-implementation/scm-create-story/SKILL.md +6 -0
  201. package/src/bmm-skills/4-implementation/scm-create-story/checklist.md +357 -0
  202. package/src/bmm-skills/4-implementation/scm-create-story/discover-inputs.md +88 -0
  203. package/src/bmm-skills/4-implementation/scm-create-story/template.md +49 -0
  204. package/src/bmm-skills/4-implementation/scm-create-story/workflow.md +380 -0
  205. package/src/bmm-skills/4-implementation/scm-dev-story/SKILL.md +6 -0
  206. package/src/bmm-skills/4-implementation/scm-dev-story/checklist.md +80 -0
  207. package/src/bmm-skills/4-implementation/scm-dev-story/workflow.md +450 -0
  208. package/src/bmm-skills/4-implementation/scm-qa-generate-e2e-tests/SKILL.md +6 -0
  209. package/src/bmm-skills/4-implementation/scm-qa-generate-e2e-tests/checklist.md +33 -0
  210. package/src/bmm-skills/4-implementation/scm-qa-generate-e2e-tests/workflow.md +136 -0
  211. package/src/bmm-skills/4-implementation/scm-quick-dev/SKILL.md +6 -0
  212. package/src/bmm-skills/4-implementation/scm-quick-dev/spec-template.md +88 -0
  213. package/src/bmm-skills/4-implementation/scm-quick-dev/step-01-clarify-and-route.md +66 -0
  214. package/src/bmm-skills/4-implementation/scm-quick-dev/step-02-plan.md +35 -0
  215. package/src/bmm-skills/4-implementation/scm-quick-dev/step-03-implement.md +37 -0
  216. package/src/bmm-skills/4-implementation/scm-quick-dev/step-04-review.md +49 -0
  217. package/src/bmm-skills/4-implementation/scm-quick-dev/step-05-present.md +63 -0
  218. package/src/bmm-skills/4-implementation/scm-quick-dev/step-oneshot.md +62 -0
  219. package/src/bmm-skills/4-implementation/scm-quick-dev/workflow.md +79 -0
  220. package/src/bmm-skills/4-implementation/scm-retrospective/SKILL.md +6 -0
  221. package/src/bmm-skills/4-implementation/scm-retrospective/workflow.md +1479 -0
  222. package/src/bmm-skills/4-implementation/scm-sprint-planning/SKILL.md +6 -0
  223. package/src/bmm-skills/4-implementation/scm-sprint-planning/checklist.md +33 -0
  224. package/src/bmm-skills/4-implementation/scm-sprint-planning/sprint-status-template.yaml +56 -0
  225. package/src/bmm-skills/4-implementation/scm-sprint-planning/workflow.md +263 -0
  226. package/src/bmm-skills/4-implementation/scm-sprint-status/SKILL.md +6 -0
  227. package/src/bmm-skills/4-implementation/scm-sprint-status/workflow.md +261 -0
  228. package/src/bmm-skills/module-help.csv +31 -0
  229. package/src/bmm-skills/module.yaml +50 -0
  230. package/src/core-skills/module-help.csv +11 -0
  231. package/src/core-skills/module.yaml +25 -0
  232. package/src/core-skills/scm-advanced-elicitation/SKILL.md +136 -0
  233. package/src/core-skills/scm-advanced-elicitation/methods.csv +51 -0
  234. package/src/core-skills/scm-brainstorming/SKILL.md +6 -0
  235. package/src/core-skills/scm-brainstorming/brain-methods.csv +62 -0
  236. package/src/core-skills/scm-brainstorming/steps/step-01-session-setup.md +214 -0
  237. package/src/core-skills/scm-brainstorming/steps/step-01b-continue.md +124 -0
  238. package/src/core-skills/scm-brainstorming/steps/step-02a-user-selected.md +229 -0
  239. package/src/core-skills/scm-brainstorming/steps/step-02b-ai-recommended.md +239 -0
  240. package/src/core-skills/scm-brainstorming/steps/step-02c-random-selection.md +211 -0
  241. package/src/core-skills/scm-brainstorming/steps/step-02d-progressive-flow.md +266 -0
  242. package/src/core-skills/scm-brainstorming/steps/step-03-technique-execution.md +401 -0
  243. package/src/core-skills/scm-brainstorming/steps/step-04-idea-organization.md +305 -0
  244. package/src/core-skills/scm-brainstorming/template.md +15 -0
  245. package/src/core-skills/scm-brainstorming/workflow.md +53 -0
  246. package/src/core-skills/scm-distillator/SKILL.md +177 -0
  247. package/src/core-skills/scm-distillator/agents/distillate-compressor.md +116 -0
  248. package/src/core-skills/scm-distillator/agents/round-trip-reconstructor.md +68 -0
  249. package/src/core-skills/scm-distillator/resources/compression-rules.md +51 -0
  250. package/src/core-skills/scm-distillator/resources/distillate-format-reference.md +227 -0
  251. package/src/core-skills/scm-distillator/resources/splitting-strategy.md +78 -0
  252. package/src/core-skills/scm-distillator/scripts/analyze_sources.py +300 -0
  253. package/src/core-skills/scm-distillator/scripts/tests/test_analyze_sources.py +204 -0
  254. package/src/core-skills/scm-editorial-review-prose/SKILL.md +86 -0
  255. package/src/core-skills/scm-editorial-review-structure/SKILL.md +179 -0
  256. package/src/core-skills/scm-help/SKILL.md +73 -0
  257. package/src/core-skills/scm-index-docs/SKILL.md +66 -0
  258. package/src/core-skills/scm-party-mode/SKILL.md +125 -0
  259. package/src/core-skills/scm-review-adversarial-general/SKILL.md +37 -0
  260. package/src/core-skills/scm-review-edge-case-hunter/SKILL.md +67 -0
  261. package/src/core-skills/scm-shard-doc/SKILL.md +105 -0
  262. package/tools/format-workflow-md.js +263 -0
  263. package/tools/installer/README.md +60 -0
  264. package/tools/installer/cli-utils.js +181 -0
  265. package/tools/installer/commands/install.js +80 -0
  266. package/tools/installer/commands/status.js +65 -0
  267. package/tools/installer/commands/uninstall.js +167 -0
  268. package/tools/installer/core/config.js +52 -0
  269. package/tools/installer/core/custom-module-cache.js +260 -0
  270. package/tools/installer/core/existing-install.js +127 -0
  271. package/tools/installer/core/install-paths.js +129 -0
  272. package/tools/installer/core/installer.js +1790 -0
  273. package/tools/installer/core/manifest-generator.js +701 -0
  274. package/tools/installer/core/manifest.js +1040 -0
  275. package/tools/installer/custom-handler.js +112 -0
  276. package/tools/installer/external-official-modules.yaml +63 -0
  277. package/tools/installer/file-ops.js +204 -0
  278. package/tools/installer/ide/_config-driven.js +536 -0
  279. package/tools/installer/ide/manager.js +247 -0
  280. package/tools/installer/ide/platform-codes.js +37 -0
  281. package/tools/installer/ide/platform-codes.yaml +192 -0
  282. package/tools/installer/ide/shared/agent-command-generator.js +180 -0
  283. package/tools/installer/ide/shared/module-injections.js +136 -0
  284. package/tools/installer/ide/shared/path-utils.js +364 -0
  285. package/tools/installer/ide/shared/scm-artifacts.js +208 -0
  286. package/tools/installer/ide/shared/skill-manifest.js +72 -0
  287. package/tools/installer/ide/templates/agent-command-template.md +14 -0
  288. package/tools/installer/ide/templates/combined/antigravity.md +8 -0
  289. package/tools/installer/ide/templates/combined/default-agent.md +15 -0
  290. package/tools/installer/ide/templates/combined/default-task.md +10 -0
  291. package/tools/installer/ide/templates/combined/default-tool.md +10 -0
  292. package/tools/installer/ide/templates/combined/default-workflow.md +6 -0
  293. package/tools/installer/ide/templates/combined/gemini-agent.toml +14 -0
  294. package/tools/installer/ide/templates/combined/gemini-task.toml +11 -0
  295. package/tools/installer/ide/templates/combined/gemini-tool.toml +11 -0
  296. package/tools/installer/ide/templates/combined/gemini-workflow-yaml.toml +16 -0
  297. package/tools/installer/ide/templates/combined/gemini-workflow.toml +14 -0
  298. package/tools/installer/ide/templates/combined/kiro-agent.md +16 -0
  299. package/tools/installer/ide/templates/combined/kiro-task.md +9 -0
  300. package/tools/installer/ide/templates/combined/kiro-tool.md +9 -0
  301. package/tools/installer/ide/templates/combined/kiro-workflow.md +7 -0
  302. package/tools/installer/ide/templates/combined/opencode-agent.md +15 -0
  303. package/tools/installer/ide/templates/combined/opencode-task.md +13 -0
  304. package/tools/installer/ide/templates/combined/opencode-tool.md +13 -0
  305. package/tools/installer/ide/templates/combined/opencode-workflow-yaml.md +16 -0
  306. package/tools/installer/ide/templates/combined/opencode-workflow.md +16 -0
  307. package/tools/installer/ide/templates/combined/rovodev.md +9 -0
  308. package/tools/installer/ide/templates/combined/trae.md +9 -0
  309. package/tools/installer/ide/templates/combined/windsurf-workflow.md +10 -0
  310. package/tools/installer/ide/templates/split/.gitkeep +0 -0
  311. package/tools/installer/install-messages.yaml +35 -0
  312. package/tools/installer/message-loader.js +83 -0
  313. package/tools/installer/modules/custom-modules.js +197 -0
  314. package/tools/installer/modules/external-manager.js +354 -0
  315. package/tools/installer/modules/official-modules.js +2043 -0
  316. package/tools/installer/project-root.js +77 -0
  317. package/tools/installer/prompts.js +809 -0
  318. package/tools/installer/scm-cli.js +108 -0
  319. package/tools/installer/ui.js +1683 -0
  320. package/tools/installer/yaml-format.js +245 -0
  321. package/tools/javascript-conventions.md +5 -0
  322. package/tools/migrate-custom-module-paths.js +124 -0
  323. package/tools/platform-codes.yaml +169 -0
  324. package/tools/validate-skills.js +736 -0
@@ -0,0 +1,736 @@
1
+ /**
2
+ * Deterministic Skill Validator
3
+ *
4
+ * Validates 14 deterministic rules across all skill directories.
5
+ * Acts as a fast first-pass complement to the inference-based skill validator.
6
+ *
7
+ * What it checks:
8
+ * - SKILL-01: SKILL.md exists
9
+ * - SKILL-02: SKILL.md frontmatter has name
10
+ * - SKILL-03: SKILL.md frontmatter has description
11
+ * - SKILL-04: name format (lowercase, hyphens, no forbidden substrings)
12
+ * - SKILL-05: name matches directory basename
13
+ * - SKILL-06: description quality (length, "Use when"/"Use if")
14
+ * - SKILL-07: SKILL.md has body content after frontmatter
15
+ * - WF-01: workflow.md frontmatter has no name
16
+ * - WF-02: workflow.md frontmatter has no description
17
+ * - PATH-02: no installed_path variable
18
+ * - STEP-01: step filename format
19
+ * - STEP-06: step frontmatter has no name/description
20
+ * - STEP-07: step count 2-10
21
+ * - SEQ-02: no time estimates
22
+ *
23
+ * Usage:
24
+ * node tools/validate-skills.js # All skills, human-readable
25
+ * node tools/validate-skills.js path/to/skill-dir # Single skill
26
+ * node tools/validate-skills.js --strict # Exit 1 on HIGH+ findings
27
+ * node tools/validate-skills.js --json # JSON output
28
+ */
29
+
30
+ const fs = require('node:fs');
31
+ const path = require('node:path');
32
+
33
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
34
+ const SRC_DIR = path.join(PROJECT_ROOT, 'src');
35
+
36
+ // --- CLI Parsing ---
37
+
38
+ const args = process.argv.slice(2);
39
+ const STRICT = args.includes('--strict');
40
+ const JSON_OUTPUT = args.includes('--json');
41
+ const positionalArgs = args.filter((a) => !a.startsWith('--'));
42
+
43
+ // --- Constants ---
44
+
45
+ const NAME_REGEX = /^scm-[a-z0-9]+(-[a-z0-9]+)*$/;
46
+ const STEP_FILENAME_REGEX = /^step-\d{2}[a-z]?-[a-z0-9-]+\.md$/;
47
+ const TIME_ESTIMATE_PATTERNS = [/takes?\s+\d+\s*min/i, /~\s*\d+\s*min/i, /estimated\s+time/i, /\bETA\b/];
48
+
49
+ const SEVERITY_ORDER = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
50
+
51
+ // --- Output Escaping ---
52
+
53
+ function escapeAnnotation(str) {
54
+ return str.replaceAll('%', '%25').replaceAll('\r', '%0D').replaceAll('\n', '%0A');
55
+ }
56
+
57
+ function escapeTableCell(str) {
58
+ return String(str).replaceAll('|', String.raw`\|`);
59
+ }
60
+
61
+ // --- Frontmatter Parsing ---
62
+
63
+ /**
64
+ * Parse YAML frontmatter from a markdown file.
65
+ * Returns an object with key-value pairs, or null if no frontmatter.
66
+ */
67
+ function parseFrontmatter(content) {
68
+ const trimmed = content.trimStart();
69
+ if (!trimmed.startsWith('---')) return null;
70
+
71
+ let endIndex = trimmed.indexOf('\n---\n', 3);
72
+ if (endIndex === -1) {
73
+ // Handle file ending with \n---
74
+ if (trimmed.endsWith('\n---')) {
75
+ endIndex = trimmed.length - 4;
76
+ } else {
77
+ return null;
78
+ }
79
+ }
80
+
81
+ const fmBlock = trimmed.slice(3, endIndex).trim();
82
+ if (fmBlock === '') return {};
83
+
84
+ const result = {};
85
+ for (const line of fmBlock.split('\n')) {
86
+ const colonIndex = line.indexOf(':');
87
+ if (colonIndex === -1) continue;
88
+ // Skip indented lines (nested YAML values)
89
+ if (line[0] === ' ' || line[0] === '\t') continue;
90
+ const key = line.slice(0, colonIndex).trim();
91
+ let value = line.slice(colonIndex + 1).trim();
92
+ // Strip surrounding quotes (single or double)
93
+ if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) {
94
+ value = value.slice(1, -1);
95
+ }
96
+ result[key] = value;
97
+ }
98
+
99
+ return result;
100
+ }
101
+
102
+ /**
103
+ * Parse YAML frontmatter, handling multiline values (description often spans lines).
104
+ * Returns an object with key-value pairs, or null if no frontmatter.
105
+ */
106
+ function parseFrontmatterMultiline(content) {
107
+ const trimmed = content.trimStart();
108
+ if (!trimmed.startsWith('---')) return null;
109
+
110
+ let endIndex = trimmed.indexOf('\n---\n', 3);
111
+ if (endIndex === -1) {
112
+ // Handle file ending with \n---
113
+ if (trimmed.endsWith('\n---')) {
114
+ endIndex = trimmed.length - 4;
115
+ } else {
116
+ return null;
117
+ }
118
+ }
119
+
120
+ const fmBlock = trimmed.slice(3, endIndex).trim();
121
+ if (fmBlock === '') return {};
122
+
123
+ const result = {};
124
+ let currentKey = null;
125
+ let currentValue = '';
126
+
127
+ for (const line of fmBlock.split('\n')) {
128
+ const colonIndex = line.indexOf(':');
129
+ // New key-value pair: must start at column 0 (no leading whitespace) and have a colon
130
+ if (colonIndex > 0 && line[0] !== ' ' && line[0] !== '\t') {
131
+ // Save previous key
132
+ if (currentKey !== null) {
133
+ result[currentKey] = stripQuotes(currentValue.trim());
134
+ }
135
+ currentKey = line.slice(0, colonIndex).trim();
136
+ currentValue = line.slice(colonIndex + 1);
137
+ } else if (currentKey !== null) {
138
+ // Skip YAML comment lines
139
+ if (line.trimStart().startsWith('#')) continue;
140
+ // Continuation of multiline value
141
+ currentValue += '\n' + line;
142
+ }
143
+ }
144
+
145
+ // Save last key
146
+ if (currentKey !== null) {
147
+ result[currentKey] = stripQuotes(currentValue.trim());
148
+ }
149
+
150
+ return result;
151
+ }
152
+
153
+ function stripQuotes(value) {
154
+ if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) {
155
+ return value.slice(1, -1);
156
+ }
157
+ return value;
158
+ }
159
+
160
+ // --- Safe File Reading ---
161
+
162
+ /**
163
+ * Read a file safely, returning null on error.
164
+ * Pushes a warning finding if the file cannot be read.
165
+ */
166
+ function safeReadFile(filePath, findings, relFile) {
167
+ try {
168
+ return fs.readFileSync(filePath, 'utf-8');
169
+ } catch (error) {
170
+ findings.push({
171
+ rule: 'READ-ERR',
172
+ title: 'File Read Error',
173
+ severity: 'MEDIUM',
174
+ file: relFile || path.basename(filePath),
175
+ detail: `Cannot read file: ${error.message}`,
176
+ fix: 'Check file permissions and ensure the file exists.',
177
+ });
178
+ return null;
179
+ }
180
+ }
181
+
182
+ // --- Code Block Stripping ---
183
+
184
+ function stripCodeBlocks(content) {
185
+ return content.replaceAll(/```[\s\S]*?```/g, (m) => m.replaceAll(/[^\n]/g, ''));
186
+ }
187
+
188
+ // --- Skill Discovery ---
189
+
190
+ function discoverSkillDirs(rootDirs) {
191
+ const skillDirs = [];
192
+
193
+ function walk(dir) {
194
+ if (!fs.existsSync(dir)) return;
195
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
196
+
197
+ for (const entry of entries) {
198
+ if (!entry.isDirectory()) continue;
199
+ if (entry.name === 'node_modules' || entry.name === '.git') continue;
200
+
201
+ const fullPath = path.join(dir, entry.name);
202
+ const skillMd = path.join(fullPath, 'SKILL.md');
203
+
204
+ if (fs.existsSync(skillMd)) {
205
+ skillDirs.push(fullPath);
206
+ }
207
+
208
+ // Keep walking into subdirectories to find nested skills
209
+ walk(fullPath);
210
+ }
211
+ }
212
+
213
+ for (const rootDir of rootDirs) {
214
+ walk(rootDir);
215
+ }
216
+
217
+ return skillDirs.sort();
218
+ }
219
+
220
+ // --- File Collection ---
221
+
222
+ function collectSkillFiles(skillDir) {
223
+ const files = [];
224
+
225
+ function walk(dir) {
226
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
227
+ for (const entry of entries) {
228
+ if (entry.name === 'node_modules' || entry.name === '.git') continue;
229
+ const fullPath = path.join(dir, entry.name);
230
+ if (entry.isDirectory()) {
231
+ walk(fullPath);
232
+ } else if (entry.isFile()) {
233
+ files.push(fullPath);
234
+ }
235
+ }
236
+ }
237
+
238
+ walk(skillDir);
239
+ return files;
240
+ }
241
+
242
+ // --- Rule Checks ---
243
+
244
+ function validateSkill(skillDir) {
245
+ const findings = [];
246
+ const dirName = path.basename(skillDir);
247
+ const skillMdPath = path.join(skillDir, 'SKILL.md');
248
+ const workflowMdPath = path.join(skillDir, 'workflow.md');
249
+ const stepsDir = path.join(skillDir, 'steps');
250
+
251
+ // Collect all files in the skill for PATH-02 and SEQ-02
252
+ const allFiles = collectSkillFiles(skillDir);
253
+
254
+ // --- SKILL-01: SKILL.md must exist ---
255
+ if (!fs.existsSync(skillMdPath)) {
256
+ findings.push({
257
+ rule: 'SKILL-01',
258
+ title: 'SKILL.md Must Exist',
259
+ severity: 'CRITICAL',
260
+ file: 'SKILL.md',
261
+ detail: 'SKILL.md not found in skill directory.',
262
+ fix: 'Create SKILL.md as the skill entrypoint.',
263
+ });
264
+ // Cannot check SKILL-02 through SKILL-07 without SKILL.md
265
+ return findings;
266
+ }
267
+
268
+ const skillContent = safeReadFile(skillMdPath, findings, 'SKILL.md');
269
+ if (skillContent === null) return findings;
270
+ const skillFm = parseFrontmatterMultiline(skillContent);
271
+
272
+ // --- SKILL-02: frontmatter has name ---
273
+ if (!skillFm || !('name' in skillFm)) {
274
+ findings.push({
275
+ rule: 'SKILL-02',
276
+ title: 'SKILL.md Must Have name in Frontmatter',
277
+ severity: 'CRITICAL',
278
+ file: 'SKILL.md',
279
+ detail: 'Frontmatter is missing the `name` field.',
280
+ fix: 'Add `name: <skill-name>` to the frontmatter.',
281
+ });
282
+ } else if (skillFm.name === '') {
283
+ findings.push({
284
+ rule: 'SKILL-02',
285
+ title: 'SKILL.md Must Have name in Frontmatter',
286
+ severity: 'CRITICAL',
287
+ file: 'SKILL.md',
288
+ detail: 'Frontmatter `name` field is empty.',
289
+ fix: 'Set `name` to the skill directory name (kebab-case).',
290
+ });
291
+ }
292
+
293
+ // --- SKILL-03: frontmatter has description ---
294
+ if (!skillFm || !('description' in skillFm)) {
295
+ findings.push({
296
+ rule: 'SKILL-03',
297
+ title: 'SKILL.md Must Have description in Frontmatter',
298
+ severity: 'CRITICAL',
299
+ file: 'SKILL.md',
300
+ detail: 'Frontmatter is missing the `description` field.',
301
+ fix: 'Add `description: <what it does and when to use it>` to the frontmatter.',
302
+ });
303
+ } else if (skillFm.description === '') {
304
+ findings.push({
305
+ rule: 'SKILL-03',
306
+ title: 'SKILL.md Must Have description in Frontmatter',
307
+ severity: 'CRITICAL',
308
+ file: 'SKILL.md',
309
+ detail: 'Frontmatter `description` field is empty.',
310
+ fix: 'Add a description stating what the skill does and when to use it.',
311
+ });
312
+ }
313
+
314
+ const name = skillFm && skillFm.name;
315
+ const description = skillFm && skillFm.description;
316
+
317
+ // --- SKILL-04: name format ---
318
+ if (name && !NAME_REGEX.test(name)) {
319
+ findings.push({
320
+ rule: 'SKILL-04',
321
+ title: 'name Format',
322
+ severity: 'HIGH',
323
+ file: 'SKILL.md',
324
+ detail: `name "${name}" does not match pattern: ${NAME_REGEX}`,
325
+ fix: 'Rename to comply with lowercase letters, numbers, and hyphens only (max 64 chars).',
326
+ });
327
+ }
328
+
329
+ // --- SKILL-05: name matches directory ---
330
+ if (name && name !== dirName) {
331
+ findings.push({
332
+ rule: 'SKILL-05',
333
+ title: 'name Must Match Directory Name',
334
+ severity: 'HIGH',
335
+ file: 'SKILL.md',
336
+ detail: `name "${name}" does not match directory name "${dirName}".`,
337
+ fix: `Change name to "${dirName}" or rename the directory.`,
338
+ });
339
+ }
340
+
341
+ // --- SKILL-06: description quality ---
342
+ if (description) {
343
+ if (description.length > 1024) {
344
+ findings.push({
345
+ rule: 'SKILL-06',
346
+ title: 'description Quality',
347
+ severity: 'MEDIUM',
348
+ file: 'SKILL.md',
349
+ detail: `description is ${description.length} characters (max 1024).`,
350
+ fix: 'Shorten the description to 1024 characters or less.',
351
+ });
352
+ }
353
+
354
+ if (!/use\s+when\b/i.test(description) && !/use\s+if\b/i.test(description)) {
355
+ findings.push({
356
+ rule: 'SKILL-06',
357
+ title: 'description Quality',
358
+ severity: 'MEDIUM',
359
+ file: 'SKILL.md',
360
+ detail: 'description does not contain "Use when" or "Use if" trigger phrase.',
361
+ fix: 'Append a "Use when..." clause to explain when to invoke this skill.',
362
+ });
363
+ }
364
+ }
365
+
366
+ // --- SKILL-07: SKILL.md must have body content after frontmatter ---
367
+ {
368
+ const trimmed = skillContent.trimStart();
369
+ let bodyStart = -1;
370
+ if (trimmed.startsWith('---')) {
371
+ let endIdx = trimmed.indexOf('\n---\n', 3);
372
+ if (endIdx !== -1) {
373
+ bodyStart = endIdx + 4;
374
+ } else if (trimmed.endsWith('\n---')) {
375
+ bodyStart = trimmed.length; // no body at all
376
+ }
377
+ } else {
378
+ bodyStart = 0; // no frontmatter, entire file is body
379
+ }
380
+ const body = bodyStart >= 0 ? trimmed.slice(bodyStart).trim() : '';
381
+ if (body === '') {
382
+ findings.push({
383
+ rule: 'SKILL-07',
384
+ title: 'SKILL.md Must Have Body Content',
385
+ severity: 'HIGH',
386
+ file: 'SKILL.md',
387
+ detail: 'SKILL.md has no content after frontmatter. L2 instructions are required.',
388
+ fix: 'Add markdown body with skill instructions after the closing ---.',
389
+ });
390
+ }
391
+ }
392
+
393
+ // --- WF-01 / WF-02: non-SKILL.md files must NOT have name/description ---
394
+ // TODO: scm-agent-tech-writer has sub-skill files with intentional name/description
395
+ const WF_SKIP_SKILLS = new Set(['scm-agent-tech-writer']);
396
+ for (const filePath of allFiles) {
397
+ if (path.extname(filePath) !== '.md') continue;
398
+ if (path.basename(filePath) === 'SKILL.md') continue;
399
+ if (WF_SKIP_SKILLS.has(dirName)) continue;
400
+
401
+ const relFile = path.relative(skillDir, filePath);
402
+ const content = safeReadFile(filePath, findings, relFile);
403
+ if (content === null) continue;
404
+ const fm = parseFrontmatter(content);
405
+ if (!fm) continue;
406
+
407
+ if ('name' in fm) {
408
+ findings.push({
409
+ rule: 'WF-01',
410
+ title: 'Only SKILL.md May Have name in Frontmatter',
411
+ severity: 'HIGH',
412
+ file: relFile,
413
+ detail: `${relFile} frontmatter contains \`name\` — this belongs only in SKILL.md.`,
414
+ fix: "Remove the `name:` line from this file's frontmatter.",
415
+ });
416
+ }
417
+
418
+ if ('description' in fm) {
419
+ findings.push({
420
+ rule: 'WF-02',
421
+ title: 'Only SKILL.md May Have description in Frontmatter',
422
+ severity: 'HIGH',
423
+ file: relFile,
424
+ detail: `${relFile} frontmatter contains \`description\` — this belongs only in SKILL.md.`,
425
+ fix: "Remove the `description:` line from this file's frontmatter.",
426
+ });
427
+ }
428
+ }
429
+
430
+ // --- PATH-02: no installed_path ---
431
+ for (const filePath of allFiles) {
432
+ // Only check markdown and yaml files
433
+ const ext = path.extname(filePath);
434
+ if (!['.md', '.yaml', '.yml'].includes(ext)) continue;
435
+
436
+ const relFile = path.relative(skillDir, filePath);
437
+ const content = safeReadFile(filePath, findings, relFile);
438
+ if (content === null) continue;
439
+
440
+ // Check frontmatter for installed_path key
441
+ const fm = parseFrontmatter(content);
442
+ if (fm && 'installed_path' in fm) {
443
+ findings.push({
444
+ rule: 'PATH-02',
445
+ title: 'No installed_path Variable',
446
+ severity: 'HIGH',
447
+ file: relFile,
448
+ detail: 'Frontmatter contains `installed_path:` key.',
449
+ fix: 'Remove `installed_path` from frontmatter. Use relative paths instead.',
450
+ });
451
+ }
452
+
453
+ // Check content for any mention of installed_path (variable ref, prose, bare text)
454
+ const stripped = stripCodeBlocks(content);
455
+ const lines = stripped.split('\n');
456
+ for (const [i, line] of lines.entries()) {
457
+ if (/installed_path/i.test(line)) {
458
+ findings.push({
459
+ rule: 'PATH-02',
460
+ title: 'No installed_path Variable',
461
+ severity: 'HIGH',
462
+ file: relFile,
463
+ line: i + 1,
464
+ detail: '`installed_path` reference found in content.',
465
+ fix: 'Remove all installed_path usage. Use relative paths (`./path` or `../path`) instead.',
466
+ });
467
+ }
468
+ }
469
+ }
470
+
471
+ // --- STEP-01: step filename format ---
472
+ // --- STEP-06: step frontmatter no name/description ---
473
+ // --- STEP-07: step count ---
474
+ // Only check the literal steps/ directory (variant directories like steps-c, steps-v
475
+ // use different naming conventions and are excluded per the rule specification)
476
+ if (fs.existsSync(stepsDir) && fs.statSync(stepsDir).isDirectory()) {
477
+ const stepDirName = 'steps';
478
+ const stepFiles = fs.readdirSync(stepsDir).filter((f) => f.endsWith('.md'));
479
+
480
+ // STEP-01: filename format
481
+ for (const stepFile of stepFiles) {
482
+ if (!STEP_FILENAME_REGEX.test(stepFile)) {
483
+ findings.push({
484
+ rule: 'STEP-01',
485
+ title: 'Step File Naming',
486
+ severity: 'MEDIUM',
487
+ file: path.join(stepDirName, stepFile),
488
+ detail: `Filename "${stepFile}" does not match pattern: ${STEP_FILENAME_REGEX}`,
489
+ fix: 'Rename to step-NN-description.md (NN = zero-padded number, optional letter suffix).',
490
+ });
491
+ }
492
+ }
493
+
494
+ // STEP-06: step frontmatter has no name/description
495
+ for (const stepFile of stepFiles) {
496
+ const stepPath = path.join(stepsDir, stepFile);
497
+ const stepContent = safeReadFile(stepPath, findings, path.join(stepDirName, stepFile));
498
+ if (stepContent === null) continue;
499
+ const stepFm = parseFrontmatter(stepContent);
500
+
501
+ if (stepFm) {
502
+ if ('name' in stepFm) {
503
+ findings.push({
504
+ rule: 'STEP-06',
505
+ title: 'Step File Frontmatter: No name or description',
506
+ severity: 'MEDIUM',
507
+ file: path.join(stepDirName, stepFile),
508
+ detail: 'Step file frontmatter contains `name:` — this is metadata noise.',
509
+ fix: 'Remove `name:` from step file frontmatter.',
510
+ });
511
+ }
512
+ if ('description' in stepFm) {
513
+ findings.push({
514
+ rule: 'STEP-06',
515
+ title: 'Step File Frontmatter: No name or description',
516
+ severity: 'MEDIUM',
517
+ file: path.join(stepDirName, stepFile),
518
+ detail: 'Step file frontmatter contains `description:` — this is metadata noise.',
519
+ fix: 'Remove `description:` from step file frontmatter.',
520
+ });
521
+ }
522
+ }
523
+ }
524
+
525
+ // STEP-07: step count 2-10
526
+ const stepCount = stepFiles.filter((f) => f.startsWith('step-')).length;
527
+ if (stepCount > 0 && (stepCount < 2 || stepCount > 10)) {
528
+ const detail =
529
+ stepCount < 2
530
+ ? `Only ${stepCount} step file found — consider inlining into workflow.md.`
531
+ : `${stepCount} step files found — more than 10 risks LLM context degradation.`;
532
+ findings.push({
533
+ rule: 'STEP-07',
534
+ title: 'Step Count',
535
+ severity: 'LOW',
536
+ file: stepDirName + '/',
537
+ detail,
538
+ fix: stepCount > 10 ? 'Consider consolidating steps.' : 'Consider expanding or inlining.',
539
+ });
540
+ }
541
+ }
542
+
543
+ // --- SEQ-02: no time estimates ---
544
+ for (const filePath of allFiles) {
545
+ const ext = path.extname(filePath);
546
+ if (!['.md', '.yaml', '.yml'].includes(ext)) continue;
547
+
548
+ const relFile = path.relative(skillDir, filePath);
549
+ const content = safeReadFile(filePath, findings, relFile);
550
+ if (content === null) continue;
551
+ const stripped = stripCodeBlocks(content);
552
+ const lines = stripped.split('\n');
553
+
554
+ for (const [i, line] of lines.entries()) {
555
+ for (const pattern of TIME_ESTIMATE_PATTERNS) {
556
+ if (pattern.test(line)) {
557
+ findings.push({
558
+ rule: 'SEQ-02',
559
+ title: 'No Time Estimates',
560
+ severity: 'LOW',
561
+ file: relFile,
562
+ line: i + 1,
563
+ detail: `Time estimate pattern found: "${line.trim()}"`,
564
+ fix: 'Remove time estimates — AI execution speed varies too much.',
565
+ });
566
+ break; // Only report once per line
567
+ }
568
+ }
569
+ }
570
+ }
571
+
572
+ return findings;
573
+ }
574
+
575
+ // --- Output Formatting ---
576
+
577
+ function formatHumanReadable(results) {
578
+ const output = [];
579
+ let totalFindings = 0;
580
+ const severityCounts = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
581
+
582
+ output.push(
583
+ `\nValidating skills in: ${SRC_DIR}`,
584
+ `Mode: ${STRICT ? 'STRICT (exit 1 on HIGH+)' : 'WARNING (exit 0)'}${JSON_OUTPUT ? ' + JSON' : ''}\n`,
585
+ );
586
+
587
+ let totalSkills = 0;
588
+ let skillsWithFindings = 0;
589
+
590
+ for (const { skillDir, findings } of results) {
591
+ totalSkills++;
592
+ const relDir = path.relative(PROJECT_ROOT, skillDir);
593
+
594
+ if (findings.length > 0) {
595
+ skillsWithFindings++;
596
+ output.push(`\n${relDir}`);
597
+
598
+ for (const f of findings) {
599
+ totalFindings++;
600
+ severityCounts[f.severity]++;
601
+ const location = f.line ? ` (line ${f.line})` : '';
602
+ output.push(` [${f.severity}] ${f.rule} — ${f.title}`, ` File: ${f.file}${location}`, ` ${f.detail}`);
603
+
604
+ if (process.env.GITHUB_ACTIONS) {
605
+ const absFile = path.join(skillDir, f.file);
606
+ const ghFile = path.relative(PROJECT_ROOT, absFile);
607
+ const line = f.line || 1;
608
+ const level = f.severity === 'LOW' ? 'notice' : 'warning';
609
+ console.log(`::${level} file=${ghFile},line=${line}::${escapeAnnotation(`${f.rule}: ${f.detail}`)}`);
610
+ }
611
+ }
612
+ }
613
+ }
614
+
615
+ // Summary
616
+ output.push(
617
+ `\n${'─'.repeat(60)}`,
618
+ `\nSummary:`,
619
+ ` Skills scanned: ${totalSkills}`,
620
+ ` Skills with findings: ${skillsWithFindings}`,
621
+ ` Total findings: ${totalFindings}`,
622
+ );
623
+
624
+ if (totalFindings > 0) {
625
+ output.push('', ` | Severity | Count |`, ` |----------|-------|`);
626
+ for (const sev of ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']) {
627
+ if (severityCounts[sev] > 0) {
628
+ output.push(` | ${sev.padEnd(8)} | ${String(severityCounts[sev]).padStart(5)} |`);
629
+ }
630
+ }
631
+ }
632
+
633
+ const hasHighPlus = severityCounts.CRITICAL > 0 || severityCounts.HIGH > 0;
634
+
635
+ if (totalFindings === 0) {
636
+ output.push(`\n All skills passed validation!`);
637
+ } else if (STRICT && hasHighPlus) {
638
+ output.push(`\n [STRICT MODE] HIGH+ findings found — exiting with failure.`);
639
+ } else if (STRICT) {
640
+ output.push(`\n [STRICT MODE] Only MEDIUM/LOW findings — pass.`);
641
+ } else {
642
+ output.push(`\n Run with --strict to treat HIGH+ findings as errors.`);
643
+ }
644
+
645
+ output.push('');
646
+
647
+ // Write GitHub Actions step summary
648
+ if (process.env.GITHUB_STEP_SUMMARY) {
649
+ let summary = '## Skill Validation\n\n';
650
+ if (totalFindings > 0) {
651
+ summary += '| Skill | Rule | Severity | File | Detail |\n';
652
+ summary += '|-------|------|----------|------|--------|\n';
653
+ for (const { skillDir, findings } of results) {
654
+ const relDir = path.relative(PROJECT_ROOT, skillDir);
655
+ for (const f of findings) {
656
+ summary += `| ${escapeTableCell(relDir)} | ${f.rule} | ${f.severity} | ${escapeTableCell(f.file)} | ${escapeTableCell(f.detail)} |\n`;
657
+ }
658
+ }
659
+ summary += '\n';
660
+ }
661
+ summary += `**${totalSkills} skills scanned, ${totalFindings} findings**\n`;
662
+ fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summary);
663
+ }
664
+
665
+ return { output: output.join('\n'), hasHighPlus };
666
+ }
667
+
668
+ function formatJson(results) {
669
+ const allFindings = [];
670
+ for (const { skillDir, findings } of results) {
671
+ const relDir = path.relative(PROJECT_ROOT, skillDir);
672
+ for (const f of findings) {
673
+ allFindings.push({
674
+ skill: relDir,
675
+ rule: f.rule,
676
+ title: f.title,
677
+ severity: f.severity,
678
+ file: f.file,
679
+ line: f.line || null,
680
+ detail: f.detail,
681
+ fix: f.fix,
682
+ });
683
+ }
684
+ }
685
+
686
+ // Sort by severity
687
+ allFindings.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]);
688
+
689
+ const hasHighPlus = allFindings.some((f) => f.severity === 'CRITICAL' || f.severity === 'HIGH');
690
+
691
+ return { output: JSON.stringify(allFindings, null, 2), hasHighPlus };
692
+ }
693
+
694
+ // --- Main ---
695
+
696
+ if (require.main === module) {
697
+ // Determine which skills to validate
698
+ let skillDirs;
699
+
700
+ if (positionalArgs.length > 0) {
701
+ // Single skill directory specified
702
+ const target = path.resolve(positionalArgs[0]);
703
+ if (!fs.existsSync(target) || !fs.statSync(target).isDirectory()) {
704
+ console.error(`Error: "${positionalArgs[0]}" is not a valid directory.`);
705
+ process.exit(2);
706
+ }
707
+ skillDirs = [target];
708
+ } else {
709
+ // Discover all skills
710
+ skillDirs = discoverSkillDirs([SRC_DIR]);
711
+ }
712
+
713
+ if (skillDirs.length === 0) {
714
+ console.error('No skill directories found.');
715
+ process.exit(2);
716
+ }
717
+
718
+ // Validate each skill
719
+ const results = [];
720
+ for (const skillDir of skillDirs) {
721
+ const findings = validateSkill(skillDir);
722
+ results.push({ skillDir, findings });
723
+ }
724
+
725
+ // Format output
726
+ const { output, hasHighPlus } = JSON_OUTPUT ? formatJson(results) : formatHumanReadable(results);
727
+ console.log(output);
728
+
729
+ // Exit code
730
+ if (STRICT && hasHighPlus) {
731
+ process.exit(1);
732
+ }
733
+ }
734
+
735
+ // --- Exports (for testing) ---
736
+ module.exports = { parseFrontmatter, parseFrontmatterMultiline, validateSkill, discoverSkillDirs };