@zeyue0329/xiaoma-cli 1.0.49 → 1.6.5

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 (895) hide show
  1. package/.github/workflows/quality.yaml +116 -0
  2. package/.husky/pre-commit +26 -0
  3. package/.idea/codeStyles/Project.xml +60 -0
  4. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  5. package/.idea/jsLibraryMappings.xml +6 -0
  6. package/.idea/modules.xml +1 -1
  7. package/.idea/vcs.xml +0 -1
  8. package/.idea/workspace.xml +40 -24
  9. package/.markdownlint-cli2.yaml +41 -0
  10. package/.prettierignore +12 -0
  11. package/.vscode/settings.json +96 -0
  12. package/LICENSE +30 -0
  13. package/README.md +108 -2
  14. package/XIAOMA-CLI-GUIDE.md +512 -0
  15. package/{.idea/XiaoMa-Cli.iml → XiaoMa-Cli.iml} +1 -1
  16. package/custom/src/agents/commit-poet/commit-poet.agent.yaml +129 -0
  17. package/custom/src/agents/commit-poet/installation-guide.md +36 -0
  18. package/custom/src/agents/toolsmith/installation-guide.md +36 -0
  19. package/custom/src/agents/toolsmith/toolsmith-sidecar/instructions.md +70 -0
  20. package/custom/src/agents/toolsmith/toolsmith-sidecar/knowledge/bundlers.md +111 -0
  21. package/custom/src/agents/toolsmith/toolsmith-sidecar/knowledge/deploy.md +70 -0
  22. package/custom/src/agents/toolsmith/toolsmith-sidecar/knowledge/docs.md +114 -0
  23. package/custom/src/agents/toolsmith/toolsmith-sidecar/knowledge/installers.md +134 -0
  24. package/custom/src/agents/toolsmith/toolsmith-sidecar/knowledge/modules.md +160 -0
  25. package/custom/src/agents/toolsmith/toolsmith-sidecar/knowledge/tests.md +103 -0
  26. package/custom/src/agents/toolsmith/toolsmith-sidecar/memories.md +17 -0
  27. package/custom/src/agents/toolsmith/toolsmith.agent.yaml +108 -0
  28. package/docs/BUNDLE_DISTRIBUTION_SETUP.md +95 -0
  29. package/docs/agent-customization-guide.md +208 -0
  30. package/docs/custom-agent-installation.md +183 -0
  31. package/docs/document-sharding-guide.md +449 -0
  32. package/docs/explanation/advanced-elicitation.md +49 -0
  33. package/docs/explanation/adversarial-review.md +59 -0
  34. package/docs/explanation/brainstorming.md +33 -0
  35. package/docs/explanation/established-projects-faq.md +50 -0
  36. package/docs/explanation/party-mode.md +59 -0
  37. package/docs/explanation/preventing-agent-conflicts.md +112 -0
  38. package/docs/explanation/project-context.md +157 -0
  39. package/docs/explanation/quick-dev-new-preview.md +73 -0
  40. package/docs/explanation/quick-flow.md +77 -0
  41. package/docs/explanation/why-solutioning-matters.md +77 -0
  42. package/docs/how-to/customize-xiaoma.md +172 -0
  43. package/docs/how-to/established-projects.md +117 -0
  44. package/docs/how-to/get-answers-about-xiaoma.md +134 -0
  45. package/docs/how-to/install-xiaoma.md +107 -0
  46. package/docs/how-to/non-interactive-installation.md +171 -0
  47. package/docs/how-to/project-context.md +136 -0
  48. package/docs/how-to/quick-fixes.md +123 -0
  49. package/docs/how-to/shard-large-documents.md +78 -0
  50. package/docs/how-to/upgrade-to-v6.md +100 -0
  51. package/docs/ide-info/auggie.md +31 -0
  52. package/docs/ide-info/claude-code.md +25 -0
  53. package/docs/ide-info/cline.md +31 -0
  54. package/docs/ide-info/codex.md +21 -0
  55. package/docs/ide-info/crush.md +30 -0
  56. package/docs/ide-info/cursor.md +25 -0
  57. package/docs/ide-info/gemini.md +25 -0
  58. package/docs/ide-info/github-copilot.md +26 -0
  59. package/docs/ide-info/iflow.md +33 -0
  60. package/docs/ide-info/kilo.md +24 -0
  61. package/docs/ide-info/opencode.md +24 -0
  62. package/docs/ide-info/qwen.md +25 -0
  63. package/docs/ide-info/roo.md +27 -0
  64. package/docs/ide-info/rovo-dev.md +388 -0
  65. package/docs/ide-info/trae.md +25 -0
  66. package/docs/ide-info/windsurf.md +22 -0
  67. package/docs/index.md +60 -0
  68. package/docs/installers-bundlers/ide-injections.md +186 -0
  69. package/docs/installers-bundlers/installers-modules-platforms-reference.md +379 -0
  70. package/docs/rag/rag.md +856 -0
  71. package/docs/reference/agents.md +28 -0
  72. package/docs/reference/commands.md +145 -0
  73. package/docs/reference/modules.md +76 -0
  74. package/docs/reference/testing.md +106 -0
  75. package/docs/reference/workflow-map.md +89 -0
  76. package/docs/roadmap.mdx +136 -0
  77. package/docs/superpowers/plans/2026-03-11-upstream-sync-with-branding.md +586 -0
  78. package/docs/tutorials/getting-started.md +273 -0
  79. package/docs/v4-to-v6-upgrade.md +220 -0
  80. package/docs/v6-open-items.md +17 -0
  81. package/docs/web-bundles-gemini-gpt-guide.md +468 -0
  82. package/docs/zh-cn/404.md +9 -0
  83. package/docs/zh-cn/_STYLE_GUIDE.md +370 -0
  84. package/docs/zh-cn/explanation/advanced-elicitation.md +62 -0
  85. package/docs/zh-cn/explanation/adversarial-review.md +71 -0
  86. package/docs/zh-cn/explanation/brainstorming.md +43 -0
  87. package/docs/zh-cn/explanation/established-projects-faq.md +60 -0
  88. package/docs/zh-cn/explanation/party-mode.md +79 -0
  89. package/docs/zh-cn/explanation/preventing-agent-conflicts.md +137 -0
  90. package/docs/zh-cn/explanation/project-context.md +176 -0
  91. package/docs/zh-cn/explanation/quick-flow.md +93 -0
  92. package/docs/zh-cn/explanation/why-solutioning-matters.md +90 -0
  93. package/docs/zh-cn/how-to/customize-xiaoma.md +182 -0
  94. package/docs/zh-cn/how-to/established-projects.md +134 -0
  95. package/docs/zh-cn/how-to/get-answers-about-xiaoma.md +144 -0
  96. package/docs/zh-cn/how-to/install-xiaoma.md +105 -0
  97. package/docs/zh-cn/how-to/non-interactive-installation.md +181 -0
  98. package/docs/zh-cn/how-to/project-context.md +152 -0
  99. package/docs/zh-cn/how-to/quick-fixes.md +140 -0
  100. package/docs/zh-cn/how-to/shard-large-documents.md +86 -0
  101. package/docs/zh-cn/how-to/upgrade-to-v6.md +120 -0
  102. package/docs/zh-cn/index.md +69 -0
  103. package/docs/zh-cn/reference/agents.md +41 -0
  104. package/docs/zh-cn/reference/commands.md +166 -0
  105. package/docs/zh-cn/reference/modules.md +94 -0
  106. package/docs/zh-cn/reference/testing.md +122 -0
  107. package/docs/zh-cn/reference/workflow-map.md +104 -0
  108. package/docs/zh-cn/roadmap.mdx +152 -0
  109. package/docs/zh-cn/tutorials/getting-started.md +300 -0
  110. package/eslint.config.mjs +144 -0
  111. package/package.json +56 -58
  112. package/prettier.config.mjs +32 -0
  113. package/src/core/_module-installer/install-config.yaml +29 -0
  114. package/src/core/_module-installer/installer.js +60 -0
  115. package/src/core/agents/xiaoma-master.agent.yaml +30 -0
  116. package/src/core/agents/xiaoma-skill-manifest.yaml +3 -0
  117. package/src/core/agents/xiaoma-web-orchestrator.agent.xml +113 -0
  118. package/src/core/module-help.csv +10 -0
  119. package/src/core/module.yaml +25 -0
  120. package/src/core/resources/excalidraw/README.md +160 -0
  121. package/src/core/resources/excalidraw/excalidraw-helpers.md +127 -0
  122. package/src/core/resources/excalidraw/library-loader.md +50 -0
  123. package/src/core/resources/excalidraw/validate-json-instructions.md +79 -0
  124. package/src/core/tasks/advanced-elicitation-methods.csv +51 -0
  125. package/src/core/tasks/advanced-elicitation.xml +116 -0
  126. package/src/core/tasks/editorial-review-prose.xml +102 -0
  127. package/src/core/tasks/editorial-review-structure.xml +208 -0
  128. package/src/core/tasks/help.md +92 -0
  129. package/src/core/tasks/index-docs.xml +65 -0
  130. package/src/core/tasks/review-adversarial-general.xml +49 -0
  131. package/src/core/tasks/review-edge-case-hunter.xml +63 -0
  132. package/src/core/tasks/shard-doc.xml +108 -0
  133. package/src/core/tasks/validate-workflow.xml +89 -0
  134. package/src/core/tasks/workflow.xml +235 -0
  135. package/src/core/tasks/xiaoma-help/SKILL.md +6 -0
  136. package/src/core/tasks/xiaoma-help/workflow.md +88 -0
  137. package/src/core/tasks/xiaoma-help/xiaoma-skill-manifest.yaml +1 -0
  138. package/src/core/tasks/xiaoma-review-adversarial-general/SKILL.md +6 -0
  139. package/src/core/tasks/xiaoma-review-adversarial-general/workflow.md +32 -0
  140. package/src/core/tasks/xiaoma-review-adversarial-general/xiaoma-skill-manifest.yaml +1 -0
  141. package/src/core/tasks/xiaoma-review-edge-case-hunter/SKILL.md +6 -0
  142. package/src/core/tasks/xiaoma-review-edge-case-hunter/workflow.md +62 -0
  143. package/src/core/tasks/xiaoma-review-edge-case-hunter/xiaoma-skill-manifest.yaml +1 -0
  144. package/src/core/tasks/xiaoma-skill-manifest.yaml +19 -0
  145. package/src/core/tools/shard-doc.xml +109 -0
  146. package/src/core/workflows/advanced-elicitation/methods.csv +51 -0
  147. package/src/core/workflows/advanced-elicitation/workflow.md +138 -0
  148. package/src/core/workflows/advanced-elicitation/workflow.xml +118 -0
  149. package/src/core/workflows/advanced-elicitation/xiaoma-skill-manifest.yaml +3 -0
  150. package/src/core/workflows/brainstorming/brain-methods.csv +62 -0
  151. package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +210 -0
  152. package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -0
  153. package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -0
  154. package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -0
  155. package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -0
  156. package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -0
  157. package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +399 -0
  158. package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -0
  159. package/src/core/workflows/brainstorming/template.md +15 -0
  160. package/src/core/workflows/brainstorming/workflow.md +60 -0
  161. package/src/core/workflows/brainstorming/xiaoma-skill-manifest.yaml +3 -0
  162. package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +138 -0
  163. package/src/core/workflows/party-mode/steps/step-02-discussion-orchestration.md +187 -0
  164. package/src/core/workflows/party-mode/steps/step-03-graceful-exit.md +168 -0
  165. package/src/core/workflows/party-mode/workflow.md +194 -0
  166. package/src/core/workflows/party-mode/xiaoma-skill-manifest.yaml +3 -0
  167. package/src/utility/agent-components/activation-rules.txt +6 -0
  168. package/src/utility/agent-components/activation-steps.txt +14 -0
  169. package/src/utility/agent-components/agent-command-header.md +1 -0
  170. package/src/utility/agent-components/agent.customize.template.yaml +41 -0
  171. package/src/utility/agent-components/handler-action.txt +4 -0
  172. package/src/utility/agent-components/handler-data.txt +5 -0
  173. package/src/utility/agent-components/handler-exec.txt +6 -0
  174. package/src/utility/agent-components/handler-multi.txt +13 -0
  175. package/src/utility/agent-components/handler-tmpl.txt +5 -0
  176. package/src/utility/agent-components/handler-validate-workflow.txt +7 -0
  177. package/src/utility/agent-components/handler-workflow.txt +10 -0
  178. package/src/utility/agent-components/menu-handlers.txt +6 -0
  179. package/src/utility/models/action-command-header.md +0 -0
  180. package/src/utility/models/agent-activation-ide.xml +51 -0
  181. package/src/utility/models/agent-activation-web.xml +50 -0
  182. package/src/utility/models/agent-command-header.md +1 -0
  183. package/src/utility/models/agent-config-template.md +23 -0
  184. package/src/utility/models/agent-in-team-activation.xml +3 -0
  185. package/src/utility/models/fragments/activation-rules.xml +7 -0
  186. package/src/utility/models/fragments/activation-steps.xml +16 -0
  187. package/src/utility/models/fragments/handler-action.xml +4 -0
  188. package/src/utility/models/fragments/handler-data.xml +5 -0
  189. package/src/utility/models/fragments/handler-exec.xml +6 -0
  190. package/src/utility/models/fragments/handler-multi.xml +14 -0
  191. package/src/utility/models/fragments/handler-tmpl.xml +5 -0
  192. package/src/utility/models/fragments/handler-validate-workflow.xml +7 -0
  193. package/src/utility/models/fragments/handler-workflow.xml +9 -0
  194. package/src/utility/models/fragments/menu-handlers.xml +6 -0
  195. package/src/utility/models/fragments/web-bundle-activation-steps.xml +32 -0
  196. package/src/utility/templates/agent.customize.template.yaml +42 -0
  197. package/src/xmc/_module-installer/install-config.yaml +53 -0
  198. package/src/xmc/_module-installer/installer.js +131 -0
  199. package/src/xmc/_module-installer/platform-specifics/claude-code.js +35 -0
  200. package/src/xmc/_module-installer/platform-specifics/windsurf.js +32 -0
  201. package/src/xmc/agents/analyst.agent.yaml +43 -0
  202. package/src/xmc/agents/architect.agent.yaml +29 -0
  203. package/src/xmc/agents/dev.agent.yaml +38 -0
  204. package/src/xmc/agents/pm.agent.yaml +44 -0
  205. package/src/xmc/agents/qa.agent.yaml +58 -0
  206. package/src/xmc/agents/quick-flow-solo-dev.agent.yaml +36 -0
  207. package/src/xmc/agents/sm.agent.yaml +37 -0
  208. package/src/xmc/agents/tech-writer/tech-writer-sidecar/documentation-standards.md +224 -0
  209. package/src/xmc/agents/tech-writer/tech-writer.agent.yaml +46 -0
  210. package/src/xmc/agents/tech-writer/xiaoma-skill-manifest.yaml +3 -0
  211. package/src/xmc/agents/ux-designer.agent.yaml +27 -0
  212. package/src/xmc/agents/xiaoma-skill-manifest.yaml +39 -0
  213. package/src/xmc/data/project-context-template.md +26 -0
  214. package/src/xmc/module-help.csv +32 -0
  215. package/src/xmc/module.yaml +50 -0
  216. package/src/xmc/sub-modules/claude-code/config.yaml +5 -0
  217. package/src/xmc/sub-modules/claude-code/injections.yaml +242 -0
  218. package/src/xmc/sub-modules/claude-code/readme.md +87 -0
  219. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-analysis/api-documenter.md +102 -0
  220. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-analysis/codebase-analyzer.md +82 -0
  221. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-analysis/data-analyst.md +101 -0
  222. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-analysis/pattern-detector.md +84 -0
  223. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-planning/dependency-mapper.md +83 -0
  224. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-planning/epic-optimizer.md +81 -0
  225. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-planning/requirements-analyst.md +61 -0
  226. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-planning/technical-decisions-curator.md +168 -0
  227. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-planning/trend-spotter.md +115 -0
  228. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-planning/user-journey-mapper.md +123 -0
  229. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-planning/user-researcher.md +72 -0
  230. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-research/market-researcher.md +51 -0
  231. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-research/tech-debt-auditor.md +106 -0
  232. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-review/document-reviewer.md +102 -0
  233. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-review/technical-evaluator.md +68 -0
  234. package/src/xmc/sub-modules/claude-code/sub-agents/xiaoma-review/test-coverage-analyzer.md +108 -0
  235. package/src/xmc/teams/default-party.csv +20 -0
  236. package/src/xmc/teams/team-fullstack.yaml +12 -0
  237. package/src/xmc/testarch/knowledge/api-request.md +303 -0
  238. package/src/xmc/testarch/knowledge/auth-session.md +356 -0
  239. package/src/xmc/testarch/knowledge/burn-in.md +273 -0
  240. package/src/xmc/testarch/knowledge/ci-burn-in.md +675 -0
  241. package/src/xmc/testarch/knowledge/component-tdd.md +486 -0
  242. package/src/xmc/testarch/knowledge/contract-testing.md +957 -0
  243. package/src/xmc/testarch/knowledge/data-factories.md +500 -0
  244. package/src/xmc/testarch/knowledge/email-auth.md +721 -0
  245. package/src/xmc/testarch/knowledge/error-handling.md +725 -0
  246. package/src/xmc/testarch/knowledge/feature-flags.md +750 -0
  247. package/src/xmc/testarch/knowledge/file-utils.md +260 -0
  248. package/src/xmc/testarch/knowledge/fixture-architecture.md +401 -0
  249. package/src/xmc/testarch/knowledge/fixtures-composition.md +382 -0
  250. package/src/xmc/testarch/knowledge/intercept-network-call.md +280 -0
  251. package/src/xmc/testarch/knowledge/log.md +294 -0
  252. package/src/xmc/testarch/knowledge/network-error-monitor.md +272 -0
  253. package/src/xmc/testarch/knowledge/network-first.md +486 -0
  254. package/src/xmc/testarch/knowledge/network-recorder.md +265 -0
  255. package/src/xmc/testarch/knowledge/nfr-criteria.md +670 -0
  256. package/src/xmc/testarch/knowledge/overview.md +284 -0
  257. package/src/xmc/testarch/knowledge/playwright-config.md +730 -0
  258. package/src/xmc/testarch/knowledge/probability-impact.md +601 -0
  259. package/src/xmc/testarch/knowledge/recurse.md +296 -0
  260. package/src/xmc/testarch/knowledge/risk-governance.md +615 -0
  261. package/src/xmc/testarch/knowledge/selective-testing.md +732 -0
  262. package/src/xmc/testarch/knowledge/selector-resilience.md +527 -0
  263. package/src/xmc/testarch/knowledge/test-healing-patterns.md +644 -0
  264. package/src/xmc/testarch/knowledge/test-levels-framework.md +473 -0
  265. package/src/xmc/testarch/knowledge/test-priorities-matrix.md +373 -0
  266. package/src/xmc/testarch/knowledge/test-quality.md +664 -0
  267. package/src/xmc/testarch/knowledge/timing-debugging.md +372 -0
  268. package/src/xmc/testarch/knowledge/visual-debugging.md +524 -0
  269. package/src/xmc/testarch/tea-index.csv +33 -0
  270. package/src/xmc/workflows/1-analysis/create-product-brief/product-brief.template.md +10 -0
  271. package/src/xmc/workflows/1-analysis/create-product-brief/steps/step-01-init.md +177 -0
  272. package/src/xmc/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +161 -0
  273. package/src/xmc/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +199 -0
  274. package/src/xmc/workflows/1-analysis/create-product-brief/steps/step-03-users.md +202 -0
  275. package/src/xmc/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +205 -0
  276. package/src/xmc/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +219 -0
  277. package/src/xmc/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +162 -0
  278. package/src/xmc/workflows/1-analysis/create-product-brief/workflow.md +57 -0
  279. package/src/xmc/workflows/1-analysis/create-product-brief/xiaoma-skill-manifest.yaml +3 -0
  280. package/src/xmc/workflows/1-analysis/research/domain-steps/step-01-init.md +137 -0
  281. package/src/xmc/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +229 -0
  282. package/src/xmc/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +238 -0
  283. package/src/xmc/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +206 -0
  284. package/src/xmc/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +234 -0
  285. package/src/xmc/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +444 -0
  286. package/src/xmc/workflows/1-analysis/research/market-steps/step-01-init.md +182 -0
  287. package/src/xmc/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +237 -0
  288. package/src/xmc/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +249 -0
  289. package/src/xmc/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +259 -0
  290. package/src/xmc/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +177 -0
  291. package/src/xmc/workflows/1-analysis/research/market-steps/step-06-research-completion.md +476 -0
  292. package/src/xmc/workflows/1-analysis/research/research.template.md +29 -0
  293. package/src/xmc/workflows/1-analysis/research/technical-steps/step-01-init.md +137 -0
  294. package/src/xmc/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +239 -0
  295. package/src/xmc/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +248 -0
  296. package/src/xmc/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +202 -0
  297. package/src/xmc/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +233 -0
  298. package/src/xmc/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +487 -0
  299. package/src/xmc/workflows/1-analysis/research/workflow-domain-research.md +54 -0
  300. package/src/xmc/workflows/1-analysis/research/workflow-market-research.md +54 -0
  301. package/src/xmc/workflows/1-analysis/research/workflow-technical-research.md +54 -0
  302. package/src/xmc/workflows/1-analysis/research/xiaoma-skill-manifest.yaml +14 -0
  303. package/src/xmc/workflows/2-plan-workflows/create-prd/data/domain-complexity.csv +15 -0
  304. package/src/xmc/workflows/2-plan-workflows/create-prd/data/prd-purpose.md +197 -0
  305. package/src/xmc/workflows/2-plan-workflows/create-prd/data/project-types.csv +11 -0
  306. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-01-init.md +191 -0
  307. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +152 -0
  308. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +224 -0
  309. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +154 -0
  310. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +170 -0
  311. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +226 -0
  312. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +213 -0
  313. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +207 -0
  314. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +226 -0
  315. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +237 -0
  316. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +228 -0
  317. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +231 -0
  318. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +242 -0
  319. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +217 -0
  320. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +124 -0
  321. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +247 -0
  322. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +208 -0
  323. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +249 -0
  324. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +253 -0
  325. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +168 -0
  326. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +226 -0
  327. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +191 -0
  328. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +209 -0
  329. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +174 -0
  330. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
  331. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +228 -0
  332. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +217 -0
  333. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
  334. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
  335. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +263 -0
  336. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +209 -0
  337. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
  338. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +242 -0
  339. package/src/xmc/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +231 -0
  340. package/src/xmc/workflows/2-plan-workflows/create-prd/templates/prd-template.md +10 -0
  341. package/src/xmc/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +63 -0
  342. package/src/xmc/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -0
  343. package/src/xmc/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -0
  344. package/src/xmc/workflows/2-plan-workflows/create-prd/xiaoma-skill-manifest.yaml +14 -0
  345. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-01-init.md +135 -0
  346. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +127 -0
  347. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +190 -0
  348. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +216 -0
  349. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +219 -0
  350. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +234 -0
  351. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +252 -0
  352. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +254 -0
  353. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +224 -0
  354. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +224 -0
  355. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +241 -0
  356. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +248 -0
  357. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +237 -0
  358. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +264 -0
  359. package/src/xmc/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +171 -0
  360. package/src/xmc/workflows/2-plan-workflows/create-ux-design/ux-design-template.md +13 -0
  361. package/src/xmc/workflows/2-plan-workflows/create-ux-design/workflow.md +42 -0
  362. package/src/xmc/workflows/2-plan-workflows/create-ux-design/xiaoma-skill-manifest.yaml +3 -0
  363. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +184 -0
  364. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +172 -0
  365. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +173 -0
  366. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +133 -0
  367. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +245 -0
  368. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -0
  369. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/templates/readiness-report-template.md +4 -0
  370. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -0
  371. package/src/xmc/workflows/3-solutioning/check-implementation-readiness/xiaoma-skill-manifest.yaml +3 -0
  372. package/src/xmc/workflows/3-solutioning/create-architecture/architecture-decision-template.md +12 -0
  373. package/src/xmc/workflows/3-solutioning/create-architecture/data/domain-complexity.csv +13 -0
  374. package/src/xmc/workflows/3-solutioning/create-architecture/data/project-types.csv +7 -0
  375. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-01-init.md +153 -0
  376. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +173 -0
  377. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-02-context.md +224 -0
  378. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +329 -0
  379. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +318 -0
  380. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +359 -0
  381. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +379 -0
  382. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +359 -0
  383. package/src/xmc/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +76 -0
  384. package/src/xmc/workflows/3-solutioning/create-architecture/workflow.md +49 -0
  385. package/src/xmc/workflows/3-solutioning/create-architecture/xiaoma-skill-manifest.yaml +3 -0
  386. package/src/xmc/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +259 -0
  387. package/src/xmc/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +233 -0
  388. package/src/xmc/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +272 -0
  389. package/src/xmc/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +149 -0
  390. package/src/xmc/workflows/3-solutioning/create-epics-and-stories/templates/epics-template.md +57 -0
  391. package/src/xmc/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -0
  392. package/src/xmc/workflows/3-solutioning/create-epics-and-stories/xiaoma-skill-manifest.yaml +3 -0
  393. package/src/xmc/workflows/4-implementation/code-review/checklist.md +23 -0
  394. package/src/xmc/workflows/4-implementation/code-review/discover-inputs.md +88 -0
  395. package/src/xmc/workflows/4-implementation/code-review/workflow.md +271 -0
  396. package/src/xmc/workflows/4-implementation/code-review/xiaoma-skill-manifest.yaml +3 -0
  397. package/src/xmc/workflows/4-implementation/correct-course/checklist.md +288 -0
  398. package/src/xmc/workflows/4-implementation/correct-course/workflow.md +274 -0
  399. package/src/xmc/workflows/4-implementation/correct-course/xiaoma-skill-manifest.yaml +3 -0
  400. package/src/xmc/workflows/4-implementation/create-story/checklist.md +357 -0
  401. package/src/xmc/workflows/4-implementation/create-story/discover-inputs.md +88 -0
  402. package/src/xmc/workflows/4-implementation/create-story/template.md +49 -0
  403. package/src/xmc/workflows/4-implementation/create-story/workflow.md +388 -0
  404. package/src/xmc/workflows/4-implementation/create-story/xiaoma-skill-manifest.yaml +3 -0
  405. package/src/xmc/workflows/4-implementation/dev-story/checklist.md +80 -0
  406. package/src/xmc/workflows/4-implementation/dev-story/workflow.md +457 -0
  407. package/src/xmc/workflows/4-implementation/dev-story/xiaoma-skill-manifest.yaml +3 -0
  408. package/src/xmc/workflows/4-implementation/retrospective/workflow.md +1485 -0
  409. package/src/xmc/workflows/4-implementation/retrospective/xiaoma-skill-manifest.yaml +3 -0
  410. package/src/xmc/workflows/4-implementation/sprint-planning/checklist.md +33 -0
  411. package/src/xmc/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +56 -0
  412. package/src/xmc/workflows/4-implementation/sprint-planning/workflow.md +271 -0
  413. package/src/xmc/workflows/4-implementation/sprint-planning/xiaoma-skill-manifest.yaml +3 -0
  414. package/src/xmc/workflows/4-implementation/sprint-status/workflow.md +267 -0
  415. package/src/xmc/workflows/4-implementation/sprint-status/xiaoma-skill-manifest.yaml +3 -0
  416. package/src/xmc/workflows/document-project/checklist.md +245 -0
  417. package/src/xmc/workflows/document-project/documentation-requirements.csv +12 -0
  418. package/src/xmc/workflows/document-project/instructions.md +128 -0
  419. package/src/xmc/workflows/document-project/templates/deep-dive-template.md +345 -0
  420. package/src/xmc/workflows/document-project/templates/index-template.md +169 -0
  421. package/src/xmc/workflows/document-project/templates/project-overview-template.md +103 -0
  422. package/src/xmc/workflows/document-project/templates/project-scan-report-schema.json +160 -0
  423. package/src/xmc/workflows/document-project/templates/source-tree-template.md +135 -0
  424. package/src/xmc/workflows/document-project/workflow.md +39 -0
  425. package/src/xmc/workflows/document-project/workflows/deep-dive-instructions.md +297 -0
  426. package/src/xmc/workflows/document-project/workflows/deep-dive-workflow.md +42 -0
  427. package/src/xmc/workflows/document-project/workflows/full-scan-instructions.md +1105 -0
  428. package/src/xmc/workflows/document-project/workflows/full-scan-workflow.md +42 -0
  429. package/src/xmc/workflows/document-project/xiaoma-skill-manifest.yaml +3 -0
  430. package/src/xmc/workflows/generate-project-context/project-context-template.md +21 -0
  431. package/src/xmc/workflows/generate-project-context/steps/step-01-discover.md +184 -0
  432. package/src/xmc/workflows/generate-project-context/steps/step-02-generate.md +318 -0
  433. package/src/xmc/workflows/generate-project-context/steps/step-03-complete.md +278 -0
  434. package/src/xmc/workflows/generate-project-context/workflow.md +49 -0
  435. package/src/xmc/workflows/generate-project-context/xiaoma-skill-manifest.yaml +3 -0
  436. package/src/xmc/workflows/qa-generate-e2e-tests/checklist.md +33 -0
  437. package/src/xmc/workflows/qa-generate-e2e-tests/workflow.md +143 -0
  438. package/src/xmc/workflows/qa-generate-e2e-tests/xiaoma-skill-manifest.yaml +3 -0
  439. package/src/xmc/workflows/xiaoma-quick-flow/quick-dev/steps/step-01-mode-detection.md +174 -0
  440. package/src/xmc/workflows/xiaoma-quick-flow/quick-dev/steps/step-02-context-gathering.md +118 -0
  441. package/src/xmc/workflows/xiaoma-quick-flow/quick-dev/steps/step-03-execute.md +111 -0
  442. package/src/xmc/workflows/xiaoma-quick-flow/quick-dev/steps/step-04-self-check.md +111 -0
  443. package/src/xmc/workflows/xiaoma-quick-flow/quick-dev/steps/step-05-adversarial-review.md +98 -0
  444. package/src/xmc/workflows/xiaoma-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -0
  445. package/src/xmc/workflows/xiaoma-quick-flow/quick-dev/workflow.md +50 -0
  446. package/src/xmc/workflows/xiaoma-quick-flow/quick-dev/xiaoma-skill-manifest.yaml +3 -0
  447. package/src/xmc/workflows/xiaoma-quick-flow/quick-spec/steps/step-01-understand.md +189 -0
  448. package/src/xmc/workflows/xiaoma-quick-flow/quick-spec/steps/step-02-investigate.md +143 -0
  449. package/src/xmc/workflows/xiaoma-quick-flow/quick-spec/steps/step-03-generate.md +126 -0
  450. package/src/xmc/workflows/xiaoma-quick-flow/quick-spec/steps/step-04-review.md +198 -0
  451. package/src/xmc/workflows/xiaoma-quick-flow/quick-spec/tech-spec-template.md +74 -0
  452. package/src/xmc/workflows/xiaoma-quick-flow/quick-spec/workflow.md +79 -0
  453. package/src/xmc/workflows/xiaoma-quick-flow/quick-spec/xiaoma-skill-manifest.yaml +3 -0
  454. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/SKILL.md +6 -0
  455. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/steps/step-01-clarify-and-route.md +54 -0
  456. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/steps/step-02-plan.md +39 -0
  457. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/steps/step-03-implement.md +35 -0
  458. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/steps/step-04-review.md +55 -0
  459. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/steps/step-05-present.md +19 -0
  460. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/tech-spec-template.md +90 -0
  461. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/workflow.md +84 -0
  462. package/src/xmc/workflows/xiaoma-quick-flow/xiaoma-quick-dev-new-preview/xiaoma-skill-manifest.yaml +1 -0
  463. package/test/README.md +295 -0
  464. package/test/adversarial-review-tests/README.md +56 -0
  465. package/test/adversarial-review-tests/sample-content.md +46 -0
  466. package/test/adversarial-review-tests/test-cases.yaml +103 -0
  467. package/test/fixtures/agent-schema/invalid/critical-actions/actions-as-string.agent.yaml +27 -0
  468. package/test/fixtures/agent-schema/invalid/critical-actions/empty-string-in-actions.agent.yaml +30 -0
  469. package/test/fixtures/agent-schema/invalid/menu/empty-menu.agent.yaml +22 -0
  470. package/test/fixtures/agent-schema/invalid/menu/missing-menu.agent.yaml +20 -0
  471. package/test/fixtures/agent-schema/invalid/menu-commands/empty-command-target.agent.yaml +25 -0
  472. package/test/fixtures/agent-schema/invalid/menu-commands/no-command-target.agent.yaml +24 -0
  473. package/test/fixtures/agent-schema/invalid/menu-triggers/camel-case.agent.yaml +25 -0
  474. package/test/fixtures/agent-schema/invalid/menu-triggers/compound-invalid-format.agent.yaml +25 -0
  475. package/test/fixtures/agent-schema/invalid/menu-triggers/compound-mismatched-kebab.agent.yaml +25 -0
  476. package/test/fixtures/agent-schema/invalid/menu-triggers/duplicate-triggers.agent.yaml +31 -0
  477. package/test/fixtures/agent-schema/invalid/menu-triggers/empty-trigger.agent.yaml +25 -0
  478. package/test/fixtures/agent-schema/invalid/menu-triggers/leading-asterisk.agent.yaml +25 -0
  479. package/test/fixtures/agent-schema/invalid/menu-triggers/snake-case.agent.yaml +25 -0
  480. package/test/fixtures/agent-schema/invalid/menu-triggers/trigger-with-spaces.agent.yaml +25 -0
  481. package/test/fixtures/agent-schema/invalid/metadata/empty-module-string.agent.yaml +26 -0
  482. package/test/fixtures/agent-schema/invalid/metadata/empty-name.agent.yaml +24 -0
  483. package/test/fixtures/agent-schema/invalid/metadata/extra-metadata-fields.agent.yaml +27 -0
  484. package/test/fixtures/agent-schema/invalid/metadata/missing-id.agent.yaml +23 -0
  485. package/test/fixtures/agent-schema/invalid/persona/empty-principles-array.agent.yaml +24 -0
  486. package/test/fixtures/agent-schema/invalid/persona/empty-string-in-principles.agent.yaml +27 -0
  487. package/test/fixtures/agent-schema/invalid/persona/extra-persona-fields.agent.yaml +27 -0
  488. package/test/fixtures/agent-schema/invalid/persona/missing-role.agent.yaml +24 -0
  489. package/test/fixtures/agent-schema/invalid/prompts/empty-content.agent.yaml +29 -0
  490. package/test/fixtures/agent-schema/invalid/prompts/extra-prompt-fields.agent.yaml +31 -0
  491. package/test/fixtures/agent-schema/invalid/prompts/missing-content.agent.yaml +28 -0
  492. package/test/fixtures/agent-schema/invalid/prompts/missing-id.agent.yaml +28 -0
  493. package/test/fixtures/agent-schema/invalid/top-level/empty-file.agent.yaml +5 -0
  494. package/test/fixtures/agent-schema/invalid/top-level/extra-top-level-keys.agent.yaml +28 -0
  495. package/test/fixtures/agent-schema/invalid/top-level/missing-agent-key.agent.yaml +11 -0
  496. package/test/fixtures/agent-schema/invalid/yaml-errors/invalid-indentation.agent.yaml +19 -0
  497. package/test/fixtures/agent-schema/invalid/yaml-errors/malformed-yaml.agent.yaml +18 -0
  498. package/test/fixtures/agent-schema/valid/critical-actions/empty-critical-actions.agent.yaml +24 -0
  499. package/test/fixtures/agent-schema/valid/critical-actions/no-critical-actions.agent.yaml +22 -0
  500. package/test/fixtures/agent-schema/valid/critical-actions/valid-critical-actions.agent.yaml +27 -0
  501. package/test/fixtures/agent-schema/valid/menu/multiple-menu-items.agent.yaml +31 -0
  502. package/test/fixtures/agent-schema/valid/menu/single-menu-item.agent.yaml +22 -0
  503. package/test/fixtures/agent-schema/valid/menu-commands/all-command-types.agent.yaml +38 -0
  504. package/test/fixtures/agent-schema/valid/menu-commands/multiple-commands.agent.yaml +23 -0
  505. package/test/fixtures/agent-schema/valid/menu-triggers/compound-triggers.agent.yaml +31 -0
  506. package/test/fixtures/agent-schema/valid/menu-triggers/kebab-case-triggers.agent.yaml +34 -0
  507. package/test/fixtures/agent-schema/valid/metadata/core-agent-with-module.agent.yaml +24 -0
  508. package/test/fixtures/agent-schema/valid/metadata/empty-module-name-in-path.agent.yaml +24 -0
  509. package/test/fixtures/agent-schema/valid/metadata/malformed-path-treated-as-core.agent.yaml +24 -0
  510. package/test/fixtures/agent-schema/valid/metadata/module-agent-correct.agent.yaml +24 -0
  511. package/test/fixtures/agent-schema/valid/metadata/module-agent-missing-module.agent.yaml +23 -0
  512. package/test/fixtures/agent-schema/valid/metadata/wrong-module-value.agent.yaml +24 -0
  513. package/test/fixtures/agent-schema/valid/persona/complete-persona.agent.yaml +24 -0
  514. package/test/fixtures/agent-schema/valid/prompts/empty-prompts.agent.yaml +24 -0
  515. package/test/fixtures/agent-schema/valid/prompts/no-prompts.agent.yaml +22 -0
  516. package/test/fixtures/agent-schema/valid/prompts/valid-prompts-minimal.agent.yaml +28 -0
  517. package/test/fixtures/agent-schema/valid/prompts/valid-prompts-with-description.agent.yaml +30 -0
  518. package/test/fixtures/agent-schema/valid/top-level/minimal-core-agent.agent.yaml +24 -0
  519. package/test/fixtures/file-refs-csv/invalid/all-empty-workflow.csv +3 -0
  520. package/test/fixtures/file-refs-csv/invalid/empty-data.csv +1 -0
  521. package/test/fixtures/file-refs-csv/invalid/no-workflow-column.csv +3 -0
  522. package/test/fixtures/file-refs-csv/invalid/unresolvable-vars.csv +3 -0
  523. package/test/fixtures/file-refs-csv/valid/core-style.csv +3 -0
  524. package/test/fixtures/file-refs-csv/valid/minimal.csv +2 -0
  525. package/test/fixtures/file-refs-csv/valid/xmc-style.csv +3 -0
  526. package/test/test-agent-schema.js +387 -0
  527. package/test/test-cli-integration.sh +159 -0
  528. package/test/test-file-refs-csv.js +133 -0
  529. package/test/test-install-to-xiaoma.js +154 -0
  530. package/test/test-installation-components.js +1802 -0
  531. package/test/test-rehype-plugins.mjs +1050 -0
  532. package/test/test-workflow-path-regex.js +88 -0
  533. package/test/unit-test-schema.js +133 -0
  534. package/tools/build-docs.mjs +464 -0
  535. package/tools/cli/README.md +60 -0
  536. package/tools/cli/bundlers/bundle-web.js +179 -0
  537. package/tools/cli/bundlers/bundlers/bundle-web.js +179 -0
  538. package/tools/cli/bundlers/bundlers/test-analyst.js +28 -0
  539. package/tools/cli/bundlers/bundlers/test-bundler.js +119 -0
  540. package/tools/cli/bundlers/bundlers/web-bundler.js +1754 -0
  541. package/tools/cli/bundlers/test-analyst.js +28 -0
  542. package/tools/cli/bundlers/test-bundler.js +119 -0
  543. package/tools/cli/bundlers/web-bundler.js +1754 -0
  544. package/tools/cli/commands/agent-install.js +409 -0
  545. package/tools/cli/commands/build.js +458 -0
  546. package/tools/cli/commands/cleanup.js +144 -0
  547. package/tools/cli/commands/install.js +87 -0
  548. package/tools/cli/commands/list.js +43 -0
  549. package/tools/cli/commands/status.js +65 -0
  550. package/tools/cli/commands/uninstall.js +167 -0
  551. package/tools/cli/commands/update.js +28 -0
  552. package/tools/cli/external-official-modules.yaml +56 -0
  553. package/tools/cli/installers/install-messages.yaml +39 -0
  554. package/tools/cli/installers/lib/core/config-collector.js +1285 -0
  555. package/tools/cli/installers/lib/core/custom-module-cache.js +260 -0
  556. package/tools/cli/installers/lib/core/dependency-resolver.js +743 -0
  557. package/tools/cli/installers/lib/core/detector.js +223 -0
  558. package/tools/cli/installers/lib/core/ide-config-manager.js +157 -0
  559. package/tools/cli/installers/lib/core/installer.js +3195 -0
  560. package/tools/cli/installers/lib/core/manifest-generator.js +1374 -0
  561. package/tools/cli/installers/lib/core/manifest.js +1038 -0
  562. package/tools/cli/installers/lib/custom/handler.js +358 -0
  563. package/tools/cli/installers/lib/ide/_base-ide.js +674 -0
  564. package/tools/cli/installers/lib/ide/_config-driven.js +1053 -0
  565. package/tools/cli/installers/lib/ide/antigravity.js +510 -0
  566. package/tools/cli/installers/lib/ide/auggie.js +232 -0
  567. package/tools/cli/installers/lib/ide/claude-code.js +512 -0
  568. package/tools/cli/installers/lib/ide/cline.js +269 -0
  569. package/tools/cli/installers/lib/ide/codex.js +440 -0
  570. package/tools/cli/installers/lib/ide/crush.js +287 -0
  571. package/tools/cli/installers/lib/ide/cursor.js +400 -0
  572. package/tools/cli/installers/lib/ide/gemini.js +253 -0
  573. package/tools/cli/installers/lib/ide/github-copilot.js +699 -0
  574. package/tools/cli/installers/lib/ide/iflow.js +172 -0
  575. package/tools/cli/installers/lib/ide/kilo.js +269 -0
  576. package/tools/cli/installers/lib/ide/manager.js +304 -0
  577. package/tools/cli/installers/lib/ide/opencode.js +257 -0
  578. package/tools/cli/installers/lib/ide/platform-codes.js +100 -0
  579. package/tools/cli/installers/lib/ide/platform-codes.yaml +321 -0
  580. package/tools/cli/installers/lib/ide/qwen.js +372 -0
  581. package/tools/cli/installers/lib/ide/roo.js +324 -0
  582. package/tools/cli/installers/lib/ide/rovo-dev.js +290 -0
  583. package/tools/cli/installers/lib/ide/rovodev.js +257 -0
  584. package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +181 -0
  585. package/tools/cli/installers/lib/ide/shared/module-injections.js +136 -0
  586. package/tools/cli/installers/lib/ide/shared/path-utils.js +364 -0
  587. package/tools/cli/installers/lib/ide/shared/skill-manifest.js +90 -0
  588. package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +368 -0
  589. package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +179 -0
  590. package/tools/cli/installers/lib/ide/shared/xiaoma-artifacts.js +181 -0
  591. package/tools/cli/installers/lib/ide/templates/agent-command-template.md +14 -0
  592. package/tools/cli/installers/lib/ide/templates/combined/antigravity.md +8 -0
  593. package/tools/cli/installers/lib/ide/templates/combined/default-agent.md +15 -0
  594. package/tools/cli/installers/lib/ide/templates/combined/default-task.md +10 -0
  595. package/tools/cli/installers/lib/ide/templates/combined/default-tool.md +10 -0
  596. package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +14 -0
  597. package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +6 -0
  598. package/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml +14 -0
  599. package/tools/cli/installers/lib/ide/templates/combined/gemini-task.toml +11 -0
  600. package/tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml +11 -0
  601. package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml +16 -0
  602. package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml +14 -0
  603. package/tools/cli/installers/lib/ide/templates/combined/kiro-agent.md +16 -0
  604. package/tools/cli/installers/lib/ide/templates/combined/kiro-task.md +9 -0
  605. package/tools/cli/installers/lib/ide/templates/combined/kiro-tool.md +9 -0
  606. package/tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md +15 -0
  607. package/tools/cli/installers/lib/ide/templates/combined/kiro-workflow.md +7 -0
  608. package/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md +15 -0
  609. package/tools/cli/installers/lib/ide/templates/combined/opencode-task.md +13 -0
  610. package/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md +13 -0
  611. package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md +16 -0
  612. package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md +16 -0
  613. package/tools/cli/installers/lib/ide/templates/combined/rovodev.md +9 -0
  614. package/tools/cli/installers/lib/ide/templates/combined/trae.md +9 -0
  615. package/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md +10 -0
  616. package/tools/cli/installers/lib/ide/templates/gemini-agent-command.toml +14 -0
  617. package/tools/cli/installers/lib/ide/templates/gemini-task-command.toml +12 -0
  618. package/tools/cli/installers/lib/ide/templates/split/.gitkeep +0 -0
  619. package/tools/cli/installers/lib/ide/templates/workflow-command-template.md +13 -0
  620. package/tools/cli/installers/lib/ide/templates/workflow-commander.md +5 -0
  621. package/tools/cli/installers/lib/ide/trae.js +313 -0
  622. package/tools/cli/installers/lib/ide/windsurf.js +258 -0
  623. package/tools/cli/installers/lib/message-loader.js +83 -0
  624. package/tools/cli/installers/lib/modules/external-manager.js +136 -0
  625. package/tools/cli/installers/lib/modules/manager.js +1382 -0
  626. package/tools/cli/lib/activation-builder.js +165 -0
  627. package/tools/cli/lib/agent/compiler.js +516 -0
  628. package/tools/cli/lib/agent/installer.js +680 -0
  629. package/tools/cli/lib/agent/template-engine.js +152 -0
  630. package/tools/cli/lib/agent-analyzer.js +97 -0
  631. package/tools/cli/lib/agent-party-generator.js +194 -0
  632. package/tools/cli/lib/cli-utils.js +182 -0
  633. package/tools/cli/lib/config.js +213 -0
  634. package/tools/cli/lib/file-ops.js +204 -0
  635. package/tools/cli/lib/platform-codes.js +116 -0
  636. package/tools/cli/lib/project-root.js +77 -0
  637. package/tools/cli/lib/prompts.js +809 -0
  638. package/tools/cli/lib/replace-project-root.js +239 -0
  639. package/tools/cli/lib/ui.js +1940 -0
  640. package/tools/cli/lib/xml-handler.js +177 -0
  641. package/tools/cli/lib/xml-to-markdown.js +82 -0
  642. package/tools/{yaml-format.js → cli/lib/yaml-format.js} +39 -71
  643. package/tools/cli/lib/yaml-xml-builder.js +570 -0
  644. package/tools/cli/regenerate-manifests.js +28 -0
  645. package/tools/cli/test-yaml-builder.js +43 -0
  646. package/tools/cli/xiaoma-cli.js +106 -0
  647. package/tools/docs/_prompt-external-modules-page.md +59 -0
  648. package/tools/docs/fix-refs.md +91 -0
  649. package/tools/docs/native-skills-migration-checklist.md +281 -0
  650. package/tools/fix-doc-links.js +285 -0
  651. package/tools/flattener/aggregate.js +12 -30
  652. package/tools/flattener/binary.js +43 -46
  653. package/tools/flattener/discovery.js +15 -23
  654. package/tools/flattener/files.js +6 -6
  655. package/tools/flattener/flattener/aggregate.js +76 -0
  656. package/tools/flattener/flattener/binary.js +80 -0
  657. package/tools/flattener/flattener/discovery.js +71 -0
  658. package/tools/flattener/flattener/files.js +35 -0
  659. package/tools/flattener/flattener/ignoreRules.js +172 -0
  660. package/tools/flattener/flattener/main.js +483 -0
  661. package/tools/flattener/flattener/projectRoot.js +201 -0
  662. package/tools/flattener/flattener/prompts.js +44 -0
  663. package/tools/flattener/flattener/stats.helpers.js +368 -0
  664. package/tools/flattener/flattener/stats.js +75 -0
  665. package/tools/flattener/flattener/test-matrix.js +409 -0
  666. package/tools/flattener/flattener/xml.js +88 -0
  667. package/tools/flattener/ignoreRules.js +122 -127
  668. package/tools/flattener/main.js +140 -330
  669. package/tools/flattener/projectRoot.js +71 -81
  670. package/tools/flattener/prompts.js +10 -12
  671. package/tools/flattener/stats.helpers.js +63 -119
  672. package/tools/flattener/stats.js +2 -7
  673. package/tools/flattener/test-matrix.js +169 -228
  674. package/tools/flattener/xml.js +23 -31
  675. package/tools/format-workflow-md.js +263 -0
  676. package/tools/lib/xml-utils.js +13 -0
  677. package/tools/migrate-custom-module-paths.js +124 -0
  678. package/tools/platform-codes.yaml +157 -0
  679. package/tools/schema/agent.js +489 -0
  680. package/tools/validate-agent-schema.js +110 -0
  681. package/tools/validate-bundles.js +87 -0
  682. package/tools/validate-doc-links.js +409 -0
  683. package/tools/validate-file-refs.js +556 -0
  684. package/tools/validate-svg-changes.sh +356 -0
  685. package/tools/xiaoma-npx-wrapper.js +18 -24
  686. package/web-bundles/xmc/agents/analyst.xml +109 -0
  687. package/web-bundles/xmc/agents/architect.xml +101 -0
  688. package/web-bundles/xmc/agents/dev.xml +106 -0
  689. package/web-bundles/xmc/agents/pm.xml +112 -0
  690. package/web-bundles/xmc/agents/qa.xml +126 -0
  691. package/web-bundles/xmc/agents/quick-flow-solo-dev.xml +104 -0
  692. package/web-bundles/xmc/agents/sm.xml +109 -0
  693. package/web-bundles/xmc/agents/ux-designer.xml +100 -0
  694. package/web-bundles/xmc/teams/team-fullstack.xml +1192 -0
  695. package/.claude/agents/tech-translator.md +0 -124
  696. package/.claude/settings.local.json +0 -37
  697. package/.idea/misc.xml +0 -6
  698. package/.xiaoma-core/.coordinator-state.json +0 -19
  699. package/CLAUDE.md +0 -283
  700. package/JAVA-BACKEND-COMMANDS-REFERENCE.md +0 -300
  701. package/JAVA-BACKEND-ITERATION-GUIDE.md +0 -2116
  702. package/common/tasks/create-doc.md +0 -103
  703. package/common/tasks/execute-checklist.md +0 -88
  704. package/common/utils/bmad-doc-template.md +0 -327
  705. package/common/utils/workflow-management.md +0 -71
  706. package/dist/agents/analyst.txt +0 -6308
  707. package/dist/agents/architect.txt +0 -5046
  708. package/dist/agents/automation-orchestrator.txt +0 -396
  709. package/dist/agents/dev.txt +0 -1180
  710. package/dist/agents/full-requirement-orchestrator.txt +0 -505
  711. package/dist/agents/pm.txt +0 -3078
  712. package/dist/agents/po.txt +0 -1358
  713. package/dist/agents/qa.txt +0 -2002
  714. package/dist/agents/sm.txt +0 -3044
  715. package/dist/agents/ux-expert.txt +0 -707
  716. package/dist/agents/workflow-executor.txt +0 -1029
  717. package/dist/agents/workflow-helper.txt +0 -93
  718. package/dist/agents/xiaoma-master.txt +0 -9008
  719. package/dist/agents/xiaoma-orchestrator.txt +0 -1523
  720. package/dist/teams/team-all.txt +0 -23101
  721. package/dist/teams/team-fullstack-with-database.txt +0 -25076
  722. package/dist/teams/team-fullstack.txt +0 -15820
  723. package/dist/teams/team-ide-minimal.txt +0 -8285
  724. package/dist/teams/team-no-ui.txt +0 -14368
  725. package/docs/GUIDING-PRINCIPLES.md +0 -91
  726. package/docs/architecture/workflow-coordinator-implementation.md +0 -1188
  727. package/docs/architecture-sharding-modification.md +0 -623
  728. package/docs/automated-requirements-analysis-outputs.md +0 -896
  729. package/docs/core-architecture.md +0 -219
  730. package/docs/enhanced-ide-development-workflow.md +0 -248
  731. package/docs/prd/workflow-coordinator-prd.md +0 -1214
  732. package/docs/user-guide.md +0 -530
  733. package/docs/versioning-and-releases.md +0 -155
  734. package/docs/versions.md +0 -48
  735. package/docs/working-in-the-brownfield.md +0 -597
  736. package/tools/api-server.js +0 -367
  737. package/tools/builders/web-builder.js +0 -830
  738. package/tools/bump-all-versions.js +0 -133
  739. package/tools/cli.js +0 -157
  740. package/tools/installer/README.md +0 -8
  741. package/tools/installer/bin/xiaoma.js +0 -477
  742. package/tools/installer/config/ide-agent-config.yaml +0 -58
  743. package/tools/installer/config/install.config.yaml +0 -164
  744. package/tools/installer/lib/config-loader.js +0 -286
  745. package/tools/installer/lib/file-manager.js +0 -446
  746. package/tools/installer/lib/ide-base-setup.js +0 -238
  747. package/tools/installer/lib/ide-setup.js +0 -2027
  748. package/tools/installer/lib/installer.js +0 -2333
  749. package/tools/installer/lib/memory-profiler.js +0 -235
  750. package/tools/installer/lib/module-manager.js +0 -116
  751. package/tools/installer/lib/resource-locator.js +0 -334
  752. package/tools/installer/package-lock.json +0 -715
  753. package/tools/installer/package.json +0 -44
  754. package/tools/lib/dependency-resolver.js +0 -186
  755. package/tools/lib/yaml-utils.js +0 -34
  756. package/tools/md-assets/web-agent-startup-instructions.md +0 -39
  757. package/tools/preview-release-notes.js +0 -74
  758. package/tools/setup-hooks.sh +0 -37
  759. package/tools/shared/bannerArt.js +0 -105
  760. package/tools/sync-installer-version.js +0 -41
  761. package/tools/sync-version.sh +0 -23
  762. package/tools/upgraders/v3-to-v4-upgrader.js +0 -753
  763. package/tools/version-bump.js +0 -100
  764. package/tools/workflow-coordinator/README.md +0 -38
  765. package/tools/workflow-coordinator/USAGE.md +0 -548
  766. package/tools/workflow-coordinator/package-lock.json +0 -4868
  767. package/tools/workflow-coordinator/package.json +0 -35
  768. package/tools/workflow-coordinator/src/api/server.js +0 -207
  769. package/tools/workflow-coordinator/src/controller/workflow-controller.js +0 -263
  770. package/tools/workflow-coordinator/src/index.js +0 -113
  771. package/tools/workflow-coordinator/src/parser/workflow-parser.js +0 -144
  772. package/tools/workflow-coordinator/src/utils/state-manager.js +0 -59
  773. package/tools/workflow-coordinator/src/utils/validator.js +0 -86
  774. package/tools/workflow-coordinator/test/integration-test.js +0 -266
  775. package/tools/workflow-coordinator/test/quick-test.js +0 -127
  776. package/xiaoma-core/agent-teams/team-all.yaml +0 -15
  777. package/xiaoma-core/agent-teams/team-fullstack-with-database.yaml +0 -27
  778. package/xiaoma-core/agent-teams/team-fullstack.yaml +0 -19
  779. package/xiaoma-core/agent-teams/team-ide-minimal.yaml +0 -11
  780. package/xiaoma-core/agent-teams/team-no-ui.yaml +0 -14
  781. package/xiaoma-core/agents/analyst.md +0 -91
  782. package/xiaoma-core/agents/architect.md +0 -88
  783. package/xiaoma-core/agents/automated-fix-validator.yaml +0 -579
  784. package/xiaoma-core/agents/automated-quality-validator.yaml +0 -549
  785. package/xiaoma-core/agents/automation-orchestrator.md +0 -353
  786. package/xiaoma-core/agents/dev.md +0 -144
  787. package/xiaoma-core/agents/enhanced-workflow-orchestrator.yaml +0 -304
  788. package/xiaoma-core/agents/full-requirement-orchestrator.md +0 -462
  789. package/xiaoma-core/agents/global-requirements-auditor.yaml +0 -520
  790. package/xiaoma-core/agents/intelligent-template-adapter.yaml +0 -389
  791. package/xiaoma-core/agents/issue-dispatcher.yaml +0 -627
  792. package/xiaoma-core/agents/master-execution-engine.yaml +0 -543
  793. package/xiaoma-core/agents/pm.md +0 -85
  794. package/xiaoma-core/agents/po.md +0 -77
  795. package/xiaoma-core/agents/qa.md +0 -88
  796. package/xiaoma-core/agents/requirements-coverage-auditor.yaml +0 -373
  797. package/xiaoma-core/agents/sm.md +0 -125
  798. package/xiaoma-core/agents/ux-expert.md +0 -67
  799. package/xiaoma-core/agents/workflow-executor.md +0 -1031
  800. package/xiaoma-core/agents/workflow-helper.md +0 -481
  801. package/xiaoma-core/agents/xiaoma-master.md +0 -108
  802. package/xiaoma-core/agents/xiaoma-orchestrator.md +0 -145
  803. package/xiaoma-core/checklists/architect-checklist.md +0 -440
  804. package/xiaoma-core/checklists/change-checklist.md +0 -184
  805. package/xiaoma-core/checklists/dev-completion-checklist.md +0 -324
  806. package/xiaoma-core/checklists/pm-checklist.md +0 -372
  807. package/xiaoma-core/checklists/po-master-checklist.md +0 -434
  808. package/xiaoma-core/checklists/po-story-validation-checklist.md +0 -219
  809. package/xiaoma-core/checklists/qa-approval-checklist.md +0 -393
  810. package/xiaoma-core/checklists/story-dod-checklist.md +0 -96
  811. package/xiaoma-core/checklists/story-draft-checklist.md +0 -155
  812. package/xiaoma-core/core-config.yaml +0 -23
  813. package/xiaoma-core/data/bmad-kb.md +0 -809
  814. package/xiaoma-core/data/brainstorming-techniques.md +0 -38
  815. package/xiaoma-core/data/elicitation-methods.md +0 -156
  816. package/xiaoma-core/data/technical-preferences.md +0 -5
  817. package/xiaoma-core/data/test-levels-framework.md +0 -148
  818. package/xiaoma-core/data/test-priorities-matrix.md +0 -174
  819. package/xiaoma-core/scripts/build-validation/pre-dev-validation.sh +0 -71
  820. package/xiaoma-core/scripts/build-validation/progressive-validation.sh +0 -88
  821. package/xiaoma-core/scripts/build-validation/quick-check.sh +0 -69
  822. package/xiaoma-core/tasks/advanced-elicitation.md +0 -119
  823. package/xiaoma-core/tasks/analyze-existing-database.md +0 -155
  824. package/xiaoma-core/tasks/apply-qa-fixes.md +0 -150
  825. package/xiaoma-core/tasks/automated-story-cycle.md +0 -370
  826. package/xiaoma-core/tasks/batch-story-generation.md +0 -354
  827. package/xiaoma-core/tasks/brownfield-create-epic.md +0 -162
  828. package/xiaoma-core/tasks/brownfield-create-story.md +0 -149
  829. package/xiaoma-core/tasks/correct-course.md +0 -72
  830. package/xiaoma-core/tasks/create-brownfield-story.md +0 -314
  831. package/xiaoma-core/tasks/create-database-design.md +0 -161
  832. package/xiaoma-core/tasks/create-deep-research-prompt.md +0 -280
  833. package/xiaoma-core/tasks/create-enhanced-story-with-database.md +0 -250
  834. package/xiaoma-core/tasks/create-incremental-architecture.md +0 -525
  835. package/xiaoma-core/tasks/create-next-story.md +0 -114
  836. package/xiaoma-core/tasks/create-prd-from-rag.md +0 -435
  837. package/xiaoma-core/tasks/create-story-with-rag.md +0 -559
  838. package/xiaoma-core/tasks/develop-story-with-rag.md +0 -536
  839. package/xiaoma-core/tasks/document-project.md +0 -345
  840. package/xiaoma-core/tasks/facilitate-brainstorming-session.md +0 -138
  841. package/xiaoma-core/tasks/generate-ai-frontend-prompt.md +0 -53
  842. package/xiaoma-core/tasks/generate-database-ddl.md +0 -240
  843. package/xiaoma-core/tasks/generate-database-entities.md +0 -501
  844. package/xiaoma-core/tasks/generate-rag-questions.md +0 -312
  845. package/xiaoma-core/tasks/index-docs.md +0 -175
  846. package/xiaoma-core/tasks/kb-mode-interaction.md +0 -77
  847. package/xiaoma-core/tasks/nfr-assess.md +0 -345
  848. package/xiaoma-core/tasks/project-integration-testing.md +0 -477
  849. package/xiaoma-core/tasks/qa-gate.md +0 -163
  850. package/xiaoma-core/tasks/requirement-analysis-with-rag.md +0 -1318
  851. package/xiaoma-core/tasks/requirements-coverage-audit.md +0 -198
  852. package/xiaoma-core/tasks/review-story.md +0 -316
  853. package/xiaoma-core/tasks/risk-profile.md +0 -355
  854. package/xiaoma-core/tasks/serial-development-orchestration.md +0 -426
  855. package/xiaoma-core/tasks/shard-doc.md +0 -187
  856. package/xiaoma-core/tasks/test-design.md +0 -176
  857. package/xiaoma-core/tasks/trace-requirements.md +0 -266
  858. package/xiaoma-core/tasks/validate-next-story.md +0 -136
  859. package/xiaoma-core/templates/api-design-tmpl.yaml +0 -704
  860. package/xiaoma-core/templates/architecture-tmpl.yaml +0 -650
  861. package/xiaoma-core/templates/brainstorming-output-tmpl.yaml +0 -156
  862. package/xiaoma-core/templates/brownfield-architecture-tmpl.yaml +0 -476
  863. package/xiaoma-core/templates/brownfield-prd-tmpl.yaml +0 -280
  864. package/xiaoma-core/templates/competitor-analysis-tmpl.yaml +0 -336
  865. package/xiaoma-core/templates/database-design-tmpl.yaml +0 -266
  866. package/xiaoma-core/templates/enhanced-story-with-database-tmpl.yaml +0 -428
  867. package/xiaoma-core/templates/front-end-architecture-tmpl.yaml +0 -272
  868. package/xiaoma-core/templates/front-end-spec-tmpl.yaml +0 -354
  869. package/xiaoma-core/templates/fullstack-architecture-tmpl.yaml +0 -925
  870. package/xiaoma-core/templates/global-qa-monitoring-tmpl.yaml +0 -443
  871. package/xiaoma-core/templates/incremental-architecture-tmpl.yaml +0 -601
  872. package/xiaoma-core/templates/market-research-tmpl.yaml +0 -252
  873. package/xiaoma-core/templates/maven-lombok-template.xml +0 -111
  874. package/xiaoma-core/templates/prd-from-rag-tmpl.yaml +0 -410
  875. package/xiaoma-core/templates/prd-tmpl.yaml +0 -202
  876. package/xiaoma-core/templates/project-brief-tmpl.yaml +0 -221
  877. package/xiaoma-core/templates/qa-gate-tmpl.yaml +0 -102
  878. package/xiaoma-core/templates/rag-knowledge-tmpl.yaml +0 -569
  879. package/xiaoma-core/templates/rag-questions-tmpl.yaml +0 -949
  880. package/xiaoma-core/templates/requirements-coverage-audit.yaml +0 -330
  881. package/xiaoma-core/templates/start-enhanced-workflow.yaml +0 -347
  882. package/xiaoma-core/templates/story-tmpl.yaml +0 -137
  883. package/xiaoma-core/templates/story-with-rag-tmpl.yaml +0 -360
  884. package/xiaoma-core/workflows/automated-requirements-analysis.yaml +0 -2149
  885. package/xiaoma-core/workflows/automated-requirements-development.yaml +0 -739
  886. package/xiaoma-core/workflows/automated-story-development.yaml +0 -1264
  887. package/xiaoma-core/workflows/brownfield-fullstack.yaml +0 -298
  888. package/xiaoma-core/workflows/brownfield-service.yaml +0 -188
  889. package/xiaoma-core/workflows/brownfield-ui.yaml +0 -198
  890. package/xiaoma-core/workflows/enhanced-fullstack-with-database.yaml +0 -427
  891. package/xiaoma-core/workflows/enhanced-fullstack-with-qa-loop.yaml +0 -766
  892. package/xiaoma-core/workflows/full-requirement-automation.yaml +0 -1305
  893. package/xiaoma-core/workflows/greenfield-fullstack.yaml +0 -241
  894. package/xiaoma-core/workflows/greenfield-service.yaml +0 -207
  895. package/xiaoma-core/workflows/greenfield-ui.yaml +0 -236
@@ -0,0 +1,1940 @@
1
+ const path = require('node:path');
2
+ const os = require('node:os');
3
+ const fs = require('fs-extra');
4
+ const { CLIUtils } = require('./cli-utils');
5
+ const { CustomHandler } = require('../installers/lib/custom/handler');
6
+ const { ExternalModuleManager } = require('../installers/lib/modules/external-manager');
7
+ const prompts = require('./prompts');
8
+
9
+ // Separator class for visual grouping in select/multiselect prompts
10
+ // Note: @clack/prompts doesn't support separators natively, they are filtered out
11
+ class Separator {
12
+ constructor(text = '────────') {
13
+ this.line = text;
14
+ this.name = text;
15
+ }
16
+ type = 'separator';
17
+ }
18
+
19
+ // Separator for choice lists (compatible interface)
20
+ const choiceUtils = { Separator };
21
+
22
+ /**
23
+ * UI utilities for the installer
24
+ */
25
+ class UI {
26
+ /**
27
+ * Prompt for installation configuration
28
+ * @param {Object} options - Command-line options from install command
29
+ * @returns {Object} Installation configuration
30
+ */
31
+ async promptInstall(options = {}) {
32
+ await CLIUtils.displayLogo();
33
+
34
+ // Display version-specific start message from install-messages.yaml
35
+ const { MessageLoader } = require('../installers/lib/message-loader');
36
+ const messageLoader = new MessageLoader();
37
+ await messageLoader.displayStartMessage();
38
+
39
+ // Get directory from options or prompt
40
+ let confirmedDirectory;
41
+ if (options.directory) {
42
+ // Use provided directory from command-line
43
+ const expandedDir = this.expandUserPath(options.directory);
44
+ const validation = this.validateDirectorySync(expandedDir);
45
+ if (validation) {
46
+ throw new Error(`Invalid directory: ${validation}`);
47
+ }
48
+ confirmedDirectory = expandedDir;
49
+ await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`);
50
+ } else {
51
+ confirmedDirectory = await this.getConfirmedDirectory();
52
+ }
53
+
54
+ // Preflight: Check for legacy XiaoMa v4 footprints immediately after getting directory
55
+ const { Detector } = require('../installers/lib/core/detector');
56
+ const { Installer } = require('../installers/lib/core/installer');
57
+ const detector = new Detector();
58
+ const installer = new Installer();
59
+ const legacyV4 = await detector.detectLegacyV4(confirmedDirectory);
60
+ if (legacyV4.hasLegacyV4) {
61
+ await installer.handleLegacyV4Migration(confirmedDirectory, legacyV4);
62
+ }
63
+
64
+ // Check for legacy folders and prompt for rename before showing any menus
65
+ let hasLegacyCfg = false;
66
+ let hasLegacyXiaoMaFolder = false;
67
+ let xiaomaDir = null;
68
+ let legacyXiaoMaPath = null;
69
+
70
+ // First check for legacy .xiaoma folder (instead of _xiaoma)
71
+ // Only check if directory exists
72
+ if (await fs.pathExists(confirmedDirectory)) {
73
+ const entries = await fs.readdir(confirmedDirectory, { withFileTypes: true });
74
+ for (const entry of entries) {
75
+ if (entry.isDirectory() && (entry.name === '.xiaoma' || entry.name === 'xiaoma')) {
76
+ hasLegacyXiaoMaFolder = true;
77
+ legacyXiaoMaPath = path.join(confirmedDirectory, entry.name);
78
+ xiaomaDir = legacyXiaoMaPath;
79
+
80
+ // Check if it has _cfg folder
81
+ const cfgPath = path.join(legacyXiaoMaPath, '_cfg');
82
+ if (await fs.pathExists(cfgPath)) {
83
+ hasLegacyCfg = true;
84
+ }
85
+ break;
86
+ }
87
+ }
88
+ }
89
+
90
+ // If no .xiaoma or xiaoma found, check for current installations _xiaoma
91
+ if (!hasLegacyXiaoMaFolder) {
92
+ const xiaomaResult = await installer.findXiaomaDir(confirmedDirectory);
93
+ xiaomaDir = xiaomaResult.xiaomaDir;
94
+ hasLegacyCfg = xiaomaResult.hasLegacyCfg;
95
+ }
96
+
97
+ // Handle legacy .xiaoma or _cfg folder - these are very old (v4 or alpha)
98
+ // Show version warning instead of offering conversion
99
+ if (hasLegacyXiaoMaFolder || hasLegacyCfg) {
100
+ await prompts.log.warn('LEGACY INSTALLATION DETECTED');
101
+ await prompts.note(
102
+ 'Found a ".xiaoma"/"xiaoma" folder, or a legacy "_cfg" folder under the xiaoma folder -\n' +
103
+ 'this is from an old XiaoMa version that is out of date for automatic upgrade,\n' +
104
+ 'manual intervention required.\n\n' +
105
+ 'You have a legacy version installed (v4 or alpha).\n' +
106
+ 'Legacy installations may have compatibility issues.\n\n' +
107
+ 'For the best experience, we strongly recommend:\n' +
108
+ ' 1. Delete your current XiaoMa installation folder (.xiaoma or xiaoma)\n' +
109
+ ' 2. Run a fresh installation\n\n' +
110
+ 'If you do not want to start fresh, you can attempt to proceed beyond this\n' +
111
+ 'point IF you have ensured the xiaoma folder is named _xiaoma, and under it there\n' +
112
+ 'is a _config folder. If you have a folder under your xiaoma folder named _cfg,\n' +
113
+ 'you would need to rename it _config, and then restart the installer.\n\n' +
114
+ 'Benefits of a fresh install:\n' +
115
+ ' \u2022 Cleaner configuration without legacy artifacts\n' +
116
+ ' \u2022 All new features properly configured\n' +
117
+ ' \u2022 Fewer potential conflicts\n\n' +
118
+ 'If you have already produced output from an earlier alpha version, you can\n' +
119
+ 'still retain those artifacts. After installation, ensure you configured during\n' +
120
+ 'install the proper file locations for artifacts depending on the module you\n' +
121
+ 'are using, or move the files to the proper locations.',
122
+ 'Legacy Installation Detected',
123
+ );
124
+
125
+ const proceed = await prompts.select({
126
+ message: 'How would you like to proceed?',
127
+ choices: [
128
+ {
129
+ name: 'Cancel and do a fresh install (recommended)',
130
+ value: 'cancel',
131
+ },
132
+ {
133
+ name: 'Proceed anyway (will attempt update, potentially may fail or have unstable behavior)',
134
+ value: 'proceed',
135
+ },
136
+ ],
137
+ default: 'cancel',
138
+ });
139
+
140
+ if (proceed === 'cancel') {
141
+ await prompts.note(
142
+ '1. Delete the existing xiaoma folder in your project\n' + "2. Run 'xiaoma install' again",
143
+ 'To do a fresh install',
144
+ );
145
+ process.exit(0);
146
+ return;
147
+ }
148
+
149
+ const s = await prompts.spinner();
150
+ s.start('Updating folder structure...');
151
+ try {
152
+ // Handle .xiaoma folder
153
+ if (hasLegacyXiaoMaFolder) {
154
+ const newXiaoMaPath = path.join(confirmedDirectory, '_xiaoma');
155
+ await fs.move(legacyXiaoMaPath, newXiaoMaPath);
156
+ xiaomaDir = newXiaoMaPath;
157
+ s.stop(`Renamed "${path.basename(legacyXiaoMaPath)}" to "_xiaoma"`);
158
+ }
159
+
160
+ // Handle _cfg folder (either from .xiaoma or standalone)
161
+ const cfgPath = path.join(xiaomaDir, '_cfg');
162
+ if (await fs.pathExists(cfgPath)) {
163
+ s.start('Renaming configuration folder...');
164
+ const newCfgPath = path.join(xiaomaDir, '_config');
165
+ await fs.move(cfgPath, newCfgPath);
166
+ s.stop('Renamed "_cfg" to "_config"');
167
+ }
168
+ } catch (error) {
169
+ s.stop('Failed to update folder structure');
170
+ await prompts.log.error(`Error: ${error.message}`);
171
+ process.exit(1);
172
+ }
173
+ }
174
+
175
+ // Check if there's an existing XiaoMa installation (after any folder renames)
176
+ const hasExistingInstall = await fs.pathExists(xiaomaDir);
177
+
178
+ let customContentConfig = { hasCustomContent: false };
179
+ if (!hasExistingInstall) {
180
+ customContentConfig._shouldAsk = true;
181
+ }
182
+
183
+ // Track action type (only set if there's an existing installation)
184
+ let actionType;
185
+
186
+ // Only show action menu if there's an existing installation
187
+ if (hasExistingInstall) {
188
+ // Get version information
189
+ const { existingInstall, xiaomaDir } = await this.getExistingInstallation(confirmedDirectory);
190
+ const packageJsonPath = path.join(__dirname, '../../../package.json');
191
+ const currentVersion = require(packageJsonPath).version;
192
+ const installedVersion = existingInstall.version || 'unknown';
193
+
194
+ // Check if version is pre beta
195
+ const shouldProceed = await this.showLegacyVersionWarning(installedVersion, currentVersion, path.basename(xiaomaDir), options);
196
+
197
+ // If user chose to cancel, exit the installer
198
+ if (!shouldProceed) {
199
+ process.exit(0);
200
+ return;
201
+ }
202
+
203
+ // Build menu choices dynamically
204
+ const choices = [];
205
+
206
+ // Always show Quick Update first (allows refreshing installation even on same version)
207
+ if (installedVersion !== 'unknown') {
208
+ choices.push({
209
+ name: `Quick Update (v${installedVersion} → v${currentVersion})`,
210
+ value: 'quick-update',
211
+ });
212
+ }
213
+
214
+ // Add custom agent compilation option
215
+ if (installedVersion !== 'unknown') {
216
+ choices.push({
217
+ name: 'Recompile Agents (apply customizations only)',
218
+ value: 'compile-agents',
219
+ });
220
+ }
221
+
222
+ // Common actions
223
+ choices.push({ name: 'Modify XiaoMa Installation', value: 'update' });
224
+
225
+ // Check if action is provided via command-line
226
+ if (options.action) {
227
+ const validActions = choices.map((c) => c.value);
228
+ if (!validActions.includes(options.action)) {
229
+ throw new Error(`Invalid action: ${options.action}. Valid actions: ${validActions.join(', ')}`);
230
+ }
231
+ actionType = options.action;
232
+ await prompts.log.info(`Using action from command-line: ${actionType}`);
233
+ } else if (options.yes) {
234
+ // Default to quick-update if available, otherwise first available choice
235
+ if (choices.length === 0) {
236
+ throw new Error('No valid actions available for this installation');
237
+ }
238
+ const hasQuickUpdate = choices.some((c) => c.value === 'quick-update');
239
+ actionType = hasQuickUpdate ? 'quick-update' : choices[0].value;
240
+ await prompts.log.info(`Non-interactive mode (--yes): defaulting to ${actionType}`);
241
+ } else {
242
+ actionType = await prompts.select({
243
+ message: 'How would you like to proceed?',
244
+ choices: choices,
245
+ default: choices[0].value,
246
+ });
247
+ }
248
+
249
+ // Handle quick update separately
250
+ if (actionType === 'quick-update') {
251
+ // Pass --custom-content through so installer can re-cache if cache is missing
252
+ let customContentForQuickUpdate = { hasCustomContent: false };
253
+ if (options.customContent) {
254
+ const paths = options.customContent
255
+ .split(',')
256
+ .map((p) => p.trim())
257
+ .filter(Boolean);
258
+ if (paths.length > 0) {
259
+ const customPaths = [];
260
+ const selectedModuleIds = [];
261
+ const sources = [];
262
+ for (const customPath of paths) {
263
+ const expandedPath = this.expandUserPath(customPath);
264
+ const validation = this.validateCustomContentPathSync(expandedPath);
265
+ if (validation) continue;
266
+ let moduleMeta;
267
+ try {
268
+ const moduleYamlPath = path.join(expandedPath, 'module.yaml');
269
+ moduleMeta = require('yaml').parse(await fs.readFile(moduleYamlPath, 'utf-8'));
270
+ } catch {
271
+ continue;
272
+ }
273
+ if (!moduleMeta?.code) continue;
274
+ customPaths.push(expandedPath);
275
+ selectedModuleIds.push(moduleMeta.code);
276
+ sources.push({ path: expandedPath, id: moduleMeta.code, name: moduleMeta.name || moduleMeta.code });
277
+ }
278
+ if (customPaths.length > 0) {
279
+ customContentForQuickUpdate = {
280
+ hasCustomContent: true,
281
+ selected: true,
282
+ sources,
283
+ selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
284
+ selectedModuleIds,
285
+ };
286
+ }
287
+ }
288
+ }
289
+ return {
290
+ actionType: 'quick-update',
291
+ directory: confirmedDirectory,
292
+ customContent: customContentForQuickUpdate,
293
+ skipPrompts: options.yes || false,
294
+ };
295
+ }
296
+
297
+ // Handle compile agents separately
298
+ if (actionType === 'compile-agents') {
299
+ // Only recompile agents with customizations, don't update any files
300
+ return {
301
+ actionType: 'compile-agents',
302
+ directory: confirmedDirectory,
303
+ customContent: { hasCustomContent: false },
304
+ skipPrompts: options.yes || false,
305
+ };
306
+ }
307
+
308
+ // If actionType === 'update', handle it with the new flow
309
+ // Return early with modify configuration
310
+ if (actionType === 'update') {
311
+ // Get existing installation info
312
+ const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory);
313
+
314
+ await prompts.log.message(`Found existing modules: ${[...installedModuleIds].join(', ')}`);
315
+
316
+ // Unified module selection - all modules in one grouped multiselect
317
+ let selectedModules;
318
+ if (options.modules) {
319
+ // Use modules from command-line
320
+ selectedModules = options.modules
321
+ .split(',')
322
+ .map((m) => m.trim())
323
+ .filter(Boolean);
324
+ await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`);
325
+ } else if (options.yes) {
326
+ selectedModules = await this.getDefaultModules(installedModuleIds);
327
+ await prompts.log.info(
328
+ `Non-interactive mode (--yes): using default modules (installed + defaults): ${selectedModules.join(', ')}`,
329
+ );
330
+ } else {
331
+ selectedModules = await this.selectAllModules(installedModuleIds);
332
+ }
333
+
334
+ // After module selection, ask about custom modules
335
+ let customModuleResult = { selectedCustomModules: [], customContentConfig: { hasCustomContent: false } };
336
+
337
+ if (options.customContent) {
338
+ // Use custom content from command-line
339
+ const paths = options.customContent
340
+ .split(',')
341
+ .map((p) => p.trim())
342
+ .filter(Boolean);
343
+ await prompts.log.info(`Using custom content from command-line: ${paths.join(', ')}`);
344
+
345
+ // Build custom content config similar to promptCustomContentSource
346
+ const customPaths = [];
347
+ const selectedModuleIds = [];
348
+ const sources = [];
349
+
350
+ for (const customPath of paths) {
351
+ const expandedPath = this.expandUserPath(customPath);
352
+ const validation = this.validateCustomContentPathSync(expandedPath);
353
+ if (validation) {
354
+ await prompts.log.warn(`Skipping invalid custom content path: ${customPath} - ${validation}`);
355
+ continue;
356
+ }
357
+
358
+ // Read module metadata
359
+ let moduleMeta;
360
+ try {
361
+ const moduleYamlPath = path.join(expandedPath, 'module.yaml');
362
+ const moduleYaml = await fs.readFile(moduleYamlPath, 'utf-8');
363
+ const yaml = require('yaml');
364
+ moduleMeta = yaml.parse(moduleYaml);
365
+ } catch (error) {
366
+ await prompts.log.warn(`Skipping custom content path: ${customPath} - failed to read module.yaml: ${error.message}`);
367
+ continue;
368
+ }
369
+
370
+ if (!moduleMeta) {
371
+ await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`);
372
+ continue;
373
+ }
374
+
375
+ if (!moduleMeta.code) {
376
+ await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`);
377
+ continue;
378
+ }
379
+
380
+ customPaths.push(expandedPath);
381
+ selectedModuleIds.push(moduleMeta.code);
382
+ sources.push({
383
+ path: expandedPath,
384
+ id: moduleMeta.code,
385
+ name: moduleMeta.name || moduleMeta.code,
386
+ });
387
+ }
388
+
389
+ if (customPaths.length > 0) {
390
+ customModuleResult = {
391
+ selectedCustomModules: selectedModuleIds,
392
+ customContentConfig: {
393
+ hasCustomContent: true,
394
+ selected: true,
395
+ sources,
396
+ selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
397
+ selectedModuleIds: selectedModuleIds,
398
+ },
399
+ };
400
+ }
401
+ } else if (options.yes) {
402
+ // Non-interactive mode: preserve existing custom modules (matches default: false)
403
+ const cacheDir = path.join(xiaomaDir, '_config', 'custom');
404
+ if (await fs.pathExists(cacheDir)) {
405
+ const entries = await fs.readdir(cacheDir, { withFileTypes: true });
406
+ for (const entry of entries) {
407
+ if (entry.isDirectory()) {
408
+ customModuleResult.selectedCustomModules.push(entry.name);
409
+ }
410
+ }
411
+ await prompts.log.info(
412
+ `Non-interactive mode (--yes): preserving ${customModuleResult.selectedCustomModules.length} existing custom module(s)`,
413
+ );
414
+ } else {
415
+ await prompts.log.info('Non-interactive mode (--yes): no existing custom modules found');
416
+ }
417
+ } else {
418
+ const changeCustomModules = await prompts.confirm({
419
+ message: 'Modify custom modules, agents, or workflows?',
420
+ default: false,
421
+ });
422
+
423
+ if (changeCustomModules) {
424
+ customModuleResult = await this.handleCustomModulesInModifyFlow(confirmedDirectory, selectedModules);
425
+ } else {
426
+ // Preserve existing custom modules if user doesn't want to modify them
427
+ const { Installer } = require('../installers/lib/core/installer');
428
+ const installer = new Installer();
429
+ const { xiaomaDir } = await installer.findXiaomaDir(confirmedDirectory);
430
+
431
+ const cacheDir = path.join(xiaomaDir, '_config', 'custom');
432
+ if (await fs.pathExists(cacheDir)) {
433
+ const entries = await fs.readdir(cacheDir, { withFileTypes: true });
434
+ for (const entry of entries) {
435
+ if (entry.isDirectory()) {
436
+ customModuleResult.selectedCustomModules.push(entry.name);
437
+ }
438
+ }
439
+ }
440
+ }
441
+ }
442
+
443
+ // Merge any selected custom modules
444
+ if (customModuleResult.selectedCustomModules.length > 0) {
445
+ selectedModules.push(...customModuleResult.selectedCustomModules);
446
+ }
447
+
448
+ // Filter out core - it's always installed via installCore flag
449
+ selectedModules = selectedModules.filter((m) => m !== 'core');
450
+
451
+ // Get tool selection
452
+ const toolSelection = await this.promptToolSelection(confirmedDirectory, options);
453
+
454
+ const coreConfig = await this.collectCoreConfig(confirmedDirectory, options);
455
+
456
+ return {
457
+ actionType: 'update',
458
+ directory: confirmedDirectory,
459
+ installCore: true,
460
+ modules: selectedModules,
461
+ ides: toolSelection.ides,
462
+ skipIde: toolSelection.skipIde,
463
+ coreConfig: coreConfig,
464
+ customContent: customModuleResult.customContentConfig,
465
+ skipPrompts: options.yes || false,
466
+ };
467
+ }
468
+ }
469
+
470
+ // This section is only for new installations (update returns early above)
471
+ const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory);
472
+
473
+ // Unified module selection - all modules in one grouped multiselect
474
+ let selectedModules;
475
+ if (options.modules) {
476
+ // Use modules from command-line
477
+ selectedModules = options.modules
478
+ .split(',')
479
+ .map((m) => m.trim())
480
+ .filter(Boolean);
481
+ await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`);
482
+ } else if (options.yes) {
483
+ // Use default modules when --yes flag is set
484
+ selectedModules = await this.getDefaultModules(installedModuleIds);
485
+ await prompts.log.info(`Using default modules (--yes flag): ${selectedModules.join(', ')}`);
486
+ } else {
487
+ selectedModules = await this.selectAllModules(installedModuleIds);
488
+ }
489
+
490
+ // Ask about custom content (local modules/agents/workflows)
491
+ if (options.customContent) {
492
+ // Use custom content from command-line
493
+ const paths = options.customContent
494
+ .split(',')
495
+ .map((p) => p.trim())
496
+ .filter(Boolean);
497
+ await prompts.log.info(`Using custom content from command-line: ${paths.join(', ')}`);
498
+
499
+ // Build custom content config similar to promptCustomContentSource
500
+ const customPaths = [];
501
+ const selectedModuleIds = [];
502
+ const sources = [];
503
+
504
+ for (const customPath of paths) {
505
+ const expandedPath = this.expandUserPath(customPath);
506
+ const validation = this.validateCustomContentPathSync(expandedPath);
507
+ if (validation) {
508
+ await prompts.log.warn(`Skipping invalid custom content path: ${customPath} - ${validation}`);
509
+ continue;
510
+ }
511
+
512
+ // Read module metadata
513
+ let moduleMeta;
514
+ try {
515
+ const moduleYamlPath = path.join(expandedPath, 'module.yaml');
516
+ const moduleYaml = await fs.readFile(moduleYamlPath, 'utf-8');
517
+ const yaml = require('yaml');
518
+ moduleMeta = yaml.parse(moduleYaml);
519
+ } catch (error) {
520
+ await prompts.log.warn(`Skipping custom content path: ${customPath} - failed to read module.yaml: ${error.message}`);
521
+ continue;
522
+ }
523
+
524
+ if (!moduleMeta) {
525
+ await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`);
526
+ continue;
527
+ }
528
+
529
+ if (!moduleMeta.code) {
530
+ await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`);
531
+ continue;
532
+ }
533
+
534
+ customPaths.push(expandedPath);
535
+ selectedModuleIds.push(moduleMeta.code);
536
+ sources.push({
537
+ path: expandedPath,
538
+ id: moduleMeta.code,
539
+ name: moduleMeta.name || moduleMeta.code,
540
+ });
541
+ }
542
+
543
+ if (customPaths.length > 0) {
544
+ customContentConfig = {
545
+ hasCustomContent: true,
546
+ selected: true,
547
+ sources,
548
+ selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
549
+ selectedModuleIds: selectedModuleIds,
550
+ };
551
+ }
552
+ } else if (!options.yes) {
553
+ const wantsCustomContent = await prompts.confirm({
554
+ message: 'Add custom modules, agents, or workflows from your computer?',
555
+ default: false,
556
+ });
557
+
558
+ if (wantsCustomContent) {
559
+ customContentConfig = await this.promptCustomContentSource();
560
+ }
561
+ }
562
+
563
+ // Add custom content modules if any were selected
564
+ if (customContentConfig && customContentConfig.selectedModuleIds) {
565
+ selectedModules.push(...customContentConfig.selectedModuleIds);
566
+ }
567
+
568
+ selectedModules = selectedModules.filter((m) => m !== 'core');
569
+ let toolSelection = await this.promptToolSelection(confirmedDirectory, options);
570
+ const coreConfig = await this.collectCoreConfig(confirmedDirectory, options);
571
+
572
+ return {
573
+ actionType: 'install',
574
+ directory: confirmedDirectory,
575
+ installCore: true,
576
+ modules: selectedModules,
577
+ ides: toolSelection.ides,
578
+ skipIde: toolSelection.skipIde,
579
+ coreConfig: coreConfig,
580
+ customContent: customContentConfig,
581
+ skipPrompts: options.yes || false,
582
+ };
583
+ }
584
+
585
+ /**
586
+ * Prompt for tool/IDE selection (called after module configuration)
587
+ * Uses a split prompt approach:
588
+ * 1. Recommended tools - standard multiselect for preferred tools
589
+ * 2. Additional tools - autocompleteMultiselect with search capability
590
+ * @param {string} projectDir - Project directory to check for existing IDEs
591
+ * @param {Object} options - Command-line options
592
+ * @returns {Object} Tool configuration
593
+ */
594
+ async promptToolSelection(projectDir, options = {}) {
595
+ // Check for existing configured IDEs - use findXiaomaDir to detect custom folder names
596
+ const { Detector } = require('../installers/lib/core/detector');
597
+ const { Installer } = require('../installers/lib/core/installer');
598
+ const detector = new Detector();
599
+ const installer = new Installer();
600
+ const xiaomaResult = await installer.findXiaomaDir(projectDir || process.cwd());
601
+ const xiaomaDir = xiaomaResult.xiaomaDir;
602
+ const existingInstall = await detector.detect(xiaomaDir);
603
+ const configuredIdes = existingInstall.ides || [];
604
+
605
+ // Get IDE manager to fetch available IDEs dynamically
606
+ const { IdeManager } = require('../installers/lib/ide/manager');
607
+ const ideManager = new IdeManager();
608
+ await ideManager.ensureInitialized(); // IMPORTANT: Must initialize before getting IDEs
609
+
610
+ const preferredIdes = ideManager.getPreferredIdes();
611
+ const otherIdes = ideManager.getOtherIdes();
612
+
613
+ // Determine which configured IDEs are in "preferred" vs "other" categories
614
+ const configuredPreferred = configuredIdes.filter((id) => preferredIdes.some((ide) => ide.value === id));
615
+ const configuredOther = configuredIdes.filter((id) => otherIdes.some((ide) => ide.value === id));
616
+
617
+ // Warn about previously configured tools that are no longer available
618
+ const allKnownValues = new Set([...preferredIdes, ...otherIdes].map((ide) => ide.value));
619
+ const unknownTools = configuredIdes.filter((id) => id && typeof id === 'string' && !allKnownValues.has(id));
620
+ if (unknownTools.length > 0) {
621
+ await prompts.log.warn(`Previously configured tools are no longer available: ${unknownTools.join(', ')}`);
622
+ }
623
+
624
+ // ─────────────────────────────────────────────────────────────────────────────
625
+ // UPGRADE PATH: If tools already configured, show all tools with configured at top
626
+ // ─────────────────────────────────────────────────────────────────────────────
627
+ if (configuredIdes.length > 0) {
628
+ const allTools = [...preferredIdes, ...otherIdes];
629
+
630
+ // Non-interactive: handle --tools and --yes flags before interactive prompt
631
+ if (options.tools) {
632
+ if (options.tools.toLowerCase() === 'none') {
633
+ await prompts.log.info('Skipping tool configuration (--tools none)');
634
+ return { ides: [], skipIde: true };
635
+ }
636
+ const selectedIdes = options.tools
637
+ .split(',')
638
+ .map((t) => t.trim())
639
+ .filter(Boolean);
640
+ await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
641
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
642
+ return { ides: selectedIdes, skipIde: false };
643
+ }
644
+
645
+ if (options.yes) {
646
+ await prompts.log.info(`Non-interactive mode (--yes): keeping configured tools: ${configuredIdes.join(', ')}`);
647
+ await this.displaySelectedTools(configuredIdes, preferredIdes, allTools);
648
+ return { ides: configuredIdes, skipIde: false };
649
+ }
650
+
651
+ // Sort: configured tools first, then preferred, then others
652
+ const sortedTools = [
653
+ ...allTools.filter((ide) => configuredIdes.includes(ide.value)),
654
+ ...allTools.filter((ide) => !configuredIdes.includes(ide.value)),
655
+ ];
656
+
657
+ const upgradeOptions = sortedTools.map((ide) => {
658
+ const isConfigured = configuredIdes.includes(ide.value);
659
+ const isPreferred = preferredIdes.some((p) => p.value === ide.value);
660
+ let label = ide.name;
661
+ if (isPreferred) label += ' ⭐';
662
+ if (isConfigured) label += ' ✅';
663
+ return { label, value: ide.value };
664
+ });
665
+
666
+ // Sort initialValues to match display order
667
+ const sortedInitialValues = sortedTools.filter((ide) => configuredIdes.includes(ide.value)).map((ide) => ide.value);
668
+
669
+ const upgradeSelected = await prompts.autocompleteMultiselect({
670
+ message: 'Integrate with',
671
+ options: upgradeOptions,
672
+ initialValues: sortedInitialValues,
673
+ required: false,
674
+ maxItems: 8,
675
+ });
676
+
677
+ const selectedIdes = upgradeSelected || [];
678
+
679
+ if (selectedIdes.length === 0) {
680
+ const confirmNoTools = await prompts.confirm({
681
+ message: 'No tools selected. Continue without installing any tools?',
682
+ default: false,
683
+ });
684
+
685
+ if (!confirmNoTools) {
686
+ return this.promptToolSelection(projectDir, options);
687
+ }
688
+
689
+ return { ides: [], skipIde: true };
690
+ }
691
+
692
+ // Display selected tools
693
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
694
+
695
+ return { ides: selectedIdes, skipIde: false };
696
+ }
697
+
698
+ // ─────────────────────────────────────────────────────────────────────────────
699
+ // NEW INSTALL: Show all tools with search
700
+ // ─────────────────────────────────────────────────────────────────────────────
701
+ const allTools = [...preferredIdes, ...otherIdes];
702
+
703
+ const allToolOptions = allTools.map((ide) => {
704
+ const isPreferred = preferredIdes.some((p) => p.value === ide.value);
705
+ let label = ide.name;
706
+ if (isPreferred) label += ' ⭐';
707
+ return {
708
+ label,
709
+ value: ide.value,
710
+ };
711
+ });
712
+
713
+ let selectedIdes = [];
714
+
715
+ // Check if tools are provided via command-line
716
+ if (options.tools) {
717
+ // Check for explicit "none" value to skip tool installation
718
+ if (options.tools.toLowerCase() === 'none') {
719
+ await prompts.log.info('Skipping tool configuration (--tools none)');
720
+ return { ides: [], skipIde: true };
721
+ } else {
722
+ selectedIdes = options.tools
723
+ .split(',')
724
+ .map((t) => t.trim())
725
+ .filter(Boolean);
726
+ await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
727
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
728
+ return { ides: selectedIdes, skipIde: false };
729
+ }
730
+ } else if (options.yes) {
731
+ // If --yes flag is set, skip tool prompt and use previously configured tools or empty
732
+ if (configuredIdes.length > 0) {
733
+ await prompts.log.info(`Using previously configured tools (--yes flag): ${configuredIdes.join(', ')}`);
734
+ await this.displaySelectedTools(configuredIdes, preferredIdes, allTools);
735
+ return { ides: configuredIdes, skipIde: false };
736
+ } else {
737
+ await prompts.log.info('Skipping tool configuration (--yes flag, no previous tools)');
738
+ return { ides: [], skipIde: true };
739
+ }
740
+ }
741
+
742
+ // Interactive mode
743
+ const interactiveSelectedIdes = await prompts.autocompleteMultiselect({
744
+ message: 'Integrate with:',
745
+ options: allToolOptions,
746
+ initialValues: configuredIdes.length > 0 ? configuredIdes : undefined,
747
+ required: false,
748
+ maxItems: 8,
749
+ });
750
+
751
+ selectedIdes = interactiveSelectedIdes || [];
752
+
753
+ // ─────────────────────────────────────────────────────────────────────────────
754
+ // STEP 3: Confirm if no tools selected
755
+ // ─────────────────────────────────────────────────────────────────────────────
756
+ if (selectedIdes.length === 0) {
757
+ const confirmNoTools = await prompts.confirm({
758
+ message: 'No tools selected. Continue without installing any tools?',
759
+ default: false,
760
+ });
761
+
762
+ if (!confirmNoTools) {
763
+ // User wants to select tools - recurse
764
+ return this.promptToolSelection(projectDir, options);
765
+ }
766
+
767
+ return {
768
+ ides: [],
769
+ skipIde: true,
770
+ };
771
+ }
772
+
773
+ // Display selected tools
774
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
775
+
776
+ return {
777
+ ides: selectedIdes,
778
+ skipIde: selectedIdes.length === 0,
779
+ };
780
+ }
781
+
782
+ /**
783
+ * Prompt for update configuration
784
+ * @returns {Object} Update configuration
785
+ */
786
+ async promptUpdate() {
787
+ const backupFirst = await prompts.confirm({
788
+ message: 'Create backup before updating?',
789
+ default: true,
790
+ });
791
+
792
+ const preserveCustomizations = await prompts.confirm({
793
+ message: 'Preserve local customizations?',
794
+ default: true,
795
+ });
796
+
797
+ return { backupFirst, preserveCustomizations };
798
+ }
799
+
800
+ /**
801
+ * Confirm action
802
+ * @param {string} message - Confirmation message
803
+ * @param {boolean} defaultValue - Default value
804
+ * @returns {boolean} User confirmation
805
+ */
806
+ async confirm(message, defaultValue = false) {
807
+ return await prompts.confirm({
808
+ message,
809
+ default: defaultValue,
810
+ });
811
+ }
812
+
813
+ /**
814
+ * Get confirmed directory from user
815
+ * @returns {string} Confirmed directory path
816
+ */
817
+ async getConfirmedDirectory() {
818
+ let confirmedDirectory = null;
819
+ while (!confirmedDirectory) {
820
+ const directoryAnswer = await this.promptForDirectory();
821
+ await this.displayDirectoryInfo(directoryAnswer.directory);
822
+
823
+ if (await this.confirmDirectory(directoryAnswer.directory)) {
824
+ confirmedDirectory = directoryAnswer.directory;
825
+ }
826
+ }
827
+ return confirmedDirectory;
828
+ }
829
+
830
+ /**
831
+ * Get existing installation info and installed modules
832
+ * @param {string} directory - Installation directory
833
+ * @returns {Object} Object with existingInstall, installedModuleIds, and xiaomaDir
834
+ */
835
+ async getExistingInstallation(directory) {
836
+ const { Detector } = require('../installers/lib/core/detector');
837
+ const { Installer } = require('../installers/lib/core/installer');
838
+ const detector = new Detector();
839
+ const installer = new Installer();
840
+ const xiaomaDirResult = await installer.findXiaomaDir(directory);
841
+ const xiaomaDir = xiaomaDirResult.xiaomaDir;
842
+ const existingInstall = await detector.detect(xiaomaDir);
843
+ const installedModuleIds = new Set(existingInstall.modules.map((mod) => mod.id));
844
+
845
+ return { existingInstall, installedModuleIds, xiaomaDir };
846
+ }
847
+
848
+ /**
849
+ * Collect core configuration
850
+ * @param {string} directory - Installation directory
851
+ * @param {Object} options - Command-line options
852
+ * @returns {Object} Core configuration
853
+ */
854
+ async collectCoreConfig(directory, options = {}) {
855
+ const { ConfigCollector } = require('../installers/lib/core/config-collector');
856
+ const configCollector = new ConfigCollector();
857
+
858
+ // If options are provided, set them directly
859
+ if (options.userName || options.communicationLanguage || options.documentOutputLanguage || options.outputFolder) {
860
+ const coreConfig = {};
861
+ if (options.userName) {
862
+ coreConfig.user_name = options.userName;
863
+ await prompts.log.info(`Using user name from command-line: ${options.userName}`);
864
+ }
865
+ if (options.communicationLanguage) {
866
+ coreConfig.communication_language = options.communicationLanguage;
867
+ await prompts.log.info(`Using communication language from command-line: ${options.communicationLanguage}`);
868
+ }
869
+ if (options.documentOutputLanguage) {
870
+ coreConfig.document_output_language = options.documentOutputLanguage;
871
+ await prompts.log.info(`Using document output language from command-line: ${options.documentOutputLanguage}`);
872
+ }
873
+ if (options.outputFolder) {
874
+ coreConfig.output_folder = options.outputFolder;
875
+ await prompts.log.info(`Using output folder from command-line: ${options.outputFolder}`);
876
+ }
877
+
878
+ // Load existing config to merge with provided options
879
+ await configCollector.loadExistingConfig(directory);
880
+
881
+ // Merge provided options with existing config (or defaults)
882
+ const existingConfig = configCollector.collectedConfig.core || {};
883
+ configCollector.collectedConfig.core = { ...existingConfig, ...coreConfig };
884
+
885
+ // If not all options are provided, collect the missing ones interactively (unless --yes flag)
886
+ if (
887
+ !options.yes &&
888
+ (!options.userName || !options.communicationLanguage || !options.documentOutputLanguage || !options.outputFolder)
889
+ ) {
890
+ await configCollector.collectModuleConfig('core', directory, false, true);
891
+ }
892
+ } else if (options.yes) {
893
+ // Use all defaults when --yes flag is set
894
+ await configCollector.loadExistingConfig(directory);
895
+ const existingConfig = configCollector.collectedConfig.core || {};
896
+
897
+ // If no existing config, use defaults
898
+ if (Object.keys(existingConfig).length === 0) {
899
+ let safeUsername;
900
+ try {
901
+ safeUsername = os.userInfo().username;
902
+ } catch {
903
+ safeUsername = process.env.USER || process.env.USERNAME || 'User';
904
+ }
905
+ const defaultUsername = safeUsername.charAt(0).toUpperCase() + safeUsername.slice(1);
906
+ configCollector.collectedConfig.core = {
907
+ user_name: defaultUsername,
908
+ communication_language: 'English',
909
+ document_output_language: 'English',
910
+ output_folder: '_xiaoma-output',
911
+ };
912
+ await prompts.log.info('Using default configuration (--yes flag)');
913
+ }
914
+ } else {
915
+ // Load existing configs first if they exist
916
+ await configCollector.loadExistingConfig(directory);
917
+ // Now collect with existing values as defaults (false = don't skip loading, true = skip completion message)
918
+ await configCollector.collectModuleConfig('core', directory, false, true);
919
+ }
920
+
921
+ const coreConfig = configCollector.collectedConfig.core;
922
+ // Ensure we always have a core config object, even if empty
923
+ return coreConfig || {};
924
+ }
925
+
926
+ /**
927
+ * Get module choices for selection
928
+ * @param {Set} installedModuleIds - Currently installed module IDs
929
+ * @param {Object} customContentConfig - Custom content configuration
930
+ * @returns {Array} Module choices for prompt
931
+ */
932
+ async getModuleChoices(installedModuleIds, customContentConfig = null) {
933
+ const color = await prompts.getColor();
934
+ const moduleChoices = [];
935
+ const isNewInstallation = installedModuleIds.size === 0;
936
+
937
+ const customContentItems = [];
938
+
939
+ // Add custom content items
940
+ if (customContentConfig && customContentConfig.hasCustomContent && customContentConfig.customPath) {
941
+ // Existing installation - show from directory
942
+ const customHandler = new CustomHandler();
943
+ const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
944
+
945
+ for (const customFile of customFiles) {
946
+ const customInfo = await customHandler.getCustomInfo(customFile);
947
+ if (customInfo) {
948
+ customContentItems.push({
949
+ name: `${color.cyan('\u2713')} ${customInfo.name} ${color.dim(`(${customInfo.relativePath})`)}`,
950
+ value: `__CUSTOM_CONTENT__${customFile}`, // Unique value for each custom content
951
+ checked: true, // Default to selected since user chose to provide custom content
952
+ path: customInfo.path, // Track path to avoid duplicates
953
+ hint: customInfo.description || undefined,
954
+ });
955
+ }
956
+ }
957
+ }
958
+
959
+ // Add official modules
960
+ const { ModuleManager } = require('../installers/lib/modules/manager');
961
+ const moduleManager = new ModuleManager();
962
+ const { modules: availableModules, customModules: customModulesFromCache } = await moduleManager.listAvailable();
963
+
964
+ // First, add all items to appropriate sections
965
+ const allCustomModules = [];
966
+
967
+ // Add custom content items from directory
968
+ allCustomModules.push(...customContentItems);
969
+
970
+ // Add custom modules from cache
971
+ for (const mod of customModulesFromCache) {
972
+ // Skip if this module is already in customContentItems (by path)
973
+ const isDuplicate = allCustomModules.some((item) => item.path && mod.path && path.resolve(item.path) === path.resolve(mod.path));
974
+
975
+ if (!isDuplicate) {
976
+ allCustomModules.push({
977
+ name: `${color.cyan('\u2713')} ${mod.name} ${color.dim('(cached)')}`,
978
+ value: mod.id,
979
+ checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id),
980
+ hint: mod.description || undefined,
981
+ });
982
+ }
983
+ }
984
+
985
+ // Add separators and modules in correct order
986
+ if (allCustomModules.length > 0) {
987
+ // Add separator for custom content, all custom modules, and official content separator
988
+ moduleChoices.push(
989
+ new choiceUtils.Separator('── Custom Content ──'),
990
+ ...allCustomModules,
991
+ new choiceUtils.Separator('── Official Content ──'),
992
+ );
993
+ }
994
+
995
+ // Add official modules (only non-custom ones)
996
+ for (const mod of availableModules) {
997
+ if (!mod.isCustom) {
998
+ moduleChoices.push({
999
+ name: mod.name,
1000
+ value: mod.id,
1001
+ checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id),
1002
+ hint: mod.description || undefined,
1003
+ });
1004
+ }
1005
+ }
1006
+
1007
+ return moduleChoices;
1008
+ }
1009
+
1010
+ /**
1011
+ * Select all modules (official + community) using grouped multiselect.
1012
+ * Core is shown as locked but filtered from the result since it's always installed separately.
1013
+ * @param {Set} installedModuleIds - Currently installed module IDs
1014
+ * @returns {Array} Selected module codes (excluding core)
1015
+ */
1016
+ async selectAllModules(installedModuleIds = new Set()) {
1017
+ const { ModuleManager } = require('../installers/lib/modules/manager');
1018
+ const moduleManager = new ModuleManager();
1019
+ const { modules: localModules } = await moduleManager.listAvailable();
1020
+
1021
+ // Get external modules
1022
+ const externalManager = new ExternalModuleManager();
1023
+ const externalModules = await externalManager.listAvailable();
1024
+
1025
+ // Build flat options list with group hints for autocompleteMultiselect
1026
+ const allOptions = [];
1027
+ const initialValues = [];
1028
+ const lockedValues = ['core'];
1029
+
1030
+ // Core module is always installed — show it locked at the top
1031
+ allOptions.push({ label: 'XiaoMa Core Module', value: 'core', hint: 'Core configuration and shared resources' });
1032
+ initialValues.push('core');
1033
+
1034
+ // Helper to build module entry with proper sorting and selection
1035
+ const buildModuleEntry = (mod, value, group) => {
1036
+ const isInstalled = installedModuleIds.has(value);
1037
+ return {
1038
+ label: mod.name,
1039
+ value,
1040
+ hint: mod.description || group,
1041
+ // Pre-select only if already installed (not on fresh install)
1042
+ selected: isInstalled,
1043
+ };
1044
+ };
1045
+
1046
+ // Local modules (BMM, BMB, etc.)
1047
+ const localEntries = [];
1048
+ for (const mod of localModules) {
1049
+ if (!mod.isCustom && mod.id !== 'core') {
1050
+ const entry = buildModuleEntry(mod, mod.id, 'Local');
1051
+ localEntries.push(entry);
1052
+ if (entry.selected) {
1053
+ initialValues.push(mod.id);
1054
+ }
1055
+ }
1056
+ }
1057
+ allOptions.push(...localEntries.map(({ label, value, hint }) => ({ label, value, hint })));
1058
+
1059
+ // Group 2: XiaoMa Official Modules (type: xiaoma-org)
1060
+ const officialModules = [];
1061
+ for (const mod of externalModules) {
1062
+ if (mod.type === 'xiaoma-org') {
1063
+ const entry = buildModuleEntry(mod, mod.code, 'Official');
1064
+ officialModules.push(entry);
1065
+ if (entry.selected) {
1066
+ initialValues.push(mod.code);
1067
+ }
1068
+ }
1069
+ }
1070
+ allOptions.push(...officialModules.map(({ label, value, hint }) => ({ label, value, hint })));
1071
+
1072
+ // Group 3: Community Modules (type: community)
1073
+ const communityModules = [];
1074
+ for (const mod of externalModules) {
1075
+ if (mod.type === 'community') {
1076
+ const entry = buildModuleEntry(mod, mod.code, 'Community');
1077
+ communityModules.push(entry);
1078
+ if (entry.selected) {
1079
+ initialValues.push(mod.code);
1080
+ }
1081
+ }
1082
+ }
1083
+ allOptions.push(...communityModules.map(({ label, value, hint }) => ({ label, value, hint })));
1084
+
1085
+ const selected = await prompts.autocompleteMultiselect({
1086
+ message: 'Select modules to install:',
1087
+ options: allOptions,
1088
+ initialValues: initialValues.length > 0 ? initialValues : undefined,
1089
+ lockedValues,
1090
+ required: true,
1091
+ maxItems: allOptions.length,
1092
+ });
1093
+
1094
+ const result = selected ? selected.filter((m) => m !== 'core') : [];
1095
+
1096
+ // Display selected modules as bulleted list
1097
+ if (result.length > 0) {
1098
+ const moduleLines = result.map((moduleId) => {
1099
+ const opt = allOptions.find((o) => o.value === moduleId);
1100
+ return ` \u2022 ${opt?.label || moduleId}`;
1101
+ });
1102
+ await prompts.log.message('Selected modules:\n' + moduleLines.join('\n'));
1103
+ }
1104
+
1105
+ return result;
1106
+ }
1107
+
1108
+ /**
1109
+ * Get default modules for non-interactive mode
1110
+ * @param {Set} installedModuleIds - Already installed module IDs
1111
+ * @returns {Array} Default module codes
1112
+ */
1113
+ async getDefaultModules(installedModuleIds = new Set()) {
1114
+ const { ModuleManager } = require('../installers/lib/modules/manager');
1115
+ const moduleManager = new ModuleManager();
1116
+ const { modules: localModules } = await moduleManager.listAvailable();
1117
+
1118
+ const defaultModules = [];
1119
+
1120
+ // Add default-selected local modules (typically BMM)
1121
+ for (const mod of localModules) {
1122
+ if (mod.defaultSelected === true || installedModuleIds.has(mod.id)) {
1123
+ defaultModules.push(mod.id);
1124
+ }
1125
+ }
1126
+
1127
+ // If no defaults found, use 'xmc' as the fallback default
1128
+ if (defaultModules.length === 0) {
1129
+ defaultModules.push('xmc');
1130
+ }
1131
+
1132
+ return defaultModules;
1133
+ }
1134
+
1135
+ /**
1136
+ * Prompt for directory selection
1137
+ * @returns {Object} Directory answer from prompt
1138
+ */
1139
+ async promptForDirectory() {
1140
+ // Use sync validation because @clack/prompts doesn't support async validate
1141
+ const directory = await prompts.text({
1142
+ message: 'Installation directory:',
1143
+ default: process.cwd(),
1144
+ placeholder: process.cwd(),
1145
+ validate: (input) => this.validateDirectorySync(input),
1146
+ });
1147
+
1148
+ // Apply filter logic
1149
+ let filteredDir = directory;
1150
+ if (!filteredDir || filteredDir.trim() === '') {
1151
+ filteredDir = process.cwd();
1152
+ } else {
1153
+ filteredDir = this.expandUserPath(filteredDir);
1154
+ }
1155
+
1156
+ return { directory: filteredDir };
1157
+ }
1158
+
1159
+ /**
1160
+ * Display directory information
1161
+ * @param {string} directory - The directory path
1162
+ */
1163
+ async displayDirectoryInfo(directory) {
1164
+ await prompts.log.info(`Resolved installation path: ${directory}`);
1165
+
1166
+ const dirExists = await fs.pathExists(directory);
1167
+ if (dirExists) {
1168
+ // Show helpful context about the existing path
1169
+ const stats = await fs.stat(directory);
1170
+ if (stats.isDirectory()) {
1171
+ const files = await fs.readdir(directory);
1172
+ if (files.length > 0) {
1173
+ // Check for any xiaoma installation (any folder with _config/manifest.yaml)
1174
+ const { Installer } = require('../installers/lib/core/installer');
1175
+ const installer = new Installer();
1176
+ const xiaomaResult = await installer.findXiaomaDir(directory);
1177
+ const hasXiaoMaInstall =
1178
+ (await fs.pathExists(xiaomaResult.xiaomaDir)) &&
1179
+ (await fs.pathExists(path.join(xiaomaResult.xiaomaDir, '_config', 'manifest.yaml')));
1180
+
1181
+ const xiaomaNote = hasXiaoMaInstall ? ` including existing XiaoMa installation (${path.basename(xiaomaResult.xiaomaDir)})` : '';
1182
+ await prompts.log.message(`Directory exists and contains ${files.length} item(s)${xiaomaNote}`);
1183
+ } else {
1184
+ await prompts.log.message('Directory exists and is empty');
1185
+ }
1186
+ }
1187
+ }
1188
+ }
1189
+
1190
+ /**
1191
+ * Confirm directory selection
1192
+ * @param {string} directory - The directory path
1193
+ * @returns {boolean} Whether user confirmed
1194
+ */
1195
+ async confirmDirectory(directory) {
1196
+ const dirExists = await fs.pathExists(directory);
1197
+
1198
+ if (dirExists) {
1199
+ const proceed = await prompts.confirm({
1200
+ message: 'Install to this directory?',
1201
+ default: true,
1202
+ });
1203
+
1204
+ if (!proceed) {
1205
+ await prompts.log.warn("Let's try again with a different path.");
1206
+ }
1207
+
1208
+ return proceed;
1209
+ } else {
1210
+ // Ask for confirmation to create the directory
1211
+ const create = await prompts.confirm({
1212
+ message: `Create directory: ${directory}?`,
1213
+ default: false,
1214
+ });
1215
+
1216
+ if (!create) {
1217
+ await prompts.log.warn("Let's try again with a different path.");
1218
+ }
1219
+
1220
+ return create;
1221
+ }
1222
+ }
1223
+
1224
+ /**
1225
+ * Validate directory path for installation (sync version for clack prompts)
1226
+ * @param {string} input - User input path
1227
+ * @returns {string|undefined} Error message or undefined if valid
1228
+ */
1229
+ validateDirectorySync(input) {
1230
+ // Allow empty input to use the default
1231
+ if (!input || input.trim() === '') {
1232
+ return; // Empty means use default, undefined = valid for clack
1233
+ }
1234
+
1235
+ let expandedPath;
1236
+ try {
1237
+ expandedPath = this.expandUserPath(input.trim());
1238
+ } catch (error) {
1239
+ return error.message;
1240
+ }
1241
+
1242
+ // Check if the path exists
1243
+ const pathExists = fs.pathExistsSync(expandedPath);
1244
+
1245
+ if (!pathExists) {
1246
+ // Find the first existing parent directory
1247
+ const existingParent = this.findExistingParentSync(expandedPath);
1248
+
1249
+ if (!existingParent) {
1250
+ return 'Cannot create directory: no existing parent directory found';
1251
+ }
1252
+
1253
+ // Check if the existing parent is writable
1254
+ try {
1255
+ fs.accessSync(existingParent, fs.constants.W_OK);
1256
+ // Path doesn't exist but can be created - will prompt for confirmation later
1257
+ return;
1258
+ } catch {
1259
+ // Provide a detailed error message explaining both issues
1260
+ return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`;
1261
+ }
1262
+ }
1263
+
1264
+ // If it exists, validate it's a directory and writable
1265
+ const stat = fs.statSync(expandedPath);
1266
+ if (!stat.isDirectory()) {
1267
+ return `Path exists but is not a directory: ${expandedPath}`;
1268
+ }
1269
+
1270
+ // Check write permissions
1271
+ try {
1272
+ fs.accessSync(expandedPath, fs.constants.W_OK);
1273
+ } catch {
1274
+ return `Directory is not writable: ${expandedPath}`;
1275
+ }
1276
+
1277
+ return;
1278
+ }
1279
+
1280
+ /**
1281
+ * Validate directory path for installation (async version)
1282
+ * @param {string} input - User input path
1283
+ * @returns {string|true} Error message or true if valid
1284
+ */
1285
+ async validateDirectory(input) {
1286
+ // Allow empty input to use the default
1287
+ if (!input || input.trim() === '') {
1288
+ return true; // Empty means use default
1289
+ }
1290
+
1291
+ let expandedPath;
1292
+ try {
1293
+ expandedPath = this.expandUserPath(input.trim());
1294
+ } catch (error) {
1295
+ return error.message;
1296
+ }
1297
+
1298
+ // Check if the path exists
1299
+ const pathExists = await fs.pathExists(expandedPath);
1300
+
1301
+ if (!pathExists) {
1302
+ // Find the first existing parent directory
1303
+ const existingParent = await this.findExistingParent(expandedPath);
1304
+
1305
+ if (!existingParent) {
1306
+ return 'Cannot create directory: no existing parent directory found';
1307
+ }
1308
+
1309
+ // Check if the existing parent is writable
1310
+ try {
1311
+ await fs.access(existingParent, fs.constants.W_OK);
1312
+ // Path doesn't exist but can be created - will prompt for confirmation later
1313
+ return true;
1314
+ } catch {
1315
+ // Provide a detailed error message explaining both issues
1316
+ return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`;
1317
+ }
1318
+ }
1319
+
1320
+ // If it exists, validate it's a directory and writable
1321
+ const stat = await fs.stat(expandedPath);
1322
+ if (!stat.isDirectory()) {
1323
+ return `Path exists but is not a directory: ${expandedPath}`;
1324
+ }
1325
+
1326
+ // Check write permissions
1327
+ try {
1328
+ await fs.access(expandedPath, fs.constants.W_OK);
1329
+ } catch {
1330
+ return `Directory is not writable: ${expandedPath}`;
1331
+ }
1332
+
1333
+ return true;
1334
+ }
1335
+
1336
+ /**
1337
+ * Find the first existing parent directory (sync version)
1338
+ * @param {string} targetPath - The path to check
1339
+ * @returns {string|null} The first existing parent directory, or null if none found
1340
+ */
1341
+ findExistingParentSync(targetPath) {
1342
+ let currentPath = path.resolve(targetPath);
1343
+
1344
+ // Walk up the directory tree until we find an existing directory
1345
+ while (currentPath !== path.dirname(currentPath)) {
1346
+ // Stop at root
1347
+ const parent = path.dirname(currentPath);
1348
+ if (fs.pathExistsSync(parent)) {
1349
+ return parent;
1350
+ }
1351
+ currentPath = parent;
1352
+ }
1353
+
1354
+ return null; // No existing parent found (shouldn't happen in practice)
1355
+ }
1356
+
1357
+ /**
1358
+ * Find the first existing parent directory (async version)
1359
+ * @param {string} targetPath - The path to check
1360
+ * @returns {string|null} The first existing parent directory, or null if none found
1361
+ */
1362
+ async findExistingParent(targetPath) {
1363
+ let currentPath = path.resolve(targetPath);
1364
+
1365
+ // Walk up the directory tree until we find an existing directory
1366
+ while (currentPath !== path.dirname(currentPath)) {
1367
+ // Stop at root
1368
+ const parent = path.dirname(currentPath);
1369
+ if (await fs.pathExists(parent)) {
1370
+ return parent;
1371
+ }
1372
+ currentPath = parent;
1373
+ }
1374
+
1375
+ return null; // No existing parent found (shouldn't happen in practice)
1376
+ }
1377
+
1378
+ /**
1379
+ * Expands the user-provided path: handles ~ and resolves to absolute.
1380
+ * @param {string} inputPath - User input path.
1381
+ * @returns {string} Absolute expanded path.
1382
+ */
1383
+ expandUserPath(inputPath) {
1384
+ if (typeof inputPath !== 'string') {
1385
+ throw new TypeError('Path must be a string.');
1386
+ }
1387
+
1388
+ let expanded = inputPath.trim();
1389
+
1390
+ // Handle tilde expansion
1391
+ if (expanded.startsWith('~')) {
1392
+ if (expanded === '~') {
1393
+ expanded = os.homedir();
1394
+ } else if (expanded.startsWith('~' + path.sep)) {
1395
+ const pathAfterHome = expanded.slice(2); // Remove ~/ or ~\
1396
+ expanded = path.join(os.homedir(), pathAfterHome);
1397
+ } else {
1398
+ const restOfPath = expanded.slice(1);
1399
+ const separatorIndex = restOfPath.indexOf(path.sep);
1400
+ const username = separatorIndex === -1 ? restOfPath : restOfPath.slice(0, separatorIndex);
1401
+ if (username) {
1402
+ throw new Error(`Path expansion for ~${username} is not supported. Please use an absolute path or ~${path.sep}`);
1403
+ }
1404
+ }
1405
+ }
1406
+
1407
+ // Resolve to the absolute path relative to the current working directory
1408
+ return path.resolve(expanded);
1409
+ }
1410
+
1411
+ /**
1412
+ * Load existing configurations to use as defaults
1413
+ * @param {string} directory - Installation directory
1414
+ * @returns {Object} Existing configurations
1415
+ */
1416
+ async loadExistingConfigurations(directory) {
1417
+ const configs = {
1418
+ hasCustomContent: false,
1419
+ coreConfig: {},
1420
+ ideConfig: { ides: [], skipIde: false },
1421
+ };
1422
+
1423
+ try {
1424
+ // Load core config
1425
+ configs.coreConfig = await this.collectCoreConfig(directory);
1426
+
1427
+ // Load IDE configuration
1428
+ const configuredIdes = await this.getConfiguredIdes(directory);
1429
+ if (configuredIdes.length > 0) {
1430
+ configs.ideConfig.ides = configuredIdes;
1431
+ configs.ideConfig.skipIde = false;
1432
+ }
1433
+
1434
+ return configs;
1435
+ } catch {
1436
+ // If loading fails, return empty configs
1437
+ await prompts.log.warn('Could not load existing configurations');
1438
+ return configs;
1439
+ }
1440
+ }
1441
+
1442
+ /**
1443
+ * Get configured IDEs from existing installation
1444
+ * @param {string} directory - Installation directory
1445
+ * @returns {Array} List of configured IDEs
1446
+ */
1447
+ async getConfiguredIdes(directory) {
1448
+ const { Detector } = require('../installers/lib/core/detector');
1449
+ const { Installer } = require('../installers/lib/core/installer');
1450
+ const detector = new Detector();
1451
+ const installer = new Installer();
1452
+ const xiaomaResult = await installer.findXiaomaDir(directory);
1453
+ const existingInstall = await detector.detect(xiaomaResult.xiaomaDir);
1454
+ return existingInstall.ides || [];
1455
+ }
1456
+
1457
+ /**
1458
+ * Validate custom content path synchronously
1459
+ * @param {string} input - User input path
1460
+ * @returns {string|undefined} Error message or undefined if valid
1461
+ */
1462
+ validateCustomContentPathSync(input) {
1463
+ // Allow empty input to cancel
1464
+ if (!input || input.trim() === '') {
1465
+ return; // Allow empty to exit
1466
+ }
1467
+
1468
+ try {
1469
+ // Expand the path
1470
+ const expandedPath = this.expandUserPath(input.trim());
1471
+
1472
+ // Check if path exists
1473
+ if (!fs.pathExistsSync(expandedPath)) {
1474
+ return 'Path does not exist';
1475
+ }
1476
+
1477
+ // Check if it's a directory
1478
+ const stat = fs.statSync(expandedPath);
1479
+ if (!stat.isDirectory()) {
1480
+ return 'Path must be a directory';
1481
+ }
1482
+
1483
+ // Check for module.yaml in the root
1484
+ const moduleYamlPath = path.join(expandedPath, 'module.yaml');
1485
+ if (!fs.pathExistsSync(moduleYamlPath)) {
1486
+ return 'Directory must contain a module.yaml file in the root';
1487
+ }
1488
+
1489
+ // Try to parse the module.yaml to get the module ID
1490
+ try {
1491
+ const yaml = require('yaml');
1492
+ const content = fs.readFileSync(moduleYamlPath, 'utf8');
1493
+ const moduleData = yaml.parse(content);
1494
+ if (!moduleData.code) {
1495
+ return 'module.yaml must contain a "code" field for the module ID';
1496
+ }
1497
+ } catch (error) {
1498
+ return 'Invalid module.yaml file: ' + error.message;
1499
+ }
1500
+
1501
+ return; // Valid
1502
+ } catch (error) {
1503
+ return 'Error validating path: ' + error.message;
1504
+ }
1505
+ }
1506
+
1507
+ /**
1508
+ * Prompt user for custom content source location
1509
+ * @returns {Object} Custom content configuration
1510
+ */
1511
+ async promptCustomContentSource() {
1512
+ const customContentConfig = { hasCustomContent: true, sources: [] };
1513
+
1514
+ // Keep asking for more sources until user is done
1515
+ while (true) {
1516
+ // First ask if user wants to add another module or continue
1517
+ if (customContentConfig.sources.length > 0) {
1518
+ const action = await prompts.select({
1519
+ message: 'Would you like to:',
1520
+ choices: [
1521
+ { name: 'Add another custom module', value: 'add' },
1522
+ { name: 'Continue with installation', value: 'continue' },
1523
+ ],
1524
+ default: 'continue',
1525
+ });
1526
+
1527
+ if (action === 'continue') {
1528
+ break;
1529
+ }
1530
+ }
1531
+
1532
+ let sourcePath;
1533
+ let isValid = false;
1534
+
1535
+ while (!isValid) {
1536
+ // Use sync validation because @clack/prompts doesn't support async validate
1537
+ const inputPath = await prompts.text({
1538
+ message: 'Path to custom module folder (press Enter to skip):',
1539
+ validate: (input) => this.validateCustomContentPathSync(input),
1540
+ });
1541
+
1542
+ // If user pressed Enter without typing anything, exit the loop
1543
+ if (!inputPath || inputPath.trim() === '') {
1544
+ // If we have no modules yet, return false for no custom content
1545
+ if (customContentConfig.sources.length === 0) {
1546
+ return { hasCustomContent: false };
1547
+ }
1548
+ return customContentConfig;
1549
+ }
1550
+
1551
+ sourcePath = this.expandUserPath(inputPath);
1552
+ isValid = true;
1553
+ }
1554
+
1555
+ // Read module.yaml to get module info
1556
+ const yaml = require('yaml');
1557
+ const moduleYamlPath = path.join(sourcePath, 'module.yaml');
1558
+ const moduleContent = await fs.readFile(moduleYamlPath, 'utf8');
1559
+ const moduleData = yaml.parse(moduleContent);
1560
+
1561
+ // Add to sources
1562
+ customContentConfig.sources.push({
1563
+ path: sourcePath,
1564
+ id: moduleData.code,
1565
+ name: moduleData.name || moduleData.code,
1566
+ });
1567
+
1568
+ await prompts.log.success(`Confirmed local custom module: ${moduleData.name || moduleData.code}`);
1569
+ }
1570
+
1571
+ // Ask if user wants to add these to the installation
1572
+ const shouldInstall = await prompts.confirm({
1573
+ message: `Install these ${customContentConfig.sources.length} custom modules?`,
1574
+ default: true,
1575
+ });
1576
+
1577
+ if (shouldInstall) {
1578
+ customContentConfig.selected = true;
1579
+ // Store paths to module.yaml files, not directories
1580
+ customContentConfig.selectedFiles = customContentConfig.sources.map((s) => path.join(s.path, 'module.yaml'));
1581
+ // Also include module IDs for installation
1582
+ customContentConfig.selectedModuleIds = customContentConfig.sources.map((s) => s.id);
1583
+ }
1584
+
1585
+ return customContentConfig;
1586
+ }
1587
+
1588
+ /**
1589
+ * Handle custom modules in the modify flow
1590
+ * @param {string} directory - Installation directory
1591
+ * @param {Array} selectedModules - Currently selected modules
1592
+ * @returns {Object} Result with selected custom modules and custom content config
1593
+ */
1594
+ async handleCustomModulesInModifyFlow(directory, selectedModules) {
1595
+ // Get existing installation to find custom modules
1596
+ const { existingInstall } = await this.getExistingInstallation(directory);
1597
+
1598
+ // Check if there are any custom modules in cache
1599
+ const { Installer } = require('../installers/lib/core/installer');
1600
+ const installer = new Installer();
1601
+ const { xiaomaDir } = await installer.findXiaomaDir(directory);
1602
+
1603
+ const cacheDir = path.join(xiaomaDir, '_config', 'custom');
1604
+ const cachedCustomModules = [];
1605
+
1606
+ if (await fs.pathExists(cacheDir)) {
1607
+ const entries = await fs.readdir(cacheDir, { withFileTypes: true });
1608
+ for (const entry of entries) {
1609
+ if (entry.isDirectory()) {
1610
+ const moduleYamlPath = path.join(cacheDir, entry.name, 'module.yaml');
1611
+ if (await fs.pathExists(moduleYamlPath)) {
1612
+ const yaml = require('yaml');
1613
+ const content = await fs.readFile(moduleYamlPath, 'utf8');
1614
+ const moduleData = yaml.parse(content);
1615
+
1616
+ cachedCustomModules.push({
1617
+ id: entry.name,
1618
+ name: moduleData.name || entry.name,
1619
+ description: moduleData.description || 'Custom module from cache',
1620
+ checked: selectedModules.includes(entry.name),
1621
+ fromCache: true,
1622
+ });
1623
+ }
1624
+ }
1625
+ }
1626
+ }
1627
+
1628
+ const result = {
1629
+ selectedCustomModules: [],
1630
+ customContentConfig: { hasCustomContent: false },
1631
+ };
1632
+
1633
+ // Ask user about custom modules
1634
+ await prompts.log.info('Custom Modules');
1635
+ if (cachedCustomModules.length > 0) {
1636
+ await prompts.log.message('Found custom modules in your installation:');
1637
+ } else {
1638
+ await prompts.log.message('No custom modules currently installed.');
1639
+ }
1640
+
1641
+ // Build choices dynamically based on whether we have existing modules
1642
+ const choices = [];
1643
+ if (cachedCustomModules.length > 0) {
1644
+ choices.push(
1645
+ { name: 'Keep all existing custom modules', value: 'keep' },
1646
+ { name: 'Select which custom modules to keep', value: 'select' },
1647
+ { name: 'Add new custom modules', value: 'add' },
1648
+ { name: 'Remove all custom modules', value: 'remove' },
1649
+ );
1650
+ } else {
1651
+ choices.push({ name: 'Add new custom modules', value: 'add' }, { name: 'Cancel (no custom modules)', value: 'cancel' });
1652
+ }
1653
+
1654
+ const customAction = await prompts.select({
1655
+ message: cachedCustomModules.length > 0 ? 'Manage custom modules?' : 'Add custom modules?',
1656
+ choices: choices,
1657
+ default: cachedCustomModules.length > 0 ? 'keep' : 'add',
1658
+ });
1659
+
1660
+ switch (customAction) {
1661
+ case 'keep': {
1662
+ // Keep all existing custom modules
1663
+ result.selectedCustomModules = cachedCustomModules.map((m) => m.id);
1664
+ await prompts.log.message(`Keeping ${result.selectedCustomModules.length} custom module(s)`);
1665
+ break;
1666
+ }
1667
+
1668
+ case 'select': {
1669
+ // Let user choose which to keep
1670
+ const selectChoices = cachedCustomModules.map((m) => ({
1671
+ name: `${m.name} (${m.id})`,
1672
+ value: m.id,
1673
+ checked: m.checked,
1674
+ }));
1675
+
1676
+ // Add "None / I changed my mind" option at the end
1677
+ const choicesWithSkip = [
1678
+ ...selectChoices,
1679
+ {
1680
+ name: '⚠ None / I changed my mind - keep no custom modules',
1681
+ value: '__NONE__',
1682
+ checked: false,
1683
+ },
1684
+ ];
1685
+
1686
+ const keepModules = await prompts.multiselect({
1687
+ message: 'Select custom modules to keep (use arrow keys, space to toggle):',
1688
+ choices: choicesWithSkip,
1689
+ required: true,
1690
+ });
1691
+
1692
+ // If user selected both "__NONE__" and other modules, honor the "None" choice
1693
+ if (keepModules && keepModules.includes('__NONE__') && keepModules.length > 1) {
1694
+ await prompts.log.warn('"None / I changed my mind" was selected, so no custom modules will be kept.');
1695
+ result.selectedCustomModules = [];
1696
+ } else {
1697
+ // Filter out the special '__NONE__' value
1698
+ result.selectedCustomModules = keepModules ? keepModules.filter((m) => m !== '__NONE__') : [];
1699
+ }
1700
+ break;
1701
+ }
1702
+
1703
+ case 'add': {
1704
+ // By default, keep existing modules when adding new ones
1705
+ // User chose "Add new" not "Replace", so we assume they want to keep existing
1706
+ result.selectedCustomModules = cachedCustomModules.map((m) => m.id);
1707
+
1708
+ // Then prompt for new ones (reuse existing method)
1709
+ const newCustomContent = await this.promptCustomContentSource();
1710
+ if (newCustomContent.hasCustomContent && newCustomContent.selected) {
1711
+ result.selectedCustomModules.push(...newCustomContent.selectedModuleIds);
1712
+ result.customContentConfig = newCustomContent;
1713
+ }
1714
+ break;
1715
+ }
1716
+
1717
+ case 'remove': {
1718
+ // Remove all custom modules
1719
+ await prompts.log.warn('All custom modules will be removed from the installation');
1720
+ break;
1721
+ }
1722
+
1723
+ case 'cancel': {
1724
+ // User cancelled - no custom modules
1725
+ await prompts.log.message('No custom modules will be added');
1726
+ break;
1727
+ }
1728
+ }
1729
+
1730
+ return result;
1731
+ }
1732
+
1733
+ /**
1734
+ * Check if installed version is a legacy version that needs fresh install
1735
+ * @param {string} installedVersion - The installed version
1736
+ * @returns {boolean} True if legacy (v4 or any alpha)
1737
+ */
1738
+ isLegacyVersion(installedVersion) {
1739
+ if (!installedVersion || installedVersion === 'unknown') {
1740
+ return true; // Treat unknown as legacy for safety
1741
+ }
1742
+ // Check if version string contains -alpha or -Alpha (any v6 alpha)
1743
+ return /-alpha\./i.test(installedVersion);
1744
+ }
1745
+
1746
+ /**
1747
+ * Show warning for legacy version (v4 or alpha) and ask if user wants to proceed
1748
+ * @param {string} installedVersion - The installed version
1749
+ * @param {string} currentVersion - The current version
1750
+ * @param {string} xiaomaFolderName - Name of the XiaoMa folder
1751
+ * @returns {Promise<boolean>} True if user wants to proceed, false if they cancel
1752
+ */
1753
+ async showLegacyVersionWarning(installedVersion, currentVersion, xiaomaFolderName, options = {}) {
1754
+ if (!this.isLegacyVersion(installedVersion)) {
1755
+ return true; // Not legacy, proceed
1756
+ }
1757
+
1758
+ let warningContent;
1759
+ if (installedVersion === 'unknown') {
1760
+ warningContent = 'Unable to detect your installed XiaoMa version.\n' + 'This appears to be a legacy or unsupported installation.';
1761
+ } else {
1762
+ warningContent =
1763
+ `You are updating from ${installedVersion} to ${currentVersion}.\n` + 'You have a legacy version installed (v4 or alpha).';
1764
+ }
1765
+
1766
+ warningContent +=
1767
+ '\n\nFor the best experience, we recommend:\n' +
1768
+ ' 1. Delete your current XiaoMa installation folder\n' +
1769
+ ` (the "${xiaomaFolderName}/" folder in your project)\n` +
1770
+ ' 2. Run a fresh installation\n\n' +
1771
+ 'Benefits of a fresh install:\n' +
1772
+ ' \u2022 Cleaner configuration without legacy artifacts\n' +
1773
+ ' \u2022 All new features properly configured\n' +
1774
+ ' \u2022 Fewer potential conflicts';
1775
+
1776
+ await prompts.log.warn('VERSION WARNING');
1777
+ await prompts.note(warningContent, 'Version Warning');
1778
+
1779
+ if (options.yes) {
1780
+ await prompts.log.warn('Non-interactive mode (--yes): auto-proceeding with legacy update');
1781
+ return true;
1782
+ }
1783
+
1784
+ const proceed = await prompts.select({
1785
+ message: 'How would you like to proceed?',
1786
+ choices: [
1787
+ {
1788
+ name: 'Proceed with update anyway (may have issues)',
1789
+ value: 'proceed',
1790
+ },
1791
+ {
1792
+ name: 'Cancel (recommended - do a fresh install instead)',
1793
+ value: 'cancel',
1794
+ },
1795
+ ],
1796
+ default: 'cancel',
1797
+ });
1798
+
1799
+ if (proceed === 'cancel') {
1800
+ await prompts.note(
1801
+ `1. Delete the "${xiaomaFolderName}/" folder in your project\n` + "2. Run 'xiaoma install' again",
1802
+ 'To do a fresh install',
1803
+ );
1804
+ }
1805
+
1806
+ return proceed === 'proceed';
1807
+ }
1808
+
1809
+ /**
1810
+ * Display module versions with update availability
1811
+ * @param {Array} modules - Array of module info objects with version info
1812
+ * @param {Array} availableUpdates - Array of available updates
1813
+ */
1814
+ async displayModuleVersions(modules, availableUpdates = []) {
1815
+ // Group modules by source
1816
+ const builtIn = modules.filter((m) => m.source === 'built-in');
1817
+ const external = modules.filter((m) => m.source === 'external');
1818
+ const custom = modules.filter((m) => m.source === 'custom');
1819
+ const unknown = modules.filter((m) => m.source === 'unknown');
1820
+
1821
+ const lines = [];
1822
+ const formatGroup = (group, title) => {
1823
+ if (group.length === 0) return;
1824
+ lines.push(title);
1825
+ for (const mod of group) {
1826
+ const updateInfo = availableUpdates.find((u) => u.name === mod.name);
1827
+ const versionDisplay = mod.version || 'unknown';
1828
+ if (updateInfo) {
1829
+ lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2192 ${updateInfo.latestVersion} \u2191`);
1830
+ } else {
1831
+ lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2713`);
1832
+ }
1833
+ }
1834
+ };
1835
+
1836
+ formatGroup(builtIn, 'Built-in Modules');
1837
+ formatGroup(external, 'External Modules (Official)');
1838
+ formatGroup(custom, 'Custom Modules');
1839
+ formatGroup(unknown, 'Other Modules');
1840
+
1841
+ await prompts.note(lines.join('\n'), 'Module Versions');
1842
+ }
1843
+
1844
+ /**
1845
+ * Prompt user to select which modules to update
1846
+ * @param {Array} availableUpdates - Array of available updates
1847
+ * @returns {Array} Selected module names to update
1848
+ */
1849
+ async promptUpdateSelection(availableUpdates) {
1850
+ if (availableUpdates.length === 0) {
1851
+ return [];
1852
+ }
1853
+
1854
+ await prompts.log.info('Available Updates');
1855
+
1856
+ const choices = availableUpdates.map((update) => ({
1857
+ name: `${update.name} (v${update.installedVersion} \u2192 v${update.latestVersion})`,
1858
+ value: update.name,
1859
+ checked: true, // Default to selecting all updates
1860
+ }));
1861
+
1862
+ // Add "Update All" and "Cancel" options
1863
+ const action = await prompts.select({
1864
+ message: 'How would you like to proceed?',
1865
+ choices: [
1866
+ { name: 'Update all available modules', value: 'all' },
1867
+ { name: 'Select specific modules to update', value: 'select' },
1868
+ { name: 'Skip updates for now', value: 'skip' },
1869
+ ],
1870
+ default: 'all',
1871
+ });
1872
+
1873
+ if (action === 'all') {
1874
+ return availableUpdates.map((u) => u.name);
1875
+ }
1876
+
1877
+ if (action === 'skip') {
1878
+ return [];
1879
+ }
1880
+
1881
+ // Allow specific selection
1882
+ const selected = await prompts.multiselect({
1883
+ message: 'Select modules to update (use arrow keys, space to toggle):',
1884
+ choices: choices,
1885
+ required: true,
1886
+ });
1887
+
1888
+ return selected || [];
1889
+ }
1890
+
1891
+ /**
1892
+ * Display status of all installed modules
1893
+ * @param {Object} statusData - Status data with modules, installation info, and available updates
1894
+ */
1895
+ async displayStatus(statusData) {
1896
+ const { installation, modules, availableUpdates, xiaomaDir } = statusData;
1897
+
1898
+ // Installation info
1899
+ const infoLines = [
1900
+ `Version: ${installation.version || 'unknown'}`,
1901
+ `Location: ${xiaomaDir}`,
1902
+ `Installed: ${new Date(installation.installDate).toLocaleDateString()}`,
1903
+ `Last Updated: ${installation.lastUpdated ? new Date(installation.lastUpdated).toLocaleDateString() : 'unknown'}`,
1904
+ ];
1905
+
1906
+ await prompts.note(infoLines.join('\n'), 'XiaoMa Status');
1907
+
1908
+ // Module versions
1909
+ await this.displayModuleVersions(modules, availableUpdates);
1910
+
1911
+ // Update summary
1912
+ if (availableUpdates.length > 0) {
1913
+ await prompts.log.warn(`${availableUpdates.length} update(s) available`);
1914
+ await prompts.log.message('Run \'xiaoma install\' and select "Quick Update" to update');
1915
+ } else {
1916
+ await prompts.log.success('All modules are up to date');
1917
+ }
1918
+ }
1919
+
1920
+ /**
1921
+ * Display list of selected tools after IDE selection
1922
+ * @param {Array} selectedIdes - Array of selected IDE values
1923
+ * @param {Array} preferredIdes - Array of preferred IDE objects
1924
+ * @param {Array} allTools - Array of all tool objects
1925
+ */
1926
+ async displaySelectedTools(selectedIdes, preferredIdes, allTools) {
1927
+ if (selectedIdes.length === 0) return;
1928
+
1929
+ const preferredValues = new Set(preferredIdes.map((ide) => ide.value));
1930
+ const toolLines = selectedIdes.map((ideValue) => {
1931
+ const tool = allTools.find((t) => t.value === ideValue);
1932
+ const name = tool?.name || ideValue;
1933
+ const marker = preferredValues.has(ideValue) ? ' \u2B50' : '';
1934
+ return ` \u2022 ${name}${marker}`;
1935
+ });
1936
+ await prompts.log.message('Selected tools:\n' + toolLines.join('\n'));
1937
+ }
1938
+ }
1939
+
1940
+ module.exports = { UI };