@zeyue0329/xiaoma-cli 1.0.7 → 1.0.10

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 (321) hide show
  1. package/.github/FORK_GUIDE.md +106 -0
  2. package/.github/FUNDING.yaml +15 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
  5. package/.github/workflows/discord.yaml +26 -0
  6. package/.github/workflows/format-check.yaml +44 -0
  7. package/.github/workflows/manual-release.yaml +174 -0
  8. package/.github/workflows/pr-validation.yaml +55 -0
  9. package/.husky/pre-commit +3 -0
  10. package/.vscode/settings.json +26 -1
  11. package/CHANGELOG.md +686 -0
  12. package/CONTRIBUTING.md +250 -0
  13. package/LICENSE +6 -1
  14. package/common/tasks/create-doc.md +2 -0
  15. package/common/tasks/execute-checklist.md +2 -7
  16. package/common/utils/bmad-doc-template.md +7 -5
  17. package/common/utils/workflow-management.md +2 -0
  18. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +2103 -0
  19. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +1627 -0
  20. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +822 -0
  21. package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +8486 -0
  22. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.txt +3210 -0
  23. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +3244 -0
  24. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.txt +317 -0
  25. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +982 -0
  26. package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +12854 -0
  27. package/dist/expansion-packs/bmad-creative-writing/agents/beta-reader.txt +921 -0
  28. package/dist/expansion-packs/bmad-creative-writing/agents/book-critic.txt +81 -0
  29. package/dist/expansion-packs/bmad-creative-writing/agents/character-psychologist.txt +886 -0
  30. package/dist/expansion-packs/bmad-creative-writing/agents/cover-designer.txt +85 -0
  31. package/dist/expansion-packs/bmad-creative-writing/agents/dialog-specialist.txt +903 -0
  32. package/dist/expansion-packs/bmad-creative-writing/agents/editor.txt +837 -0
  33. package/dist/expansion-packs/bmad-creative-writing/agents/genre-specialist.txt +989 -0
  34. package/dist/expansion-packs/bmad-creative-writing/agents/narrative-designer.txt +888 -0
  35. package/dist/expansion-packs/bmad-creative-writing/agents/plot-architect.txt +1173 -0
  36. package/dist/expansion-packs/bmad-creative-writing/agents/world-builder.txt +914 -0
  37. package/dist/expansion-packs/bmad-creative-writing/teams/agent-team.txt +6071 -0
  38. package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +2079 -0
  39. package/docs/GUIDING-PRINCIPLES.md +91 -0
  40. package/docs/core-architecture.md +219 -0
  41. package/docs/enhanced-ide-development-workflow.md +248 -0
  42. package/docs/expansion-packs.md +200 -0
  43. package/docs/how-to-contribute-with-pull-requests.md +158 -0
  44. package/docs/user-guide.md +530 -0
  45. package/docs/versioning-and-releases.md +155 -0
  46. package/docs/versions.md +48 -0
  47. package/docs/working-in-the-brownfield.md +597 -0
  48. package/eslint.config.mjs +119 -0
  49. package/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/phaser-2d-nodejs-game-team.yaml +14 -0
  50. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.md +73 -0
  51. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +80 -0
  52. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +66 -0
  53. package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-design-checklist.md +203 -0
  54. package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-story-dod-checklist.md +162 -0
  55. package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +9 -0
  56. package/expansion-packs/bmad-2d-phaser-game-dev/data/bmad-kb.md +252 -0
  57. package/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +649 -0
  58. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/advanced-elicitation.md +112 -0
  59. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/create-game-story.md +218 -0
  60. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/game-design-brainstorming.md +292 -0
  61. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +614 -0
  62. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +357 -0
  63. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +344 -0
  64. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +254 -0
  65. package/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +485 -0
  66. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +184 -0
  67. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +176 -0
  68. package/expansion-packs/bmad-2d-unity-game-dev/agent-teams/unity-2d-game-team.yaml +15 -0
  69. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.md +82 -0
  70. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.md +79 -0
  71. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +80 -0
  72. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.md +67 -0
  73. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-architect-checklist.md +393 -0
  74. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-change-checklist.md +205 -0
  75. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-design-checklist.md +203 -0
  76. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-story-dod-checklist.md +126 -0
  77. package/expansion-packs/bmad-2d-unity-game-dev/config.yaml +7 -0
  78. package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +771 -0
  79. package/expansion-packs/bmad-2d-unity-game-dev/data/development-guidelines.md +588 -0
  80. package/expansion-packs/bmad-2d-unity-game-dev/tasks/advanced-elicitation.md +112 -0
  81. package/expansion-packs/bmad-2d-unity-game-dev/tasks/correct-course-game.md +143 -0
  82. package/expansion-packs/bmad-2d-unity-game-dev/tasks/create-game-story.md +186 -0
  83. package/expansion-packs/bmad-2d-unity-game-dev/tasks/game-design-brainstorming.md +292 -0
  84. package/expansion-packs/bmad-2d-unity-game-dev/tasks/validate-game-story.md +202 -0
  85. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-architecture-tmpl.yaml +1031 -0
  86. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +357 -0
  87. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +706 -0
  88. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +257 -0
  89. package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +485 -0
  90. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +184 -0
  91. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +176 -0
  92. package/expansion-packs/bmad-creative-writing/README.md +146 -0
  93. package/expansion-packs/bmad-creative-writing/agent-teams/agent-team.yaml +20 -0
  94. package/expansion-packs/bmad-creative-writing/agents/beta-reader.md +94 -0
  95. package/expansion-packs/bmad-creative-writing/agents/book-critic.md +40 -0
  96. package/expansion-packs/bmad-creative-writing/agents/character-psychologist.md +93 -0
  97. package/expansion-packs/bmad-creative-writing/agents/cover-designer.md +46 -0
  98. package/expansion-packs/bmad-creative-writing/agents/dialog-specialist.md +92 -0
  99. package/expansion-packs/bmad-creative-writing/agents/editor.md +93 -0
  100. package/expansion-packs/bmad-creative-writing/agents/genre-specialist.md +95 -0
  101. package/expansion-packs/bmad-creative-writing/agents/narrative-designer.md +93 -0
  102. package/expansion-packs/bmad-creative-writing/agents/plot-architect.md +95 -0
  103. package/expansion-packs/bmad-creative-writing/agents/world-builder.md +94 -0
  104. package/expansion-packs/bmad-creative-writing/checklists/beta-feedback-closure-checklist.md +23 -0
  105. package/expansion-packs/bmad-creative-writing/checklists/character-consistency-checklist.md +23 -0
  106. package/expansion-packs/bmad-creative-writing/checklists/comedic-timing-checklist.md +23 -0
  107. package/expansion-packs/bmad-creative-writing/checklists/cyberpunk-aesthetic-checklist.md +23 -0
  108. package/expansion-packs/bmad-creative-writing/checklists/ebook-formatting-checklist.md +21 -0
  109. package/expansion-packs/bmad-creative-writing/checklists/epic-poetry-meter-checklist.md +23 -0
  110. package/expansion-packs/bmad-creative-writing/checklists/fantasy-magic-system-checklist.md +23 -0
  111. package/expansion-packs/bmad-creative-writing/checklists/foreshadowing-payoff-checklist.md +22 -0
  112. package/expansion-packs/bmad-creative-writing/checklists/genre-tropes-checklist.md +22 -0
  113. package/expansion-packs/bmad-creative-writing/checklists/historical-accuracy-checklist.md +23 -0
  114. package/expansion-packs/bmad-creative-writing/checklists/horror-suspense-checklist.md +23 -0
  115. package/expansion-packs/bmad-creative-writing/checklists/kdp-cover-ready-checklist.md +25 -0
  116. package/expansion-packs/bmad-creative-writing/checklists/line-edit-quality-checklist.md +23 -0
  117. package/expansion-packs/bmad-creative-writing/checklists/marketing-copy-checklist.md +23 -0
  118. package/expansion-packs/bmad-creative-writing/checklists/mystery-clue-trail-checklist.md +23 -0
  119. package/expansion-packs/bmad-creative-writing/checklists/orbital-mechanics-checklist.md +23 -0
  120. package/expansion-packs/bmad-creative-writing/checklists/plot-structure-checklist.md +59 -0
  121. package/expansion-packs/bmad-creative-writing/checklists/publication-readiness-checklist.md +23 -0
  122. package/expansion-packs/bmad-creative-writing/checklists/romance-emotional-beats-checklist.md +23 -0
  123. package/expansion-packs/bmad-creative-writing/checklists/scene-quality-checklist.md +23 -0
  124. package/expansion-packs/bmad-creative-writing/checklists/scifi-technology-plausibility-checklist.md +22 -0
  125. package/expansion-packs/bmad-creative-writing/checklists/sensitivity-representation-checklist.md +23 -0
  126. package/expansion-packs/bmad-creative-writing/checklists/steampunk-gadget-checklist.md +23 -0
  127. package/expansion-packs/bmad-creative-writing/checklists/thriller-pacing-stakes-checklist.md +23 -0
  128. package/expansion-packs/bmad-creative-writing/checklists/timeline-continuity-checklist.md +23 -0
  129. package/expansion-packs/bmad-creative-writing/checklists/world-building-continuity-checklist.md +23 -0
  130. package/expansion-packs/bmad-creative-writing/checklists/ya-appropriateness-checklist.md +23 -0
  131. package/expansion-packs/bmad-creative-writing/config.yaml +12 -0
  132. package/expansion-packs/bmad-creative-writing/data/bmad-kb.md +209 -0
  133. package/expansion-packs/bmad-creative-writing/data/story-structures.md +67 -0
  134. package/expansion-packs/bmad-creative-writing/docs/brief.md +212 -0
  135. package/expansion-packs/bmad-creative-writing/tasks/advanced-elicitation.md +119 -0
  136. package/expansion-packs/bmad-creative-writing/tasks/analyze-reader-feedback.md +23 -0
  137. package/expansion-packs/bmad-creative-writing/tasks/analyze-story-structure.md +67 -0
  138. package/expansion-packs/bmad-creative-writing/tasks/assemble-kdp-package.md +29 -0
  139. package/expansion-packs/bmad-creative-writing/tasks/brainstorm-premise.md +23 -0
  140. package/expansion-packs/bmad-creative-writing/tasks/build-world.md +24 -0
  141. package/expansion-packs/bmad-creative-writing/tasks/character-depth-pass.md +22 -0
  142. package/expansion-packs/bmad-creative-writing/tasks/create-doc.md +103 -0
  143. package/expansion-packs/bmad-creative-writing/tasks/create-draft-section.md +26 -0
  144. package/expansion-packs/bmad-creative-writing/tasks/critical-review.md +26 -0
  145. package/expansion-packs/bmad-creative-writing/tasks/develop-character.md +24 -0
  146. package/expansion-packs/bmad-creative-writing/tasks/execute-checklist.md +88 -0
  147. package/expansion-packs/bmad-creative-writing/tasks/expand-premise.md +23 -0
  148. package/expansion-packs/bmad-creative-writing/tasks/expand-synopsis.md +23 -0
  149. package/expansion-packs/bmad-creative-writing/tasks/final-polish.md +23 -0
  150. package/expansion-packs/bmad-creative-writing/tasks/generate-cover-brief.md +25 -0
  151. package/expansion-packs/bmad-creative-writing/tasks/generate-cover-prompts.md +26 -0
  152. package/expansion-packs/bmad-creative-writing/tasks/generate-scene-list.md +23 -0
  153. package/expansion-packs/bmad-creative-writing/tasks/incorporate-feedback.md +25 -0
  154. package/expansion-packs/bmad-creative-writing/tasks/outline-scenes.md +23 -0
  155. package/expansion-packs/bmad-creative-writing/tasks/provide-feedback.md +24 -0
  156. package/expansion-packs/bmad-creative-writing/tasks/publish-chapter.md +23 -0
  157. package/expansion-packs/bmad-creative-writing/tasks/quick-feedback.md +22 -0
  158. package/expansion-packs/bmad-creative-writing/tasks/select-next-arc.md +23 -0
  159. package/expansion-packs/bmad-creative-writing/tasks/workshop-dialog.md +64 -0
  160. package/expansion-packs/bmad-creative-writing/templates/beta-feedback-form.yaml +97 -0
  161. package/expansion-packs/bmad-creative-writing/templates/chapter-draft-tmpl.yaml +82 -0
  162. package/expansion-packs/bmad-creative-writing/templates/character-profile-tmpl.yaml +92 -0
  163. package/expansion-packs/bmad-creative-writing/templates/cover-design-brief-tmpl.yaml +98 -0
  164. package/expansion-packs/bmad-creative-writing/templates/premise-brief-tmpl.yaml +78 -0
  165. package/expansion-packs/bmad-creative-writing/templates/scene-list-tmpl.yaml +55 -0
  166. package/expansion-packs/bmad-creative-writing/templates/story-outline-tmpl.yaml +96 -0
  167. package/expansion-packs/bmad-creative-writing/templates/world-guide-tmpl.yaml +89 -0
  168. package/expansion-packs/bmad-creative-writing/workflows/book-cover-design-workflow.md +218 -0
  169. package/expansion-packs/bmad-creative-writing/workflows/novel-greenfield-workflow.yaml +56 -0
  170. package/expansion-packs/bmad-creative-writing/workflows/novel-serial-workflow.yaml +50 -0
  171. package/expansion-packs/bmad-creative-writing/workflows/novel-snowflake-workflow.yaml +69 -0
  172. package/expansion-packs/bmad-creative-writing/workflows/novel-writing.yaml +91 -0
  173. package/expansion-packs/bmad-creative-writing/workflows/screenplay-development.yaml +85 -0
  174. package/expansion-packs/bmad-creative-writing/workflows/series-planning.yaml +78 -0
  175. package/expansion-packs/bmad-creative-writing/workflows/short-story-creation.yaml +64 -0
  176. package/expansion-packs/bmad-infrastructure-devops/README.md +147 -0
  177. package/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.md +73 -0
  178. package/expansion-packs/bmad-infrastructure-devops/checklists/infrastructure-checklist.md +486 -0
  179. package/expansion-packs/bmad-infrastructure-devops/config.yaml +10 -0
  180. package/expansion-packs/bmad-infrastructure-devops/data/bmad-kb.md +307 -0
  181. package/expansion-packs/bmad-infrastructure-devops/tasks/review-infrastructure.md +161 -0
  182. package/expansion-packs/bmad-infrastructure-devops/tasks/validate-infrastructure.md +155 -0
  183. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +425 -0
  184. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +630 -0
  185. package/implement-fork-friendly-ci.sh +229 -0
  186. package/package.json +75 -45
  187. package/prettier.config.mjs +32 -0
  188. package/test.md +1 -0
  189. package/tools/builders/web-builder.js +143 -149
  190. package/tools/bump-all-versions.js +42 -33
  191. package/tools/bump-expansion-version.js +23 -16
  192. package/tools/cli.js +15 -15
  193. package/tools/flattener/aggregate.js +76 -0
  194. package/tools/flattener/binary.js +80 -0
  195. package/tools/flattener/discovery.js +71 -0
  196. package/tools/flattener/files.js +35 -0
  197. package/tools/flattener/ignoreRules.js +176 -0
  198. package/tools/flattener/main.js +458 -460
  199. package/tools/flattener/projectRoot.js +206 -0
  200. package/tools/flattener/prompts.js +44 -0
  201. package/tools/flattener/stats.helpers.js +395 -0
  202. package/tools/flattener/stats.js +80 -0
  203. package/tools/flattener/test-matrix.js +413 -0
  204. package/tools/flattener/xml.js +88 -0
  205. package/tools/installer/README.md +1 -1
  206. package/tools/installer/bin/xiaoma.js +392 -99
  207. package/tools/installer/config/ide-agent-config.yaml +1 -1
  208. package/tools/installer/config/install.config.yaml +60 -9
  209. package/tools/installer/lib/config-loader.js +55 -51
  210. package/tools/installer/lib/file-manager.js +92 -114
  211. package/tools/installer/lib/ide-base-setup.js +57 -56
  212. package/tools/installer/lib/ide-setup.js +821 -414
  213. package/tools/installer/lib/installer.js +924 -696
  214. package/tools/installer/lib/memory-profiler.js +54 -53
  215. package/tools/installer/lib/module-manager.js +19 -15
  216. package/tools/installer/lib/resource-locator.js +31 -33
  217. package/tools/installer/package.json +24 -23
  218. package/tools/lib/dependency-resolver.js +39 -43
  219. package/tools/lib/yaml-utils.js +7 -7
  220. package/tools/md-assets/web-agent-startup-instructions.md +6 -6
  221. package/tools/preview-release-notes.js +66 -0
  222. package/tools/setup-hooks.sh +37 -0
  223. package/tools/shared/bannerArt.js +105 -0
  224. package/tools/sync-installer-version.js +7 -9
  225. package/tools/sync-version.sh +23 -0
  226. package/tools/update-expansion-version.js +14 -15
  227. package/tools/upgraders/v3-to-v4-upgrader.js +203 -294
  228. package/tools/version-bump.js +41 -26
  229. package/tools/xiaoma-npx-wrapper.js +14 -14
  230. package/tools/yaml-format.js +56 -43
  231. package/xiaoma-core/agent-teams/team-all.yaml +3 -2
  232. package/xiaoma-core/agent-teams/team-fullstack.yaml +2 -1
  233. package/xiaoma-core/agent-teams/team-ide-minimal.yaml +1 -0
  234. package/xiaoma-core/agent-teams/team-no-ui.yaml +2 -1
  235. package/xiaoma-core/agents/analyst.md +20 -17
  236. package/xiaoma-core/agents/architect.md +15 -14
  237. package/xiaoma-core/agents/{xiaoma-master.md → bmad-master.md} +29 -27
  238. package/xiaoma-core/agents/{xiaoma-orchestrator.md → bmad-orchestrator.md} +36 -39
  239. package/xiaoma-core/agents/dev.md +23 -18
  240. package/xiaoma-core/agents/pm.md +18 -15
  241. package/xiaoma-core/agents/po.md +13 -10
  242. package/xiaoma-core/agents/qa.md +46 -24
  243. package/xiaoma-core/agents/sm.md +11 -8
  244. package/xiaoma-core/agents/ux-expert.md +10 -7
  245. package/xiaoma-core/checklists/architect-checklist.md +2 -5
  246. package/xiaoma-core/checklists/change-checklist.md +4 -2
  247. package/xiaoma-core/checklists/pm-checklist.md +2 -5
  248. package/xiaoma-core/checklists/po-master-checklist.md +2 -9
  249. package/xiaoma-core/checklists/story-dod-checklist.md +2 -7
  250. package/xiaoma-core/checklists/story-draft-checklist.md +2 -3
  251. package/xiaoma-core/core-config.yaml +4 -1
  252. package/xiaoma-core/data/{xiaoma-kb.md → bmad-kb.md} +48 -42
  253. package/xiaoma-core/data/brainstorming-techniques.md +2 -0
  254. package/xiaoma-core/data/elicitation-methods.md +22 -0
  255. package/xiaoma-core/data/technical-preferences.md +2 -0
  256. package/xiaoma-core/data/test-levels-framework.md +148 -0
  257. package/xiaoma-core/data/test-priorities-matrix.md +174 -0
  258. package/xiaoma-core/tasks/advanced-elicitation.md +2 -0
  259. package/xiaoma-core/tasks/apply-qa-fixes.md +150 -0
  260. package/xiaoma-core/tasks/brownfield-create-epic.md +2 -0
  261. package/xiaoma-core/tasks/brownfield-create-story.md +2 -0
  262. package/xiaoma-core/tasks/correct-course.md +2 -0
  263. package/xiaoma-core/tasks/create-brownfield-story.md +14 -4
  264. package/xiaoma-core/tasks/create-deep-research-prompt.md +2 -11
  265. package/xiaoma-core/tasks/create-next-story.md +3 -1
  266. package/xiaoma-core/tasks/document-project.md +17 -13
  267. package/xiaoma-core/tasks/facilitate-brainstorming-session.md +5 -3
  268. package/xiaoma-core/tasks/generate-ai-frontend-prompt.md +2 -0
  269. package/xiaoma-core/tasks/index-docs.md +2 -6
  270. package/xiaoma-core/tasks/kb-mode-interaction.md +17 -15
  271. package/xiaoma-core/tasks/nfr-assess.md +345 -0
  272. package/xiaoma-core/tasks/qa-gate.md +163 -0
  273. package/xiaoma-core/tasks/review-story.md +245 -74
  274. package/xiaoma-core/tasks/risk-profile.md +355 -0
  275. package/xiaoma-core/tasks/shard-doc.md +2 -2
  276. package/xiaoma-core/tasks/test-design.md +176 -0
  277. package/xiaoma-core/tasks/trace-requirements.md +266 -0
  278. package/xiaoma-core/tasks/validate-next-story.md +5 -3
  279. package/xiaoma-core/templates/architecture-tmpl.yaml +50 -49
  280. package/xiaoma-core/templates/brainstorming-output-tmpl.yaml +5 -5
  281. package/xiaoma-core/templates/brownfield-architecture-tmpl.yaml +32 -31
  282. package/xiaoma-core/templates/brownfield-prd-tmpl.yaml +14 -13
  283. package/xiaoma-core/templates/competitor-analysis-tmpl.yaml +20 -6
  284. package/xiaoma-core/templates/front-end-architecture-tmpl.yaml +22 -9
  285. package/xiaoma-core/templates/front-end-spec-tmpl.yaml +25 -24
  286. package/xiaoma-core/templates/fullstack-architecture-tmpl.yaml +123 -104
  287. package/xiaoma-core/templates/market-research-tmpl.yaml +3 -2
  288. package/xiaoma-core/templates/prd-tmpl.yaml +10 -9
  289. package/xiaoma-core/templates/project-brief-tmpl.yaml +5 -4
  290. package/xiaoma-core/templates/qa-gate-tmpl.yaml +103 -0
  291. package/xiaoma-core/templates/story-tmpl.yaml +13 -12
  292. package/xiaoma-core/workflows/brownfield-fullstack.yaml +13 -12
  293. package/xiaoma-core/workflows/brownfield-service.yaml +5 -4
  294. package/xiaoma-core/workflows/brownfield-ui.yaml +5 -4
  295. package/xiaoma-core/workflows/greenfield-fullstack.yaml +7 -6
  296. package/xiaoma-core/workflows/greenfield-service.yaml +5 -4
  297. package/xiaoma-core/workflows/greenfield-ui.yaml +6 -5
  298. package/.releaserc.json +0 -18
  299. package/README.md +0 -532
  300. package/dist/agents/analyst.txt +0 -2882
  301. package/dist/agents/architect.txt +0 -3543
  302. package/dist/agents/dev.txt +0 -428
  303. package/dist/agents/pm.txt +0 -2229
  304. package/dist/agents/po.txt +0 -1364
  305. package/dist/agents/qa.txt +0 -386
  306. package/dist/agents/sm.txt +0 -668
  307. package/dist/agents/ux-expert.txt +0 -701
  308. package/dist/agents/xiaoma-master.txt +0 -8756
  309. package/dist/agents/xiaoma-orchestrator.txt +0 -1490
  310. package/dist/teams/team-all.txt +0 -11062
  311. package/dist/teams/team-fullstack.txt +0 -10392
  312. package/dist/teams/team-ide-minimal.txt +0 -3507
  313. package/dist/teams/team-no-ui.txt +0 -8951
  314. package/docs/quick-start.md +0 -179
  315. package/tools/bmad-npx-wrapper.js +0 -39
  316. package/tools/installer/package-lock.json +0 -704
  317. package/tools/semantic-release-sync-installer.js +0 -30
  318. package/xiaoma-core/bmad-core/user-guide.md +0 -0
  319. package/xiaoma-core/enhanced-ide-development-workflow.md +0 -43
  320. package/xiaoma-core/user-guide.md +0 -251
  321. package/xiaoma-core/working-in-the-brownfield.md +0 -364
@@ -0,0 +1,80 @@
1
+ const H = require('./stats.helpers.js');
2
+
3
+ async function calculateStatistics(aggregatedContent, xmlFileSize, rootDir) {
4
+ const { textFiles, binaryFiles, errors } = aggregatedContent;
5
+
6
+ const totalLines = textFiles.reduce((sum, f) => sum + (f.lines || 0), 0);
7
+ const estimatedTokens = Math.ceil(xmlFileSize / 4);
8
+
9
+ // Build enriched file list
10
+ const allFiles = await H.enrichAllFiles(textFiles, binaryFiles);
11
+ const totalBytes = allFiles.reduce((s, f) => s + f.size, 0);
12
+ const sizes = allFiles.map((f) => f.size).sort((a, b) => a - b);
13
+ const avgSize = sizes.length > 0 ? totalBytes / sizes.length : 0;
14
+ const medianSize = sizes.length > 0 ? H.percentile(sizes, 50) : 0;
15
+ const p90 = H.percentile(sizes, 90);
16
+ const p95 = H.percentile(sizes, 95);
17
+ const p99 = H.percentile(sizes, 99);
18
+
19
+ const histogram = H.buildHistogram(allFiles);
20
+ const byExtensionArr = H.aggregateByExtension(allFiles);
21
+ const byDirectoryArr = H.aggregateByDirectory(allFiles);
22
+ const { depthDist, longestPaths } = H.computeDepthAndLongest(allFiles);
23
+ const temporal = H.computeTemporal(allFiles, Date.now());
24
+ const quality = H.computeQuality(allFiles, textFiles);
25
+ const duplicateCandidates = H.computeDuplicates(allFiles, textFiles);
26
+ const compressibilityRatio = H.estimateCompressibility(textFiles);
27
+ const git = H.computeGitInfo(allFiles, rootDir, quality.largeThreshold);
28
+ const largestFiles = H.computeLargestFiles(allFiles, totalBytes);
29
+ const markdownReport = H.buildMarkdownReport(
30
+ largestFiles,
31
+ byExtensionArr,
32
+ byDirectoryArr,
33
+ totalBytes,
34
+ );
35
+
36
+ return {
37
+ // Back-compat summary
38
+ totalFiles: textFiles.length + binaryFiles.length,
39
+ textFiles: textFiles.length,
40
+ binaryFiles: binaryFiles.length,
41
+ errorFiles: errors.length,
42
+ totalSize: H.formatSize(totalBytes),
43
+ totalBytes,
44
+ xmlSize: H.formatSize(xmlFileSize),
45
+ totalLines,
46
+ estimatedTokens: estimatedTokens.toLocaleString(),
47
+
48
+ // Distributions and percentiles
49
+ avgFileSize: avgSize,
50
+ medianFileSize: medianSize,
51
+ p90,
52
+ p95,
53
+ p99,
54
+ histogram,
55
+
56
+ // Extensions and directories
57
+ byExtension: byExtensionArr,
58
+ byDirectory: byDirectoryArr,
59
+ depthDistribution: depthDist,
60
+ longestPaths,
61
+
62
+ // Temporal
63
+ temporal,
64
+
65
+ // Quality signals
66
+ quality,
67
+
68
+ // Duplicates and compressibility
69
+ duplicateCandidates,
70
+ compressibilityRatio,
71
+
72
+ // Git-aware
73
+ git,
74
+
75
+ largestFiles,
76
+ markdownReport,
77
+ };
78
+ }
79
+
80
+ module.exports = { calculateStatistics };
@@ -0,0 +1,413 @@
1
+ /* deno-lint-ignore-file */
2
+ /*
3
+ Automatic test matrix for project root detection.
4
+ Creates temporary fixtures for various ecosystems and validates findProjectRoot().
5
+ No external options or flags required. Safe to run multiple times.
6
+ */
7
+
8
+ const os = require('node:os');
9
+ const path = require('node:path');
10
+ const fs = require('fs-extra');
11
+ const { promisify } = require('node:util');
12
+ const { execFile } = require('node:child_process');
13
+ const process = require('node:process');
14
+ const execFileAsync = promisify(execFile);
15
+
16
+ const { findProjectRoot } = require('./projectRoot.js');
17
+
18
+ async function cmdAvailable(cmd) {
19
+ try {
20
+ await execFileAsync(cmd, ['--version'], { timeout: 500, windowsHide: true });
21
+ return true;
22
+ } catch {
23
+ return false;
24
+ }
25
+
26
+ async function testSvnMarker() {
27
+ const root = await mkTmpDir('svn');
28
+ const nested = path.join(root, 'proj', 'code');
29
+ await fs.ensureDir(nested);
30
+ await fs.ensureDir(path.join(root, '.svn'));
31
+ const found = await findProjectRoot(nested);
32
+ assertEqual(found, root, '.svn marker should be detected');
33
+ return { name: 'svn-marker', ok: true };
34
+ }
35
+
36
+ async function testSymlinkStart() {
37
+ const root = await mkTmpDir('symlink-start');
38
+ const nested = path.join(root, 'a', 'b');
39
+ await fs.ensureDir(nested);
40
+ await fs.writeFile(path.join(root, '.project-root'), '\n');
41
+ const tmp = await mkTmpDir('symlink-tmp');
42
+ const link = path.join(tmp, 'link-to-b');
43
+ try {
44
+ await fs.symlink(nested, link);
45
+ } catch {
46
+ // symlink may not be permitted on some systems; skip
47
+ return { name: 'symlink-start', ok: true, skipped: true };
48
+ }
49
+ const found = await findProjectRoot(link);
50
+ assertEqual(found, root, 'should resolve symlinked start to real root');
51
+ return { name: 'symlink-start', ok: true };
52
+ }
53
+
54
+ async function testSubmoduleLikeInnerGitFile() {
55
+ const root = await mkTmpDir('submodule-like');
56
+ const mid = path.join(root, 'mid');
57
+ const leaf = path.join(mid, 'leaf');
58
+ await fs.ensureDir(leaf);
59
+ // outer repo
60
+ await fs.ensureDir(path.join(root, '.git'));
61
+ // inner submodule-like .git file
62
+ await fs.writeFile(path.join(mid, '.git'), 'gitdir: ../.git/modules/mid\n');
63
+ const found = await findProjectRoot(leaf);
64
+ assertEqual(found, root, 'outermost .git should win on tie weight');
65
+ return { name: 'submodule-like-gitfile', ok: true };
66
+ }
67
+ }
68
+
69
+ async function mkTmpDir(name) {
70
+ const base = await fs.realpath(os.tmpdir());
71
+ const dir = await fs.mkdtemp(path.join(base, `flattener-${name}-`));
72
+ return dir;
73
+ }
74
+
75
+ function assertEqual(actual, expected, msg) {
76
+ if (actual !== expected) {
77
+ throw new Error(`${msg}: expected="${expected}" actual="${actual}"`);
78
+ }
79
+ }
80
+
81
+ async function testSentinel() {
82
+ const root = await mkTmpDir('sentinel');
83
+ const nested = path.join(root, 'a', 'b', 'c');
84
+ await fs.ensureDir(nested);
85
+ await fs.writeFile(path.join(root, '.project-root'), '\n');
86
+ const found = await findProjectRoot(nested);
87
+ await assertEqual(found, root, 'sentinel .project-root should win');
88
+ return { name: 'sentinel', ok: true };
89
+ }
90
+
91
+ async function testOtherSentinels() {
92
+ const root = await mkTmpDir('other-sentinels');
93
+ const nested = path.join(root, 'x', 'y');
94
+ await fs.ensureDir(nested);
95
+ await fs.writeFile(path.join(root, '.workspace-root'), '\n');
96
+ const found1 = await findProjectRoot(nested);
97
+ assertEqual(found1, root, 'sentinel .workspace-root should win');
98
+
99
+ await fs.remove(path.join(root, '.workspace-root'));
100
+ await fs.writeFile(path.join(root, '.repo-root'), '\n');
101
+ const found2 = await findProjectRoot(nested);
102
+ assertEqual(found2, root, 'sentinel .repo-root should win');
103
+ return { name: 'other-sentinels', ok: true };
104
+ }
105
+
106
+ async function testGitCliAndMarker() {
107
+ const hasGit = await cmdAvailable('git');
108
+ if (!hasGit) return { name: 'git-cli', ok: true, skipped: true };
109
+
110
+ const root = await mkTmpDir('git');
111
+ const nested = path.join(root, 'pkg', 'src');
112
+ await fs.ensureDir(nested);
113
+ await execFileAsync('git', ['init'], { cwd: root, timeout: 2000 });
114
+ const found = await findProjectRoot(nested);
115
+ await assertEqual(found, root, 'git toplevel should be detected');
116
+ return { name: 'git-cli', ok: true };
117
+ }
118
+
119
+ async function testHgMarkerOrCli() {
120
+ // Prefer simple marker test to avoid requiring Mercurial install
121
+ const root = await mkTmpDir('hg');
122
+ const nested = path.join(root, 'lib');
123
+ await fs.ensureDir(nested);
124
+ await fs.ensureDir(path.join(root, '.hg'));
125
+ const found = await findProjectRoot(nested);
126
+ await assertEqual(found, root, '.hg marker should be detected');
127
+ return { name: 'hg-marker', ok: true };
128
+ }
129
+
130
+ async function testWorkspacePnpm() {
131
+ const root = await mkTmpDir('pnpm-workspace');
132
+ const pkgA = path.join(root, 'packages', 'a');
133
+ await fs.ensureDir(pkgA);
134
+ await fs.writeFile(path.join(root, 'pnpm-workspace.yaml'), 'packages:\n - packages/*\n');
135
+ const found = await findProjectRoot(pkgA);
136
+ await assertEqual(found, root, 'pnpm-workspace.yaml should be detected');
137
+ return { name: 'pnpm-workspace', ok: true };
138
+ }
139
+
140
+ async function testPackageJsonWorkspaces() {
141
+ const root = await mkTmpDir('package-workspaces');
142
+ const pkgA = path.join(root, 'packages', 'a');
143
+ await fs.ensureDir(pkgA);
144
+ await fs.writeJson(
145
+ path.join(root, 'package.json'),
146
+ { private: true, workspaces: ['packages/*'] },
147
+ { spaces: 2 },
148
+ );
149
+ const found = await findProjectRoot(pkgA);
150
+ await assertEqual(found, root, 'package.json workspaces should be detected');
151
+ return { name: 'package.json-workspaces', ok: true };
152
+ }
153
+
154
+ async function testLockfiles() {
155
+ const root = await mkTmpDir('lockfiles');
156
+ const nested = path.join(root, 'src');
157
+ await fs.ensureDir(nested);
158
+ await fs.writeFile(path.join(root, 'yarn.lock'), '\n');
159
+ const found = await findProjectRoot(nested);
160
+ await assertEqual(found, root, 'yarn.lock should be detected');
161
+ return { name: 'lockfiles', ok: true };
162
+ }
163
+
164
+ async function testLanguageConfigs() {
165
+ const root = await mkTmpDir('lang-configs');
166
+ const nested = path.join(root, 'x', 'y');
167
+ await fs.ensureDir(nested);
168
+ await fs.writeFile(path.join(root, 'pyproject.toml'), "[tool.poetry]\nname='tmp'\n");
169
+ const found = await findProjectRoot(nested);
170
+ await assertEqual(found, root, 'pyproject.toml should be detected');
171
+ return { name: 'language-configs', ok: true };
172
+ }
173
+
174
+ async function testPreferOuterOnTie() {
175
+ const root = await mkTmpDir('tie');
176
+ const mid = path.join(root, 'mid');
177
+ const leaf = path.join(mid, 'leaf');
178
+ await fs.ensureDir(leaf);
179
+ // same weight marker at two levels
180
+ await fs.writeFile(path.join(root, 'requirements.txt'), '\n');
181
+ await fs.writeFile(path.join(mid, 'requirements.txt'), '\n');
182
+ const found = await findProjectRoot(leaf);
183
+ await assertEqual(found, root, 'outermost directory should win on equal weight');
184
+ return { name: 'prefer-outermost-tie', ok: true };
185
+ }
186
+
187
+ // Additional coverage: Bazel, Nx/Turbo/Rush, Go workspaces, Deno, Java/Scala, PHP, Rust, Nix, Changesets, env markers,
188
+ // and priority interaction between package.json and lockfiles.
189
+
190
+ async function testBazelWorkspace() {
191
+ const root = await mkTmpDir('bazel');
192
+ const nested = path.join(root, 'apps', 'svc');
193
+ await fs.ensureDir(nested);
194
+ await fs.writeFile(path.join(root, 'WORKSPACE'), 'workspace(name="tmp")\n');
195
+ const found = await findProjectRoot(nested);
196
+ await assertEqual(found, root, 'Bazel WORKSPACE should be detected');
197
+ return { name: 'bazel-workspace', ok: true };
198
+ }
199
+
200
+ async function testNx() {
201
+ const root = await mkTmpDir('nx');
202
+ const nested = path.join(root, 'apps', 'web');
203
+ await fs.ensureDir(nested);
204
+ await fs.writeJson(path.join(root, 'nx.json'), { npmScope: 'tmp' }, { spaces: 2 });
205
+ const found = await findProjectRoot(nested);
206
+ await assertEqual(found, root, 'nx.json should be detected');
207
+ return { name: 'nx', ok: true };
208
+ }
209
+
210
+ async function testTurbo() {
211
+ const root = await mkTmpDir('turbo');
212
+ const nested = path.join(root, 'packages', 'x');
213
+ await fs.ensureDir(nested);
214
+ await fs.writeJson(path.join(root, 'turbo.json'), { pipeline: {} }, { spaces: 2 });
215
+ const found = await findProjectRoot(nested);
216
+ await assertEqual(found, root, 'turbo.json should be detected');
217
+ return { name: 'turbo', ok: true };
218
+ }
219
+
220
+ async function testRush() {
221
+ const root = await mkTmpDir('rush');
222
+ const nested = path.join(root, 'apps', 'a');
223
+ await fs.ensureDir(nested);
224
+ await fs.writeJson(path.join(root, 'rush.json'), { projectFolderMinDepth: 1 }, { spaces: 2 });
225
+ const found = await findProjectRoot(nested);
226
+ await assertEqual(found, root, 'rush.json should be detected');
227
+ return { name: 'rush', ok: true };
228
+ }
229
+
230
+ async function testGoWorkAndMod() {
231
+ const root = await mkTmpDir('gowork');
232
+ const mod = path.join(root, 'modA');
233
+ const nested = path.join(mod, 'pkg');
234
+ await fs.ensureDir(nested);
235
+ await fs.writeFile(path.join(root, 'go.work'), 'go 1.22\nuse ./modA\n');
236
+ await fs.writeFile(path.join(mod, 'go.mod'), 'module example.com/a\ngo 1.22\n');
237
+ const found = await findProjectRoot(nested);
238
+ await assertEqual(found, root, 'go.work should define the workspace root');
239
+ return { name: 'go-work', ok: true };
240
+ }
241
+
242
+ async function testDenoJson() {
243
+ const root = await mkTmpDir('deno');
244
+ const nested = path.join(root, 'src');
245
+ await fs.ensureDir(nested);
246
+ await fs.writeJson(path.join(root, 'deno.json'), { tasks: {} }, { spaces: 2 });
247
+ const found = await findProjectRoot(nested);
248
+ await assertEqual(found, root, 'deno.json should be detected');
249
+ return { name: 'deno-json', ok: true };
250
+ }
251
+
252
+ async function testGradleSettings() {
253
+ const root = await mkTmpDir('gradle');
254
+ const nested = path.join(root, 'app');
255
+ await fs.ensureDir(nested);
256
+ await fs.writeFile(path.join(root, 'settings.gradle'), "rootProject.name='tmp'\n");
257
+ const found = await findProjectRoot(nested);
258
+ await assertEqual(found, root, 'settings.gradle should be detected');
259
+ return { name: 'gradle-settings', ok: true };
260
+ }
261
+
262
+ async function testMavenPom() {
263
+ const root = await mkTmpDir('maven');
264
+ const nested = path.join(root, 'module');
265
+ await fs.ensureDir(nested);
266
+ await fs.writeFile(path.join(root, 'pom.xml'), '<project></project>\n');
267
+ const found = await findProjectRoot(nested);
268
+ await assertEqual(found, root, 'pom.xml should be detected');
269
+ return { name: 'maven-pom', ok: true };
270
+ }
271
+
272
+ async function testSbtBuild() {
273
+ const root = await mkTmpDir('sbt');
274
+ const nested = path.join(root, 'sub');
275
+ await fs.ensureDir(nested);
276
+ await fs.writeFile(path.join(root, 'build.sbt'), 'name := "tmp"\n');
277
+ const found = await findProjectRoot(nested);
278
+ await assertEqual(found, root, 'build.sbt should be detected');
279
+ return { name: 'sbt-build', ok: true };
280
+ }
281
+
282
+ async function testComposer() {
283
+ const root = await mkTmpDir('composer');
284
+ const nested = path.join(root, 'src');
285
+ await fs.ensureDir(nested);
286
+ await fs.writeJson(path.join(root, 'composer.json'), { name: 'tmp/pkg' }, { spaces: 2 });
287
+ await fs.writeFile(path.join(root, 'composer.lock'), '{}\n');
288
+ const found = await findProjectRoot(nested);
289
+ await assertEqual(found, root, 'composer.{json,lock} should be detected');
290
+ return { name: 'composer', ok: true };
291
+ }
292
+
293
+ async function testCargo() {
294
+ const root = await mkTmpDir('cargo');
295
+ const nested = path.join(root, 'src');
296
+ await fs.ensureDir(nested);
297
+ await fs.writeFile(path.join(root, 'Cargo.toml'), "[package]\nname='tmp'\nversion='0.0.0'\n");
298
+ const found = await findProjectRoot(nested);
299
+ await assertEqual(found, root, 'Cargo.toml should be detected');
300
+ return { name: 'cargo', ok: true };
301
+ }
302
+
303
+ async function testNixFlake() {
304
+ const root = await mkTmpDir('nix');
305
+ const nested = path.join(root, 'work');
306
+ await fs.ensureDir(nested);
307
+ await fs.writeFile(path.join(root, 'flake.nix'), '{ }\n');
308
+ const found = await findProjectRoot(nested);
309
+ await assertEqual(found, root, 'flake.nix should be detected');
310
+ return { name: 'nix-flake', ok: true };
311
+ }
312
+
313
+ async function testChangesetConfig() {
314
+ const root = await mkTmpDir('changeset');
315
+ const nested = path.join(root, 'pkg');
316
+ await fs.ensureDir(nested);
317
+ await fs.ensureDir(path.join(root, '.changeset'));
318
+ await fs.writeJson(
319
+ path.join(root, '.changeset', 'config.json'),
320
+ { $schema: 'https://unpkg.com/@changesets/config@2.3.1/schema.json' },
321
+ { spaces: 2 },
322
+ );
323
+ const found = await findProjectRoot(nested);
324
+ await assertEqual(found, root, '.changeset/config.json should be detected');
325
+ return { name: 'changesets', ok: true };
326
+ }
327
+
328
+ async function testEnvCustomMarker() {
329
+ const root = await mkTmpDir('env-marker');
330
+ const nested = path.join(root, 'dir');
331
+ await fs.ensureDir(nested);
332
+ await fs.writeFile(path.join(root, 'MY_ROOT'), '\n');
333
+ const prev = process.env.PROJECT_ROOT_MARKERS;
334
+ process.env.PROJECT_ROOT_MARKERS = 'MY_ROOT';
335
+ try {
336
+ const found = await findProjectRoot(nested);
337
+ await assertEqual(found, root, 'custom env marker should be honored');
338
+ } finally {
339
+ if (prev === undefined) delete process.env.PROJECT_ROOT_MARKERS;
340
+ else process.env.PROJECT_ROOT_MARKERS = prev;
341
+ }
342
+ return { name: 'env-custom-marker', ok: true };
343
+ }
344
+
345
+ async function testPackageLowPriorityVsLock() {
346
+ const root = await mkTmpDir('pkg-vs-lock');
347
+ const nested = path.join(root, 'nested');
348
+ await fs.ensureDir(path.join(nested, 'deep'));
349
+ await fs.writeJson(path.join(nested, 'package.json'), { name: 'nested' }, { spaces: 2 });
350
+ await fs.writeFile(path.join(root, 'yarn.lock'), '\n');
351
+ const found = await findProjectRoot(path.join(nested, 'deep'));
352
+ await assertEqual(found, root, 'lockfile at root should outrank nested package.json');
353
+ return { name: 'package-vs-lock-priority', ok: true };
354
+ }
355
+
356
+ async function run() {
357
+ const tests = [
358
+ testSentinel,
359
+ testOtherSentinels,
360
+ testGitCliAndMarker,
361
+ testHgMarkerOrCli,
362
+ testWorkspacePnpm,
363
+ testPackageJsonWorkspaces,
364
+ testLockfiles,
365
+ testLanguageConfigs,
366
+ testPreferOuterOnTie,
367
+ testBazelWorkspace,
368
+ testNx,
369
+ testTurbo,
370
+ testRush,
371
+ testGoWorkAndMod,
372
+ testDenoJson,
373
+ testGradleSettings,
374
+ testMavenPom,
375
+ testSbtBuild,
376
+ testComposer,
377
+ testCargo,
378
+ testNixFlake,
379
+ testChangesetConfig,
380
+ testEnvCustomMarker,
381
+ testPackageLowPriorityVsLock,
382
+ testSvnMarker,
383
+ testSymlinkStart,
384
+ testSubmoduleLikeInnerGitFile,
385
+ ];
386
+
387
+ const results = [];
388
+ for (const t of tests) {
389
+ try {
390
+ const r = await t();
391
+ results.push({ ...r, ok: true });
392
+ console.log(`✔ ${r.name}${r.skipped ? ' (skipped)' : ''}`);
393
+ } catch (error) {
394
+ console.error(`✖ ${t.name}:`, error && error.message ? error.message : error);
395
+ results.push({ name: t.name, ok: false, error: String(error) });
396
+ }
397
+ }
398
+
399
+ const failed = results.filter((r) => !r.ok);
400
+ console.log('\nSummary:');
401
+ for (const r of results) {
402
+ console.log(`- ${r.name}: ${r.ok ? 'ok' : 'FAIL'}${r.skipped ? ' (skipped)' : ''}`);
403
+ }
404
+
405
+ if (failed.length > 0) {
406
+ process.exitCode = 1;
407
+ }
408
+ }
409
+
410
+ run().catch((error) => {
411
+ console.error('Fatal error:', error);
412
+ process.exit(1);
413
+ });
@@ -0,0 +1,88 @@
1
+ const fs = require('fs-extra');
2
+
3
+ function escapeXml(string_) {
4
+ if (typeof string_ !== 'string') {
5
+ return String(string_);
6
+ }
7
+ return string_.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll("'", '&apos;');
8
+ }
9
+
10
+ function indentFileContent(content) {
11
+ if (typeof content !== 'string') {
12
+ return String(content);
13
+ }
14
+ return content.split('\n').map((line) => ` ${line}`);
15
+ }
16
+
17
+ function generateXMLOutput(aggregatedContent, outputPath) {
18
+ const { textFiles } = aggregatedContent;
19
+ const writeStream = fs.createWriteStream(outputPath, { encoding: 'utf8' });
20
+
21
+ return new Promise((resolve, reject) => {
22
+ writeStream.on('error', reject);
23
+ writeStream.on('finish', resolve);
24
+
25
+ writeStream.write('<?xml version="1.0" encoding="UTF-8"?>\n');
26
+ writeStream.write('<files>\n');
27
+
28
+ // Sort files by path for deterministic order
29
+ const filesSorted = [...textFiles].sort((a, b) => a.path.localeCompare(b.path));
30
+ let index = 0;
31
+
32
+ const writeNext = () => {
33
+ if (index >= filesSorted.length) {
34
+ writeStream.write('</files>\n');
35
+ writeStream.end();
36
+ return;
37
+ }
38
+
39
+ const file = filesSorted[index++];
40
+ const p = escapeXml(file.path);
41
+ const content = typeof file.content === 'string' ? file.content : '';
42
+
43
+ if (content.length === 0) {
44
+ writeStream.write(`\t<file path='${p}'/>\n`);
45
+ setTimeout(writeNext, 0);
46
+ return;
47
+ }
48
+
49
+ const needsCdata = content.includes('<') || content.includes('&') || content.includes(']]>');
50
+ if (needsCdata) {
51
+ // Open tag and CDATA on their own line with tab indent; content lines indented with two tabs
52
+ writeStream.write(`\t<file path='${p}'><![CDATA[\n`);
53
+ // Safely split any occurrences of "]]>" inside content, trim trailing newlines, indent each line with two tabs
54
+ const safe = content.replaceAll(']]>', ']]]]><![CDATA[>');
55
+ const trimmed = safe.replace(/[\r\n]+$/, '');
56
+ const indented =
57
+ trimmed.length > 0
58
+ ? trimmed
59
+ .split('\n')
60
+ .map((line) => `\t\t${line}`)
61
+ .join('\n')
62
+ : '';
63
+ writeStream.write(indented);
64
+ // Close CDATA and attach closing tag directly after the last content line
65
+ writeStream.write(']]></file>\n');
66
+ } else {
67
+ // Write opening tag then newline; indent content with two tabs; attach closing tag directly after last content char
68
+ writeStream.write(`\t<file path='${p}'>\n`);
69
+ const trimmed = content.replace(/[\r\n]+$/, '');
70
+ const indented =
71
+ trimmed.length > 0
72
+ ? trimmed
73
+ .split('\n')
74
+ .map((line) => `\t\t${line}`)
75
+ .join('\n')
76
+ : '';
77
+ writeStream.write(indented);
78
+ writeStream.write(`</file>\n`);
79
+ }
80
+
81
+ setTimeout(writeNext, 0);
82
+ };
83
+
84
+ writeNext();
85
+ });
86
+ }
87
+
88
+ module.exports = { generateXMLOutput };
@@ -1,4 +1,4 @@
1
- # XiaoMa Web Installer
1
+ # BMad Method Installer
2
2
 
3
3
  ## Usage
4
4