@zeyue0329/xiaoma-cli 1.12.0 → 1.15.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 (675) hide show
  1. package/package.json +24 -14
  2. package/src/core-skills/module-help.csv +13 -0
  3. package/src/{core → core-skills}/module.yaml +8 -0
  4. package/src/{core/skills/xiaoma-advanced-elicitation/workflow.md → core-skills/xiaoma-advanced-elicitation/SKILL.md} +10 -3
  5. package/src/core-skills/xiaoma-advanced-elicitation/methods.csv +70 -0
  6. package/src/{core/skills → core-skills}/xiaoma-brainstorming/steps/step-03-technique-execution.md +6 -4
  7. package/src/{core/skills → core-skills}/xiaoma-brainstorming/workflow.md +1 -1
  8. package/src/core-skills/xiaoma-customize/SKILL.md +111 -0
  9. package/src/core-skills/xiaoma-customize/scripts/list_customizable_skills.js +172 -0
  10. package/src/{core/skills → core-skills}/xiaoma-distillator/resources/distillate-format-reference.md +1 -1
  11. package/src/{core/skills → core-skills}/xiaoma-distillator/scripts/analyze_sources.py +2 -2
  12. package/src/{core/skills/xiaoma-editorial-review-prose/workflow.md → core-skills/xiaoma-editorial-review-prose/SKILL.md} +5 -0
  13. package/src/{core/skills/xiaoma-editorial-review-structure/workflow.md → core-skills/xiaoma-editorial-review-structure/SKILL.md} +5 -0
  14. package/src/core-skills/xiaoma-help/SKILL.md +75 -0
  15. package/src/{core/skills/xiaoma-index-docs/workflow.md → core-skills/xiaoma-index-docs/SKILL.md} +5 -0
  16. package/src/core-skills/xiaoma-party-mode/SKILL.md +128 -0
  17. package/src/{core/skills/xiaoma-review-adversarial-general/workflow.md → core-skills/xiaoma-review-adversarial-general/SKILL.md} +5 -0
  18. package/src/{core/skills/xiaoma-review-edge-case-hunter/workflow.md → core-skills/xiaoma-review-edge-case-hunter/SKILL.md} +5 -0
  19. package/src/{core/skills/xiaoma-shard-doc/workflow.md → core-skills/xiaoma-shard-doc/SKILL.md} +5 -0
  20. package/src/core-skills/xiaoma-spec/SKILL.md +129 -0
  21. package/src/core-skills/xiaoma-spec/assets/headless-schemas.md +33 -0
  22. package/src/core-skills/xiaoma-spec/assets/spec-template.md +49 -0
  23. package/src/core-skills/xiaoma-spec/customize.toml +53 -0
  24. package/src/scripts/resolve_config.js +163 -0
  25. package/src/scripts/resolve_customization.js +188 -0
  26. package/src/scripts/toml.js +338 -0
  27. package/src/xmc-skills/1-analysis/research/xiaoma-domain-research/SKILL.md +96 -0
  28. package/src/xmc-skills/1-analysis/research/xiaoma-domain-research/customize.toml +41 -0
  29. package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-domain-research/domain-steps/step-06-research-synthesis.md +6 -0
  30. package/src/xmc-skills/1-analysis/research/xiaoma-market-research/SKILL.md +96 -0
  31. package/src/xmc-skills/1-analysis/research/xiaoma-market-research/customize.toml +41 -0
  32. package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-market-research/steps/step-06-research-completion.md +6 -0
  33. package/src/xmc-skills/1-analysis/research/xiaoma-technical-research/SKILL.md +96 -0
  34. package/src/xmc-skills/1-analysis/research/xiaoma-technical-research/customize.toml +41 -0
  35. package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-technical-research/technical-steps/step-06-research-synthesis.md +6 -0
  36. package/src/xmc-skills/1-analysis/xiaoma-agent-analyst/SKILL.md +76 -0
  37. package/src/xmc-skills/1-analysis/xiaoma-agent-analyst/customize.toml +90 -0
  38. package/src/xmc-skills/1-analysis/xiaoma-agent-tech-writer/SKILL.md +76 -0
  39. package/src/xmc-skills/1-analysis/xiaoma-agent-tech-writer/customize.toml +81 -0
  40. package/src/xmc-skills/1-analysis/xiaoma-agent-tech-writer/explain-concept.md +20 -0
  41. package/src/xmc-skills/1-analysis/xiaoma-agent-tech-writer/mermaid-gen.md +20 -0
  42. package/src/xmc-skills/1-analysis/xiaoma-agent-tech-writer/validate-doc.md +19 -0
  43. package/src/xmc-skills/1-analysis/xiaoma-agent-tech-writer/write-document.md +20 -0
  44. package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/checklist.md +5 -2
  45. package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/steps/step-01-init-and-validate.md +18 -1
  46. package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/steps/step-02-requirements-analysis.md +3 -1
  47. package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/steps/step-03-architecture-analysis.md +5 -3
  48. package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/steps/step-04-create-prd.md +12 -14
  49. package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/steps/step-05-validate-prd.md +18 -15
  50. package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/steps/step-06-create-epics.md +9 -5
  51. package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/steps/step-07-create-architecture.md +10 -7
  52. package/src/xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline/steps/step-08-finalize.md +184 -0
  53. package/src/xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline/workflow.md +140 -0
  54. package/src/xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline/xiaoma-skill-manifest.yaml +24 -0
  55. package/src/xmc-skills/1-analysis/xiaoma-document-project/SKILL.md +62 -0
  56. package/src/xmc-skills/1-analysis/xiaoma-document-project/customize.toml +41 -0
  57. package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/workflows/deep-dive-instructions.md +1 -0
  58. package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/workflows/full-scan-instructions.md +1 -0
  59. package/src/xmc-skills/1-analysis/xiaoma-prfaq/SKILL.md +135 -0
  60. package/src/xmc-skills/1-analysis/xiaoma-prfaq/agents/artifact-analyzer.md +60 -0
  61. package/src/xmc-skills/1-analysis/xiaoma-prfaq/agents/web-researcher.md +49 -0
  62. package/src/xmc-skills/1-analysis/xiaoma-prfaq/assets/prfaq-template.md +62 -0
  63. package/src/xmc-skills/1-analysis/xiaoma-prfaq/customize.toml +41 -0
  64. package/src/xmc-skills/1-analysis/xiaoma-prfaq/references/customer-faq.md +55 -0
  65. package/src/xmc-skills/1-analysis/xiaoma-prfaq/references/internal-faq.md +51 -0
  66. package/src/xmc-skills/1-analysis/xiaoma-prfaq/references/press-release.md +60 -0
  67. package/src/xmc-skills/1-analysis/xiaoma-prfaq/references/verdict.md +83 -0
  68. package/src/xmc-skills/1-analysis/xiaoma-prfaq/xiaoma-manifest.json +16 -0
  69. package/src/xmc-skills/1-analysis/xiaoma-product-brief/SKILL.md +91 -0
  70. package/src/xmc-skills/1-analysis/xiaoma-product-brief/assets/brief-template.md +41 -0
  71. package/src/xmc-skills/1-analysis/xiaoma-product-brief/customize.toml +99 -0
  72. package/src/xmc-skills/2-plan-workflows/xiaoma-agent-pm/SKILL.md +76 -0
  73. package/src/xmc-skills/2-plan-workflows/xiaoma-agent-pm/customize.toml +75 -0
  74. package/src/xmc-skills/2-plan-workflows/xiaoma-agent-ux-designer/SKILL.md +76 -0
  75. package/src/xmc-skills/2-plan-workflows/xiaoma-agent-ux-designer/customize.toml +60 -0
  76. package/src/xmc-skills/2-plan-workflows/xiaoma-create-prd/SKILL.md +30 -0
  77. package/src/xmc-skills/2-plan-workflows/xiaoma-create-prd/customize.toml +41 -0
  78. package/src/xmc-skills/2-plan-workflows/xiaoma-edit-prd/SKILL.md +30 -0
  79. package/src/xmc-skills/2-plan-workflows/xiaoma-edit-prd/customize.toml +42 -0
  80. package/src/xmc-skills/2-plan-workflows/xiaoma-prd/SKILL.md +92 -0
  81. package/src/xmc-skills/2-plan-workflows/xiaoma-prd/assets/headless-schemas.md +76 -0
  82. package/src/xmc-skills/2-plan-workflows/xiaoma-prd/assets/prd-template.md +165 -0
  83. package/src/xmc-skills/2-plan-workflows/xiaoma-prd/assets/prd-validation-checklist.md +217 -0
  84. package/src/xmc-skills/2-plan-workflows/xiaoma-prd/assets/validation-report-template.html +325 -0
  85. package/src/xmc-skills/2-plan-workflows/xiaoma-prd/customize.toml +147 -0
  86. package/src/xmc-skills/2-plan-workflows/xiaoma-prd/references/headless.md +39 -0
  87. package/src/xmc-skills/2-plan-workflows/xiaoma-prd/references/validate.md +97 -0
  88. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/SKILL.md +90 -0
  89. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/color-themes.md +9 -0
  90. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/design-directions.md +9 -0
  91. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/design-example-editorial.md +158 -0
  92. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/design-example-mobile.md +93 -0
  93. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/design-example-shadcn.md +109 -0
  94. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/excalidraw-wireframe.md +19 -0
  95. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/experience-example-mobile.md +112 -0
  96. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/experience-example-shadcn.md +133 -0
  97. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/headless-schemas.md +84 -0
  98. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/key-screens.md +29 -0
  99. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/assets/validation-report-template.html +319 -0
  100. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/customize.toml +100 -0
  101. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/references/creative-tools.md +19 -0
  102. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/references/design-md-spec.md +50 -0
  103. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/references/headless.md +37 -0
  104. package/src/xmc-skills/2-plan-workflows/xiaoma-ux/references/validate.md +115 -0
  105. package/src/xmc-skills/2-plan-workflows/xiaoma-validate-prd/SKILL.md +30 -0
  106. package/src/xmc-skills/2-plan-workflows/xiaoma-validate-prd/customize.toml +31 -0
  107. package/src/xmc-skills/3-solutioning/xiaoma-agent-architect/SKILL.md +76 -0
  108. package/src/xmc-skills/3-solutioning/xiaoma-agent-architect/customize.toml +65 -0
  109. package/src/xmc-skills/3-solutioning/xiaoma-check-implementation-readiness/SKILL.md +91 -0
  110. package/src/xmc-skills/3-solutioning/xiaoma-check-implementation-readiness/customize.toml +41 -0
  111. package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-check-implementation-readiness/steps/step-01-document-discovery.md +1 -1
  112. package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-check-implementation-readiness/steps/step-02-prd-analysis.md +1 -1
  113. package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-check-implementation-readiness/steps/step-03-epic-coverage-validation.md +1 -1
  114. package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-check-implementation-readiness/steps/step-06-final-assessment.md +6 -0
  115. package/src/xmc-skills/3-solutioning/xiaoma-create-architecture/SKILL.md +74 -0
  116. package/src/xmc-skills/3-solutioning/xiaoma-create-architecture/customize.toml +41 -0
  117. package/src/xmc-skills/3-solutioning/xiaoma-create-architecture/references/headless.md +37 -0
  118. package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-07-validation.md +23 -21
  119. package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-08-complete.md +6 -0
  120. package/src/xmc-skills/3-solutioning/xiaoma-create-epics-and-stories/SKILL.md +93 -0
  121. package/src/xmc-skills/3-solutioning/xiaoma-create-epics-and-stories/customize.toml +41 -0
  122. package/src/xmc-skills/3-solutioning/xiaoma-create-epics-and-stories/references/headless.md +35 -0
  123. package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-epics-and-stories/steps/step-02-design-epics.md +34 -4
  124. package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-epics-and-stories/steps/step-04-final-validation.md +12 -0
  125. package/src/xmc-skills/3-solutioning/xiaoma-generate-project-context/SKILL.md +81 -0
  126. package/src/xmc-skills/3-solutioning/xiaoma-generate-project-context/customize.toml +41 -0
  127. package/src/{xmc/workflows → xmc-skills/3-solutioning}/xiaoma-generate-project-context/steps/step-03-complete.md +6 -0
  128. package/src/xmc-skills/4-implementation/xiaoma-agent-dev/SKILL.md +76 -0
  129. package/src/xmc-skills/4-implementation/xiaoma-agent-dev/customize.toml +131 -0
  130. package/src/xmc-skills/4-implementation/xiaoma-auto-story-pipeline/checklist.md +29 -0
  131. package/src/{xmc/workflows/4-implementation/auto-story-pipeline → xmc-skills/4-implementation/xiaoma-auto-story-pipeline}/steps/step-01-init-and-validate.md +16 -8
  132. package/src/xmc-skills/4-implementation/xiaoma-auto-story-pipeline/steps/step-02-create-story.md +111 -0
  133. package/src/{xmc/workflows/4-implementation/auto-story-pipeline → xmc-skills/4-implementation/xiaoma-auto-story-pipeline}/steps/step-03-validate-story.md +4 -2
  134. package/src/{xmc/workflows/4-implementation/auto-story-pipeline → xmc-skills/4-implementation/xiaoma-auto-story-pipeline}/steps/step-04-develop-story.md +10 -6
  135. package/src/xmc-skills/4-implementation/xiaoma-auto-story-pipeline/steps/step-05-code-review.md +99 -0
  136. package/src/{xmc/workflows/4-implementation/auto-story-pipeline → xmc-skills/4-implementation/xiaoma-auto-story-pipeline}/steps/step-06-test-story.md +25 -12
  137. package/src/{xmc/workflows/4-implementation/auto-story-pipeline → xmc-skills/4-implementation/xiaoma-auto-story-pipeline}/steps/step-07-fix-and-retest.md +28 -13
  138. package/src/xmc-skills/4-implementation/xiaoma-auto-story-pipeline/steps/step-08-complete-story.md +174 -0
  139. package/src/xmc-skills/4-implementation/xiaoma-auto-story-pipeline/steps/step-09-finalize.md +145 -0
  140. package/src/xmc-skills/4-implementation/xiaoma-auto-story-pipeline/workflow.md +127 -0
  141. package/src/xmc-skills/4-implementation/xiaoma-auto-story-pipeline/xiaoma-skill-manifest.yaml +27 -0
  142. package/src/{xmc/workflows/4-implementation/auto-story-pipeline-batch → xmc-skills/4-implementation/xiaoma-auto-story-pipeline-batch}/SKILL.md +2 -2
  143. package/src/xmc-skills/4-implementation/xiaoma-auto-story-pipeline-batch/checklist.md +45 -0
  144. package/src/{xmc/workflows/4-implementation/auto-story-pipeline-batch → xmc-skills/4-implementation/xiaoma-auto-story-pipeline-batch}/workflow.md +150 -7
  145. package/src/{xmc/workflows/4-implementation/auto-story-pipeline-batch → xmc-skills/4-implementation/xiaoma-auto-story-pipeline-batch}/xiaoma-skill-manifest.yaml +2 -2
  146. package/src/xmc-skills/4-implementation/xiaoma-checkpoint-preview/SKILL.md +68 -0
  147. package/src/xmc-skills/4-implementation/xiaoma-checkpoint-preview/customize.toml +41 -0
  148. package/src/xmc-skills/4-implementation/xiaoma-checkpoint-preview/generate-trail.md +38 -0
  149. package/src/xmc-skills/4-implementation/xiaoma-checkpoint-preview/step-01-orientation.md +105 -0
  150. package/src/xmc-skills/4-implementation/xiaoma-checkpoint-preview/step-02-walkthrough.md +89 -0
  151. package/src/xmc-skills/4-implementation/xiaoma-checkpoint-preview/step-03-detail-pass.md +106 -0
  152. package/src/xmc-skills/4-implementation/xiaoma-checkpoint-preview/step-04-testing.md +74 -0
  153. package/src/xmc-skills/4-implementation/xiaoma-checkpoint-preview/step-05-wrapup.md +30 -0
  154. package/src/xmc-skills/4-implementation/xiaoma-code-review/SKILL.md +90 -0
  155. package/src/xmc-skills/4-implementation/xiaoma-code-review/customize.toml +41 -0
  156. package/src/xmc-skills/4-implementation/xiaoma-code-review/steps/step-01-gather-context.md +85 -0
  157. package/src/xmc-skills/4-implementation/xiaoma-code-review/steps/step-02-review.md +35 -0
  158. package/src/{xmc/workflows → xmc-skills}/4-implementation/xiaoma-code-review/steps/step-03-triage.md +7 -8
  159. package/src/xmc-skills/4-implementation/xiaoma-code-review/steps/step-04-present.md +132 -0
  160. package/src/{xmc/workflows/4-implementation/xiaoma-correct-course/workflow.md → xmc-skills/4-implementation/xiaoma-correct-course/SKILL.md} +65 -31
  161. package/src/{xmc/workflows → xmc-skills}/4-implementation/xiaoma-correct-course/checklist.md +2 -2
  162. package/src/xmc-skills/4-implementation/xiaoma-correct-course/customize.toml +41 -0
  163. package/src/{xmc/workflows/4-implementation/xiaoma-create-story/workflow.md → xmc-skills/4-implementation/xiaoma-create-story/SKILL.md} +60 -11
  164. package/src/xmc-skills/4-implementation/xiaoma-create-story/customize.toml +41 -0
  165. package/src/xmc-skills/4-implementation/xiaoma-create-story/references/headless.md +32 -0
  166. package/src/{xmc/workflows/4-implementation/xiaoma-dev-story/workflow.md → xmc-skills/4-implementation/xiaoma-dev-story/SKILL.md} +70 -20
  167. package/src/xmc-skills/4-implementation/xiaoma-dev-story/customize.toml +41 -0
  168. package/src/xmc-skills/4-implementation/xiaoma-investigate/SKILL.md +196 -0
  169. package/src/xmc-skills/4-implementation/xiaoma-investigate/customize.toml +62 -0
  170. package/src/xmc-skills/4-implementation/xiaoma-investigate/references/case-file-template.md +127 -0
  171. package/src/{xmc/workflows/xiaoma-qa-generate-e2e-tests/workflow.md → xmc-skills/4-implementation/xiaoma-qa-generate-e2e-tests/SKILL.md} +51 -23
  172. package/src/{xmc/workflows → xmc-skills/4-implementation}/xiaoma-qa-generate-e2e-tests/checklist.md +1 -5
  173. package/src/xmc-skills/4-implementation/xiaoma-qa-generate-e2e-tests/customize.toml +41 -0
  174. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/SKILL.md +111 -0
  175. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/compile-epic-context.md +62 -0
  176. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/customize.toml +41 -0
  177. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/spec-template.md +88 -0
  178. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/step-01-clarify-and-route.md +100 -0
  179. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/step-02-plan.md +47 -0
  180. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/step-03-implement.md +41 -0
  181. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/step-04-review.md +50 -0
  182. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/step-05-present.md +78 -0
  183. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/step-oneshot.md +71 -0
  184. package/src/xmc-skills/4-implementation/xiaoma-quick-dev/sync-sprint-status.md +19 -0
  185. package/src/{xmc/workflows/4-implementation/xiaoma-retrospective/workflow.md → xmc-skills/4-implementation/xiaoma-retrospective/SKILL.md} +185 -152
  186. package/src/xmc-skills/4-implementation/xiaoma-retrospective/customize.toml +41 -0
  187. package/src/{xmc/workflows/4-implementation/xiaoma-sprint-planning/workflow.md → xmc-skills/4-implementation/xiaoma-sprint-planning/SKILL.md} +59 -15
  188. package/src/xmc-skills/4-implementation/xiaoma-sprint-planning/customize.toml +41 -0
  189. package/src/xmc-skills/4-implementation/xiaoma-sprint-planning/references/headless.md +28 -0
  190. package/src/{xmc/workflows → xmc-skills}/4-implementation/xiaoma-sprint-planning/sprint-status-template.yaml +3 -3
  191. package/src/{xmc/workflows/4-implementation/xiaoma-sprint-status/workflow.md → xmc-skills/4-implementation/xiaoma-sprint-status/SKILL.md} +57 -20
  192. package/src/xmc-skills/4-implementation/xiaoma-sprint-status/customize.toml +41 -0
  193. package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/checklist.md +6 -0
  194. package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/steps/step-01-init-and-validate.md +28 -4
  195. package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/steps/step-02-run-requirements-pipeline.md +2 -1
  196. package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/steps/step-03-bridge-sprint-planning.md +63 -9
  197. package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/steps/step-04-run-story-pipeline.md +2 -1
  198. package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/steps/step-05-finalize.md +30 -3
  199. package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/workflow.md +7 -8
  200. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/SKILL.md +6 -0
  201. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/checklist.md +47 -0
  202. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/steps/step-01-init-and-validate.md +156 -0
  203. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/steps/step-02-create-epics.md +157 -0
  204. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/steps/step-03-bridge-sprint-planning.md +197 -0
  205. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/steps/step-04-batch-create-stories.md +310 -0
  206. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/steps/step-05-finalize.md +351 -0
  207. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/workflow.md +104 -0
  208. package/src/xmc-skills/5-full-pipeline/xiaoma-auto-prd-to-stories/xiaoma-skill-manifest.yaml +3 -0
  209. package/src/xmc-skills/module-help.csv +32 -0
  210. package/src/xmc-skills/module.yaml +95 -0
  211. package/src/xpm-skills/module-help.csv +3 -0
  212. package/src/xpm-skills/module.yaml +36 -0
  213. package/src/xpm-skills/xiaoma-agent-patent-advisor/SKILL.md +75 -0
  214. package/src/xpm-skills/xiaoma-agent-patent-advisor/customize.toml +46 -0
  215. package/src/xpm-skills/xiaoma-patent-mining/SKILL.md +6 -0
  216. package/src/xpm-skills/xiaoma-patent-mining/references/docx-format-spec.md +183 -0
  217. package/src/xpm-skills/xiaoma-patent-mining/scripts/md2docx.js +777 -0
  218. package/src/xpm-skills/xiaoma-patent-mining/steps/step-01-project-analysis.md +65 -0
  219. package/src/xpm-skills/xiaoma-patent-mining/steps/step-02-patent-mining.md +87 -0
  220. package/src/xpm-skills/xiaoma-patent-mining/steps/step-03-disclosure-writing.md +110 -0
  221. package/src/xpm-skills/xiaoma-patent-mining/steps/step-04-ai-taste-removal.md +85 -0
  222. package/src/xpm-skills/xiaoma-patent-mining/steps/step-05-docx-generation.md +111 -0
  223. package/src/xpm-skills/xiaoma-patent-mining/workflow.md +94 -0
  224. package/tools/format-workflow-md.js +263 -0
  225. package/tools/{cli → installer}/README.md +2 -2
  226. package/tools/installer/cli-utils.js +57 -0
  227. package/tools/installer/commands/install.js +146 -0
  228. package/tools/{cli → installer}/commands/status.js +15 -7
  229. package/tools/{cli → installer}/commands/uninstall.js +7 -7
  230. package/tools/installer/core/config.js +73 -0
  231. package/tools/installer/core/existing-install.js +121 -0
  232. package/tools/installer/core/install-paths.js +132 -0
  233. package/tools/installer/core/installer.js +1624 -0
  234. package/tools/installer/core/legacy-warnings.js +156 -0
  235. package/tools/installer/core/manifest-generator.js +859 -0
  236. package/tools/installer/core/manifest.js +434 -0
  237. package/tools/{cli/lib → installer}/file-ops.js +1 -1
  238. package/tools/installer/fs-native.js +116 -0
  239. package/tools/installer/ide/_config-driven.js +972 -0
  240. package/tools/{cli/installers/lib → installer}/ide/manager.js +82 -62
  241. package/tools/installer/ide/platform-codes.js +80 -0
  242. package/tools/installer/ide/platform-codes.yaml +322 -0
  243. package/tools/installer/ide/shared/installed-skills.js +50 -0
  244. package/tools/{cli/installers/lib → installer}/ide/shared/path-utils.js +0 -145
  245. package/tools/{cli/installers/lib → installer}/ide/shared/skill-manifest.js +3 -36
  246. package/tools/installer/list-options.js +210 -0
  247. package/tools/{cli/installers/lib → installer}/message-loader.js +3 -3
  248. package/tools/installer/modules/channel-plan.js +203 -0
  249. package/tools/installer/modules/channel-resolver.js +241 -0
  250. package/tools/installer/modules/custom-module-manager.js +912 -0
  251. package/tools/installer/modules/external-manager.js +533 -0
  252. package/tools/installer/modules/module-help-schema.js +13 -0
  253. package/tools/{cli/installers/lib/core/config-collector.js → installer/modules/official-modules.js} +1052 -110
  254. package/tools/installer/modules/plugin-resolver.js +398 -0
  255. package/tools/installer/modules/version-resolver.js +336 -0
  256. package/tools/installer/project-root.js +230 -0
  257. package/tools/{cli/lib → installer}/prompts.js +143 -100
  258. package/tools/installer/set-overrides.js +330 -0
  259. package/tools/installer/ui.js +2078 -0
  260. package/tools/{cli → installer}/xiaoma-cli.js +9 -10
  261. package/tools/{cli/lib → installer}/yaml-format.js +1 -1
  262. package/tools/migrate-custom-module-paths.js +124 -0
  263. package/tools/schema/step.js +855 -0
  264. package/tools/skill-validator.md +323 -0
  265. package/tools/validate-file-refs.js +566 -0
  266. package/tools/validate-frontmatter-prose-routing.js +334 -0
  267. package/tools/validate-skills.js +702 -0
  268. package/tools/validate-step-schemas.js +401 -0
  269. package/tools/validate-svg-changes.sh +1 -1
  270. package/tools/validate-trigger-column-vs-emits.js +375 -0
  271. package/tools/validate-warnings-samples.js +261 -0
  272. package/tools/xiaoma/rebrand.mjs +0 -0
  273. package/tools/xiaoma-npx-wrapper.js +2 -2
  274. package/CLAUDE.md +0 -110
  275. package/README.md +0 -128
  276. package/demo/xiaoma-bug-circle-resolve/SKILL.md +0 -6
  277. package/demo/xiaoma-bug-circle-resolve/workflow.md +0 -212
  278. package/demo/xiaoma-bug-resolve/SKILL.md +0 -6
  279. package/demo/xiaoma-bug-resolve/workflow.md +0 -269
  280. package/docs/roadshow/01-/351/241/271/347/233/256/346/246/202/350/247/210/344/270/216/346/236/266/346/236/204.md +0 -189
  281. package/docs/roadshow/02-/346/231/272/350/203/275/344/275/223/347/263/273/347/273/237/350/257/246/350/247/243.md +0 -464
  282. package/docs/roadshow/03-/346/231/272/350/203/275/344/275/223/344/272/244/344/272/222/346/265/201/347/250/213/345/233/276.md +0 -334
  283. package/docs/roadshow/04-/345/267/245/344/275/234/346/265/201/346/211/247/350/241/214/350/257/246/350/247/243.md +0 -1038
  284. package/docs/roadshow/05-/346/212/200/346/234/257/345/256/236/347/216/260/344/270/216/345/210/233/346/226/260/344/272/256/347/202/271.md +0 -205
  285. package/docs/roadshow/06-/350/267/257/346/274/224/346/200/273/347/273/223/344/270/216/346/274/224/347/244/272/345/273/272/350/256/256.md +0 -167
  286. package/patent-disclosure-optimized/SKILL.md +0 -298
  287. package/src/core/module-help.csv +0 -11
  288. package/src/core/skills/xiaoma-advanced-elicitation/SKILL.md +0 -6
  289. package/src/core/skills/xiaoma-advanced-elicitation/methods.csv +0 -51
  290. package/src/core/skills/xiaoma-editorial-review-prose/SKILL.md +0 -6
  291. package/src/core/skills/xiaoma-editorial-review-structure/SKILL.md +0 -6
  292. package/src/core/skills/xiaoma-help/SKILL.md +0 -6
  293. package/src/core/skills/xiaoma-help/workflow.md +0 -88
  294. package/src/core/skills/xiaoma-help/xiaoma-skill-manifest.yaml +0 -1
  295. package/src/core/skills/xiaoma-index-docs/SKILL.md +0 -6
  296. package/src/core/skills/xiaoma-index-docs/xiaoma-skill-manifest.yaml +0 -1
  297. package/src/core/skills/xiaoma-party-mode/SKILL.md +0 -6
  298. package/src/core/skills/xiaoma-party-mode/steps/step-01-agent-loading.md +0 -138
  299. package/src/core/skills/xiaoma-party-mode/steps/step-02-discussion-orchestration.md +0 -187
  300. package/src/core/skills/xiaoma-party-mode/steps/step-03-graceful-exit.md +0 -167
  301. package/src/core/skills/xiaoma-party-mode/workflow.md +0 -190
  302. package/src/core/skills/xiaoma-party-mode/xiaoma-skill-manifest.yaml +0 -1
  303. package/src/core/skills/xiaoma-review-adversarial-general/SKILL.md +0 -6
  304. package/src/core/skills/xiaoma-review-adversarial-general/xiaoma-skill-manifest.yaml +0 -1
  305. package/src/core/skills/xiaoma-review-edge-case-hunter/SKILL.md +0 -6
  306. package/src/core/skills/xiaoma-review-edge-case-hunter/xiaoma-skill-manifest.yaml +0 -1
  307. package/src/core/skills/xiaoma-shard-doc/SKILL.md +0 -6
  308. package/src/core/skills/xiaoma-shard-doc/xiaoma-skill-manifest.yaml +0 -1
  309. package/src/core/tasks/xiaoma-create-prd/SKILL.md +0 -6
  310. package/src/core/tasks/xiaoma-create-prd/data/prd-purpose.md +0 -197
  311. package/src/core/tasks/xiaoma-create-prd/steps-c/step-01-init.md +0 -178
  312. package/src/core/tasks/xiaoma-create-prd/steps-c/step-01b-continue.md +0 -161
  313. package/src/core/tasks/xiaoma-create-prd/steps-c/step-02-discovery.md +0 -208
  314. package/src/core/tasks/xiaoma-create-prd/steps-c/step-02b-vision.md +0 -142
  315. package/src/core/tasks/xiaoma-create-prd/steps-c/step-02c-executive-summary.md +0 -158
  316. package/src/core/tasks/xiaoma-create-prd/steps-c/step-03-success.md +0 -214
  317. package/src/core/tasks/xiaoma-create-prd/steps-c/step-04-journeys.md +0 -201
  318. package/src/core/tasks/xiaoma-create-prd/steps-c/step-05-domain.md +0 -194
  319. package/src/core/tasks/xiaoma-create-prd/steps-c/step-06-innovation.md +0 -211
  320. package/src/core/tasks/xiaoma-create-prd/steps-c/step-07-project-type.md +0 -222
  321. package/src/core/tasks/xiaoma-create-prd/steps-c/step-08-scoping.md +0 -216
  322. package/src/core/tasks/xiaoma-create-prd/steps-c/step-09-functional.md +0 -219
  323. package/src/core/tasks/xiaoma-create-prd/steps-c/step-10-nonfunctional.md +0 -230
  324. package/src/core/tasks/xiaoma-create-prd/steps-c/step-11-polish.md +0 -221
  325. package/src/core/tasks/xiaoma-create-prd/steps-c/step-12-complete.md +0 -115
  326. package/src/core/tasks/xiaoma-create-prd/templates/prd-template.md +0 -10
  327. package/src/core/tasks/xiaoma-create-prd/workflow.md +0 -62
  328. package/src/core/tasks/xiaoma-create-prd/xiaoma-skill-manifest.yaml +0 -1
  329. package/src/utility/agent-components/activation-rules.txt +0 -6
  330. package/src/utility/agent-components/activation-steps.txt +0 -14
  331. package/src/utility/agent-components/agent-command-header.md +0 -1
  332. package/src/utility/agent-components/agent.customize.template.yaml +0 -41
  333. package/src/utility/agent-components/handler-action.txt +0 -4
  334. package/src/utility/agent-components/handler-data.txt +0 -5
  335. package/src/utility/agent-components/handler-exec.txt +0 -6
  336. package/src/utility/agent-components/handler-multi.txt +0 -13
  337. package/src/utility/agent-components/handler-tmpl.txt +0 -5
  338. package/src/utility/agent-components/menu-handlers.txt +0 -6
  339. package/src/xmc/agents/analyst.agent.yaml +0 -47
  340. package/src/xmc/agents/architect.agent.yaml +0 -29
  341. package/src/xmc/agents/dev.agent.yaml +0 -38
  342. package/src/xmc/agents/pm.agent.yaml +0 -44
  343. package/src/xmc/agents/qa.agent.yaml +0 -58
  344. package/src/xmc/agents/quick-flow-solo-dev.agent.yaml +0 -36
  345. package/src/xmc/agents/sm.agent.yaml +0 -49
  346. package/src/xmc/agents/tech-writer/tech-writer-sidecar/documentation-standards.md +0 -224
  347. package/src/xmc/agents/tech-writer/tech-writer.agent.yaml +0 -46
  348. package/src/xmc/agents/tech-writer/xiaoma-skill-manifest.yaml +0 -3
  349. package/src/xmc/agents/ux-designer.agent.yaml +0 -27
  350. package/src/xmc/agents/xiaoma-skill-manifest.yaml +0 -39
  351. package/src/xmc/data/project-context-template.md +0 -26
  352. package/src/xmc/module-help.csv +0 -32
  353. package/src/xmc/module.yaml +0 -50
  354. package/src/xmc/teams/default-party.csv +0 -20
  355. package/src/xmc/teams/team-fullstack.yaml +0 -12
  356. package/src/xmc/workflows/1-analysis/auto-requirements-pipeline/steps/step-08-finalize.md +0 -124
  357. package/src/xmc/workflows/1-analysis/auto-requirements-pipeline/workflow.md +0 -107
  358. package/src/xmc/workflows/1-analysis/auto-requirements-pipeline/xiaoma-skill-manifest.yaml +0 -3
  359. package/src/xmc/workflows/1-analysis/research/market-steps/step-01-init.md +0 -182
  360. package/src/xmc/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +0 -237
  361. package/src/xmc/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +0 -249
  362. package/src/xmc/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +0 -259
  363. package/src/xmc/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +0 -177
  364. package/src/xmc/workflows/1-analysis/research/market-steps/step-06-research-completion.md +0 -476
  365. package/src/xmc/workflows/1-analysis/research/xiaoma-domain-research/SKILL.md +0 -6
  366. package/src/xmc/workflows/1-analysis/research/xiaoma-domain-research/workflow.md +0 -49
  367. package/src/xmc/workflows/1-analysis/research/xiaoma-domain-research/xiaoma-skill-manifest.yaml +0 -1
  368. package/src/xmc/workflows/1-analysis/research/xiaoma-market-research/SKILL.md +0 -6
  369. package/src/xmc/workflows/1-analysis/research/xiaoma-market-research/workflow.md +0 -49
  370. package/src/xmc/workflows/1-analysis/research/xiaoma-market-research/xiaoma-skill-manifest.yaml +0 -1
  371. package/src/xmc/workflows/1-analysis/research/xiaoma-technical-research/SKILL.md +0 -6
  372. package/src/xmc/workflows/1-analysis/research/xiaoma-technical-research/research.template.md +0 -29
  373. package/src/xmc/workflows/1-analysis/research/xiaoma-technical-research/workflow.md +0 -50
  374. package/src/xmc/workflows/1-analysis/research/xiaoma-technical-research/xiaoma-skill-manifest.yaml +0 -1
  375. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/SKILL.md +0 -6
  376. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/product-brief.template.md +0 -10
  377. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/steps/step-01-init.md +0 -170
  378. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/steps/step-01b-continue.md +0 -158
  379. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/steps/step-02-vision.md +0 -193
  380. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/steps/step-03-users.md +0 -196
  381. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/steps/step-04-metrics.md +0 -199
  382. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/steps/step-05-scope.md +0 -213
  383. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/steps/step-06-complete.md +0 -159
  384. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/workflow.md +0 -55
  385. package/src/xmc/workflows/1-analysis/xiaoma-create-product-brief/xiaoma-skill-manifest.yaml +0 -1
  386. package/src/xmc/workflows/1-analysis/xiaoma-product-brief-preview/xiaoma-skill-manifest.yaml +0 -1
  387. package/src/xmc/workflows/2-plan-workflows/create-prd/data/domain-complexity.csv +0 -15
  388. package/src/xmc/workflows/2-plan-workflows/create-prd/data/prd-purpose.md +0 -197
  389. package/src/xmc/workflows/2-plan-workflows/create-prd/data/project-types.csv +0 -11
  390. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +0 -224
  391. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +0 -191
  392. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +0 -209
  393. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +0 -174
  394. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +0 -214
  395. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +0 -228
  396. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +0 -217
  397. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +0 -205
  398. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +0 -243
  399. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +0 -263
  400. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +0 -209
  401. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +0 -264
  402. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +0 -242
  403. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +0 -232
  404. package/src/xmc/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +0 -65
  405. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/SKILL.md +0 -6
  406. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-01-init.md +0 -135
  407. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-01b-continue.md +0 -127
  408. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-02-discovery.md +0 -190
  409. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-03-core-experience.md +0 -217
  410. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-04-emotional-response.md +0 -220
  411. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-05-inspiration.md +0 -235
  412. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-06-design-system.md +0 -253
  413. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-07-defining-experience.md +0 -255
  414. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-08-visual-foundation.md +0 -225
  415. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-09-design-directions.md +0 -225
  416. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-10-user-journeys.md +0 -242
  417. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-11-component-strategy.md +0 -249
  418. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-12-ux-patterns.md +0 -238
  419. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-13-responsive-accessibility.md +0 -265
  420. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/steps/step-14-complete.md +0 -171
  421. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/ux-design-template.md +0 -13
  422. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/workflow.md +0 -36
  423. package/src/xmc/workflows/2-plan-workflows/xiaoma-create-ux-design/xiaoma-skill-manifest.yaml +0 -1
  424. package/src/xmc/workflows/2-plan-workflows/xiaoma-edit-prd/SKILL.md +0 -6
  425. package/src/xmc/workflows/2-plan-workflows/xiaoma-edit-prd/steps-e/step-e-01-discovery.md +0 -242
  426. package/src/xmc/workflows/2-plan-workflows/xiaoma-edit-prd/steps-e/step-e-01b-legacy-conversion.md +0 -204
  427. package/src/xmc/workflows/2-plan-workflows/xiaoma-edit-prd/steps-e/step-e-02-review.md +0 -245
  428. package/src/xmc/workflows/2-plan-workflows/xiaoma-edit-prd/steps-e/step-e-03-edit.md +0 -250
  429. package/src/xmc/workflows/2-plan-workflows/xiaoma-edit-prd/steps-e/step-e-04-complete.md +0 -165
  430. package/src/xmc/workflows/2-plan-workflows/xiaoma-edit-prd/workflow.md +0 -63
  431. package/src/xmc/workflows/2-plan-workflows/xiaoma-edit-prd/xiaoma-skill-manifest.yaml +0 -1
  432. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/SKILL.md +0 -6
  433. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/data/domain-complexity.csv +0 -15
  434. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/data/prd-purpose.md +0 -197
  435. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/data/project-types.csv +0 -11
  436. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-01-discovery.md +0 -221
  437. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-02-format-detection.md +0 -188
  438. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-02b-parity-check.md +0 -206
  439. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-03-density-validation.md +0 -171
  440. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-04-brief-coverage-validation.md +0 -211
  441. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-05-measurability-validation.md +0 -225
  442. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-06-traceability-validation.md +0 -214
  443. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-07-implementation-leakage-validation.md +0 -202
  444. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-08-domain-compliance-validation.md +0 -240
  445. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-09-project-type-validation.md +0 -260
  446. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-10-smart-validation.md +0 -206
  447. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-11-holistic-quality-validation.md +0 -261
  448. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-12-completeness-validation.md +0 -239
  449. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/steps-v/step-v-13-report-complete.md +0 -229
  450. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/workflow.md +0 -62
  451. package/src/xmc/workflows/2-plan-workflows/xiaoma-validate-prd/xiaoma-skill-manifest.yaml +0 -1
  452. package/src/xmc/workflows/3-solutioning/xiaoma-check-implementation-readiness/SKILL.md +0 -6
  453. package/src/xmc/workflows/3-solutioning/xiaoma-check-implementation-readiness/workflow.md +0 -49
  454. package/src/xmc/workflows/3-solutioning/xiaoma-check-implementation-readiness/xiaoma-skill-manifest.yaml +0 -1
  455. package/src/xmc/workflows/3-solutioning/xiaoma-create-architecture/SKILL.md +0 -6
  456. package/src/xmc/workflows/3-solutioning/xiaoma-create-architecture/workflow.md +0 -38
  457. package/src/xmc/workflows/3-solutioning/xiaoma-create-architecture/xiaoma-skill-manifest.yaml +0 -1
  458. package/src/xmc/workflows/3-solutioning/xiaoma-create-epics-and-stories/SKILL.md +0 -6
  459. package/src/xmc/workflows/3-solutioning/xiaoma-create-epics-and-stories/workflow.md +0 -53
  460. package/src/xmc/workflows/3-solutioning/xiaoma-create-epics-and-stories/xiaoma-skill-manifest.yaml +0 -1
  461. package/src/xmc/workflows/4-implementation/auto-story-pipeline/checklist.md +0 -22
  462. package/src/xmc/workflows/4-implementation/auto-story-pipeline/steps/step-02-create-story.md +0 -102
  463. package/src/xmc/workflows/4-implementation/auto-story-pipeline/steps/step-05-code-review.md +0 -95
  464. package/src/xmc/workflows/4-implementation/auto-story-pipeline/steps/step-08-complete-story.md +0 -114
  465. package/src/xmc/workflows/4-implementation/auto-story-pipeline/steps/step-09-finalize.md +0 -69
  466. package/src/xmc/workflows/4-implementation/auto-story-pipeline/workflow.md +0 -89
  467. package/src/xmc/workflows/4-implementation/auto-story-pipeline/xiaoma-skill-manifest.yaml +0 -3
  468. package/src/xmc/workflows/4-implementation/xiaoma-code-review/SKILL.md +0 -6
  469. package/src/xmc/workflows/4-implementation/xiaoma-code-review/checklist.md +0 -23
  470. package/src/xmc/workflows/4-implementation/xiaoma-code-review/steps/step-01-gather-context.md +0 -61
  471. package/src/xmc/workflows/4-implementation/xiaoma-code-review/steps/step-02-review.md +0 -41
  472. package/src/xmc/workflows/4-implementation/xiaoma-code-review/steps/step-04-present.md +0 -38
  473. package/src/xmc/workflows/4-implementation/xiaoma-code-review/workflow.md +0 -54
  474. package/src/xmc/workflows/4-implementation/xiaoma-code-review/xiaoma-skill-manifest.yaml +0 -1
  475. package/src/xmc/workflows/4-implementation/xiaoma-correct-course/SKILL.md +0 -6
  476. package/src/xmc/workflows/4-implementation/xiaoma-correct-course/xiaoma-skill-manifest.yaml +0 -1
  477. package/src/xmc/workflows/4-implementation/xiaoma-create-story/SKILL.md +0 -6
  478. package/src/xmc/workflows/4-implementation/xiaoma-create-story/discover-inputs.md +0 -88
  479. package/src/xmc/workflows/4-implementation/xiaoma-create-story/xiaoma-skill-manifest.yaml +0 -1
  480. package/src/xmc/workflows/4-implementation/xiaoma-dev-story/SKILL.md +0 -6
  481. package/src/xmc/workflows/4-implementation/xiaoma-dev-story/xiaoma-skill-manifest.yaml +0 -1
  482. package/src/xmc/workflows/4-implementation/xiaoma-retrospective/SKILL.md +0 -6
  483. package/src/xmc/workflows/4-implementation/xiaoma-retrospective/xiaoma-skill-manifest.yaml +0 -1
  484. package/src/xmc/workflows/4-implementation/xiaoma-sprint-planning/SKILL.md +0 -6
  485. package/src/xmc/workflows/4-implementation/xiaoma-sprint-planning/xiaoma-skill-manifest.yaml +0 -1
  486. package/src/xmc/workflows/4-implementation/xiaoma-sprint-status/SKILL.md +0 -6
  487. package/src/xmc/workflows/4-implementation/xiaoma-sprint-status/xiaoma-skill-manifest.yaml +0 -1
  488. package/src/xmc/workflows/xiaoma-document-project/SKILL.md +0 -6
  489. package/src/xmc/workflows/xiaoma-document-project/workflow.md +0 -27
  490. package/src/xmc/workflows/xiaoma-document-project/xiaoma-skill-manifest.yaml +0 -1
  491. package/src/xmc/workflows/xiaoma-generate-project-context/SKILL.md +0 -6
  492. package/src/xmc/workflows/xiaoma-generate-project-context/workflow.md +0 -43
  493. package/src/xmc/workflows/xiaoma-generate-project-context/xiaoma-skill-manifest.yaml +0 -1
  494. package/src/xmc/workflows/xiaoma-qa-generate-e2e-tests/SKILL.md +0 -6
  495. package/src/xmc/workflows/xiaoma-qa-generate-e2e-tests/xiaoma-skill-manifest.yaml +0 -1
  496. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/SKILL.md +0 -6
  497. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/steps/step-01-mode-detection.md +0 -169
  498. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/steps/step-02-context-gathering.md +0 -114
  499. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/steps/step-03-execute.md +0 -107
  500. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/steps/step-04-self-check.md +0 -107
  501. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/steps/step-05-adversarial-review.md +0 -94
  502. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/steps/step-06-resolve-findings.md +0 -144
  503. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/workflow.md +0 -38
  504. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev/xiaoma-skill-manifest.yaml +0 -1
  505. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/xiaoma-skill-manifest.yaml +0 -1
  506. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-spec/xiaoma-skill-manifest.yaml +0 -1
  507. package/tools/cli/commands/install.js +0 -87
  508. package/tools/cli/external-official-modules.yaml +0 -4
  509. package/tools/cli/installers/lib/core/custom-module-cache.js +0 -260
  510. package/tools/cli/installers/lib/core/dependency-resolver.js +0 -743
  511. package/tools/cli/installers/lib/core/detector.js +0 -223
  512. package/tools/cli/installers/lib/core/ide-config-manager.js +0 -157
  513. package/tools/cli/installers/lib/core/installer.js +0 -3212
  514. package/tools/cli/installers/lib/core/manifest-generator.js +0 -1374
  515. package/tools/cli/installers/lib/core/manifest.js +0 -1040
  516. package/tools/cli/installers/lib/custom/handler.js +0 -358
  517. package/tools/cli/installers/lib/ide/_base-ide.js +0 -673
  518. package/tools/cli/installers/lib/ide/_config-driven.js +0 -1058
  519. package/tools/cli/installers/lib/ide/platform-codes.js +0 -100
  520. package/tools/cli/installers/lib/ide/platform-codes.yaml +0 -321
  521. package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +0 -181
  522. package/tools/cli/installers/lib/ide/shared/module-injections.js +0 -136
  523. package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +0 -368
  524. package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +0 -179
  525. package/tools/cli/installers/lib/ide/shared/xiaoma-artifacts.js +0 -181
  526. package/tools/cli/installers/lib/ide/templates/agent-command-template.md +0 -14
  527. package/tools/cli/installers/lib/ide/templates/combined/antigravity.md +0 -8
  528. package/tools/cli/installers/lib/ide/templates/combined/default-agent.md +0 -15
  529. package/tools/cli/installers/lib/ide/templates/combined/default-task.md +0 -10
  530. package/tools/cli/installers/lib/ide/templates/combined/default-tool.md +0 -10
  531. package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +0 -6
  532. package/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml +0 -14
  533. package/tools/cli/installers/lib/ide/templates/combined/gemini-task.toml +0 -11
  534. package/tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml +0 -11
  535. package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml +0 -16
  536. package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml +0 -14
  537. package/tools/cli/installers/lib/ide/templates/combined/kiro-agent.md +0 -16
  538. package/tools/cli/installers/lib/ide/templates/combined/kiro-task.md +0 -9
  539. package/tools/cli/installers/lib/ide/templates/combined/kiro-tool.md +0 -9
  540. package/tools/cli/installers/lib/ide/templates/combined/kiro-workflow.md +0 -7
  541. package/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md +0 -15
  542. package/tools/cli/installers/lib/ide/templates/combined/opencode-task.md +0 -13
  543. package/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md +0 -13
  544. package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md +0 -16
  545. package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md +0 -16
  546. package/tools/cli/installers/lib/ide/templates/combined/rovodev.md +0 -9
  547. package/tools/cli/installers/lib/ide/templates/combined/trae.md +0 -9
  548. package/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md +0 -10
  549. package/tools/cli/installers/lib/ide/templates/split/.gitkeep +0 -0
  550. package/tools/cli/installers/lib/modules/external-manager.js +0 -136
  551. package/tools/cli/installers/lib/modules/manager.js +0 -1382
  552. package/tools/cli/lib/activation-builder.js +0 -165
  553. package/tools/cli/lib/agent/compiler.js +0 -516
  554. package/tools/cli/lib/agent/installer.js +0 -680
  555. package/tools/cli/lib/agent/template-engine.js +0 -152
  556. package/tools/cli/lib/agent-analyzer.js +0 -97
  557. package/tools/cli/lib/agent-party-generator.js +0 -194
  558. package/tools/cli/lib/cli-utils.js +0 -182
  559. package/tools/cli/lib/config.js +0 -213
  560. package/tools/cli/lib/platform-codes.js +0 -116
  561. package/tools/cli/lib/project-root.js +0 -77
  562. package/tools/cli/lib/ui.js +0 -1960
  563. package/tools/cli/lib/xml-handler.js +0 -177
  564. package/tools/cli/lib/xml-to-markdown.js +0 -82
  565. package/tools/cli/lib/yaml-xml-builder.js +0 -570
  566. package/tools/platform-codes.yaml +0 -157
  567. package/tools/schema/agent.js +0 -489
  568. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/SKILL.md +0 -0
  569. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/brain-methods.csv +0 -0
  570. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/steps/step-01-session-setup.md +0 -0
  571. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/steps/step-01b-continue.md +0 -0
  572. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/steps/step-02a-user-selected.md +0 -0
  573. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/steps/step-02b-ai-recommended.md +0 -0
  574. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/steps/step-02c-random-selection.md +0 -0
  575. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/steps/step-02d-progressive-flow.md +0 -0
  576. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/steps/step-04-idea-organization.md +0 -0
  577. /package/src/{core/skills → core-skills}/xiaoma-brainstorming/template.md +0 -0
  578. /package/src/{core/skills → core-skills}/xiaoma-distillator/SKILL.md +0 -0
  579. /package/src/{core/skills → core-skills}/xiaoma-distillator/agents/distillate-compressor.md +0 -0
  580. /package/src/{core/skills → core-skills}/xiaoma-distillator/agents/round-trip-reconstructor.md +0 -0
  581. /package/src/{core/skills → core-skills}/xiaoma-distillator/resources/compression-rules.md +0 -0
  582. /package/src/{core/skills → core-skills}/xiaoma-distillator/resources/splitting-strategy.md +0 -0
  583. /package/src/{core/skills → core-skills}/xiaoma-distillator/scripts/tests/test_analyze_sources.py +0 -0
  584. /package/src/{core/skills → core-skills}/xiaoma-distillator/xiaoma-skill-manifest.yaml +0 -0
  585. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-domain-research/domain-steps/step-01-init.md +0 -0
  586. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-domain-research/domain-steps/step-02-domain-analysis.md +0 -0
  587. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-domain-research/domain-steps/step-03-competitive-landscape.md +0 -0
  588. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-domain-research/domain-steps/step-04-regulatory-focus.md +0 -0
  589. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-domain-research/domain-steps/step-05-technical-trends.md +0 -0
  590. /package/src/{xmc/workflows/1-analysis/research → xmc-skills/1-analysis/research/xiaoma-domain-research}/research.template.md +0 -0
  591. /package/src/{xmc/workflows/1-analysis/research/xiaoma-domain-research → xmc-skills/1-analysis/research/xiaoma-market-research}/research.template.md +0 -0
  592. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-market-research/steps/step-01-init.md +0 -0
  593. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-market-research/steps/step-02-customer-behavior.md +0 -0
  594. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-market-research/steps/step-03-customer-pain-points.md +0 -0
  595. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-market-research/steps/step-04-customer-decisions.md +0 -0
  596. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-market-research/steps/step-05-competitive-analysis.md +0 -0
  597. /package/src/{xmc/workflows/1-analysis/research/xiaoma-market-research → xmc-skills/1-analysis/research/xiaoma-technical-research}/research.template.md +0 -0
  598. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-technical-research/technical-steps/step-01-init.md +0 -0
  599. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-technical-research/technical-steps/step-02-technical-overview.md +0 -0
  600. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-technical-research/technical-steps/step-03-integration-patterns.md +0 -0
  601. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-technical-research/technical-steps/step-04-architectural-patterns.md +0 -0
  602. /package/src/{xmc/workflows → xmc-skills}/1-analysis/research/xiaoma-technical-research/technical-steps/step-05-implementation-research.md +0 -0
  603. /package/src/{xmc/workflows/1-analysis/auto-requirements-pipeline → xmc-skills/1-analysis/xiaoma-auto-requirements-pipeline}/SKILL.md +0 -0
  604. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/checklist.md +0 -0
  605. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/documentation-requirements.csv +0 -0
  606. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/instructions.md +0 -0
  607. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/templates/deep-dive-template.md +0 -0
  608. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/templates/index-template.md +0 -0
  609. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/templates/project-overview-template.md +0 -0
  610. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/templates/project-scan-report-schema.json +0 -0
  611. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/templates/source-tree-template.md +0 -0
  612. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/workflows/deep-dive-workflow.md +0 -0
  613. /package/src/{xmc/workflows → xmc-skills/1-analysis}/xiaoma-document-project/workflows/full-scan-workflow.md +0 -0
  614. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/SKILL.md +0 -0
  615. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/agents/artifact-analyzer.md +0 -0
  616. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/agents/opportunity-reviewer.md +0 -0
  617. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/agents/skeptic-reviewer.md +0 -0
  618. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/agents/web-researcher.md +0 -0
  619. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/prompts/contextual-discovery.md +0 -0
  620. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/prompts/draft-and-review.md +0 -0
  621. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/prompts/finalize.md +0 -0
  622. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/prompts/guided-elicitation.md +0 -0
  623. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/resources/brief-template.md +0 -0
  624. /package/src/{xmc/workflows → xmc-skills}/1-analysis/xiaoma-product-brief-preview/xiaoma-manifest.json +0 -0
  625. /package/src/{core/skills/xiaoma-advanced-elicitation → xmc-skills/1-analysis/xiaoma-product-brief-preview}/xiaoma-skill-manifest.yaml +0 -0
  626. /package/src/{core/tasks/xiaoma-create-prd/data → xmc-skills/2-plan-workflows/xiaoma-prd/assets}/domain-complexity.csv +0 -0
  627. /package/src/{core/tasks/xiaoma-create-prd/data → xmc-skills/2-plan-workflows/xiaoma-prd/assets}/project-types.csv +0 -0
  628. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-check-implementation-readiness/steps/step-04-ux-alignment.md +0 -0
  629. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-check-implementation-readiness/steps/step-05-epic-quality-review.md +0 -0
  630. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-check-implementation-readiness/templates/readiness-report-template.md +0 -0
  631. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/architecture-decision-template.md +0 -0
  632. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/data/domain-complexity.csv +0 -0
  633. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/data/project-types.csv +0 -0
  634. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-01-init.md +0 -0
  635. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-01b-continue.md +0 -0
  636. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-02-context.md +0 -0
  637. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-03-starter.md +0 -0
  638. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-04-decisions.md +0 -0
  639. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-05-patterns.md +0 -0
  640. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-architecture/steps/step-06-structure.md +0 -0
  641. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-epics-and-stories/steps/step-01-validate-prerequisites.md +0 -0
  642. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-epics-and-stories/steps/step-03-create-stories.md +0 -0
  643. /package/src/{xmc/workflows → xmc-skills}/3-solutioning/xiaoma-create-epics-and-stories/templates/epics-template.md +0 -0
  644. /package/src/{xmc/workflows → xmc-skills/3-solutioning}/xiaoma-generate-project-context/project-context-template.md +0 -0
  645. /package/src/{xmc/workflows → xmc-skills/3-solutioning}/xiaoma-generate-project-context/steps/step-01-discover.md +0 -0
  646. /package/src/{xmc/workflows → xmc-skills/3-solutioning}/xiaoma-generate-project-context/steps/step-02-generate.md +0 -0
  647. /package/src/{xmc/workflows/4-implementation/auto-story-pipeline → xmc-skills/4-implementation/xiaoma-auto-story-pipeline}/SKILL.md +0 -0
  648. /package/src/{xmc/workflows → xmc-skills}/4-implementation/xiaoma-create-story/checklist.md +0 -0
  649. /package/src/{xmc/workflows/4-implementation/xiaoma-code-review → xmc-skills/4-implementation/xiaoma-create-story}/discover-inputs.md +0 -0
  650. /package/src/{xmc/workflows → xmc-skills}/4-implementation/xiaoma-create-story/template.md +0 -0
  651. /package/src/{xmc/workflows → xmc-skills}/4-implementation/xiaoma-dev-story/checklist.md +0 -0
  652. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-dev-new-preview/SKILL.md +0 -0
  653. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-dev-new-preview/steps/step-01-clarify-and-route.md +0 -0
  654. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-dev-new-preview/steps/step-02-plan.md +0 -0
  655. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-dev-new-preview/steps/step-03-implement.md +0 -0
  656. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-dev-new-preview/steps/step-04-review.md +0 -0
  657. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-dev-new-preview/steps/step-05-present.md +0 -0
  658. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-dev-new-preview/tech-spec-template.md +0 -0
  659. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-dev-new-preview/workflow.md +0 -0
  660. /package/src/{core/skills/xiaoma-brainstorming → xmc-skills/4-implementation/xiaoma-quick-dev-new-preview}/xiaoma-skill-manifest.yaml +0 -0
  661. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-spec/SKILL.md +0 -0
  662. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-spec/steps/step-01-understand.md +0 -0
  663. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-spec/steps/step-02-investigate.md +0 -0
  664. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-spec/steps/step-03-generate.md +0 -0
  665. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-spec/steps/step-04-review.md +0 -0
  666. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-spec/tech-spec-template.md +0 -0
  667. /package/src/{xmc/workflows/xiaoma-quick-flow → xmc-skills/4-implementation}/xiaoma-quick-spec/workflow.md +0 -0
  668. /package/src/{core/skills/xiaoma-editorial-review-prose → xmc-skills/4-implementation/xiaoma-quick-spec}/xiaoma-skill-manifest.yaml +0 -0
  669. /package/src/{xmc/workflows → xmc-skills}/4-implementation/xiaoma-sprint-planning/checklist.md +0 -0
  670. /package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/SKILL.md +0 -0
  671. /package/src/{xmc/workflows/5-full-pipeline/auto-full-pipeline → xmc-skills/5-full-pipeline/xiaoma-auto-full-pipeline}/xiaoma-skill-manifest.yaml +0 -0
  672. /package/{patent-disclosure-optimized → src/xpm-skills/xiaoma-patent-mining}/references/disclosure-template.md +0 -0
  673. /package/{patent-disclosure-optimized → src/xpm-skills/xiaoma-patent-mining}/references/mining-principles.md +0 -0
  674. /package/src/{core/skills/xiaoma-editorial-review-structure → xpm-skills/xiaoma-patent-mining}/xiaoma-skill-manifest.yaml +0 -0
  675. /package/tools/{cli/installers → installer}/install-messages.yaml +0 -0
@@ -0,0 +1,2078 @@
1
+ const path = require('node:path');
2
+ const os = require('node:os');
3
+ const semver = require('semver');
4
+ const fs = require('./fs-native');
5
+ const installerPackageJson = require('../../package.json');
6
+ const { CLIUtils } = require('./cli-utils');
7
+ const { ExternalModuleManager } = require('./modules/external-manager');
8
+ const { resolveModuleVersion } = require('./modules/version-resolver');
9
+ const { Manifest } = require('./core/manifest');
10
+ const {
11
+ parseChannelOptions,
12
+ buildPlan,
13
+ decideChannelForModule,
14
+ orphanPinWarnings,
15
+ bundledTargetWarnings,
16
+ } = require('./modules/channel-plan');
17
+ const channelResolver = require('./modules/channel-resolver');
18
+ const prompts = require('./prompts');
19
+ const { parseSetEntries } = require('./set-overrides');
20
+
21
+ const manifest = new Manifest();
22
+
23
+ /**
24
+ * Format a resolved version for display in installer labels.
25
+ * Semver-like values are normalized to a single leading "v".
26
+ * @param {string|null|undefined} version
27
+ * @returns {string}
28
+ */
29
+ function formatDisplayVersion(version) {
30
+ const trimmed = typeof version === 'string' ? version.trim() : '';
31
+ if (!trimmed) return '';
32
+
33
+ const normalized = semver.valid(semver.coerce(trimmed));
34
+ if (normalized) {
35
+ return `v${normalized}`;
36
+ }
37
+
38
+ return trimmed;
39
+ }
40
+
41
+ /**
42
+ * Build the display label for a module, showing an upgrade arrow when an
43
+ * installed semver differs from the latest resolvable semver.
44
+ * @param {string} name
45
+ * @param {string} latestVersion
46
+ * @param {string} installedVersion
47
+ * @returns {string}
48
+ */
49
+ function buildModuleLabel(name, latestVersion, installedVersion = '') {
50
+ const latestDisplay = formatDisplayVersion(latestVersion);
51
+ if (!latestDisplay) return name;
52
+
53
+ const installedDisplay = formatDisplayVersion(installedVersion);
54
+ const latestSemver = semver.valid(semver.coerce(latestVersion || ''));
55
+ const installedSemver = semver.valid(semver.coerce(installedVersion || ''));
56
+
57
+ if (installedDisplay && latestSemver && installedSemver && semver.neq(installedSemver, latestSemver)) {
58
+ return `${name} (${installedDisplay} → ${latestDisplay})`;
59
+ }
60
+
61
+ return `${name} (${latestDisplay})`;
62
+ }
63
+
64
+ /**
65
+ * Resolve the version to show for a module picker entry. External modules use
66
+ * the same channel/tag resolver as installs; bundled modules fall back to local
67
+ * source metadata.
68
+ * @param {string} moduleCode - Module code (e.g., 'core', 'xmc', 'cis')
69
+ * @param {Object} options
70
+ * @param {string|null} [options.repoUrl] - Module repository URL for tag resolution
71
+ * @param {string|null} [options.registryDefault] - Registry default channel
72
+ * @param {Object|null} [options.channelOptions] - Parsed installer channel options
73
+ * @returns {Promise<{version: string, lookupAttempted: boolean, lookupSucceeded: boolean}>}
74
+ */
75
+ async function getModuleVersion(moduleCode, { repoUrl = null, registryDefault = null, channelOptions = null } = {}) {
76
+ if (repoUrl) {
77
+ const plan = decideChannelForModule({
78
+ code: moduleCode,
79
+ channelOptions,
80
+ registryDefault,
81
+ });
82
+
83
+ try {
84
+ const resolved = await channelResolver.resolveChannel({
85
+ channel: plan.channel,
86
+ pin: plan.pin,
87
+ repoUrl,
88
+ });
89
+ if (resolved?.version) {
90
+ return {
91
+ version: resolved.version,
92
+ lookupAttempted: plan.channel === 'stable',
93
+ lookupSucceeded: true,
94
+ };
95
+ }
96
+ } catch {
97
+ // Fall back to local metadata when tag resolution is unavailable.
98
+ }
99
+ }
100
+
101
+ const versionInfo = await resolveModuleVersion(moduleCode);
102
+ return {
103
+ version: versionInfo.version || '',
104
+ lookupAttempted: !!repoUrl,
105
+ lookupSucceeded: false,
106
+ };
107
+ }
108
+
109
+ /**
110
+ * UI utilities for the installer
111
+ */
112
+ class UI {
113
+ async _retainUnavailableInstalledModules(selectedModules, installedModuleIds, xiaomaDir, options = {}) {
114
+ const { OfficialModules } = require('./modules/official-modules');
115
+ const officialCodes = new Set(['core']);
116
+
117
+ const builtInModules = (await new OfficialModules().listAvailable()).modules || [];
118
+ for (const mod of builtInModules) {
119
+ officialCodes.add(mod.id);
120
+ }
121
+
122
+ const externalManager = new ExternalModuleManager();
123
+ const registryModules = await externalManager.listAvailable();
124
+ for (const mod of registryModules) {
125
+ officialCodes.add(mod.code);
126
+ }
127
+
128
+ const { CustomModuleManager } = require('./modules/custom-module-manager');
129
+ const customMgr = new CustomModuleManager();
130
+ const selectedSet = new Set(selectedModules);
131
+ const preserveModules = [];
132
+
133
+ for (const moduleId of installedModuleIds) {
134
+ if (moduleId === 'core') continue;
135
+ if (!selectedSet.has(moduleId) && !options.preserveUnselected) continue;
136
+ if (officialCodes.has(moduleId)) continue;
137
+
138
+ const customSource = await customMgr.findModuleSourceByCode(moduleId, { xiaomaDir });
139
+ if (!customSource) {
140
+ preserveModules.push(moduleId);
141
+ }
142
+ }
143
+
144
+ const preservedSet = new Set(preserveModules);
145
+ return {
146
+ selectedModules: selectedModules.filter((moduleId) => !preservedSet.has(moduleId)),
147
+ preserveModules,
148
+ };
149
+ }
150
+
151
+ /**
152
+ * Prompt for installation configuration
153
+ * @param {Object} options - Command-line options from install command
154
+ * @returns {Object} Installation configuration
155
+ */
156
+ async promptInstall(options = {}) {
157
+ await CLIUtils.displayLogo();
158
+
159
+ // Display version-specific start message from install-messages.yaml
160
+ const { MessageLoader } = require('./message-loader');
161
+ const messageLoader = new MessageLoader();
162
+ await messageLoader.displayStartMessage();
163
+
164
+ // Parse channel flags (--channel/--all-*/--next=/--pin) once. Warnings
165
+ // are surfaced immediately so the user sees them before any git ops run.
166
+ const channelOptions = parseChannelOptions(options);
167
+ for (const warning of channelOptions.warnings) {
168
+ await prompts.log.warn(warning);
169
+ }
170
+
171
+ // When the user launched the installer from a prerelease (npx @zeyue0329/xiaoma-cli@next),
172
+ // mirror that intent for external modules: seed the global channel to 'next' so
173
+ // the module picker's version labels resolve from main HEAD (matching what
174
+ // actually gets installed) and the interactive channel gate skips — the user
175
+ // already declared "next" intent by typing @next. Explicit channel flags
176
+ // override this seed.
177
+ if (
178
+ semver.prerelease(installerPackageJson.version) !== null &&
179
+ !channelOptions.global &&
180
+ channelOptions.nextSet.size === 0 &&
181
+ channelOptions.pins.size === 0
182
+ ) {
183
+ channelOptions.global = 'next';
184
+ await prompts.log.info(
185
+ 'Launched from a prerelease — installing all external modules from main HEAD (next channel). Pass --all-stable or --pin to override.',
186
+ );
187
+ }
188
+
189
+ // Get directory from options or prompt
190
+ let confirmedDirectory;
191
+ if (options.directory) {
192
+ // Use provided directory from command-line
193
+ const expandedDir = this.expandUserPath(options.directory);
194
+ const validation = this.validateDirectorySync(expandedDir);
195
+ if (validation) {
196
+ throw new Error(`Invalid directory: ${validation}`);
197
+ }
198
+ confirmedDirectory = expandedDir;
199
+ await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`);
200
+ } else {
201
+ confirmedDirectory = await this.getConfirmedDirectory();
202
+ }
203
+
204
+ const { Installer } = require('./core/installer');
205
+ const installer = new Installer();
206
+ const { xiaomaDir } = await installer.findXiaomaDir(confirmedDirectory);
207
+
208
+ // Check if there's an existing XiaoMa installation
209
+ const hasExistingInstall = await fs.pathExists(xiaomaDir);
210
+
211
+ // Track action type (only set if there's an existing installation)
212
+ let actionType;
213
+
214
+ // Only show action menu if there's an existing installation
215
+ if (hasExistingInstall) {
216
+ // Get version information
217
+ const { existingInstall, xiaomaDir } = await this.getExistingInstallation(confirmedDirectory);
218
+
219
+ // Build menu choices dynamically
220
+ const choices = [];
221
+
222
+ // Always show Quick Update first (allows refreshing installation even on same version)
223
+ if (existingInstall.installed) {
224
+ choices.push({
225
+ name: 'Quick Update',
226
+ value: 'quick-update',
227
+ });
228
+ }
229
+
230
+ // Common actions
231
+ choices.push({ name: 'Modify XiaoMa Installation', value: 'update' });
232
+
233
+ // Check if action is provided via command-line
234
+ if (options.action) {
235
+ const validActions = choices.map((c) => c.value);
236
+ if (!validActions.includes(options.action)) {
237
+ throw new Error(`Invalid action: ${options.action}. Valid actions: ${validActions.join(', ')}`);
238
+ }
239
+ actionType = options.action;
240
+ await prompts.log.info(`Using action from command-line: ${actionType}`);
241
+ } else if (options.yes) {
242
+ // Default to quick-update if available, unless flags that require the
243
+ // full update path are present (e.g. --custom-source which re-clones
244
+ // modules at a new version — quick-update skips that entirely).
245
+ if (choices.length === 0) {
246
+ throw new Error('No valid actions available for this installation');
247
+ }
248
+ const hasQuickUpdate = choices.some((c) => c.value === 'quick-update');
249
+ const needsFullUpdate = !!options.customSource;
250
+ actionType = hasQuickUpdate && !needsFullUpdate ? 'quick-update' : (choices.find((c) => c.value === 'update') || choices[0]).value;
251
+ await prompts.log.info(`Non-interactive mode (--yes): defaulting to ${actionType}`);
252
+ } else {
253
+ actionType = await prompts.select({
254
+ message: 'How would you like to proceed?',
255
+ choices: choices,
256
+ default: choices[0].value,
257
+ });
258
+ }
259
+
260
+ // Handle quick update separately
261
+ if (actionType === 'quick-update') {
262
+ return {
263
+ actionType: 'quick-update',
264
+ directory: confirmedDirectory,
265
+ skipPrompts: options.yes || false,
266
+ };
267
+ }
268
+
269
+ // If actionType === 'update', handle it with the new flow
270
+ // Return early with modify configuration
271
+ if (actionType === 'update') {
272
+ // Get existing installation info
273
+ const { installedModuleIds, installedModuleVersions } = await this.getExistingInstallation(confirmedDirectory);
274
+
275
+ await prompts.log.message(`Found existing modules: ${[...installedModuleIds].join(', ')}`);
276
+
277
+ // Unified module selection - all modules in one grouped multiselect
278
+ let selectedModules;
279
+ if (options.modules) {
280
+ // Use modules from command-line
281
+ selectedModules = options.modules
282
+ .split(',')
283
+ .map((m) => m.trim())
284
+ .filter(Boolean);
285
+ await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`);
286
+ } else if (options.customSource && !options.yes) {
287
+ // Custom source without --modules or --yes: start with empty list
288
+ // (only custom source modules + core will be installed).
289
+ // When --yes is also set, fall through to the --yes branch so all
290
+ // installed modules are included alongside the custom source modules.
291
+ selectedModules = [];
292
+ } else if (options.yes) {
293
+ selectedModules = await this.getDefaultModules(installedModuleIds);
294
+ await prompts.log.info(
295
+ `Non-interactive mode (--yes): using default modules (installed + defaults): ${selectedModules.join(', ')}`,
296
+ );
297
+ } else {
298
+ selectedModules = await this.selectAllModules(installedModuleIds, installedModuleVersions, channelOptions);
299
+ }
300
+
301
+ // Resolve custom sources from --custom-source flag
302
+ if (options.customSource) {
303
+ const customCodes = await this._resolveCustomSourcesCli(options.customSource);
304
+ for (const code of customCodes) {
305
+ if (!selectedModules.includes(code)) selectedModules.push(code);
306
+ }
307
+ }
308
+
309
+ // Ensure core is in the modules list
310
+ if (!selectedModules.includes('core')) {
311
+ selectedModules.unshift('core');
312
+ }
313
+
314
+ const retainedModuleResult = await this._retainUnavailableInstalledModules(selectedModules, installedModuleIds, xiaomaDir, {
315
+ preserveUnselected: options.yes && !options.modules,
316
+ });
317
+ selectedModules = retainedModuleResult.selectedModules;
318
+ const preservedModules = retainedModuleResult.preserveModules;
319
+
320
+ if (preservedModules.length > 0) {
321
+ await prompts.log.warn(
322
+ `Retaining ${preservedModules.length} installed module(s) with no available source: ${preservedModules.join(', ')}`,
323
+ );
324
+ }
325
+
326
+ // For existing installs, resolve per-module update decisions BEFORE
327
+ // we clone anything. Reads the existing manifest's recorded channel
328
+ // per module and prompts the user on available upgrades (patch/minor
329
+ // default Y, major default N). Legacy entries with no channel are
330
+ // migrated here too. Mutates channelOptions.pins to lock rejections.
331
+ await this._resolveUpdateChannels({
332
+ xiaomaDir,
333
+ selectedModules,
334
+ channelOptions,
335
+ yes: options.yes || false,
336
+ });
337
+
338
+ // Get tool selection
339
+ const toolSelection = await this.promptToolSelection(confirmedDirectory, options);
340
+
341
+ const { moduleConfigs, setOverrides } = await this.collectModuleConfigs(confirmedDirectory, selectedModules, {
342
+ ...options,
343
+ channelOptions,
344
+ });
345
+
346
+ // Warn about --pin/--next flags that refer to modules the user didn't
347
+ // select, or that target bundled modules (core/xmc) where channel
348
+ // flags don't apply.
349
+ {
350
+ const bundledCodes = await this._bundledModuleCodes();
351
+ for (const warning of [
352
+ ...orphanPinWarnings(channelOptions, selectedModules),
353
+ ...bundledTargetWarnings(channelOptions, bundledCodes),
354
+ ]) {
355
+ await prompts.log.warn(warning);
356
+ }
357
+ }
358
+
359
+ return {
360
+ actionType: 'update',
361
+ directory: confirmedDirectory,
362
+ modules: selectedModules,
363
+ ides: toolSelection.ides,
364
+ skipIde: toolSelection.skipIde,
365
+ coreConfig: moduleConfigs.core || {},
366
+ moduleConfigs: moduleConfigs,
367
+ setOverrides,
368
+ skipPrompts: options.yes || false,
369
+ channelOptions,
370
+ _preserveModules: preservedModules,
371
+ };
372
+ }
373
+ }
374
+
375
+ // This section is only for new installations (update returns early above)
376
+ const { installedModuleIds, installedModuleVersions } = await this.getExistingInstallation(confirmedDirectory);
377
+
378
+ // Unified module selection - all modules in one grouped multiselect
379
+ let selectedModules;
380
+ if (options.modules) {
381
+ // Use modules from command-line
382
+ selectedModules = options.modules
383
+ .split(',')
384
+ .map((m) => m.trim())
385
+ .filter(Boolean);
386
+ await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`);
387
+ } else if (options.customSource) {
388
+ // Custom source without --modules: start with empty list (core added below)
389
+ selectedModules = [];
390
+ } else if (options.yes) {
391
+ // Use default modules when --yes flag is set
392
+ selectedModules = await this.getDefaultModules(installedModuleIds);
393
+ await prompts.log.info(`Using default modules (--yes flag): ${selectedModules.join(', ')}`);
394
+ } else {
395
+ selectedModules = await this.selectAllModules(installedModuleIds, installedModuleVersions, channelOptions);
396
+ }
397
+
398
+ // Resolve custom sources from --custom-source flag
399
+ if (options.customSource) {
400
+ const customCodes = await this._resolveCustomSourcesCli(options.customSource);
401
+ for (const code of customCodes) {
402
+ if (!selectedModules.includes(code)) selectedModules.push(code);
403
+ }
404
+ }
405
+
406
+ // Ensure core is in the modules list
407
+ if (!selectedModules.includes('core')) {
408
+ selectedModules.unshift('core');
409
+ }
410
+
411
+ // Interactive channel gate: "Ready to install (all stable)? [Y/n]"
412
+ // Only shown for fresh installs with no channel flags and an external module
413
+ // selected. Skipped for prerelease launches because channelOptions.global
414
+ // was already seeded to 'next' upstream. Non-interactive installs skip this
415
+ // and fall through to the registry default (stable) or whatever flags were
416
+ // supplied.
417
+ await this._interactiveChannelGate({ options, channelOptions, selectedModules });
418
+
419
+ let toolSelection = await this.promptToolSelection(confirmedDirectory, options);
420
+ const { moduleConfigs, setOverrides } = await this.collectModuleConfigs(confirmedDirectory, selectedModules, {
421
+ ...options,
422
+ channelOptions,
423
+ });
424
+
425
+ // Warn about --pin/--next flags that refer to modules the user didn't
426
+ // select, or that target bundled modules (core/xmc) where channel
427
+ // flags don't apply.
428
+ {
429
+ const bundledCodes = await this._bundledModuleCodes();
430
+ for (const warning of [
431
+ ...orphanPinWarnings(channelOptions, selectedModules),
432
+ ...bundledTargetWarnings(channelOptions, bundledCodes),
433
+ ]) {
434
+ await prompts.log.warn(warning);
435
+ }
436
+ }
437
+
438
+ return {
439
+ actionType: 'install',
440
+ directory: confirmedDirectory,
441
+ modules: selectedModules,
442
+ ides: toolSelection.ides,
443
+ skipIde: toolSelection.skipIde,
444
+ coreConfig: moduleConfigs.core || {},
445
+ moduleConfigs: moduleConfigs,
446
+ setOverrides,
447
+ skipPrompts: options.yes || false,
448
+ channelOptions,
449
+ };
450
+ }
451
+
452
+ /**
453
+ * Prompt for tool/IDE selection (called after module configuration)
454
+ * Uses a split prompt approach:
455
+ * 1. Recommended tools - standard multiselect for preferred tools
456
+ * 2. Additional tools - autocompleteMultiselect with search capability
457
+ * @param {string} projectDir - Project directory to check for existing IDEs
458
+ * @param {Object} options - Command-line options
459
+ * @returns {Object} Tool configuration
460
+ */
461
+ _parseToolsFlag(toolsArg, allKnownValues) {
462
+ const selectedIdes = toolsArg
463
+ .split(',')
464
+ .map((t) => t.trim())
465
+ .filter(Boolean);
466
+
467
+ if (selectedIdes.length === 0) {
468
+ const err = new Error(
469
+ '--tools was passed empty. Provide at least one tool ID (e.g. --tools claude-code) or run with --list-tools to see valid IDs.',
470
+ );
471
+ err.expected = true;
472
+ throw err;
473
+ }
474
+
475
+ const unknown = selectedIdes.filter((id) => !allKnownValues.has(id));
476
+ if (unknown.length > 0) {
477
+ const err = new Error(
478
+ [
479
+ `Unknown tool ID${unknown.length === 1 ? '' : 's'}: ${unknown.join(', ')}`,
480
+ '',
481
+ 'Run with --list-tools to see all valid IDs.',
482
+ 'Common: claude-code, cursor, copilot, windsurf, cline',
483
+ ].join('\n'),
484
+ );
485
+ err.expected = true;
486
+ throw err;
487
+ }
488
+
489
+ return selectedIdes;
490
+ }
491
+
492
+ async promptToolSelection(projectDir, options = {}) {
493
+ const { ExistingInstall } = require('./core/existing-install');
494
+ const { Installer } = require('./core/installer');
495
+ const installer = new Installer();
496
+ const { xiaomaDir } = await installer.findXiaomaDir(projectDir || process.cwd());
497
+ const existingInstall = await ExistingInstall.detect(xiaomaDir);
498
+ const configuredIdes = existingInstall.ides;
499
+
500
+ // Get IDE manager to fetch available IDEs dynamically
501
+ const { IdeManager } = require('./ide/manager');
502
+ const ideManager = new IdeManager();
503
+ await ideManager.ensureInitialized(); // IMPORTANT: Must initialize before getting IDEs
504
+
505
+ const preferredIdes = ideManager.getPreferredIdes();
506
+ const otherIdes = ideManager.getOtherIdes();
507
+
508
+ // Determine which configured IDEs are in "preferred" vs "other" categories
509
+ const configuredPreferred = configuredIdes.filter((id) => preferredIdes.some((ide) => ide.value === id));
510
+ const configuredOther = configuredIdes.filter((id) => otherIdes.some((ide) => ide.value === id));
511
+
512
+ // Warn about previously configured tools that are no longer available
513
+ const allKnownValues = new Set([...preferredIdes, ...otherIdes].map((ide) => ide.value));
514
+ const unknownTools = configuredIdes.filter((id) => id && typeof id === 'string' && !allKnownValues.has(id));
515
+ if (unknownTools.length > 0) {
516
+ await prompts.log.warn(`Previously configured tools are no longer available: ${unknownTools.join(', ')}`);
517
+ }
518
+
519
+ // ─────────────────────────────────────────────────────────────────────────────
520
+ // UPGRADE PATH: If tools already configured, show all tools with configured at top
521
+ // ─────────────────────────────────────────────────────────────────────────────
522
+ if (configuredIdes.length > 0) {
523
+ const allTools = [...preferredIdes, ...otherIdes];
524
+
525
+ // Non-interactive: handle --tools and --yes flags before interactive prompt
526
+ // Use !== undefined so an explicit --tools "" falls through to _parseToolsFlag and
527
+ // gets a specific "passed empty" error instead of being silently ignored.
528
+ if (options.tools !== undefined) {
529
+ const selectedIdes = this._parseToolsFlag(options.tools, allKnownValues);
530
+ await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
531
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
532
+ return { ides: selectedIdes, skipIde: false };
533
+ }
534
+
535
+ if (options.yes) {
536
+ await prompts.log.info(`Non-interactive mode (--yes): keeping configured tools: ${configuredIdes.join(', ')}`);
537
+ await this.displaySelectedTools(configuredIdes, preferredIdes, allTools);
538
+ return { ides: configuredIdes, skipIde: false };
539
+ }
540
+
541
+ // Sort: configured tools first, then preferred, then others
542
+ const sortedTools = [
543
+ ...allTools.filter((ide) => configuredIdes.includes(ide.value)),
544
+ ...allTools.filter((ide) => !configuredIdes.includes(ide.value)),
545
+ ];
546
+
547
+ const upgradeOptions = sortedTools.map((ide) => {
548
+ const isConfigured = configuredIdes.includes(ide.value);
549
+ const isPreferred = preferredIdes.some((p) => p.value === ide.value);
550
+ let label = ide.name;
551
+ if (isPreferred) label += ' ⭐';
552
+ if (isConfigured) label += ' ✅';
553
+ return { label, value: ide.value };
554
+ });
555
+
556
+ // Sort initialValues to match display order
557
+ const sortedInitialValues = sortedTools.filter((ide) => configuredIdes.includes(ide.value)).map((ide) => ide.value);
558
+
559
+ const upgradeSelected = await prompts.autocompleteMultiselect({
560
+ message: 'Integrate with',
561
+ options: upgradeOptions,
562
+ initialValues: sortedInitialValues,
563
+ required: false,
564
+ maxItems: 8,
565
+ });
566
+
567
+ const selectedIdes = upgradeSelected || [];
568
+
569
+ if (selectedIdes.length === 0) {
570
+ const confirmNoTools = await prompts.confirm({
571
+ message: 'No tools selected. Continue without installing any tools?',
572
+ default: false,
573
+ });
574
+
575
+ if (!confirmNoTools) {
576
+ return this.promptToolSelection(projectDir, options);
577
+ }
578
+
579
+ return { ides: [], skipIde: true };
580
+ }
581
+
582
+ // Display selected tools
583
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
584
+
585
+ return { ides: selectedIdes, skipIde: false };
586
+ }
587
+
588
+ // ─────────────────────────────────────────────────────────────────────────────
589
+ // NEW INSTALL: Show all tools with search
590
+ // ─────────────────────────────────────────────────────────────────────────────
591
+ const allTools = [...preferredIdes, ...otherIdes];
592
+
593
+ const allToolOptions = allTools.map((ide) => {
594
+ const isPreferred = preferredIdes.some((p) => p.value === ide.value);
595
+ let label = ide.name;
596
+ if (isPreferred) label += ' ⭐';
597
+ return {
598
+ label,
599
+ value: ide.value,
600
+ };
601
+ });
602
+
603
+ let selectedIdes = [];
604
+
605
+ // Check if tools are provided via command-line.
606
+ // Use !== undefined so an explicit --tools "" still hits _parseToolsFlag's empty-value error.
607
+ if (options.tools !== undefined) {
608
+ selectedIdes = this._parseToolsFlag(options.tools, allKnownValues);
609
+ await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
610
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
611
+ return { ides: selectedIdes, skipIde: false };
612
+ } else if (options.yes) {
613
+ // If --yes flag is set, skip tool prompt and use previously configured tools or empty
614
+ if (configuredIdes.length > 0) {
615
+ await prompts.log.info(`Using previously configured tools (--yes flag): ${configuredIdes.join(', ')}`);
616
+ await this.displaySelectedTools(configuredIdes, preferredIdes, allTools);
617
+ return { ides: configuredIdes, skipIde: false };
618
+ } else {
619
+ const err = new Error(
620
+ [
621
+ '--tools is required for non-interactive install (--yes / -y) when no tools are previously configured.',
622
+ '',
623
+ 'Common: claude-code, cursor, copilot, windsurf, cline',
624
+ 'See all supported tools: npx @zeyue0329/xiaoma-cli install --list-tools',
625
+ '',
626
+ 'Example: npx @zeyue0329/xiaoma-cli install --modules xmc --tools claude-code -y',
627
+ ].join('\n'),
628
+ );
629
+ err.expected = true;
630
+ throw err;
631
+ }
632
+ }
633
+
634
+ // Interactive mode
635
+ const interactiveSelectedIdes = await prompts.autocompleteMultiselect({
636
+ message: 'Integrate with:',
637
+ options: allToolOptions,
638
+ initialValues: configuredIdes.length > 0 ? configuredIdes : undefined,
639
+ required: false,
640
+ maxItems: 8,
641
+ });
642
+
643
+ selectedIdes = interactiveSelectedIdes || [];
644
+
645
+ // ─────────────────────────────────────────────────────────────────────────────
646
+ // STEP 3: Confirm if no tools selected
647
+ // ─────────────────────────────────────────────────────────────────────────────
648
+ if (selectedIdes.length === 0) {
649
+ const confirmNoTools = await prompts.confirm({
650
+ message: 'No tools selected. Continue without installing any tools?',
651
+ default: false,
652
+ });
653
+
654
+ if (!confirmNoTools) {
655
+ // User wants to select tools - recurse
656
+ return this.promptToolSelection(projectDir, options);
657
+ }
658
+
659
+ return {
660
+ ides: [],
661
+ skipIde: true,
662
+ };
663
+ }
664
+
665
+ // Display selected tools
666
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
667
+
668
+ return {
669
+ ides: selectedIdes,
670
+ skipIde: selectedIdes.length === 0,
671
+ };
672
+ }
673
+
674
+ /**
675
+ * Prompt for update configuration
676
+ * @returns {Object} Update configuration
677
+ */
678
+ async promptUpdate() {
679
+ const backupFirst = await prompts.confirm({
680
+ message: 'Create backup before updating?',
681
+ default: true,
682
+ });
683
+
684
+ const preserveCustomizations = await prompts.confirm({
685
+ message: 'Preserve local customizations?',
686
+ default: true,
687
+ });
688
+
689
+ return { backupFirst, preserveCustomizations };
690
+ }
691
+
692
+ /**
693
+ * Confirm action
694
+ * @param {string} message - Confirmation message
695
+ * @param {boolean} defaultValue - Default value
696
+ * @returns {boolean} User confirmation
697
+ */
698
+ async confirm(message, defaultValue = false) {
699
+ return await prompts.confirm({
700
+ message,
701
+ default: defaultValue,
702
+ });
703
+ }
704
+
705
+ /**
706
+ * Get confirmed directory from user
707
+ * @returns {string} Confirmed directory path
708
+ */
709
+ async getConfirmedDirectory() {
710
+ let confirmedDirectory = null;
711
+ while (!confirmedDirectory) {
712
+ const directoryAnswer = await this.promptForDirectory();
713
+ await this.displayDirectoryInfo(directoryAnswer.directory);
714
+
715
+ if (await this.confirmDirectory(directoryAnswer.directory)) {
716
+ confirmedDirectory = directoryAnswer.directory;
717
+ }
718
+ }
719
+ return confirmedDirectory;
720
+ }
721
+
722
+ /**
723
+ * Get existing installation info and installed modules
724
+ * @param {string} directory - Installation directory
725
+ * @returns {Object} Object with existingInstall, installedModuleIds, installedModuleVersions, and xiaomaDir
726
+ */
727
+ async getExistingInstallation(directory) {
728
+ const { ExistingInstall } = require('./core/existing-install');
729
+ const { Installer } = require('./core/installer');
730
+ const installer = new Installer();
731
+ const { xiaomaDir } = await installer.findXiaomaDir(directory);
732
+ const existingInstall = await ExistingInstall.detect(xiaomaDir);
733
+ const installedModuleIds = new Set(existingInstall.moduleIds);
734
+ const installedModuleVersions = new Map();
735
+ const manifestModules = await manifest.getAllModuleVersions(xiaomaDir);
736
+
737
+ for (const module of manifestModules) {
738
+ if (module?.name && module.version) {
739
+ installedModuleVersions.set(module.name, module.version);
740
+ }
741
+ }
742
+
743
+ for (const module of existingInstall.modules) {
744
+ if (module?.id && module.version && module.version !== 'unknown' && !installedModuleVersions.has(module.id)) {
745
+ installedModuleVersions.set(module.id, module.version);
746
+ }
747
+ }
748
+
749
+ if (existingInstall.hasCore && existingInstall.version && !installedModuleVersions.has('core')) {
750
+ installedModuleVersions.set('core', existingInstall.version);
751
+ }
752
+
753
+ return { existingInstall, installedModuleIds, installedModuleVersions, xiaomaDir };
754
+ }
755
+
756
+ /**
757
+ * Collect all module configurations (core + selected modules).
758
+ * All interactive prompting happens here in the UI layer.
759
+ * @param {string} directory - Installation directory
760
+ * @param {string[]} modules - Modules to configure (including 'core')
761
+ * @param {Object} options - Command-line options
762
+ * @returns {Object} Collected module configurations keyed by module name
763
+ */
764
+ async collectModuleConfigs(directory, modules, options = {}) {
765
+ const { OfficialModules } = require('./modules/official-modules');
766
+
767
+ // Parse --set up front purely to surface user-error before the install
768
+ // burns time on the network / filesystem. The actual application happens
769
+ // in installer.install() as a post-write TOML patch — see
770
+ // `tools/installer/set-overrides.js`. We also warn about overrides
771
+ // targeting modules the user didn't include, since those will silently
772
+ // miss the file the patch step looks for.
773
+ let setOverrides = {};
774
+ try {
775
+ setOverrides = parseSetEntries(options.set || []);
776
+ } catch (error) {
777
+ // install.js validated already; rethrow as-is for the user.
778
+ throw error;
779
+ }
780
+ // Drop overrides for modules that aren't in the install set so the
781
+ // post-install patch step doesn't create orphan sections in config.toml
782
+ // for modules that were never installed.
783
+ const selectedModuleSet = new Set(['core', ...modules]);
784
+ for (const moduleCode of Object.keys(setOverrides)) {
785
+ if (!selectedModuleSet.has(moduleCode)) {
786
+ await prompts.log.warn(
787
+ `--set ${moduleCode}.* — module '${moduleCode}' is not in the install set; values will be ignored. Add it to --modules to apply.`,
788
+ );
789
+ delete setOverrides[moduleCode];
790
+ }
791
+ }
792
+
793
+ const configCollector = new OfficialModules({ channelOptions: options.channelOptions });
794
+
795
+ // Seed core config from CLI options and/or --yes defaults.
796
+ const hasCoreFlags = Boolean(
797
+ options.userName || options.communicationLanguage || options.documentOutputLanguage || options.outputFolder,
798
+ );
799
+ if (hasCoreFlags || options.yes) {
800
+ const coreConfig = {};
801
+ if (options.userName) {
802
+ coreConfig.user_name = options.userName;
803
+ await prompts.log.info(`Using user name from command-line: ${options.userName}`);
804
+ }
805
+ if (options.communicationLanguage) {
806
+ coreConfig.communication_language = options.communicationLanguage;
807
+ await prompts.log.info(`Using communication language from command-line: ${options.communicationLanguage}`);
808
+ }
809
+ if (options.documentOutputLanguage) {
810
+ coreConfig.document_output_language = options.documentOutputLanguage;
811
+ await prompts.log.info(`Using document output language from command-line: ${options.documentOutputLanguage}`);
812
+ }
813
+ if (options.outputFolder) {
814
+ coreConfig.output_folder = options.outputFolder;
815
+ await prompts.log.info(`Using output folder from command-line: ${options.outputFolder}`);
816
+ }
817
+
818
+ // Load existing config to merge with provided options
819
+ await configCollector.loadExistingConfig(directory);
820
+ const existingConfig = configCollector.collectedConfig.core || {};
821
+
822
+ if (options.yes) {
823
+ // Non-interactive: EVERY core key that wasn't supplied via flag (or carried
824
+ // over from a prior install) must still receive its default. Otherwise core
825
+ // cross-references like {output_folder} have nothing to resolve against and
826
+ // leak the literal placeholder into module configs (and create a dir named
827
+ // "{output_folder}"). Precedence: flag > existing install > default.
828
+ let safeUsername;
829
+ try {
830
+ safeUsername = os.userInfo().username;
831
+ } catch {
832
+ safeUsername = process.env.USER || process.env.USERNAME || 'User';
833
+ }
834
+ const defaultUsername = safeUsername.charAt(0).toUpperCase() + safeUsername.slice(1);
835
+ const coreDefaults = {
836
+ user_name: defaultUsername,
837
+ // {directory_name} default per src/core-skills/module.yaml — matches what the
838
+ // interactive flow resolves via buildQuestion()'s {directory_name} placeholder.
839
+ project_name: path.basename(directory),
840
+ communication_language: 'English',
841
+ document_output_language: 'English',
842
+ output_folder: '_xiaoma-output',
843
+ };
844
+ configCollector.collectedConfig.core = { ...coreDefaults, ...existingConfig, ...coreConfig };
845
+ // existingConfig can carry a corrupt user_name (empty or the literal
846
+ // "[USER_NAME]" placeholder from a legacy/hand-edited install). Because core
847
+ // is seeded directly here, collectAllConfigurations skips it and the normal
848
+ // [USER_NAME] sanitizer never runs — so guard it explicitly.
849
+ const seededUserName = configCollector.collectedConfig.core.user_name;
850
+ if (!seededUserName || seededUserName === '[USER_NAME]') {
851
+ configCollector.collectedConfig.core.user_name = defaultUsername;
852
+ }
853
+ await prompts.log.info('Using default configuration for unspecified core settings (--yes flag)');
854
+ } else {
855
+ configCollector.collectedConfig.core = { ...existingConfig, ...coreConfig };
856
+ // Interactive: collect any core keys the user didn't pass as flags.
857
+ if (!options.userName || !options.communicationLanguage || !options.documentOutputLanguage || !options.outputFolder) {
858
+ await configCollector.collectModuleConfig('core', directory, false, true);
859
+ }
860
+ }
861
+ }
862
+
863
+ // Collect all module configs — core is skipped if already seeded above
864
+ await configCollector.collectAllConfigurations(modules, directory, {
865
+ skipPrompts: options.yes || false,
866
+ });
867
+
868
+ return { moduleConfigs: configCollector.collectedConfig, setOverrides };
869
+ }
870
+
871
+ /**
872
+ * Select all modules across three tiers: official, community, and custom URL.
873
+ * @param {Set} installedModuleIds - Currently installed module IDs
874
+ * @param {Map<string, string>} installedModuleVersions - Installed module versions from the local manifest
875
+ * @param {Object|null} channelOptions - Parsed installer channel options
876
+ * @returns {Array} Selected module codes (excluding core)
877
+ */
878
+ async selectAllModules(installedModuleIds = new Set(), installedModuleVersions = new Map(), channelOptions = null) {
879
+ // Phase 1: Official modules
880
+ const officialSelected = await this._selectOfficialModules(installedModuleIds, installedModuleVersions, channelOptions);
881
+
882
+ // Identify installed modules that aren't official (previously installed
883
+ // community modules or custom-source modules). Preserve them on update;
884
+ // they can be managed via --custom-source, uninstall, or a dedicated installer.
885
+ const externalManager = new ExternalModuleManager();
886
+ const registryModules = await externalManager.listAvailable();
887
+ const officialRegistryCodes = new Set(['core', 'xmc', 'xpm', ...registryModules.map((m) => m.code)]);
888
+ const installedNonOfficial = [...installedModuleIds].filter((id) => !officialRegistryCodes.has(id));
889
+
890
+ // Phase 2: Custom URL modules
891
+ const customSelected = await this._addCustomUrlModules(installedModuleIds);
892
+
893
+ const allSelected = new Set([...officialSelected, ...customSelected, ...installedNonOfficial]);
894
+
895
+ return [...allSelected];
896
+ }
897
+
898
+ /**
899
+ * Select official modules using autocompleteMultiselect.
900
+ * Extracted from the original selectAllModules - unchanged behavior.
901
+ * @param {Set} installedModuleIds - Currently installed module IDs
902
+ * @param {Map<string, string>} installedModuleVersions - Installed module versions from the local manifest
903
+ * @param {Object|null} channelOptions - Parsed installer channel options
904
+ * @returns {Array} Selected official module codes
905
+ */
906
+ async _selectOfficialModules(installedModuleIds = new Set(), installedModuleVersions = new Map(), channelOptions = null) {
907
+ // Built-in modules (core, xmc) come from local source, not the registry
908
+ const { OfficialModules } = require('./modules/official-modules');
909
+ const builtInModules = (await new OfficialModules().listAvailable()).modules || [];
910
+
911
+ // External modules come from the registry (with fallback)
912
+ const externalManager = new ExternalModuleManager();
913
+ const registryModules = await externalManager.listAvailable();
914
+
915
+ const allOptions = [];
916
+ const initialValues = [];
917
+ const lockedValues = ['core'];
918
+
919
+ const buildModuleEntry = async (code, name, description, isDefault, repoUrl = null, registryDefault = null) => {
920
+ const isInstalled = installedModuleIds.has(code);
921
+ const installedVersion = installedModuleVersions.get(code) || '';
922
+ const versionState = await getModuleVersion(code, { repoUrl, registryDefault, channelOptions });
923
+ const label = buildModuleLabel(name, versionState.version, installedVersion);
924
+ return {
925
+ label,
926
+ value: code,
927
+ hint: description,
928
+ selected: isInstalled || isDefault,
929
+ lookupAttempted: versionState.lookupAttempted,
930
+ lookupSucceeded: versionState.lookupSucceeded,
931
+ };
932
+ };
933
+
934
+ // Add built-in modules first (always available regardless of network)
935
+ const builtInCodes = new Set();
936
+ for (const mod of builtInModules) {
937
+ const code = mod.id;
938
+ builtInCodes.add(code);
939
+ const entry = await buildModuleEntry(code, mod.name, mod.description, mod.defaultSelected);
940
+ allOptions.push({ label: entry.label, value: entry.value, hint: entry.hint });
941
+ if (entry.selected) {
942
+ initialValues.push(code);
943
+ }
944
+ }
945
+
946
+ // Add external registry modules (skip built-in duplicates)
947
+ const externalRegistryModules = registryModules.filter((mod) => !mod.builtIn && !builtInCodes.has(mod.code));
948
+ let externalRegistryEntries = [];
949
+ if (externalRegistryModules.length > 0) {
950
+ const spinner = await prompts.spinner();
951
+ spinner.start('Checking latest module versions...');
952
+
953
+ externalRegistryEntries = await Promise.all(
954
+ externalRegistryModules.map(async (mod) => ({
955
+ code: mod.code,
956
+ entry: await buildModuleEntry(
957
+ mod.code,
958
+ mod.name,
959
+ mod.description,
960
+ mod.defaultSelected,
961
+ mod.url || null,
962
+ mod.defaultChannel || null,
963
+ ),
964
+ })),
965
+ );
966
+
967
+ spinner.stop('Checked latest module versions.');
968
+
969
+ const attemptedLookups = externalRegistryEntries.filter(({ entry }) => entry.lookupAttempted).length;
970
+ const successfulLookups = externalRegistryEntries.filter(({ entry }) => entry.lookupSucceeded).length;
971
+ if (attemptedLookups > 0 && successfulLookups === 0) {
972
+ await prompts.log.warn('Could not check latest module versions; showing cached/local versions.');
973
+ }
974
+ }
975
+ for (const { code, entry } of externalRegistryEntries) {
976
+ allOptions.push({ label: entry.label, value: entry.value, hint: entry.hint });
977
+ if (entry.selected) {
978
+ initialValues.push(code);
979
+ }
980
+ }
981
+
982
+ const selected = await prompts.autocompleteMultiselect({
983
+ message: 'Select official modules to install:',
984
+ options: allOptions,
985
+ initialValues: initialValues.length > 0 ? initialValues : undefined,
986
+ lockedValues,
987
+ required: true,
988
+ maxItems: allOptions.length,
989
+ });
990
+
991
+ const result = selected ? [...selected] : [];
992
+
993
+ if (result.length > 0) {
994
+ const moduleLines = result.map((moduleId) => {
995
+ const opt = allOptions.find((o) => o.value === moduleId);
996
+ return ` \u2022 ${opt?.label || moduleId}`;
997
+ });
998
+ await prompts.log.message('Selected official modules:\n' + moduleLines.join('\n'));
999
+ }
1000
+
1001
+ return result;
1002
+ }
1003
+
1004
+ /**
1005
+ * Prompt user to install modules from custom sources (Git URLs or local paths).
1006
+ * @param {Set} installedModuleIds - Currently installed module IDs
1007
+ * @returns {Array} Selected custom module code strings
1008
+ */
1009
+ async _addCustomUrlModules(installedModuleIds = new Set()) {
1010
+ const addCustom = await prompts.confirm({
1011
+ message: 'Do you want to install custom or community modules (Git URL or local path)?',
1012
+ default: false,
1013
+ });
1014
+ if (!addCustom) return [];
1015
+
1016
+ const { CustomModuleManager } = require('./modules/custom-module-manager');
1017
+ const customMgr = new CustomModuleManager();
1018
+ const selectedModules = [];
1019
+
1020
+ let addMore = true;
1021
+ while (addMore) {
1022
+ const sourceInput = await prompts.text({
1023
+ message: 'Git URL or local path:',
1024
+ placeholder: 'https://github.com/owner/repo or /path/to/module',
1025
+ validate: (input) => {
1026
+ if (!input || input.trim() === '') return 'Source is required';
1027
+ const result = customMgr.parseSource(input.trim());
1028
+ return result.isValid ? undefined : result.error;
1029
+ },
1030
+ });
1031
+
1032
+ const s = await prompts.spinner();
1033
+ s.start('Resolving source...');
1034
+
1035
+ let sourceResult;
1036
+ try {
1037
+ sourceResult = await customMgr.resolveSource(sourceInput.trim(), { skipInstall: true, silent: true });
1038
+ s.stop(sourceResult.parsed.type === 'local' ? 'Local source resolved' : 'Repository cloned');
1039
+ } catch (error) {
1040
+ s.error('Failed to resolve source');
1041
+ await prompts.log.error(` ${error.message}`);
1042
+ addMore = await prompts.confirm({ message: 'Try another source?', default: false });
1043
+ continue;
1044
+ }
1045
+
1046
+ if (sourceResult.parsed.type === 'local') {
1047
+ await prompts.log.info('LOCAL MODULE: Pointing directly at local source (changes take effect on reinstall).');
1048
+ } else {
1049
+ await prompts.log.warn(
1050
+ 'UNVERIFIED MODULE: This module has not been reviewed by the XiaoMa team.\n' + ' Only install modules from sources you trust.',
1051
+ );
1052
+ }
1053
+
1054
+ // Resolve plugins based on discovery mode vs direct mode
1055
+ s.start('Analyzing plugin structure...');
1056
+ const allResolved = [];
1057
+ const localPath = sourceResult.parsed.type === 'local' ? sourceResult.rootDir : null;
1058
+
1059
+ if (sourceResult.mode === 'discovery') {
1060
+ // Discovery mode: marketplace.json found, list available plugins
1061
+ let plugins;
1062
+ try {
1063
+ plugins = await customMgr.discoverModules(sourceResult.marketplace, sourceResult.sourceUrl);
1064
+ } catch (discoverError) {
1065
+ s.error('Failed to discover modules');
1066
+ await prompts.log.error(` ${discoverError.message}`);
1067
+ addMore = await prompts.confirm({ message: 'Try another source?', default: false });
1068
+ continue;
1069
+ }
1070
+
1071
+ const effectiveRepoPath = sourceResult.repoPath || sourceResult.rootDir;
1072
+ for (const plugin of plugins) {
1073
+ try {
1074
+ const resolved = await customMgr.resolvePlugin(effectiveRepoPath, plugin.rawPlugin, sourceResult.sourceUrl, localPath);
1075
+ if (resolved.length > 0) {
1076
+ allResolved.push(...resolved);
1077
+ } else {
1078
+ // No skills array or empty - use plugin metadata as-is (legacy)
1079
+ allResolved.push({
1080
+ code: plugin.code,
1081
+ name: plugin.displayName || plugin.name,
1082
+ version: plugin.version,
1083
+ description: plugin.description,
1084
+ strategy: 0,
1085
+ pluginName: plugin.name,
1086
+ skillPaths: [],
1087
+ });
1088
+ }
1089
+ } catch (resolveError) {
1090
+ await prompts.log.warn(` Could not resolve ${plugin.name}: ${resolveError.message}`);
1091
+ }
1092
+ }
1093
+ } else {
1094
+ // Direct mode: no marketplace.json, scan directory for skills and resolve
1095
+ const directPlugin = {
1096
+ name: sourceResult.parsed.displayName || path.basename(sourceResult.rootDir),
1097
+ source: '.',
1098
+ skills: [],
1099
+ };
1100
+
1101
+ // Scan for SKILL.md directories to populate skills array
1102
+ try {
1103
+ const entries = await fs.readdir(sourceResult.rootDir, { withFileTypes: true });
1104
+ for (const entry of entries) {
1105
+ if (entry.isDirectory()) {
1106
+ const skillMd = path.join(sourceResult.rootDir, entry.name, 'SKILL.md');
1107
+ if (await fs.pathExists(skillMd)) {
1108
+ directPlugin.skills.push(entry.name);
1109
+ }
1110
+ }
1111
+ }
1112
+ } catch (scanError) {
1113
+ s.error('Failed to scan directory');
1114
+ await prompts.log.error(` ${scanError.message}`);
1115
+ addMore = await prompts.confirm({ message: 'Try another source?', default: false });
1116
+ continue;
1117
+ }
1118
+
1119
+ if (directPlugin.skills.length > 0) {
1120
+ try {
1121
+ const resolved = await customMgr.resolvePlugin(sourceResult.rootDir, directPlugin, sourceResult.sourceUrl, localPath);
1122
+ allResolved.push(...resolved);
1123
+ } catch (resolveError) {
1124
+ await prompts.log.warn(` Could not resolve: ${resolveError.message}`);
1125
+ }
1126
+ }
1127
+ }
1128
+ s.stop(`Found ${allResolved.length} installable module${allResolved.length === 1 ? '' : 's'}`);
1129
+
1130
+ if (allResolved.length === 0) {
1131
+ await prompts.log.warn('No installable modules found in this source.');
1132
+ addMore = await prompts.confirm({ message: 'Try another source?', default: false });
1133
+ continue;
1134
+ }
1135
+
1136
+ // Build multiselect choices
1137
+ // Already-installed modules are pre-checked (update). New modules are unchecked (opt-in).
1138
+ // Unchecking an installed module means "skip update" - removal is handled elsewhere.
1139
+ const choices = allResolved.map((mod) => {
1140
+ const versionStr = mod.version ? ` v${mod.version}` : '';
1141
+ const skillCount = mod.skillPaths ? mod.skillPaths.length : 0;
1142
+ const skillStr = skillCount > 0 ? ` (${skillCount} skill${skillCount === 1 ? '' : 's'})` : '';
1143
+ const alreadyInstalled = installedModuleIds.has(mod.code);
1144
+ const hint = alreadyInstalled ? 'update' : undefined;
1145
+
1146
+ return {
1147
+ name: `${mod.name}${versionStr}${skillStr}`,
1148
+ value: mod.code,
1149
+ hint,
1150
+ checked: alreadyInstalled,
1151
+ };
1152
+ });
1153
+
1154
+ // Show descriptions before the multiselect
1155
+ for (const mod of allResolved) {
1156
+ const versionStr = mod.version ? ` v${mod.version}` : '';
1157
+ await prompts.log.info(` ${mod.name}${versionStr}\n ${mod.description}`);
1158
+ }
1159
+
1160
+ const selected = await prompts.multiselect({
1161
+ message: 'Select modules to install:',
1162
+ choices,
1163
+ required: false,
1164
+ });
1165
+
1166
+ if (selected && selected.length > 0) {
1167
+ for (const code of selected) {
1168
+ selectedModules.push(code);
1169
+ }
1170
+ }
1171
+
1172
+ addMore = await prompts.confirm({
1173
+ message: 'Add another custom source?',
1174
+ default: false,
1175
+ });
1176
+ }
1177
+
1178
+ if (selectedModules.length > 0) {
1179
+ await prompts.log.message('Selected custom modules:\n' + selectedModules.map((c) => ` \u2022 ${c}`).join('\n'));
1180
+ }
1181
+
1182
+ return selectedModules;
1183
+ }
1184
+
1185
+ /**
1186
+ * Resolve custom sources from --custom-source CLI flag (non-interactive).
1187
+ * Auto-selects all discovered modules from each source.
1188
+ * @param {string} sourcesArg - Comma-separated Git URLs or local paths
1189
+ * @returns {Array} Module codes from all resolved sources
1190
+ */
1191
+ async _resolveCustomSourcesCli(sourcesArg) {
1192
+ const { CustomModuleManager } = require('./modules/custom-module-manager');
1193
+ const customMgr = new CustomModuleManager();
1194
+ const allCodes = [];
1195
+
1196
+ const sources = sourcesArg
1197
+ .split(',')
1198
+ .map((s) => s.trim())
1199
+ .filter(Boolean);
1200
+
1201
+ for (const source of sources) {
1202
+ const s = await prompts.spinner();
1203
+ s.start(`Resolving ${source}...`);
1204
+
1205
+ let sourceResult;
1206
+ try {
1207
+ sourceResult = await customMgr.resolveSource(source, { skipInstall: true, silent: true });
1208
+ s.stop(sourceResult.parsed.type === 'local' ? 'Local source resolved' : 'Repository cloned');
1209
+ } catch (error) {
1210
+ s.error(`Failed to resolve ${source}`);
1211
+ await prompts.log.error(` ${error.message}`);
1212
+ continue;
1213
+ }
1214
+
1215
+ const s2 = await prompts.spinner();
1216
+ s2.start('Analyzing plugin structure...');
1217
+ const allResolved = [];
1218
+ const localPath = sourceResult.parsed.type === 'local' ? sourceResult.rootDir : null;
1219
+
1220
+ if (sourceResult.mode === 'discovery') {
1221
+ try {
1222
+ const plugins = await customMgr.discoverModules(sourceResult.marketplace, sourceResult.sourceUrl);
1223
+ const effectiveRepoPath = sourceResult.repoPath || sourceResult.rootDir;
1224
+ for (const plugin of plugins) {
1225
+ try {
1226
+ const resolved = await customMgr.resolvePlugin(effectiveRepoPath, plugin.rawPlugin, sourceResult.sourceUrl, localPath);
1227
+ if (resolved.length > 0) {
1228
+ allResolved.push(...resolved);
1229
+ }
1230
+ } catch {
1231
+ // Skip unresolvable plugins
1232
+ }
1233
+ }
1234
+ } catch (discoverError) {
1235
+ s2.error('Failed to discover modules');
1236
+ await prompts.log.error(` ${discoverError.message}`);
1237
+ continue;
1238
+ }
1239
+ } else {
1240
+ // Direct mode: scan for SKILL.md directories
1241
+ const directPlugin = {
1242
+ name: sourceResult.parsed.displayName || path.basename(sourceResult.rootDir),
1243
+ source: '.',
1244
+ skills: [],
1245
+ };
1246
+ try {
1247
+ const entries = await fs.readdir(sourceResult.rootDir, { withFileTypes: true });
1248
+ for (const entry of entries) {
1249
+ if (entry.isDirectory()) {
1250
+ const skillMd = path.join(sourceResult.rootDir, entry.name, 'SKILL.md');
1251
+ if (await fs.pathExists(skillMd)) {
1252
+ directPlugin.skills.push(entry.name);
1253
+ }
1254
+ }
1255
+ }
1256
+ } catch {
1257
+ // Skip unreadable directories
1258
+ }
1259
+
1260
+ if (directPlugin.skills.length > 0) {
1261
+ try {
1262
+ const resolved = await customMgr.resolvePlugin(sourceResult.rootDir, directPlugin, sourceResult.sourceUrl, localPath);
1263
+ allResolved.push(...resolved);
1264
+ } catch {
1265
+ // Skip unresolvable
1266
+ }
1267
+ }
1268
+ }
1269
+ s2.stop(`Found ${allResolved.length} module${allResolved.length === 1 ? '' : 's'}`);
1270
+
1271
+ for (const mod of allResolved) {
1272
+ allCodes.push(mod.code);
1273
+ const versionStr = mod.version ? ` v${mod.version}` : '';
1274
+ await prompts.log.info(` Custom module: ${mod.name}${versionStr}`);
1275
+ }
1276
+ }
1277
+
1278
+ return allCodes;
1279
+ }
1280
+
1281
+ /**
1282
+ * Get default modules for non-interactive mode
1283
+ * @param {Set} installedModuleIds - Already installed module IDs
1284
+ * @returns {Array} Default module codes
1285
+ */
1286
+ async getDefaultModules(installedModuleIds = new Set()) {
1287
+ // Built-in modules with default_selected come from local source
1288
+ const { OfficialModules } = require('./modules/official-modules');
1289
+ const builtInModules = (await new OfficialModules().listAvailable()).modules || [];
1290
+
1291
+ const defaultModules = [];
1292
+ const seen = new Set();
1293
+
1294
+ for (const mod of builtInModules) {
1295
+ if (mod.defaultSelected || installedModuleIds.has(mod.id)) {
1296
+ defaultModules.push(mod.id);
1297
+ seen.add(mod.id);
1298
+ }
1299
+ }
1300
+
1301
+ // Add external registry defaults
1302
+ const externalManager = new ExternalModuleManager();
1303
+ const registryModules = await externalManager.listAvailable();
1304
+
1305
+ for (const mod of registryModules) {
1306
+ if (mod.builtIn || seen.has(mod.code)) continue;
1307
+ if (mod.defaultSelected || installedModuleIds.has(mod.code)) {
1308
+ defaultModules.push(mod.code);
1309
+ }
1310
+ }
1311
+
1312
+ // If no defaults found, use 'xmc' as the fallback default
1313
+ if (defaultModules.length === 0) {
1314
+ defaultModules.push('xmc');
1315
+ }
1316
+
1317
+ return defaultModules;
1318
+ }
1319
+
1320
+ /**
1321
+ * Prompt for directory selection
1322
+ * @returns {Object} Directory answer from prompt
1323
+ */
1324
+ async promptForDirectory() {
1325
+ // Use sync validation because @clack/prompts doesn't support async validate
1326
+ const directory = await prompts.directory({
1327
+ message: 'Installation directory:',
1328
+ default: process.cwd(),
1329
+ placeholder: process.cwd(),
1330
+ validate: (input) => this.validateDirectorySync(input),
1331
+ });
1332
+
1333
+ // Apply filter logic
1334
+ let filteredDir = directory;
1335
+ if (!filteredDir || filteredDir.trim() === '') {
1336
+ filteredDir = process.cwd();
1337
+ } else {
1338
+ filteredDir = this.expandUserPath(filteredDir);
1339
+ }
1340
+
1341
+ return { directory: filteredDir };
1342
+ }
1343
+
1344
+ /**
1345
+ * Display directory information
1346
+ * @param {string} directory - The directory path
1347
+ */
1348
+ async displayDirectoryInfo(directory) {
1349
+ await prompts.log.info(`Resolved installation path: ${directory}`);
1350
+
1351
+ const dirExists = await fs.pathExists(directory);
1352
+ if (dirExists) {
1353
+ // Show helpful context about the existing path
1354
+ const stats = await fs.stat(directory);
1355
+ if (stats.isDirectory()) {
1356
+ const files = await fs.readdir(directory);
1357
+ if (files.length > 0) {
1358
+ // Check for any xiaoma installation (any folder with _config/manifest.yaml)
1359
+ const { Installer } = require('./core/installer');
1360
+ const installer = new Installer();
1361
+ const xiaomaResult = await installer.findXiaomaDir(directory);
1362
+ const hasXiaomaInstall =
1363
+ (await fs.pathExists(xiaomaResult.xiaomaDir)) &&
1364
+ (await fs.pathExists(path.join(xiaomaResult.xiaomaDir, '_config', 'manifest.yaml')));
1365
+
1366
+ const xiaomaNote = hasXiaomaInstall ? ` including existing XiaoMa installation (${path.basename(xiaomaResult.xiaomaDir)})` : '';
1367
+ await prompts.log.message(`Directory exists and contains ${files.length} item(s)${xiaomaNote}`);
1368
+ } else {
1369
+ await prompts.log.message('Directory exists and is empty');
1370
+ }
1371
+ }
1372
+ }
1373
+ }
1374
+
1375
+ /**
1376
+ * Confirm directory selection
1377
+ * @param {string} directory - The directory path
1378
+ * @returns {boolean} Whether user confirmed
1379
+ */
1380
+ async confirmDirectory(directory) {
1381
+ const dirExists = await fs.pathExists(directory);
1382
+
1383
+ if (dirExists) {
1384
+ const proceed = await prompts.confirm({
1385
+ message: 'Install to this directory?',
1386
+ default: true,
1387
+ });
1388
+
1389
+ if (!proceed) {
1390
+ await prompts.log.warn("Let's try again with a different path.");
1391
+ }
1392
+
1393
+ return proceed;
1394
+ } else {
1395
+ // Ask for confirmation to create the directory
1396
+ const create = await prompts.confirm({
1397
+ message: `Create directory: ${directory}?`,
1398
+ default: false,
1399
+ });
1400
+
1401
+ if (!create) {
1402
+ await prompts.log.warn("Let's try again with a different path.");
1403
+ }
1404
+
1405
+ return create;
1406
+ }
1407
+ }
1408
+
1409
+ /**
1410
+ * Validate directory path for installation (sync version for clack prompts)
1411
+ * @param {string} input - User input path
1412
+ * @returns {string|undefined} Error message or undefined if valid
1413
+ */
1414
+ validateDirectorySync(input) {
1415
+ // Allow empty input to use the default
1416
+ if (!input || input.trim() === '') {
1417
+ return; // Empty means use default, undefined = valid for clack
1418
+ }
1419
+
1420
+ let expandedPath;
1421
+ try {
1422
+ expandedPath = this.expandUserPath(input.trim());
1423
+ } catch (error) {
1424
+ return error.message;
1425
+ }
1426
+
1427
+ // Check if the path exists
1428
+ const pathExists = fs.pathExistsSync(expandedPath);
1429
+
1430
+ if (!pathExists) {
1431
+ // Find the first existing parent directory
1432
+ const existingParent = this.findExistingParentSync(expandedPath);
1433
+
1434
+ if (!existingParent) {
1435
+ return 'Cannot create directory: no existing parent directory found';
1436
+ }
1437
+
1438
+ // Check if the existing parent is writable
1439
+ try {
1440
+ fs.accessSync(existingParent, fs.constants.W_OK);
1441
+ // Path doesn't exist but can be created - will prompt for confirmation later
1442
+ return;
1443
+ } catch {
1444
+ // Provide a detailed error message explaining both issues
1445
+ return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`;
1446
+ }
1447
+ }
1448
+
1449
+ // If it exists, validate it's a directory and writable
1450
+ const stat = fs.statSync(expandedPath);
1451
+ if (!stat.isDirectory()) {
1452
+ return `Path exists but is not a directory: ${expandedPath}`;
1453
+ }
1454
+
1455
+ // Check write permissions
1456
+ try {
1457
+ fs.accessSync(expandedPath, fs.constants.W_OK);
1458
+ } catch {
1459
+ return `Directory is not writable: ${expandedPath}`;
1460
+ }
1461
+
1462
+ return;
1463
+ }
1464
+
1465
+ /**
1466
+ * Validate directory path for installation (async version)
1467
+ * @param {string} input - User input path
1468
+ * @returns {string|true} Error message or true if valid
1469
+ */
1470
+ async validateDirectory(input) {
1471
+ // Allow empty input to use the default
1472
+ if (!input || input.trim() === '') {
1473
+ return true; // Empty means use default
1474
+ }
1475
+
1476
+ let expandedPath;
1477
+ try {
1478
+ expandedPath = this.expandUserPath(input.trim());
1479
+ } catch (error) {
1480
+ return error.message;
1481
+ }
1482
+
1483
+ // Check if the path exists
1484
+ const pathExists = await fs.pathExists(expandedPath);
1485
+
1486
+ if (!pathExists) {
1487
+ // Find the first existing parent directory
1488
+ const existingParent = await this.findExistingParent(expandedPath);
1489
+
1490
+ if (!existingParent) {
1491
+ return 'Cannot create directory: no existing parent directory found';
1492
+ }
1493
+
1494
+ // Check if the existing parent is writable
1495
+ try {
1496
+ await fs.access(existingParent, fs.constants.W_OK);
1497
+ // Path doesn't exist but can be created - will prompt for confirmation later
1498
+ return true;
1499
+ } catch {
1500
+ // Provide a detailed error message explaining both issues
1501
+ return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`;
1502
+ }
1503
+ }
1504
+
1505
+ // If it exists, validate it's a directory and writable
1506
+ const stat = await fs.stat(expandedPath);
1507
+ if (!stat.isDirectory()) {
1508
+ return `Path exists but is not a directory: ${expandedPath}`;
1509
+ }
1510
+
1511
+ // Check write permissions
1512
+ try {
1513
+ await fs.access(expandedPath, fs.constants.W_OK);
1514
+ } catch {
1515
+ return `Directory is not writable: ${expandedPath}`;
1516
+ }
1517
+
1518
+ return true;
1519
+ }
1520
+
1521
+ /**
1522
+ * Find the first existing parent directory (sync version)
1523
+ * @param {string} targetPath - The path to check
1524
+ * @returns {string|null} The first existing parent directory, or null if none found
1525
+ */
1526
+ findExistingParentSync(targetPath) {
1527
+ let currentPath = path.resolve(targetPath);
1528
+
1529
+ // Walk up the directory tree until we find an existing directory
1530
+ while (currentPath !== path.dirname(currentPath)) {
1531
+ // Stop at root
1532
+ const parent = path.dirname(currentPath);
1533
+ if (fs.pathExistsSync(parent)) {
1534
+ return parent;
1535
+ }
1536
+ currentPath = parent;
1537
+ }
1538
+
1539
+ return null; // No existing parent found (shouldn't happen in practice)
1540
+ }
1541
+
1542
+ /**
1543
+ * Find the first existing parent directory (async version)
1544
+ * @param {string} targetPath - The path to check
1545
+ * @returns {string|null} The first existing parent directory, or null if none found
1546
+ */
1547
+ async findExistingParent(targetPath) {
1548
+ let currentPath = path.resolve(targetPath);
1549
+
1550
+ // Walk up the directory tree until we find an existing directory
1551
+ while (currentPath !== path.dirname(currentPath)) {
1552
+ // Stop at root
1553
+ const parent = path.dirname(currentPath);
1554
+ if (await fs.pathExists(parent)) {
1555
+ return parent;
1556
+ }
1557
+ currentPath = parent;
1558
+ }
1559
+
1560
+ return null; // No existing parent found (shouldn't happen in practice)
1561
+ }
1562
+
1563
+ /**
1564
+ * Expands the user-provided path: handles ~ and resolves to absolute.
1565
+ * @param {string} inputPath - User input path.
1566
+ * @returns {string} Absolute expanded path.
1567
+ */
1568
+ expandUserPath(inputPath) {
1569
+ if (typeof inputPath !== 'string') {
1570
+ throw new TypeError('Path must be a string.');
1571
+ }
1572
+
1573
+ let expanded = inputPath.trim();
1574
+
1575
+ // Handle tilde expansion
1576
+ if (expanded.startsWith('~')) {
1577
+ if (expanded === '~') {
1578
+ expanded = os.homedir();
1579
+ } else if (expanded.startsWith('~' + path.sep)) {
1580
+ const pathAfterHome = expanded.slice(2); // Remove ~/ or ~\
1581
+ expanded = path.join(os.homedir(), pathAfterHome);
1582
+ } else {
1583
+ const restOfPath = expanded.slice(1);
1584
+ const separatorIndex = restOfPath.indexOf(path.sep);
1585
+ const username = separatorIndex === -1 ? restOfPath : restOfPath.slice(0, separatorIndex);
1586
+ if (username) {
1587
+ throw new Error(`Path expansion for ~${username} is not supported. Please use an absolute path or ~${path.sep}`);
1588
+ }
1589
+ }
1590
+ }
1591
+
1592
+ // Resolve to the absolute path relative to the current working directory
1593
+ return path.resolve(expanded);
1594
+ }
1595
+
1596
+ /**
1597
+ * Get configured IDEs from existing installation
1598
+ * @param {string} directory - Installation directory
1599
+ * @returns {Array} List of configured IDEs
1600
+ */
1601
+ async getConfiguredIdes(directory) {
1602
+ const { ExistingInstall } = require('./core/existing-install');
1603
+ const { Installer } = require('./core/installer');
1604
+ const installer = new Installer();
1605
+ const { xiaomaDir } = await installer.findXiaomaDir(directory);
1606
+ const existingInstall = await ExistingInstall.detect(xiaomaDir);
1607
+ return existingInstall.ides;
1608
+ }
1609
+
1610
+ /**
1611
+ * Display module versions with update availability
1612
+ * @param {Array} modules - Array of module info objects with version info
1613
+ * @param {Array} availableUpdates - Array of available updates
1614
+ */
1615
+ async displayModuleVersions(modules, availableUpdates = []) {
1616
+ // Group modules by source
1617
+ const builtIn = modules.filter((m) => m.source === 'built-in');
1618
+ const external = modules.filter((m) => m.source === 'external');
1619
+ const community = modules.filter((m) => m.source === 'community');
1620
+ const custom = modules.filter((m) => m.source === 'custom');
1621
+ const unknown = modules.filter((m) => m.source === 'unknown');
1622
+
1623
+ const lines = [];
1624
+ const formatGroup = (group, title) => {
1625
+ if (group.length === 0) return;
1626
+ lines.push(title);
1627
+ for (const mod of group) {
1628
+ const updateInfo = availableUpdates.find((u) => u.name === mod.name);
1629
+ const versionDisplay = mod.version || 'unknown';
1630
+ if (updateInfo) {
1631
+ lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2192 ${updateInfo.latestVersion} \u2191`);
1632
+ } else {
1633
+ lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2713`);
1634
+ }
1635
+ }
1636
+ };
1637
+
1638
+ formatGroup(builtIn, 'Built-in Modules');
1639
+ formatGroup(external, 'External Modules (Official)');
1640
+ formatGroup(community, 'Community Modules');
1641
+ formatGroup(custom, 'Custom Modules');
1642
+ formatGroup(unknown, 'Other Modules');
1643
+
1644
+ await prompts.note(lines.join('\n'), 'Module Versions');
1645
+ }
1646
+
1647
+ /**
1648
+ * Prompt user to select which modules to update
1649
+ * @param {Array} availableUpdates - Array of available updates
1650
+ * @returns {Array} Selected module names to update
1651
+ */
1652
+ async promptUpdateSelection(availableUpdates) {
1653
+ if (availableUpdates.length === 0) {
1654
+ return [];
1655
+ }
1656
+
1657
+ await prompts.log.info('Available Updates');
1658
+
1659
+ const choices = availableUpdates.map((update) => ({
1660
+ name: `${update.name} (v${update.installedVersion} \u2192 v${update.latestVersion})`,
1661
+ value: update.name,
1662
+ checked: true, // Default to selecting all updates
1663
+ }));
1664
+
1665
+ // Add "Update All" and "Cancel" options
1666
+ const action = await prompts.select({
1667
+ message: 'How would you like to proceed?',
1668
+ choices: [
1669
+ { name: 'Update all available modules', value: 'all' },
1670
+ { name: 'Select specific modules to update', value: 'select' },
1671
+ { name: 'Skip updates for now', value: 'skip' },
1672
+ ],
1673
+ default: 'all',
1674
+ });
1675
+
1676
+ if (action === 'all') {
1677
+ return availableUpdates.map((u) => u.name);
1678
+ }
1679
+
1680
+ if (action === 'skip') {
1681
+ return [];
1682
+ }
1683
+
1684
+ // Allow specific selection
1685
+ const selected = await prompts.multiselect({
1686
+ message: 'Select modules to update (use arrow keys, space to toggle):',
1687
+ choices: choices,
1688
+ required: true,
1689
+ });
1690
+
1691
+ return selected || [];
1692
+ }
1693
+
1694
+ /**
1695
+ * Display status of all installed modules
1696
+ * @param {Object} statusData - Status data with modules, installation info, and available updates
1697
+ */
1698
+ async displayStatus(statusData) {
1699
+ const { installation, modules, availableUpdates, xiaomaDir } = statusData;
1700
+
1701
+ // Installation info
1702
+ const infoLines = [
1703
+ `Version: ${installation.version || 'unknown'}`,
1704
+ `Location: ${xiaomaDir}`,
1705
+ `Installed: ${new Date(installation.installDate).toLocaleDateString()}`,
1706
+ `Last Updated: ${installation.lastUpdated ? new Date(installation.lastUpdated).toLocaleDateString() : 'unknown'}`,
1707
+ ];
1708
+
1709
+ await prompts.note(infoLines.join('\n'), 'XiaoMa Status');
1710
+
1711
+ // Module versions
1712
+ await this.displayModuleVersions(modules, availableUpdates);
1713
+
1714
+ // Update summary
1715
+ if (availableUpdates.length > 0) {
1716
+ await prompts.log.warn(`${availableUpdates.length} update(s) available`);
1717
+ await prompts.log.message('Run \'xiaoma install\' and select "Quick Update" to update');
1718
+ } else {
1719
+ await prompts.log.success('All modules are up to date');
1720
+ }
1721
+ }
1722
+
1723
+ /**
1724
+ * Display list of selected tools after IDE selection
1725
+ * @param {Array} selectedIdes - Array of selected IDE values
1726
+ * @param {Array} preferredIdes - Array of preferred IDE objects
1727
+ * @param {Array} allTools - Array of all tool objects
1728
+ */
1729
+ async displaySelectedTools(selectedIdes, preferredIdes, allTools) {
1730
+ if (selectedIdes.length === 0) return;
1731
+
1732
+ const preferredValues = new Set(preferredIdes.map((ide) => ide.value));
1733
+ const toolLines = selectedIdes.map((ideValue) => {
1734
+ const tool = allTools.find((t) => t.value === ideValue);
1735
+ const name = tool?.name || ideValue;
1736
+ const marker = preferredValues.has(ideValue) ? ' \u2B50' : '';
1737
+ return ` \u2022 ${name}${marker}`;
1738
+ });
1739
+ await prompts.log.message('Selected tools:\n' + toolLines.join('\n'));
1740
+ }
1741
+
1742
+ /**
1743
+ * Return the set of module codes the registry marks as built-in (core, xmc).
1744
+ * These ship with the installer binary and have no per-module channel.
1745
+ */
1746
+ async _bundledModuleCodes() {
1747
+ const externalManager = new ExternalModuleManager();
1748
+ try {
1749
+ const modules = await externalManager.listAvailable();
1750
+ return modules.filter((m) => m.builtIn).map((m) => m.code);
1751
+ } catch {
1752
+ // Registry unreachable — fall back to the known bundled codes.
1753
+ return ['core', 'xmc'];
1754
+ }
1755
+ }
1756
+
1757
+ /**
1758
+ * Fast-path channel gate: confirm "all stable" or open the per-module picker.
1759
+ *
1760
+ * Skipped when:
1761
+ * - running non-interactively (--yes)
1762
+ * - the user already passed channel flags (--channel / --pin / --next), OR
1763
+ * the installer was launched from a prerelease (which seeds
1764
+ * channelOptions.global = 'next' upstream in promptInstall)
1765
+ * - no externals/community modules are selected
1766
+ *
1767
+ * Mutates channelOptions.pins and channelOptions.nextSet to reflect picker choices.
1768
+ */
1769
+ async _interactiveChannelGate({ options, channelOptions, selectedModules }) {
1770
+ if (options.yes) return;
1771
+ // If the user already declared their channel intent via flags, trust them
1772
+ // and skip the gate.
1773
+ const haveFlagIntent = channelOptions.global || channelOptions.nextSet.size > 0 || channelOptions.pins.size > 0;
1774
+ if (haveFlagIntent) return;
1775
+
1776
+ // Figure out which selected modules actually get a channel (externals only).
1777
+ // Bundled core/xmc and custom modules skip the picker.
1778
+ const externalManager = new ExternalModuleManager();
1779
+ const externals = await externalManager.listAvailable();
1780
+ const externalByCode = new Map(externals.map((m) => [m.code, m]));
1781
+
1782
+ const channelSelectable = selectedModules.filter((code) => {
1783
+ const info = externalByCode.get(code);
1784
+ return info && !info.builtIn;
1785
+ });
1786
+ if (channelSelectable.length === 0) return;
1787
+
1788
+ const fastPath = await prompts.confirm({
1789
+ message: `Ready to install (all stable)? Pick "n" to customize channels or pin versions.`,
1790
+ default: true,
1791
+ });
1792
+ if (fastPath) return; // stable for all, registry default applies
1793
+
1794
+ // Customize path: per-module picker.
1795
+ const { fetchStableTags, parseGitHubRepo } = require('./modules/channel-resolver');
1796
+
1797
+ for (const code of channelSelectable) {
1798
+ const info = externalByCode.get(code);
1799
+ const repoUrl = info.url;
1800
+
1801
+ // Try to pre-resolve the top stable tag so we can surface it in the picker.
1802
+ let stableLabel = 'stable (released version)';
1803
+ try {
1804
+ const parsed = repoUrl ? parseGitHubRepo(repoUrl) : null;
1805
+ if (parsed) {
1806
+ const tags = await fetchStableTags(parsed.owner, parsed.repo);
1807
+ if (tags.length > 0) {
1808
+ stableLabel = `stable ${tags[0].tag} (released version)`;
1809
+ }
1810
+ }
1811
+ } catch {
1812
+ // fall through with the generic label
1813
+ }
1814
+
1815
+ const choice = await prompts.select({
1816
+ message: `${code}: choose a channel`,
1817
+ choices: [
1818
+ { name: stableLabel, value: 'stable' },
1819
+ { name: 'next (main HEAD \u2014 current development)', value: 'next' },
1820
+ { name: 'pin (specific version)', value: 'pin' },
1821
+ ],
1822
+ default: 'stable',
1823
+ });
1824
+
1825
+ if (choice === 'next') {
1826
+ channelOptions.nextSet.add(code);
1827
+ } else if (choice === 'pin') {
1828
+ const pinValue = await prompts.text({
1829
+ message: `Enter a version tag for '${code}' (e.g. v1.6.0):`,
1830
+ validate: (value) => {
1831
+ if (!value || !/^[\w.\-+/]+$/.test(String(value).trim())) {
1832
+ return 'Must be a non-empty tag name (letters, digits, dots, hyphens).';
1833
+ }
1834
+ },
1835
+ });
1836
+ channelOptions.pins.set(code, String(pinValue).trim());
1837
+ }
1838
+ // 'stable' is the default; nothing to record.
1839
+ }
1840
+ }
1841
+
1842
+ /**
1843
+ * Resolve channel decisions for an update over an existing install.
1844
+ *
1845
+ * For each selected external/community module:
1846
+ * - Read the recorded channel from the existing manifest.
1847
+ * - On `stable`: query tags; if a newer stable exists, classify the diff
1848
+ * and prompt. Patch/minor default Y; major defaults N. `--yes` accepts
1849
+ * defaults (patches/minors) but NOT majors — a major under --yes stays
1850
+ * frozen unless the user also passes `--pin CODE=NEW_TAG`.
1851
+ * - On `next`: no prompt (pull HEAD).
1852
+ * - On `pinned`: no prompt (stays pinned).
1853
+ * - No channel recorded and `version: null`: one-time migration prompt
1854
+ * ("Switch to stable / Keep on next").
1855
+ *
1856
+ * Decisions that freeze the current version are applied by adding a pin to
1857
+ * `channelOptions.pins` so downstream clone logic honors them.
1858
+ */
1859
+ async _resolveUpdateChannels({ xiaomaDir, selectedModules, channelOptions, yes }) {
1860
+ const { Manifest } = require('./core/manifest');
1861
+ const manifestObj = new Manifest();
1862
+ const manifest = await manifestObj.read(xiaomaDir);
1863
+ const existingByName = new Map();
1864
+ for (const m of manifest?.modulesDetailed || []) {
1865
+ if (m?.name) existingByName.set(m.name, m);
1866
+ }
1867
+ if (existingByName.size === 0) return;
1868
+
1869
+ const externalManager = new ExternalModuleManager();
1870
+ const externals = await externalManager.listAvailable();
1871
+ const externalByCode = new Map(externals.map((m) => [m.code, m]));
1872
+
1873
+ const { fetchStableTags, classifyUpgrade, releaseNotesUrl } = require('./modules/channel-resolver');
1874
+ const { parseGitHubRepo } = require('./modules/channel-resolver');
1875
+
1876
+ // Interactive-only: offer a one-time gate to review / switch channels for
1877
+ // selected modules that are already installed. Default N so normal Modify
1878
+ // flows (add/remove modules) aren't interrupted.
1879
+ let reviewChannels = false;
1880
+ if (!yes) {
1881
+ const existingWithChannel = selectedModules.filter((code) => {
1882
+ const prev = existingByName.get(code);
1883
+ if (!prev) return false;
1884
+ const info = externalByCode.get(code);
1885
+ return info && !info.builtIn;
1886
+ });
1887
+ if (existingWithChannel.length > 0) {
1888
+ reviewChannels = await prompts.confirm({
1889
+ message: 'Review channel assignments (stable / next / pin) for your existing modules?',
1890
+ default: false,
1891
+ });
1892
+ }
1893
+ }
1894
+
1895
+ for (const code of selectedModules) {
1896
+ const prev = existingByName.get(code);
1897
+ if (!prev) continue;
1898
+
1899
+ const info = externalByCode.get(code);
1900
+ if (!info) continue;
1901
+ // Bundled modules (core/xmc) ship with the installer binary itself —
1902
+ // their version is stapled to the CLI version, not a git tag. Skip
1903
+ // tag-API lookups for them; the "upgrade" mechanism is `npx xiaoma@X install`.
1904
+ if (info.builtIn) continue;
1905
+
1906
+ const repoUrl = info.url;
1907
+ const parsed = repoUrl ? parseGitHubRepo(repoUrl) : null;
1908
+
1909
+ // Legacy migration: manifest carries no channel and a null/empty
1910
+ // version. Offer the one-time pick between stable and next.
1911
+ const recordedChannel = prev.channel || null;
1912
+ const needsMigration = !recordedChannel && (prev.version == null || prev.version === '');
1913
+ if (needsMigration) {
1914
+ if (yes) {
1915
+ // Conservative headless default: stable.
1916
+ continue;
1917
+ }
1918
+ const chosen = await prompts.select({
1919
+ message: `${code}: your existing install tracks the main branch. Switch to stable releases (recommended for production), or keep on main?`,
1920
+ choices: [
1921
+ { name: 'Switch to stable', value: 'stable' },
1922
+ { name: 'Keep on main (next)', value: 'next' },
1923
+ ],
1924
+ default: 'stable',
1925
+ });
1926
+ if (chosen === 'next') channelOptions.nextSet.add(code);
1927
+ continue;
1928
+ }
1929
+
1930
+ // Optional channel-switch offer. Fires only when the user opted in via
1931
+ // the gate above. 'keep' falls through to the existing per-channel
1932
+ // logic (which runs upgrade classification for stable). Any switch
1933
+ // records the new intent into channelOptions and skips upgrade prompts.
1934
+ if (reviewChannels && recordedChannel) {
1935
+ const switchChoices = [
1936
+ {
1937
+ name: `Keep on '${recordedChannel}'${prev.version ? ` @ ${prev.version}` : ''}`,
1938
+ value: 'keep',
1939
+ },
1940
+ ];
1941
+ if (recordedChannel !== 'stable') {
1942
+ switchChoices.push({ name: 'Switch to stable (released version)', value: 'stable' });
1943
+ }
1944
+ if (recordedChannel !== 'next') {
1945
+ switchChoices.push({ name: 'Switch to next (main HEAD)', value: 'next' });
1946
+ }
1947
+ switchChoices.push({ name: 'Pin to a specific version tag', value: 'pin' });
1948
+
1949
+ const choice = await prompts.select({
1950
+ message: `${code} channel:`,
1951
+ choices: switchChoices,
1952
+ default: 'keep',
1953
+ });
1954
+
1955
+ if (choice === 'next') {
1956
+ channelOptions.nextSet.add(code);
1957
+ continue;
1958
+ }
1959
+ if (choice === 'pin') {
1960
+ const pinValue = await prompts.text({
1961
+ message: `Enter a version tag for '${code}' (e.g. v1.6.0):`,
1962
+ validate: (value) => {
1963
+ if (!value || !/^[\w.\-+/]+$/.test(String(value).trim())) {
1964
+ return 'Must be a non-empty tag name (letters, digits, dots, hyphens).';
1965
+ }
1966
+ },
1967
+ });
1968
+ channelOptions.pins.set(code, String(pinValue).trim());
1969
+ continue;
1970
+ }
1971
+ if (choice === 'stable') {
1972
+ // Switch to stable: install at the top stable tag without an
1973
+ // upgrade-classification prompt (the user explicitly opted in).
1974
+ // Also warm the tag cache here so the actual clone step doesn't
1975
+ // need a second GitHub API call (can hit rate limits).
1976
+ if (parsed) {
1977
+ try {
1978
+ await fetchStableTags(parsed.owner, parsed.repo);
1979
+ } catch {
1980
+ // best effort; clone step will surface any failure
1981
+ }
1982
+ }
1983
+ continue;
1984
+ }
1985
+ // 'keep' → fall through with recordedChannel below.
1986
+ }
1987
+
1988
+ if (recordedChannel === 'pinned' || recordedChannel === 'next') {
1989
+ // Respect any explicit channel intent the user already expressed via
1990
+ // CLI flags (--channel / --all-* / --next=CODE / --pin CODE=TAG) or
1991
+ // via the interactive review gate above. Only auto-re-assert the
1992
+ // recorded channel when the user hasn't opted into anything else —
1993
+ // otherwise --all-stable (or a review "switch to stable") would be
1994
+ // silently clobbered by the prior channel.
1995
+ const alreadyDecided = channelOptions.global || channelOptions.nextSet.has(code) || channelOptions.pins.has(code);
1996
+ if (!alreadyDecided) {
1997
+ if (recordedChannel === 'pinned' && prev.version) {
1998
+ channelOptions.pins.set(code, prev.version);
1999
+ } else if (recordedChannel === 'next') {
2000
+ channelOptions.nextSet.add(code);
2001
+ }
2002
+ }
2003
+ continue;
2004
+ }
2005
+
2006
+ // Stable channel: check for a newer released tag.
2007
+ if (!parsed) continue;
2008
+ // Respect explicit CLI intent (--pin / --next=CODE / --all-*) and any
2009
+ // choice the user already made in the earlier review gate. Without this
2010
+ // guard the upgrade classifier below would unconditionally call
2011
+ // `channelOptions.pins.set(code, prev.version)` on decline/major-refuse/
2012
+ // fetch-error, silently clobbering the user's override.
2013
+ const alreadyDecided = channelOptions.global || channelOptions.nextSet.has(code) || channelOptions.pins.has(code);
2014
+ if (alreadyDecided) continue;
2015
+ let tags;
2016
+ try {
2017
+ tags = await fetchStableTags(parsed.owner, parsed.repo);
2018
+ } catch (error) {
2019
+ await prompts.log.warn(`Could not check for updates on ${code} (${error.message}). Leaving at ${prev.version}.`);
2020
+ if (prev.version) channelOptions.pins.set(code, prev.version);
2021
+ continue;
2022
+ }
2023
+ if (!tags || tags.length === 0) continue;
2024
+ const topTag = tags[0].tag; // e.g. "v1.7.0"
2025
+ const currentTag = prev.version || '';
2026
+ const diffClass = classifyUpgrade(currentTag, topTag);
2027
+
2028
+ if (diffClass === 'none') continue; // already at or above top tag
2029
+
2030
+ const notes = releaseNotesUrl(repoUrl, topTag);
2031
+ let accept;
2032
+ if (diffClass === 'major') {
2033
+ if (yes) {
2034
+ // Major under --yes is refused by design.
2035
+ await prompts.log.warn(
2036
+ `${code} ${currentTag} → ${topTag} is a new major release; staying on ${currentTag}. ` +
2037
+ `To accept, rerun with --pin ${code}=${topTag}.`,
2038
+ );
2039
+ channelOptions.pins.set(code, currentTag);
2040
+ continue;
2041
+ }
2042
+ accept = await prompts.confirm({
2043
+ message:
2044
+ `${code} ${topTag} available — new major release (may change behavior).` +
2045
+ (notes ? ` Release notes: ${notes}.` : '') +
2046
+ ' Upgrade?',
2047
+ default: false,
2048
+ });
2049
+ } else if (diffClass === 'minor') {
2050
+ if (yes) {
2051
+ accept = true;
2052
+ } else {
2053
+ accept = await prompts.confirm({
2054
+ message: `${code} ${topTag} available (new features).` + (notes ? ` Release notes: ${notes}.` : '') + ' Upgrade?',
2055
+ default: true,
2056
+ });
2057
+ }
2058
+ } else {
2059
+ // patch
2060
+ if (yes) {
2061
+ accept = true;
2062
+ } else {
2063
+ accept = await prompts.confirm({
2064
+ message: `${code} ${topTag} available. Upgrade?`,
2065
+ default: true,
2066
+ });
2067
+ }
2068
+ }
2069
+
2070
+ if (!accept && currentTag) {
2071
+ // Freeze the current version by pinning it for this run.
2072
+ channelOptions.pins.set(code, currentTag);
2073
+ }
2074
+ }
2075
+ }
2076
+ }
2077
+
2078
+ module.exports = { UI };