@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,206 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('node:path');
3
+
4
+ // Deno/Node compatibility: explicitly import process
5
+ const process = require('node:process');
6
+ const { execFile } = require('node:child_process');
7
+ const { promisify } = require('node:util');
8
+ const execFileAsync = promisify(execFile);
9
+
10
+ // Simple memoization across calls (keyed by realpath of startDir)
11
+ const _cache = new Map();
12
+
13
+ async function _tryRun(cmd, args, cwd, timeoutMs = 500) {
14
+ try {
15
+ const { stdout } = await execFileAsync(cmd, args, {
16
+ cwd,
17
+ timeout: timeoutMs,
18
+ windowsHide: true,
19
+ maxBuffer: 1024 * 1024,
20
+ });
21
+ const out = String(stdout || '').trim();
22
+ return out || null;
23
+ } catch {
24
+ return null;
25
+ }
26
+ }
27
+
28
+ async function _detectVcsTopLevel(startDir) {
29
+ // Run common VCS root queries in parallel; ignore failures
30
+ const gitP = _tryRun('git', ['rev-parse', '--show-toplevel'], startDir);
31
+ const hgP = _tryRun('hg', ['root'], startDir);
32
+ const svnP = (async () => {
33
+ const show = await _tryRun('svn', ['info', '--show-item', 'wc-root'], startDir);
34
+ if (show) return show;
35
+ const info = await _tryRun('svn', ['info'], startDir);
36
+ if (info) {
37
+ const line = info
38
+ .split(/\r?\n/)
39
+ .find((l) => l.toLowerCase().startsWith('working copy root path:'));
40
+ if (line) return line.split(':').slice(1).join(':').trim();
41
+ }
42
+ return null;
43
+ })();
44
+ const [git, hg, svn] = await Promise.all([gitP, hgP, svnP]);
45
+ return git || hg || svn || null;
46
+ }
47
+
48
+ /**
49
+ * Attempt to find the project root by walking up from startDir.
50
+ * Uses a robust, prioritized set of ecosystem markers (VCS > workspaces/monorepo > lock/build > language config).
51
+ * Also recognizes package.json with "workspaces" as a workspace root.
52
+ * You can augment markers via env PROJECT_ROOT_MARKERS as a comma-separated list of file/dir names.
53
+ * @param {string} startDir
54
+ * @returns {Promise<string|null>} project root directory or null if not found
55
+ */
56
+ async function findProjectRoot(startDir) {
57
+ try {
58
+ // Resolve symlinks for robustness (e.g., when invoked from a symlinked path)
59
+ let dir = path.resolve(startDir);
60
+ try {
61
+ dir = await fs.realpath(dir);
62
+ } catch {
63
+ // ignore if realpath fails; continue with resolved path
64
+ }
65
+ const startKey = dir; // preserve starting point for caching
66
+ if (_cache.has(startKey)) return _cache.get(startKey);
67
+ const fsRoot = path.parse(dir).root;
68
+
69
+ // Helper to safely check for existence
70
+ const exists = (p) => fs.pathExists(p);
71
+
72
+ // Build checks: an array of { makePath: (dir) => string, weight }
73
+ const checks = [];
74
+
75
+ const add = (rel, weight) => {
76
+ const makePath = (d) => (Array.isArray(rel) ? path.join(d, ...rel) : path.join(d, rel));
77
+ checks.push({ makePath, weight });
78
+ };
79
+
80
+ // Highest priority: explicit sentinel markers
81
+ add('.project-root', 110);
82
+ add('.workspace-root', 110);
83
+ add('.repo-root', 110);
84
+
85
+ // Highest priority: VCS roots
86
+ add('.git', 100);
87
+ add('.hg', 95);
88
+ add('.svn', 95);
89
+
90
+ // Monorepo/workspace indicators
91
+ add('pnpm-workspace.yaml', 90);
92
+ add('lerna.json', 90);
93
+ add('turbo.json', 90);
94
+ add('nx.json', 90);
95
+ add('rush.json', 90);
96
+ add('go.work', 90);
97
+ add('WORKSPACE', 90);
98
+ add('WORKSPACE.bazel', 90);
99
+ add('MODULE.bazel', 90);
100
+ add('pants.toml', 90);
101
+
102
+ // Lockfiles and package-manager/top-level locks
103
+ add('yarn.lock', 85);
104
+ add('pnpm-lock.yaml', 85);
105
+ add('package-lock.json', 85);
106
+ add('bun.lockb', 85);
107
+ add('Cargo.lock', 85);
108
+ add('composer.lock', 85);
109
+ add('poetry.lock', 85);
110
+ add('Pipfile.lock', 85);
111
+ add('Gemfile.lock', 85);
112
+
113
+ // Build-system root indicators
114
+ add('settings.gradle', 80);
115
+ add('settings.gradle.kts', 80);
116
+ add('gradlew', 80);
117
+ add('pom.xml', 80);
118
+ add('build.sbt', 80);
119
+ add(['project', 'build.properties'], 80);
120
+
121
+ // Language/project config markers
122
+ add('deno.json', 75);
123
+ add('deno.jsonc', 75);
124
+ add('pyproject.toml', 75);
125
+ add('Pipfile', 75);
126
+ add('requirements.txt', 75);
127
+ add('go.mod', 75);
128
+ add('Cargo.toml', 75);
129
+ add('composer.json', 75);
130
+ add('mix.exs', 75);
131
+ add('Gemfile', 75);
132
+ add('CMakeLists.txt', 75);
133
+ add('stack.yaml', 75);
134
+ add('cabal.project', 75);
135
+ add('rebar.config', 75);
136
+ add('pubspec.yaml', 75);
137
+ add('flake.nix', 75);
138
+ add('shell.nix', 75);
139
+ add('default.nix', 75);
140
+ add('.tool-versions', 75);
141
+ add('package.json', 74); // generic Node project (lower than lockfiles/workspaces)
142
+
143
+ // Changesets
144
+ add(['.changeset', 'config.json'], 70);
145
+ add('.changeset', 70);
146
+
147
+ // Custom markers via env (comma-separated names)
148
+ if (process.env.PROJECT_ROOT_MARKERS) {
149
+ for (const name of process.env.PROJECT_ROOT_MARKERS.split(',')
150
+ .map((s) => s.trim())
151
+ .filter(Boolean)) {
152
+ add(name, 72);
153
+ }
154
+ }
155
+
156
+ /** Check for package.json with "workspaces" */
157
+ const hasWorkspacePackageJson = async (d) => {
158
+ const pkgPath = path.join(d, 'package.json');
159
+ if (!(await exists(pkgPath))) return false;
160
+ try {
161
+ const raw = await fs.readFile(pkgPath, 'utf8');
162
+ const pkg = JSON.parse(raw);
163
+ return Boolean(pkg && pkg.workspaces);
164
+ } catch {
165
+ return false;
166
+ }
167
+ };
168
+
169
+ let best = null; // { dir, weight }
170
+
171
+ // Try to detect VCS toplevel once up-front; treat as authoritative slightly above .git marker
172
+ const vcsTop = await _detectVcsTopLevel(dir);
173
+ if (vcsTop) {
174
+ best = { dir: vcsTop, weight: 101 };
175
+ }
176
+
177
+ while (true) {
178
+ // Special check: package.json with "workspaces"
179
+ if ((await hasWorkspacePackageJson(dir)) && (!best || 90 >= best.weight))
180
+ best = { dir, weight: 90 };
181
+
182
+ // Evaluate all other checks in parallel
183
+ const results = await Promise.all(
184
+ checks.map(async (c) => ({ c, ok: await exists(c.makePath(dir)) })),
185
+ );
186
+
187
+ for (const { c, ok } of results) {
188
+ if (!ok) continue;
189
+ if (!best || c.weight >= best.weight) {
190
+ best = { dir, weight: c.weight };
191
+ }
192
+ }
193
+
194
+ if (dir === fsRoot) break;
195
+ dir = path.dirname(dir);
196
+ }
197
+
198
+ const out = best ? best.dir : null;
199
+ _cache.set(startKey, out);
200
+ return out;
201
+ } catch {
202
+ return null;
203
+ }
204
+ }
205
+
206
+ module.exports = { findProjectRoot };
@@ -0,0 +1,44 @@
1
+ const os = require('node:os');
2
+ const path = require('node:path');
3
+ const readline = require('node:readline');
4
+ const process = require('node:process');
5
+
6
+ function expandHome(p) {
7
+ if (!p) return p;
8
+ if (p.startsWith('~')) return path.join(os.homedir(), p.slice(1));
9
+ return p;
10
+ }
11
+
12
+ function createRl() {
13
+ return readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout,
16
+ });
17
+ }
18
+
19
+ function promptQuestion(question) {
20
+ return new Promise((resolve) => {
21
+ const rl = createRl();
22
+ rl.question(question, (answer) => {
23
+ rl.close();
24
+ resolve(answer);
25
+ });
26
+ });
27
+ }
28
+
29
+ async function promptYesNo(question, defaultYes = true) {
30
+ const suffix = defaultYes ? ' [Y/n] ' : ' [y/N] ';
31
+ const ans = (await promptQuestion(`${question}${suffix}`)).trim().toLowerCase();
32
+ if (!ans) return defaultYes;
33
+ if (['y', 'yes'].includes(ans)) return true;
34
+ if (['n', 'no'].includes(ans)) return false;
35
+ return promptYesNo(question, defaultYes);
36
+ }
37
+
38
+ async function promptPath(question, defaultValue) {
39
+ const prompt = `${question}${defaultValue ? ` (default: ${defaultValue})` : ''}: `;
40
+ const ans = (await promptQuestion(prompt)).trim();
41
+ return expandHome(ans || defaultValue);
42
+ }
43
+
44
+ module.exports = { promptYesNo, promptPath, promptQuestion, expandHome };
@@ -0,0 +1,395 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const zlib = require('node:zlib');
6
+ const { Buffer } = require('node:buffer');
7
+ const crypto = require('node:crypto');
8
+ const cp = require('node:child_process');
9
+
10
+ const KB = 1024;
11
+ const MB = 1024 * KB;
12
+
13
+ const formatSize = (bytes) => {
14
+ if (bytes < 1024) return `${bytes} B`;
15
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
16
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
17
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
18
+ };
19
+
20
+ const percentile = (sorted, p) => {
21
+ if (sorted.length === 0) return 0;
22
+ const idx = Math.min(sorted.length - 1, Math.max(0, Math.ceil((p / 100) * sorted.length) - 1));
23
+ return sorted[idx];
24
+ };
25
+
26
+ async function processWithLimit(items, fn, concurrency = 64) {
27
+ for (let i = 0; i < items.length; i += concurrency) {
28
+ await Promise.all(items.slice(i, i + concurrency).map(fn));
29
+ }
30
+ }
31
+
32
+ async function enrichAllFiles(textFiles, binaryFiles) {
33
+ /** @type {Array<{ path: string; absolutePath: string; size: number; lines?: number; isBinary: boolean; ext: string; dir: string; depth: number; hidden: boolean; mtimeMs: number; isSymlink: boolean; }>} */
34
+ const allFiles = [];
35
+
36
+ async function enrich(file, isBinary) {
37
+ const ext = (path.extname(file.path) || '').toLowerCase();
38
+ const dir = path.dirname(file.path) || '.';
39
+ const depth = file.path.split(path.sep).filter(Boolean).length;
40
+ const hidden = file.path.split(path.sep).some((seg) => seg.startsWith('.'));
41
+ let mtimeMs = 0;
42
+ let isSymlink = false;
43
+ try {
44
+ const lst = await fs.lstat(file.absolutePath);
45
+ mtimeMs = lst.mtimeMs;
46
+ isSymlink = lst.isSymbolicLink();
47
+ } catch {
48
+ /* ignore lstat errors during enrichment */
49
+ }
50
+ allFiles.push({
51
+ path: file.path,
52
+ absolutePath: file.absolutePath,
53
+ size: file.size || 0,
54
+ lines: file.lines,
55
+ isBinary,
56
+ ext,
57
+ dir,
58
+ depth,
59
+ hidden,
60
+ mtimeMs,
61
+ isSymlink,
62
+ });
63
+ }
64
+
65
+ await processWithLimit(textFiles, (f) => enrich(f, false));
66
+ await processWithLimit(binaryFiles, (f) => enrich(f, true));
67
+ return allFiles;
68
+ }
69
+
70
+ function buildHistogram(allFiles) {
71
+ const buckets = [
72
+ [1 * KB, '0–1KB'],
73
+ [10 * KB, '1–10KB'],
74
+ [100 * KB, '10–100KB'],
75
+ [1 * MB, '100KB–1MB'],
76
+ [10 * MB, '1–10MB'],
77
+ [100 * MB, '10–100MB'],
78
+ [Infinity, '>=100MB'],
79
+ ];
80
+ const histogram = buckets.map(([_, label]) => ({ label, count: 0, bytes: 0 }));
81
+ for (const f of allFiles) {
82
+ for (const [i, bucket] of buckets.entries()) {
83
+ if (f.size < bucket[0]) {
84
+ histogram[i].count++;
85
+ histogram[i].bytes += f.size;
86
+ break;
87
+ }
88
+ }
89
+ }
90
+ return histogram;
91
+ }
92
+
93
+ function aggregateByExtension(allFiles) {
94
+ const byExtension = new Map();
95
+ for (const f of allFiles) {
96
+ const key = f.ext || '<none>';
97
+ const v = byExtension.get(key) || { ext: key, count: 0, bytes: 0 };
98
+ v.count++;
99
+ v.bytes += f.size;
100
+ byExtension.set(key, v);
101
+ }
102
+ return [...byExtension.values()].sort((a, b) => b.bytes - a.bytes);
103
+ }
104
+
105
+ function aggregateByDirectory(allFiles) {
106
+ const byDirectory = new Map();
107
+ function addDirBytes(dir, bytes) {
108
+ const v = byDirectory.get(dir) || { dir, count: 0, bytes: 0 };
109
+ v.count++;
110
+ v.bytes += bytes;
111
+ byDirectory.set(dir, v);
112
+ }
113
+ for (const f of allFiles) {
114
+ const parts = f.dir === '.' ? [] : f.dir.split(path.sep);
115
+ let acc = '';
116
+ for (let i = 0; i < parts.length; i++) {
117
+ acc = i === 0 ? parts[0] : acc + path.sep + parts[i];
118
+ addDirBytes(acc, f.size);
119
+ }
120
+ if (parts.length === 0) addDirBytes('.', f.size);
121
+ }
122
+ return [...byDirectory.values()].sort((a, b) => b.bytes - a.bytes);
123
+ }
124
+
125
+ function computeDepthAndLongest(allFiles) {
126
+ const depthDistribution = new Map();
127
+ for (const f of allFiles) {
128
+ depthDistribution.set(f.depth, (depthDistribution.get(f.depth) || 0) + 1);
129
+ }
130
+ const longestPaths = [...allFiles]
131
+ .sort((a, b) => b.path.length - a.path.length)
132
+ .slice(0, 25)
133
+ .map((f) => ({ path: f.path, length: f.path.length, size: f.size }));
134
+ const depthDist = [...depthDistribution.entries()]
135
+ .sort((a, b) => a[0] - b[0])
136
+ .map(([depth, count]) => ({ depth, count }));
137
+ return { depthDist, longestPaths };
138
+ }
139
+
140
+ function computeTemporal(allFiles, nowMs) {
141
+ let oldest = null,
142
+ newest = null;
143
+ const ageBuckets = [
144
+ { label: '> 1 year', minDays: 365, maxDays: Infinity, count: 0, bytes: 0 },
145
+ { label: '6–12 months', minDays: 180, maxDays: 365, count: 0, bytes: 0 },
146
+ { label: '1–6 months', minDays: 30, maxDays: 180, count: 0, bytes: 0 },
147
+ { label: '7–30 days', minDays: 7, maxDays: 30, count: 0, bytes: 0 },
148
+ { label: '1–7 days', minDays: 1, maxDays: 7, count: 0, bytes: 0 },
149
+ { label: '< 1 day', minDays: 0, maxDays: 1, count: 0, bytes: 0 },
150
+ ];
151
+ for (const f of allFiles) {
152
+ const ageDays = Math.max(0, (nowMs - (f.mtimeMs || nowMs)) / (24 * 60 * 60 * 1000));
153
+ for (const b of ageBuckets) {
154
+ if (ageDays >= b.minDays && ageDays < b.maxDays) {
155
+ b.count++;
156
+ b.bytes += f.size;
157
+ break;
158
+ }
159
+ }
160
+ if (!oldest || f.mtimeMs < oldest.mtimeMs) oldest = f;
161
+ if (!newest || f.mtimeMs > newest.mtimeMs) newest = f;
162
+ }
163
+ return {
164
+ oldest: oldest
165
+ ? { path: oldest.path, mtime: oldest.mtimeMs ? new Date(oldest.mtimeMs).toISOString() : null }
166
+ : null,
167
+ newest: newest
168
+ ? { path: newest.path, mtime: newest.mtimeMs ? new Date(newest.mtimeMs).toISOString() : null }
169
+ : null,
170
+ ageBuckets,
171
+ };
172
+ }
173
+
174
+ function computeQuality(allFiles, textFiles) {
175
+ const zeroByteFiles = allFiles.filter((f) => f.size === 0).length;
176
+ const emptyTextFiles = textFiles.filter(
177
+ (f) => (f.size || 0) === 0 || (f.lines || 0) === 0,
178
+ ).length;
179
+ const hiddenFiles = allFiles.filter((f) => f.hidden).length;
180
+ const symlinks = allFiles.filter((f) => f.isSymlink).length;
181
+ const largeThreshold = 50 * MB;
182
+ const suspiciousThreshold = 100 * MB;
183
+ const largeFilesCount = allFiles.filter((f) => f.size >= largeThreshold).length;
184
+ const suspiciousLargeFilesCount = allFiles.filter((f) => f.size >= suspiciousThreshold).length;
185
+ return {
186
+ zeroByteFiles,
187
+ emptyTextFiles,
188
+ hiddenFiles,
189
+ symlinks,
190
+ largeFilesCount,
191
+ suspiciousLargeFilesCount,
192
+ largeThreshold,
193
+ };
194
+ }
195
+
196
+ function computeDuplicates(allFiles, textFiles) {
197
+ const duplicatesBySize = new Map();
198
+ for (const f of allFiles) {
199
+ const key = String(f.size);
200
+ const arr = duplicatesBySize.get(key) || [];
201
+ arr.push(f);
202
+ duplicatesBySize.set(key, arr);
203
+ }
204
+ const duplicateCandidates = [];
205
+ for (const [sizeKey, arr] of duplicatesBySize.entries()) {
206
+ if (arr.length < 2) continue;
207
+ const textGroup = arr.filter((f) => !f.isBinary);
208
+ const otherGroup = arr.filter((f) => f.isBinary);
209
+ const contentHashGroups = new Map();
210
+ for (const tf of textGroup) {
211
+ try {
212
+ const src = textFiles.find((x) => x.absolutePath === tf.absolutePath);
213
+ const content = src ? src.content : '';
214
+ const h = crypto.createHash('sha1').update(content).digest('hex');
215
+ const g = contentHashGroups.get(h) || [];
216
+ g.push(tf);
217
+ contentHashGroups.set(h, g);
218
+ } catch {
219
+ /* ignore hashing errors for duplicate detection */
220
+ }
221
+ }
222
+ for (const [_h, g] of contentHashGroups.entries()) {
223
+ if (g.length > 1)
224
+ duplicateCandidates.push({
225
+ reason: 'same-size+text-hash',
226
+ size: Number(sizeKey),
227
+ count: g.length,
228
+ files: g.map((f) => f.path),
229
+ });
230
+ }
231
+ if (otherGroup.length > 1) {
232
+ duplicateCandidates.push({
233
+ reason: 'same-size',
234
+ size: Number(sizeKey),
235
+ count: otherGroup.length,
236
+ files: otherGroup.map((f) => f.path),
237
+ });
238
+ }
239
+ }
240
+ return duplicateCandidates;
241
+ }
242
+
243
+ function estimateCompressibility(textFiles) {
244
+ let compSampleBytes = 0;
245
+ let compCompressedBytes = 0;
246
+ for (const tf of textFiles) {
247
+ try {
248
+ const sampleLen = Math.min(256 * 1024, tf.size || 0);
249
+ if (sampleLen <= 0) continue;
250
+ const sample = tf.content.slice(0, sampleLen);
251
+ const gz = zlib.gzipSync(Buffer.from(sample, 'utf8'));
252
+ compSampleBytes += sampleLen;
253
+ compCompressedBytes += gz.length;
254
+ } catch {
255
+ /* ignore compression errors during sampling */
256
+ }
257
+ }
258
+ return compSampleBytes > 0 ? compCompressedBytes / compSampleBytes : null;
259
+ }
260
+
261
+ function computeGitInfo(allFiles, rootDir, largeThreshold) {
262
+ const info = {
263
+ isRepo: false,
264
+ trackedCount: 0,
265
+ trackedBytes: 0,
266
+ untrackedCount: 0,
267
+ untrackedBytes: 0,
268
+ lfsCandidates: [],
269
+ };
270
+ try {
271
+ if (!rootDir) return info;
272
+ const top = cp
273
+ .execFileSync('git', ['rev-parse', '--show-toplevel'], {
274
+ cwd: rootDir,
275
+ stdio: ['ignore', 'pipe', 'ignore'],
276
+ })
277
+ .toString()
278
+ .trim();
279
+ if (!top) return info;
280
+ info.isRepo = true;
281
+ const out = cp.execFileSync('git', ['ls-files', '-z'], {
282
+ cwd: rootDir,
283
+ stdio: ['ignore', 'pipe', 'ignore'],
284
+ });
285
+ const tracked = new Set(out.toString().split('\0').filter(Boolean));
286
+ let trackedBytes = 0,
287
+ trackedCount = 0,
288
+ untrackedBytes = 0,
289
+ untrackedCount = 0;
290
+ const lfsCandidates = [];
291
+ for (const f of allFiles) {
292
+ const isTracked = tracked.has(f.path);
293
+ if (isTracked) {
294
+ trackedCount++;
295
+ trackedBytes += f.size;
296
+ if (f.size >= largeThreshold) lfsCandidates.push({ path: f.path, size: f.size });
297
+ } else {
298
+ untrackedCount++;
299
+ untrackedBytes += f.size;
300
+ }
301
+ }
302
+ info.trackedCount = trackedCount;
303
+ info.trackedBytes = trackedBytes;
304
+ info.untrackedCount = untrackedCount;
305
+ info.untrackedBytes = untrackedBytes;
306
+ info.lfsCandidates = lfsCandidates.sort((a, b) => b.size - a.size).slice(0, 50);
307
+ } catch {
308
+ /* git not available or not a repo, ignore */
309
+ }
310
+ return info;
311
+ }
312
+
313
+ function computeLargestFiles(allFiles, totalBytes) {
314
+ const toPct = (num, den) => (den === 0 ? 0 : (num / den) * 100);
315
+ return [...allFiles]
316
+ .sort((a, b) => b.size - a.size)
317
+ .slice(0, 50)
318
+ .map((f) => ({
319
+ path: f.path,
320
+ size: f.size,
321
+ sizeFormatted: formatSize(f.size),
322
+ percentOfTotal: toPct(f.size, totalBytes),
323
+ ext: f.ext || '',
324
+ isBinary: f.isBinary,
325
+ mtime: f.mtimeMs ? new Date(f.mtimeMs).toISOString() : null,
326
+ }));
327
+ }
328
+
329
+ function mdTable(rows, headers) {
330
+ const header = `| ${headers.join(' | ')} |`;
331
+ const sep = `| ${headers.map(() => '---').join(' | ')} |`;
332
+ const body = rows.map((r) => `| ${r.join(' | ')} |`).join('\n');
333
+ return `${header}\n${sep}\n${body}`;
334
+ }
335
+
336
+ function buildMarkdownReport(largestFiles, byExtensionArr, byDirectoryArr, totalBytes) {
337
+ const toPct = (num, den) => (den === 0 ? 0 : (num / den) * 100);
338
+ const md = [];
339
+ md.push(
340
+ '\n### Top Largest Files (Top 50)\n',
341
+ mdTable(
342
+ largestFiles.map((f) => [
343
+ f.path,
344
+ f.sizeFormatted,
345
+ `${f.percentOfTotal.toFixed(2)}%`,
346
+ f.ext || '',
347
+ f.isBinary ? 'binary' : 'text',
348
+ ]),
349
+ ['Path', 'Size', '% of total', 'Ext', 'Type'],
350
+ ),
351
+ '\n\n### Top Extensions by Bytes (Top 20)\n',
352
+ );
353
+ const topExtRows = byExtensionArr
354
+ .slice(0, 20)
355
+ .map((e) => [
356
+ e.ext,
357
+ String(e.count),
358
+ formatSize(e.bytes),
359
+ `${toPct(e.bytes, totalBytes).toFixed(2)}%`,
360
+ ]);
361
+ md.push(
362
+ mdTable(topExtRows, ['Ext', 'Count', 'Bytes', '% of total']),
363
+ '\n\n### Top Directories by Bytes (Top 20)\n',
364
+ );
365
+ const topDirRows = byDirectoryArr
366
+ .slice(0, 20)
367
+ .map((d) => [
368
+ d.dir,
369
+ String(d.count),
370
+ formatSize(d.bytes),
371
+ `${toPct(d.bytes, totalBytes).toFixed(2)}%`,
372
+ ]);
373
+ md.push(mdTable(topDirRows, ['Directory', 'Files', 'Bytes', '% of total']));
374
+ return md.join('\n');
375
+ }
376
+
377
+ module.exports = {
378
+ KB,
379
+ MB,
380
+ formatSize,
381
+ percentile,
382
+ processWithLimit,
383
+ enrichAllFiles,
384
+ buildHistogram,
385
+ aggregateByExtension,
386
+ aggregateByDirectory,
387
+ computeDepthAndLongest,
388
+ computeTemporal,
389
+ computeQuality,
390
+ computeDuplicates,
391
+ estimateCompressibility,
392
+ computeGitInfo,
393
+ computeLargestFiles,
394
+ buildMarkdownReport,
395
+ };