@dtt_siye/atool 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +235 -0
  3. package/VERSION +1 -0
  4. package/agents/code-reviewer.md +29 -0
  5. package/bin/atool.js +235 -0
  6. package/bin/postinstall.js +23 -0
  7. package/hooks/doc-sync-reminder +155 -0
  8. package/hooks/hooks-cursor.json +37 -0
  9. package/hooks/hooks.json +37 -0
  10. package/hooks/prompt-guard +135 -0
  11. package/hooks/session-start +286 -0
  12. package/install.sh +603 -0
  13. package/lib/analyze-source.sh +1265 -0
  14. package/lib/common.sh +1041 -0
  15. package/lib/compute-importance.sh +598 -0
  16. package/lib/detect-stack.sh +354 -0
  17. package/lib/generate-visualization.sh +266 -0
  18. package/lib/install-claude.sh +43 -0
  19. package/lib/install-cursor.sh +281 -0
  20. package/lib/install-hooks.sh +285 -0
  21. package/lib/install-kiro.sh +543 -0
  22. package/lib/install-mcp.sh +99 -0
  23. package/lib/install-skills.sh +129 -0
  24. package/lib/knowledge-graph.sh +1014 -0
  25. package/lib/multi-dimensional-analysis.sh +413 -0
  26. package/lib/pre-scan.sh +1045 -0
  27. package/lib/project-init.sh +552 -0
  28. package/lib/visualization-template.html +545 -0
  29. package/mcp/recommended.json +24 -0
  30. package/package.json +39 -0
  31. package/skills/_superpowers/.claude-plugin/marketplace.json +20 -0
  32. package/skills/_superpowers/.claude-plugin/plugin.json +20 -0
  33. package/skills/_superpowers/.codex/INSTALL.md +67 -0
  34. package/skills/_superpowers/.cursor-plugin/plugin.json +25 -0
  35. package/skills/_superpowers/.gitattributes +18 -0
  36. package/skills/_superpowers/.github/FUNDING.yml +3 -0
  37. package/skills/_superpowers/.github/ISSUE_TEMPLATE/bug_report.md +52 -0
  38. package/skills/_superpowers/.github/ISSUE_TEMPLATE/config.yml +5 -0
  39. package/skills/_superpowers/.github/ISSUE_TEMPLATE/feature_request.md +34 -0
  40. package/skills/_superpowers/.github/ISSUE_TEMPLATE/platform_support.md +23 -0
  41. package/skills/_superpowers/.github/PULL_REQUEST_TEMPLATE.md +87 -0
  42. package/skills/_superpowers/.opencode/INSTALL.md +83 -0
  43. package/skills/_superpowers/.opencode/plugins/superpowers.js +107 -0
  44. package/skills/_superpowers/CHANGELOG.md +13 -0
  45. package/skills/_superpowers/CODE_OF_CONDUCT.md +128 -0
  46. package/skills/_superpowers/GEMINI.md +2 -0
  47. package/skills/_superpowers/LICENSE +21 -0
  48. package/skills/_superpowers/README.md +187 -0
  49. package/skills/_superpowers/RELEASE-NOTES.md +1083 -0
  50. package/skills/_superpowers/agents/code-reviewer.md +48 -0
  51. package/skills/_superpowers/commands/brainstorm.md +5 -0
  52. package/skills/_superpowers/commands/execute-plan.md +5 -0
  53. package/skills/_superpowers/commands/write-plan.md +5 -0
  54. package/skills/_superpowers/docs/README.codex.md +126 -0
  55. package/skills/_superpowers/docs/README.opencode.md +130 -0
  56. package/skills/_superpowers/docs/plans/2025-11-22-opencode-support-design.md +294 -0
  57. package/skills/_superpowers/docs/plans/2025-11-22-opencode-support-implementation.md +1095 -0
  58. package/skills/_superpowers/docs/plans/2025-11-28-skills-improvements-from-user-feedback.md +711 -0
  59. package/skills/_superpowers/docs/plans/2026-01-17-visual-brainstorming.md +571 -0
  60. package/skills/_superpowers/docs/superpowers/plans/2026-01-22-document-review-system.md +301 -0
  61. package/skills/_superpowers/docs/superpowers/plans/2026-02-19-visual-brainstorming-refactor.md +523 -0
  62. package/skills/_superpowers/docs/superpowers/plans/2026-03-11-zero-dep-brainstorm-server.md +479 -0
  63. package/skills/_superpowers/docs/superpowers/plans/2026-03-23-codex-app-compatibility.md +564 -0
  64. package/skills/_superpowers/docs/superpowers/specs/2026-01-22-document-review-system-design.md +136 -0
  65. package/skills/_superpowers/docs/superpowers/specs/2026-02-19-visual-brainstorming-refactor-design.md +162 -0
  66. package/skills/_superpowers/docs/superpowers/specs/2026-03-11-zero-dep-brainstorm-server-design.md +118 -0
  67. package/skills/_superpowers/docs/superpowers/specs/2026-03-23-codex-app-compatibility-design.md +244 -0
  68. package/skills/_superpowers/docs/testing.md +303 -0
  69. package/skills/_superpowers/docs/windows/polyglot-hooks.md +212 -0
  70. package/skills/_superpowers/gemini-extension.json +6 -0
  71. package/skills/_superpowers/hooks/hooks-cursor.json +10 -0
  72. package/skills/_superpowers/hooks/hooks.json +16 -0
  73. package/skills/_superpowers/hooks/run-hook.cmd +46 -0
  74. package/skills/_superpowers/hooks/session-start +57 -0
  75. package/skills/_superpowers/package.json +6 -0
  76. package/skills/_superpowers/skills/brainstorming/SKILL.md +164 -0
  77. package/skills/_superpowers/skills/brainstorming/scripts/frame-template.html +214 -0
  78. package/skills/_superpowers/skills/brainstorming/scripts/helper.js +88 -0
  79. package/skills/_superpowers/skills/brainstorming/scripts/server.cjs +354 -0
  80. package/skills/_superpowers/skills/brainstorming/scripts/start-server.sh +148 -0
  81. package/skills/_superpowers/skills/brainstorming/scripts/stop-server.sh +56 -0
  82. package/skills/_superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  83. package/skills/_superpowers/skills/brainstorming/visual-companion.md +287 -0
  84. package/skills/_superpowers/skills/dispatching-parallel-agents/SKILL.md +182 -0
  85. package/skills/_superpowers/skills/executing-plans/SKILL.md +70 -0
  86. package/skills/_superpowers/skills/finishing-a-development-branch/SKILL.md +200 -0
  87. package/skills/_superpowers/skills/receiving-code-review/SKILL.md +213 -0
  88. package/skills/_superpowers/skills/requesting-code-review/SKILL.md +105 -0
  89. package/skills/_superpowers/skills/requesting-code-review/code-reviewer.md +146 -0
  90. package/skills/_superpowers/skills/subagent-driven-development/SKILL.md +277 -0
  91. package/skills/_superpowers/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
  92. package/skills/_superpowers/skills/subagent-driven-development/implementer-prompt.md +113 -0
  93. package/skills/_superpowers/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  94. package/skills/_superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
  95. package/skills/_superpowers/skills/systematic-debugging/SKILL.md +296 -0
  96. package/skills/_superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  97. package/skills/_superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
  98. package/skills/_superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
  99. package/skills/_superpowers/skills/systematic-debugging/find-polluter.sh +63 -0
  100. package/skills/_superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
  101. package/skills/_superpowers/skills/systematic-debugging/test-academic.md +14 -0
  102. package/skills/_superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
  103. package/skills/_superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
  104. package/skills/_superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
  105. package/skills/_superpowers/skills/test-driven-development/SKILL.md +371 -0
  106. package/skills/_superpowers/skills/test-driven-development/testing-anti-patterns.md +299 -0
  107. package/skills/_superpowers/skills/using-git-worktrees/SKILL.md +218 -0
  108. package/skills/_superpowers/skills/using-superpowers/SKILL.md +115 -0
  109. package/skills/_superpowers/skills/using-superpowers/references/codex-tools.md +100 -0
  110. package/skills/_superpowers/skills/using-superpowers/references/gemini-tools.md +33 -0
  111. package/skills/_superpowers/skills/verification-before-completion/SKILL.md +139 -0
  112. package/skills/_superpowers/skills/writing-plans/SKILL.md +152 -0
  113. package/skills/_superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  114. package/skills/_superpowers/skills/writing-skills/SKILL.md +655 -0
  115. package/skills/_superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
  116. package/skills/_superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  117. package/skills/_superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
  118. package/skills/_superpowers/skills/writing-skills/persuasion-principles.md +187 -0
  119. package/skills/_superpowers/skills/writing-skills/render-graphs.js +168 -0
  120. package/skills/_superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
  121. package/skills/_superpowers/tests/brainstorm-server/package-lock.json +36 -0
  122. package/skills/_superpowers/tests/brainstorm-server/package.json +10 -0
  123. package/skills/_superpowers/tests/brainstorm-server/server.test.js +427 -0
  124. package/skills/_superpowers/tests/brainstorm-server/windows-lifecycle.test.sh +351 -0
  125. package/skills/_superpowers/tests/brainstorm-server/ws-protocol.test.js +392 -0
  126. package/skills/_superpowers/tests/claude-code/README.md +158 -0
  127. package/skills/_superpowers/tests/claude-code/analyze-token-usage.py +168 -0
  128. package/skills/_superpowers/tests/claude-code/run-skill-tests.sh +187 -0
  129. package/skills/_superpowers/tests/claude-code/test-document-review-system.sh +177 -0
  130. package/skills/_superpowers/tests/claude-code/test-helpers.sh +202 -0
  131. package/skills/_superpowers/tests/claude-code/test-subagent-driven-development-integration.sh +314 -0
  132. package/skills/_superpowers/tests/claude-code/test-subagent-driven-development.sh +165 -0
  133. package/skills/_superpowers/tests/explicit-skill-requests/prompts/action-oriented.txt +3 -0
  134. package/skills/_superpowers/tests/explicit-skill-requests/prompts/after-planning-flow.txt +17 -0
  135. package/skills/_superpowers/tests/explicit-skill-requests/prompts/claude-suggested-it.txt +11 -0
  136. package/skills/_superpowers/tests/explicit-skill-requests/prompts/i-know-what-sdd-means.txt +8 -0
  137. package/skills/_superpowers/tests/explicit-skill-requests/prompts/mid-conversation-execute-plan.txt +3 -0
  138. package/skills/_superpowers/tests/explicit-skill-requests/prompts/please-use-brainstorming.txt +1 -0
  139. package/skills/_superpowers/tests/explicit-skill-requests/prompts/skip-formalities.txt +3 -0
  140. package/skills/_superpowers/tests/explicit-skill-requests/prompts/subagent-driven-development-please.txt +1 -0
  141. package/skills/_superpowers/tests/explicit-skill-requests/prompts/use-systematic-debugging.txt +1 -0
  142. package/skills/_superpowers/tests/explicit-skill-requests/run-all.sh +70 -0
  143. package/skills/_superpowers/tests/explicit-skill-requests/run-claude-describes-sdd.sh +100 -0
  144. package/skills/_superpowers/tests/explicit-skill-requests/run-extended-multiturn-test.sh +113 -0
  145. package/skills/_superpowers/tests/explicit-skill-requests/run-haiku-test.sh +144 -0
  146. package/skills/_superpowers/tests/explicit-skill-requests/run-multiturn-test.sh +143 -0
  147. package/skills/_superpowers/tests/explicit-skill-requests/run-test.sh +136 -0
  148. package/skills/_superpowers/tests/opencode/run-tests.sh +163 -0
  149. package/skills/_superpowers/tests/opencode/setup.sh +73 -0
  150. package/skills/_superpowers/tests/opencode/test-plugin-loading.sh +72 -0
  151. package/skills/_superpowers/tests/opencode/test-priority.sh +198 -0
  152. package/skills/_superpowers/tests/opencode/test-tools.sh +104 -0
  153. package/skills/_superpowers/tests/skill-triggering/prompts/dispatching-parallel-agents.txt +8 -0
  154. package/skills/_superpowers/tests/skill-triggering/prompts/executing-plans.txt +1 -0
  155. package/skills/_superpowers/tests/skill-triggering/prompts/requesting-code-review.txt +3 -0
  156. package/skills/_superpowers/tests/skill-triggering/prompts/systematic-debugging.txt +11 -0
  157. package/skills/_superpowers/tests/skill-triggering/prompts/test-driven-development.txt +7 -0
  158. package/skills/_superpowers/tests/skill-triggering/prompts/writing-plans.txt +10 -0
  159. package/skills/_superpowers/tests/skill-triggering/run-all.sh +60 -0
  160. package/skills/_superpowers/tests/skill-triggering/run-test.sh +88 -0
  161. package/skills/_superpowers/tests/subagent-driven-dev/go-fractals/design.md +81 -0
  162. package/skills/_superpowers/tests/subagent-driven-dev/go-fractals/plan.md +172 -0
  163. package/skills/_superpowers/tests/subagent-driven-dev/go-fractals/scaffold.sh +45 -0
  164. package/skills/_superpowers/tests/subagent-driven-dev/run-test.sh +106 -0
  165. package/skills/_superpowers/tests/subagent-driven-dev/svelte-todo/design.md +70 -0
  166. package/skills/_superpowers/tests/subagent-driven-dev/svelte-todo/plan.md +222 -0
  167. package/skills/_superpowers/tests/subagent-driven-dev/svelte-todo/scaffold.sh +46 -0
  168. package/skills/ai-project-architecture/SKILL.md +632 -0
  169. package/skills/ai-project-architecture/reference/structure-rules.md +406 -0
  170. package/skills/ai-project-architecture/templates/compliance-report.md +300 -0
  171. package/skills/ai-project-architecture/templates/migration-plan.md +433 -0
  172. package/skills/ai-project-architecture/templates/verification-checklist.md +408 -0
  173. package/skills/android-conventions/SKILL.md +125 -0
  174. package/skills/atool-init/SKILL.md +141 -0
  175. package/skills/clarify-before-build/SKILL.md +107 -0
  176. package/skills/code-review/SKILL.md +406 -0
  177. package/skills/code-review/rules/architecture.md +285 -0
  178. package/skills/code-review/rules/coupling-cohesion.md +309 -0
  179. package/skills/code-review/rules/dead-code.md +115 -0
  180. package/skills/code-review/rules/deprecation-debt.md +279 -0
  181. package/skills/code-review/rules/duplication.md +104 -0
  182. package/skills/code-review/rules/error-security.md +143 -0
  183. package/skills/code-review/rules/maintainability.md +203 -0
  184. package/skills/code-review/rules/quality.md +158 -0
  185. package/skills/devops-conventions/SKILL.md +205 -0
  186. package/skills/doc-coauthoring/SKILL.md +392 -0
  187. package/skills/doc-standards-enforcer/SKILL.md +290 -0
  188. package/skills/doc-standards-enforcer/examples/valid-document-example.md +67 -0
  189. package/skills/doc-standards-enforcer/references/101-standards-summary.md +318 -0
  190. package/skills/doc-standards-enforcer/scripts/check_references.py +175 -0
  191. package/skills/doc-standards-enforcer/scripts/fix_common_issues.py +303 -0
  192. package/skills/doc-standards-enforcer/scripts/validate_doc_standards.py +332 -0
  193. package/skills/docx/LICENSE.txt +30 -0
  194. package/skills/docx/SKILL.md +200 -0
  195. package/skills/docx/docx-js.md +350 -0
  196. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  197. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  198. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  199. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  200. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  201. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  202. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  203. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  204. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  205. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  206. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  207. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  208. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  209. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  210. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  211. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  212. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  213. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  214. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  215. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  216. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  217. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  218. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  219. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  220. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  221. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  222. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  223. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  224. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  225. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  226. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  227. package/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
  228. package/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  229. package/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  230. package/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  231. package/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  232. package/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  233. package/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  234. package/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  235. package/skills/docx/ooxml/scripts/pack.py +159 -0
  236. package/skills/docx/ooxml/scripts/unpack.py +29 -0
  237. package/skills/docx/ooxml/scripts/validate.py +69 -0
  238. package/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
  239. package/skills/docx/ooxml/scripts/validation/base.py +951 -0
  240. package/skills/docx/ooxml/scripts/validation/docx.py +274 -0
  241. package/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
  242. package/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
  243. package/skills/docx/ooxml.md +610 -0
  244. package/skills/docx/scripts/__init__.py +1 -0
  245. package/skills/docx/scripts/document.py +1276 -0
  246. package/skills/docx/scripts/templates/comments.xml +3 -0
  247. package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  248. package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  249. package/skills/docx/scripts/templates/commentsIds.xml +3 -0
  250. package/skills/docx/scripts/templates/people.xml +3 -0
  251. package/skills/docx/scripts/utilities.py +374 -0
  252. package/skills/flutter-conventions/SKILL.md +70 -0
  253. package/skills/go-conventions/SKILL.md +230 -0
  254. package/skills/harmony-conventions/SKILL.md +156 -0
  255. package/skills/java-conventions/SKILL.md +277 -0
  256. package/skills/pdf/LICENSE.txt +30 -0
  257. package/skills/pdf/SKILL.md +297 -0
  258. package/skills/pdf/forms.md +205 -0
  259. package/skills/pdf/reference.md +612 -0
  260. package/skills/pdf/scripts/check_bounding_boxes.py +70 -0
  261. package/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  262. package/skills/pdf/scripts/check_fillable_fields.py +12 -0
  263. package/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  264. package/skills/pdf/scripts/create_validation_image.py +41 -0
  265. package/skills/pdf/scripts/extract_form_field_info.py +152 -0
  266. package/skills/pdf/scripts/fill_fillable_fields.py +114 -0
  267. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  268. package/skills/pptx/LICENSE.txt +30 -0
  269. package/skills/pptx/SKILL.md +487 -0
  270. package/skills/pptx/html2pptx.md +625 -0
  271. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  272. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  273. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  274. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  275. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  276. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  277. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  278. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  279. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  280. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  281. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  282. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  283. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  284. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  285. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  286. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  287. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  288. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  289. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  290. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  291. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  292. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  293. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  294. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  295. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  296. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  297. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  298. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  299. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  300. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  301. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  302. package/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  303. package/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  304. package/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  305. package/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  306. package/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  307. package/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  308. package/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  309. package/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  310. package/skills/pptx/ooxml/scripts/pack.py +159 -0
  311. package/skills/pptx/ooxml/scripts/unpack.py +29 -0
  312. package/skills/pptx/ooxml/scripts/validate.py +69 -0
  313. package/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
  314. package/skills/pptx/ooxml/scripts/validation/base.py +951 -0
  315. package/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
  316. package/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
  317. package/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
  318. package/skills/pptx/ooxml.md +427 -0
  319. package/skills/pptx/scripts/html2pptx.js +979 -0
  320. package/skills/pptx/scripts/inventory.py +1020 -0
  321. package/skills/pptx/scripts/rearrange.py +231 -0
  322. package/skills/pptx/scripts/replace.py +385 -0
  323. package/skills/pptx/scripts/thumbnail.py +450 -0
  324. package/skills/project-analyze/SKILL.md +270 -0
  325. package/skills/project-analyze/phases/phase0-discovery.md +278 -0
  326. package/skills/project-analyze/phases/phase0.5-prescan.md +139 -0
  327. package/skills/project-analyze/phases/phase1-inventory.md +94 -0
  328. package/skills/project-analyze/phases/phase2-deep-analysis.md +249 -0
  329. package/skills/project-analyze/phases/phase2a-l4-analysis.md +94 -0
  330. package/skills/project-analyze/phases/phase2b-l5-analysis.md +97 -0
  331. package/skills/project-analyze/phases/phase3-knowledge-graph.md +120 -0
  332. package/skills/project-analyze/phases/phase3a-multi-dimensional.md +61 -0
  333. package/skills/project-analyze/phases/phase4-code-quality.md +81 -0
  334. package/skills/project-analyze/phases/phase5-synthesis.md +284 -0
  335. package/skills/project-analyze/phases/phase6-validation.md +179 -0
  336. package/skills/project-analyze/prompts/code-review-agent.md +122 -0
  337. package/skills/project-analyze/prompts/deep-analysis-agent.md +107 -0
  338. package/skills/project-analyze/prompts/inventory-agent.md +67 -0
  339. package/skills/project-analyze/prompts/l4-analysis-agent.md +98 -0
  340. package/skills/project-analyze/rules/android.md +282 -0
  341. package/skills/project-analyze/rules/devops.md +443 -0
  342. package/skills/project-analyze/rules/generic.md +243 -0
  343. package/skills/project-analyze/rules/go.md +289 -0
  344. package/skills/project-analyze/rules/harmony.md +257 -0
  345. package/skills/project-analyze/rules/java.md +507 -0
  346. package/skills/project-analyze/rules/mobile-flutter.md +315 -0
  347. package/skills/project-analyze/rules/mobile-react-native.md +283 -0
  348. package/skills/project-analyze/rules/mobile-swift.md +323 -0
  349. package/skills/project-analyze/rules/python.md +317 -0
  350. package/skills/project-analyze/rules/rust-tauri.md +243 -0
  351. package/skills/project-analyze/rules/rust.md +296 -0
  352. package/skills/project-analyze/rules/web-nextjs.md +364 -0
  353. package/skills/project-analyze/rules/web-react.md +298 -0
  354. package/skills/project-analyze/rules/web-vue.md +378 -0
  355. package/skills/project-analyze/rules/web.md +390 -0
  356. package/skills/project-query/SKILL.md +224 -0
  357. package/skills/project-query/rules/query-templates.md +212 -0
  358. package/skills/python-conventions/SKILL.md +169 -0
  359. package/skills/react-native-conventions/SKILL.md +73 -0
  360. package/skills/requirements-writer/README.md +153 -0
  361. package/skills/requirements-writer/SKILL.md +341 -0
  362. package/skills/requirements-writer/examples/prd-outline-example.md +217 -0
  363. package/skills/requirements-writer/templates/module-prd-template.md +362 -0
  364. package/skills/requirements-writer/templates/prd-outline-template.md +185 -0
  365. package/skills/requirements-writer/templates/user-story-template.md +1125 -0
  366. package/skills/rust-conventions/SKILL.md +361 -0
  367. package/skills/smart-dispatch/SKILL.md +296 -0
  368. package/skills/smart-dispatch/implementer-prompt.md +146 -0
  369. package/skills/smart-dispatch/reviewer-prompt.md +199 -0
  370. package/skills/software-architecture/SKILL.md +278 -0
  371. package/skills/swift-conventions/SKILL.md +72 -0
  372. package/skills/ui-ux-pro/SKILL.md +140 -0
  373. package/skills/verification-before-completion/SKILL.md +119 -0
  374. package/skills/web-conventions/SKILL.md +259 -0
  375. package/skills/webapp-testing/LICENSE.txt +202 -0
  376. package/skills/webapp-testing/SKILL.md +97 -0
  377. package/skills/webapp-testing/examples/console_logging.py +35 -0
  378. package/skills/webapp-testing/examples/element_discovery.py +40 -0
  379. package/skills/webapp-testing/examples/static_html_automation.py +33 -0
  380. package/skills/webapp-testing/scripts/with_server.py +106 -0
  381. package/skills/writing-plans/SKILL.md +144 -0
  382. package/skills/xlsx/LICENSE.txt +30 -0
  383. package/skills/xlsx/SKILL.md +292 -0
  384. package/skills/xlsx/recalc.py +178 -0
  385. package/templates/CLAUDE.md.android +57 -0
  386. package/templates/CLAUDE.md.devops +50 -0
  387. package/templates/CLAUDE.md.generic +34 -0
  388. package/templates/CLAUDE.md.go +67 -0
  389. package/templates/CLAUDE.md.harmony +54 -0
  390. package/templates/CLAUDE.md.java +56 -0
  391. package/templates/CLAUDE.md.mobile-flutter +38 -0
  392. package/templates/CLAUDE.md.mobile-react-native +37 -0
  393. package/templates/CLAUDE.md.mobile-swift +40 -0
  394. package/templates/CLAUDE.md.python +65 -0
  395. package/templates/CLAUDE.md.rust +68 -0
  396. package/templates/CLAUDE.md.rust-tauri +120 -0
  397. package/templates/CLAUDE.md.web +63 -0
  398. package/templates/COMPONENT.md.android +58 -0
  399. package/templates/COMPONENT.md.devops +54 -0
  400. package/templates/COMPONENT.md.generic +35 -0
  401. package/templates/COMPONENT.md.go +59 -0
  402. package/templates/COMPONENT.md.harmony +63 -0
  403. package/templates/COMPONENT.md.java +69 -0
  404. package/templates/COMPONENT.md.mobile-flutter +56 -0
  405. package/templates/COMPONENT.md.mobile-react-native +55 -0
  406. package/templates/COMPONENT.md.mobile-swift +56 -0
  407. package/templates/COMPONENT.md.python +67 -0
  408. package/templates/COMPONENT.md.rust +57 -0
  409. package/templates/COMPONENT.md.rust-tauri +66 -0
  410. package/templates/COMPONENT.md.web +39 -0
  411. package/templates/README.md.android +71 -0
  412. package/templates/README.md.devops +68 -0
  413. package/templates/README.md.generic +39 -0
  414. package/templates/README.md.go +70 -0
  415. package/templates/README.md.harmony +72 -0
  416. package/templates/README.md.java +73 -0
  417. package/templates/README.md.mobile-flutter +69 -0
  418. package/templates/README.md.mobile-react-native +65 -0
  419. package/templates/README.md.mobile-swift +69 -0
  420. package/templates/README.md.monorepo +59 -0
  421. package/templates/README.md.python +66 -0
  422. package/templates/README.md.rust +69 -0
  423. package/templates/README.md.rust-tauri +149 -0
  424. package/templates/README.md.web +94 -0
  425. package/templates/UI_STYLE.md.android +74 -0
  426. package/templates/UI_STYLE.md.devops +50 -0
  427. package/templates/UI_STYLE.md.generic +31 -0
  428. package/templates/UI_STYLE.md.go +49 -0
  429. package/templates/UI_STYLE.md.harmony +71 -0
  430. package/templates/UI_STYLE.md.java +61 -0
  431. package/templates/UI_STYLE.md.mobile-flutter +70 -0
  432. package/templates/UI_STYLE.md.mobile-react-native +71 -0
  433. package/templates/UI_STYLE.md.mobile-swift +71 -0
  434. package/templates/UI_STYLE.md.python +58 -0
  435. package/templates/UI_STYLE.md.rust +52 -0
  436. package/templates/UI_STYLE.md.rust-tauri +102 -0
  437. package/templates/UI_STYLE.md.web +92 -0
  438. package/templates/cursor-rules.android.mdc +33 -0
  439. package/templates/cursor-rules.devops.mdc +32 -0
  440. package/templates/cursor-rules.generic.mdc +25 -0
  441. package/templates/cursor-rules.go.mdc +34 -0
  442. package/templates/cursor-rules.harmony.mdc +30 -0
  443. package/templates/cursor-rules.java.mdc +30 -0
  444. package/templates/cursor-rules.mobile-flutter.mdc +42 -0
  445. package/templates/cursor-rules.mobile-react-native.mdc +43 -0
  446. package/templates/cursor-rules.mobile-swift.mdc +42 -0
  447. package/templates/cursor-rules.python.mdc +33 -0
  448. package/templates/cursor-rules.rust-tauri.mdc +67 -0
  449. package/templates/cursor-rules.rust.mdc +30 -0
  450. package/templates/cursor-rules.web.mdc +30 -0
  451. package/templates/kiro-steering.android.md +39 -0
  452. package/templates/kiro-steering.devops.md +32 -0
  453. package/templates/kiro-steering.generic.md +28 -0
  454. package/templates/kiro-steering.go.md +41 -0
  455. package/templates/kiro-steering.harmony.md +36 -0
  456. package/templates/kiro-steering.java.md +37 -0
  457. package/templates/kiro-steering.mobile-flutter.md +73 -0
  458. package/templates/kiro-steering.mobile-react-native.md +71 -0
  459. package/templates/kiro-steering.mobile-swift.md +62 -0
  460. package/templates/kiro-steering.python.md +34 -0
  461. package/templates/kiro-steering.rust-tauri.md +50 -0
  462. package/templates/kiro-steering.rust.md +36 -0
  463. package/templates/kiro-steering.web.md +41 -0
@@ -0,0 +1,1265 @@
1
+ #!/usr/bin/env bash
2
+ # aTool - lib/analyze-source.sh
3
+ # Bash-level source code analysis module for project documentation generation
4
+ # Pure bash implementation using find + grep + jq + wc — no AI/LLM required
5
+
6
+ set -euo pipefail
7
+
8
+ # ── Configuration ────────────────────────────────────────────────────────────
9
+
10
+ # Directories to exclude from scanning
11
+ ATOOL_SCAN_EXCLUDE_DIRS=(
12
+ "node_modules" ".git" "dist" "build" "target"
13
+ "vendor" "__pycache__" ".next" ".nuxt" ".output"
14
+ ".atool-docs" "coverage" ".cache" ".turbo"
15
+ )
16
+
17
+ # Max scan depth for directory listings
18
+ ATOOL_SCAN_MAX_DEPTH=3
19
+
20
+ # ── Internal Helpers ─────────────────────────────────────────────────────────
21
+
22
+ # Build find exclude arguments (space-separated for cross-shell compatibility)
23
+ _build_exclude_args() {
24
+ local args=""
25
+ for d in "${ATOOL_SCAN_EXCLUDE_DIRS[@]}"; do
26
+ args+="-not -path */${d}/* "
27
+ done
28
+ printf '%s' "$args"
29
+ }
30
+
31
+ # Count files matching a pattern in a directory
32
+ _count_files() {
33
+ local dir="$1" pattern="$2"
34
+ local exclude_args=()
35
+ for d in "${ATOOL_SCAN_EXCLUDE_DIRS[@]}"; do
36
+ exclude_args+=(-not -path "*/${d}/*")
37
+ done
38
+ # shellcheck disable=SC2068
39
+ find "$dir" -type f -name "$pattern" "${exclude_args[@]}" 2>/dev/null | wc -l | tr -d ' '
40
+ }
41
+
42
+ # Read package.json field safely
43
+ _pkg_field() {
44
+ local pkg="$1" field="$2"
45
+ if [[ -f "$pkg" ]]; then
46
+ # Use input field as raw jq expression
47
+ # Replace dots in key names with bracket notation for safety
48
+ local jq_expr
49
+ # Convert .x.y-z to .x["y-z"] for keys containing hyphens or @
50
+ jq_expr=$(echo "$field" | sed -E 's/\.([a-zA-Z_@][a-zA-Z0-9_-]*)/.\["\1"\]/g')
51
+ jq -r "${jq_expr} // empty" "$pkg" 2>/dev/null || true
52
+ fi
53
+ }
54
+
55
+ # Generic dependency detector: checks if any dep name from a list exists in package.json
56
+ # Args: PROJECT_DIR, DEP_NAME [DEP_NAME2...]
57
+ # Outputs: first matching dep name or empty
58
+ _has_dep() {
59
+ local pkg="$1"; shift
60
+ [[ ! -f "$pkg" ]] && return 1
61
+ for dep_name in "$@"; do
62
+ if jq -e --arg d "$dep_name" '(.dependencies // {} | has($d)) or (.devDependencies // {} | has($d))' "$pkg" &>/dev/null; then
63
+ echo "$dep_name"
64
+ return 0
65
+ fi
66
+ done
67
+ return 1
68
+ }
69
+
70
+ # ── Framework Detection ──────────────────────────────────────────────────────
71
+
72
+ detect_framework() {
73
+ local dir="$1"
74
+
75
+ # Tauri detection: check for src-tauri/ with Cargo.toml
76
+ if [[ -d "$dir/src-tauri" ]] && [[ -f "$dir/src-tauri/Cargo.toml" ]]; then
77
+ local frontend=""
78
+ local pkg="$dir/package.json"
79
+ if [[ -f "$pkg" ]]; then
80
+ if _has_dep "$pkg" "vue" &>/dev/null; then
81
+ frontend="Vue"
82
+ elif _has_dep "$pkg" "react" &>/dev/null; then
83
+ frontend="React"
84
+ elif _has_dep "$pkg" "svelte" &>/dev/null; then
85
+ frontend="Svelte"
86
+ fi
87
+ fi
88
+ if [[ -n "$frontend" ]]; then
89
+ echo "Tauri + ${frontend}"
90
+ else
91
+ echo "Tauri"
92
+ fi
93
+ return 0
94
+ fi
95
+
96
+ local pkg="$dir/package.json"
97
+ [[ ! -f "$pkg" ]] && return 0
98
+
99
+ local dep
100
+ if dep=$(_has_dep "$pkg" "next"); then
101
+ echo "Next.js"
102
+ elif dep=$(_has_dep "$pkg" "nuxt"); then
103
+ echo "Nuxt"
104
+ elif dep=$(_has_dep "$pkg" "vue"); then
105
+ echo "Vue"
106
+ elif dep=$(_has_dep "$pkg" "react"); then
107
+ echo "React"
108
+ elif dep=$(_has_dep "$pkg" "svelte"); then
109
+ echo "Svelte"
110
+ fi
111
+ }
112
+
113
+ detect_framework_version() {
114
+ local dir="$1"
115
+ local pkg="$dir/package.json"
116
+ [[ ! -f "$pkg" ]] && return 0
117
+
118
+ local framework
119
+ framework=$(detect_framework "$dir")
120
+
121
+ case "$framework" in
122
+ Vue) _pkg_field "$pkg" ".dependencies.vue" ;;
123
+ React) _pkg_field "$pkg" ".dependencies.react" ;;
124
+ Next.js) _pkg_field "$pkg" ".dependencies.next" ;;
125
+ Nuxt) _pkg_field "$pkg" ".dependencies.nuxt" ;;
126
+ Svelte) _pkg_field "$pkg" ".dependencies.svelte" ;;
127
+ *) ;;
128
+ esac
129
+ }
130
+
131
+ # ── UI Library Detection ─────────────────────────────────────────────────────
132
+
133
+ detect_ui_library() {
134
+ local dir="$1"
135
+ local pkg="$dir/package.json"
136
+ [[ ! -f "$pkg" ]] && return 0
137
+
138
+ local dep
139
+ # Order matters: more specific first
140
+ if dep=$(_has_dep "$pkg" "@arco-design/web-vue" "@arco-design/web-react"); then
141
+ case "$dep" in @arco-design/web-vue) echo "Arco Design Vue" ;; *) echo "Arco Design React" ;; esac
142
+ elif dep=$(_has_dep "$pkg" "ant-design-vue"); then
143
+ echo "Ant Design Vue"
144
+ elif dep=$(_has_dep "$pkg" "antd"); then
145
+ echo "Ant Design"
146
+ elif dep=$(_has_dep "$pkg" "element-plus"); then
147
+ echo "Element Plus"
148
+ elif dep=$(_has_dep "$pkg" "@mui/material" "material-ui"); then
149
+ echo "Material UI"
150
+ elif dep=$(_has_dep "$pkg" "vuetify"); then
151
+ echo "Vuetify"
152
+ elif dep=$(_has_dep "$pkg" "primevue"); then
153
+ echo "PrimeVue"
154
+ elif dep=$(_has_dep "$pkg" "naive-ui"); then
155
+ echo "Naive UI"
156
+ elif dep=$(_has_dep "$pkg" "@chakra-ui/react"); then
157
+ echo "Chakra UI"
158
+ elif dep=$(_has_dep "$pkg" "@radix-ui/react" "@headlessui/react"); then
159
+ echo "Headless UI"
160
+ elif dep=$(_has_dep "$pkg" "tailwindcss"); then
161
+ echo "Tailwind CSS (utility-first)"
162
+ elif dep=$(_has_dep "$pkg" "vant"); then
163
+ echo "Vant"
164
+ elif dep=$(_has_dep "$pkg" "bootstrap"); then
165
+ echo "Bootstrap"
166
+ fi
167
+ }
168
+
169
+ detect_ui_library_version() {
170
+ local dir="$1"
171
+ local pkg="$dir/package.json"
172
+ [[ ! -f "$pkg" ]] && return 0
173
+
174
+ local dep
175
+ dep=$(_has_dep "$pkg" "element-plus" "ant-design-vue" "antd" "vuetify" "primevue" "naive-ui" "@mui/material" "@chakra-ui/react" "tailwindcss" || true)
176
+ if [[ -n "$dep" ]]; then
177
+ _pkg_field "$pkg" ".dependencies.${dep}" || _pkg_field "$pkg" ".devDependencies.${dep}" || true
178
+ fi
179
+ }
180
+
181
+ # ── State Management Detection ───────────────────────────────────────────────
182
+
183
+ detect_state_management() {
184
+ local dir="$1"
185
+ local pkg="$dir/package.json"
186
+ [[ ! -f "$pkg" ]] && return 0
187
+
188
+ local dep
189
+ if dep=$(_has_dep "$pkg" "@reduxjs/toolkit"); then
190
+ echo "Redux Toolkit"
191
+ elif dep=$(_has_dep "$pkg" "pinia"); then
192
+ echo "Pinia"
193
+ elif dep=$(_has_dep "$pkg" "vuex"); then
194
+ echo "Vuex"
195
+ elif dep=$(_has_dep "$pkg" "redux"); then
196
+ echo "Redux"
197
+ elif dep=$(_has_dep "$pkg" "zustand"); then
198
+ echo "Zustand"
199
+ elif dep=$(_has_dep "$pkg" "mobx"); then
200
+ echo "MobX"
201
+ elif dep=$(_has_dep "$pkg" "recoil"); then
202
+ echo "Recoil"
203
+ elif dep=$(_has_dep "$pkg" "jotai"); then
204
+ echo "Jotai"
205
+ elif dep=$(_has_dep "$pkg" "effector"); then
206
+ echo "Effector"
207
+ fi
208
+ }
209
+
210
+ # ── Builder Detection ────────────────────────────────────────────────────────
211
+
212
+ detect_builder() {
213
+ local dir="$1"
214
+ local pkg="$dir/package.json"
215
+ [[ ! -f "$pkg" ]] && return 0
216
+
217
+ local dep
218
+ if dep=$(_has_dep "$pkg" "vite"); then
219
+ echo "Vite"
220
+ elif dep=$(_has_dep "$pkg" "rspack"); then
221
+ echo "Rspack"
222
+ elif dep=$(_has_dep "$pkg" "webpack"); then
223
+ echo "Webpack"
224
+ elif dep=$(_has_dep "$pkg" "next" "nuxt"); then
225
+ echo "${dep^} (built-in)"
226
+ elif dep=$(_has_dep "$pkg" "parcel"); then
227
+ echo "Parcel"
228
+ elif dep=$(_has_dep "$pkg" "esbuild"); then
229
+ echo "esbuild"
230
+ elif [[ -f "$dir/angular.json" ]]; then
231
+ echo "Angular CLI"
232
+ fi
233
+ }
234
+
235
+ # ── CSS Solution Detection ───────────────────────────────────────────────────
236
+
237
+ detect_css_solution() {
238
+ local dir="$1"
239
+ local pkg="$dir/package.json"
240
+ [[ ! -f "$pkg" ]] && return 0
241
+
242
+ local dep
243
+ if dep=$(_has_dep "$pkg" "tailwindcss"); then
244
+ echo "Tailwind CSS"
245
+ elif dep=$(_has_dep "$pkg" "sass"); then
246
+ echo "SCSS"
247
+ elif dep=$(_has_dep "$pkg" "less"); then
248
+ echo "Less"
249
+ elif dep=$(_has_dep "$pkg" "stylus"); then
250
+ echo "Stylus"
251
+ elif dep=$(_has_dep "$pkg" "unocss"); then
252
+ echo "UnoCSS"
253
+ elif dep=$(_has_dep "$pkg" "postcss"); then
254
+ echo "PostCSS"
255
+ fi
256
+ }
257
+
258
+ # ── Router Detection ─────────────────────────────────────────────────────────
259
+
260
+ detect_router() {
261
+ local dir="$1"
262
+ local pkg="$dir/package.json"
263
+ [[ ! -f "$pkg" ]] && return 0
264
+
265
+ local dep
266
+ if dep=$(_has_dep "$pkg" "vue-router"); then
267
+ echo "Vue Router"
268
+ elif dep=$(_has_dep "$pkg" "@tanstack/react-router"); then
269
+ echo "TanStack Router"
270
+ elif dep=$(_has_dep "$pkg" "react-router" "react-router-dom"); then
271
+ echo "React Router"
272
+ elif dep=$(_has_dep "$pkg" "next"); then
273
+ echo "Next.js App Router"
274
+ elif dep=$(_has_dep "$pkg" "nuxt"); then
275
+ echo "Nuxt Router"
276
+ elif dep=$(_has_dep "$pkg" "@sveltejs/kit"); then
277
+ echo "SvelteKit"
278
+ elif dep=$(_has_dep "$pkg" "svelte-spa-router"); then
279
+ echo "Svelte SPA Router"
280
+ elif dep=$(_has_dep "$pkg" "@angular/router"); then
281
+ echo "Angular Router"
282
+ fi
283
+ }
284
+
285
+ # ── HTTP Client Detection ────────────────────────────────────────────────────
286
+
287
+ detect_http_client() {
288
+ local dir="$1"
289
+ local pkg="$dir/package.json"
290
+ [[ ! -f "$pkg" ]] && return 0
291
+
292
+ local dep
293
+ if dep=$(_has_dep "$pkg" "axios"); then
294
+ echo "Axios"
295
+ elif dep=$(_has_dep "$pkg" "ky"); then
296
+ echo "Ky"
297
+ elif dep=$(_has_dep "$pkg" "ofetch"); then
298
+ echo "ofetch"
299
+ elif dep=$(_has_dep "$pkg" "@tanstack/query"); then
300
+ echo "TanStack Query"
301
+ elif dep=$(_has_dep "$pkg" "swr"); then
302
+ echo "SWR"
303
+ fi
304
+ }
305
+
306
+ # ── Package Manager Detection ────────────────────────────────────────────────
307
+
308
+ detect_package_manager() {
309
+ local dir="$1"
310
+
311
+ if [[ -f "$dir/pnpm-lock.yaml" ]]; then
312
+ echo "pnpm"
313
+ elif [[ -f "$dir/yarn.lock" ]]; then
314
+ echo "yarn"
315
+ elif [[ -f "$dir/package-lock.json" ]]; then
316
+ echo "npm"
317
+ elif [[ -f "$dir/bun.lockb" || -f "$dir/bun.lock" ]]; then
318
+ echo "bun"
319
+ elif [[ -f "$dir/package.json" ]]; then
320
+ echo "npm"
321
+ fi
322
+ }
323
+
324
+ # ── NPM Scripts Detection ────────────────────────────────────────────────────
325
+
326
+ get_npm_script() {
327
+ local dir="$1" script_name="$2"
328
+ local pkg="$dir/package.json"
329
+ [[ ! -f "$pkg" ]] && return 0
330
+ # Use bracket notation for script names with special chars (e.g. build:pro)
331
+ jq -r --arg name "$script_name" '.scripts[$name] // empty' "$pkg" 2>/dev/null || true
332
+ }
333
+
334
+ # ── Source File Scanning ─────────────────────────────────────────────────────
335
+
336
+ count_source_files() {
337
+ local dir="$1"
338
+ [[ ! -d "$dir" ]] && echo "0 files" && return 0
339
+
340
+ local total=0
341
+ local ts_count js_count vue_count svelte_count
342
+ local java_count kt_count swift_count dart_count py_count
343
+ local go_count rs_count ets_count sh_count
344
+ local css_count scss_count less_count html_count
345
+
346
+ ts_count=$(_count_files "$dir" "*.ts") && ts_count=$((ts_count - $(_count_files "$dir" "*.tsx") - $(_count_files "$dir" "*.d.ts")))
347
+ local tsx_count=$(_count_files "$dir" "*.tsx")
348
+ js_count=$(_count_files "$dir" "*.js") && js_count=$((js_count - $(_count_files "$dir" "*.jsx")))
349
+ local jsx_count=$(_count_files "$dir" "*.jsx")
350
+ vue_count=$(_count_files "$dir" "*.vue")
351
+ svelte_count=$(_count_files "$dir" "*.svelte")
352
+ java_count=$(_count_files "$dir" "*.java")
353
+ kt_count=$(_count_files "$dir" "*.kt")
354
+ swift_count=$(_count_files "$dir" "*.swift")
355
+ dart_count=$(_count_files "$dir" "*.dart")
356
+ py_count=$(_count_files "$dir" "*.py")
357
+ go_count=$(_count_files "$dir" "*.go")
358
+ rs_count=$(_count_files "$dir" "*.rs")
359
+ sh_count=$(_count_files "$dir" "*.sh")
360
+ css_count=$(_count_files "$dir" "*.css")
361
+ scss_count=$(_count_files "$dir" "*.scss")
362
+ less_count=$(_count_files "$dir" "*.less")
363
+ html_count=$(_count_files "$dir" "*.html")
364
+
365
+ # Sum with type grouping
366
+ local typescript=$((ts_count + tsx_count))
367
+ local javascript=$((js_count + jsx_count))
368
+ total=$((typescript + javascript + vue_count + svelte_count + java_count + kt_count + swift_count + dart_count + py_count + go_count + rs_count + sh_count + css_count + scss_count + less_count + html_count))
369
+
370
+ if [[ "$total" -eq 0 ]]; then
371
+ echo "0 files"
372
+ return 0
373
+ fi
374
+
375
+ local detail=""
376
+ [[ "$typescript" -gt 0 ]] && detail+="TypeScript: $typescript, "
377
+ [[ "$javascript" -gt 0 ]] && detail+="JavaScript: $javascript, "
378
+ [[ "$vue_count" -gt 0 ]] && detail+="Vue: $vue_count, "
379
+ [[ "$svelte_count" -gt 0 ]] && detail+="Svelte: $svelte_count, "
380
+ [[ "$java_count" -gt 0 ]] && detail+="Java: $java_count, "
381
+ [[ "$py_count" -gt 0 ]] && detail+="Python: $py_count, "
382
+ [[ "$scss_count" -gt 0 ]] && detail+="SCSS: $scss_count, "
383
+ [[ "$css_count" -gt 0 ]] && detail+="CSS: $css_count, "
384
+ [[ "$kt_count" -gt 0 ]] && detail+="Kotlin: $kt_count, "
385
+ [[ "$swift_count" -gt 0 ]] && detail+="Swift: $swift_count, "
386
+ [[ "$go_count" -gt 0 ]] && detail+="Go: $go_count, "
387
+ [[ "$rs_count" -gt 0 ]] && detail+="Rust: $rs_count, "
388
+ [[ "$dart_count" -gt 0 ]] && detail+="Dart: $dart_count, "
389
+
390
+ # Remove trailing ", "
391
+ detail="${detail%, }"
392
+
393
+ echo "${total} files (${detail})"
394
+ }
395
+
396
+ # Scan project structure tree
397
+ scan_project_structure() {
398
+ local dir="$1"
399
+ [[ ! -d "$dir" ]] && return 0
400
+
401
+ local src_dir=""
402
+ for candidate in "src" "lib" "app" "pkg"; do
403
+ if [[ -d "$dir/$candidate" ]]; then
404
+ src_dir="$dir/$candidate"
405
+ break
406
+ fi
407
+ done
408
+ [[ -z "$src_dir" ]] && src_dir="$dir"
409
+
410
+ local exclude_args=()
411
+ for d in "${ATOOL_SCAN_EXCLUDE_DIRS[@]}"; do
412
+ exclude_args+=(-not -path "*/${d}/*")
413
+ done
414
+ _print_tree "$src_dir" "" "$src_dir" 2 "${exclude_args[@]}"
415
+ }
416
+
417
+ _print_tree() {
418
+ local dir="$1" prefix="$2" base_dir="$3" max_depth="$4"
419
+ shift 4
420
+ # Remaining args are exclude predicates for find (array)
421
+ local -a exclude_args=("$@")
422
+
423
+ local depth=0
424
+ local tmp="$dir"
425
+ while [[ "$tmp" != "$base_dir" && "$tmp" != "/" ]]; do
426
+ tmp=$(dirname "$tmp")
427
+ depth=$((depth + 1))
428
+ done
429
+
430
+ if [[ "$depth" -ge "$max_depth" ]]; then
431
+ echo "${prefix}..."
432
+ return 0
433
+ fi
434
+
435
+ local entries
436
+ entries=$(ls -1A "$dir" 2>/dev/null | grep -v '^\.' | head -20 || true)
437
+ [[ -z "$entries" ]] && return 0
438
+
439
+ local count=0
440
+ local total
441
+ total=$(echo "$entries" | wc -l | tr -d ' ')
442
+
443
+ while IFS= read -r entry; do
444
+ [[ -z "$entry" ]] && continue
445
+ count=$((count + 1))
446
+
447
+ local is_last=false
448
+ [[ "$count" -eq "$total" ]] && is_last=true
449
+ local connector="├──"
450
+ $is_last && connector="└──"
451
+
452
+ local rel_path="${dir}/${entry}"
453
+ local entry_name="$entry"
454
+
455
+ if [[ -d "$rel_path" ]]; then
456
+ local file_count
457
+ file_count=$(find "$rel_path" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')
458
+ if [[ "$file_count" -gt 0 ]]; then
459
+ entry_name="${entry}/ (${file_count} files)"
460
+ else
461
+ entry_name="${entry}/"
462
+ fi
463
+ fi
464
+
465
+ echo "${prefix}${connector} ${entry_name}"
466
+
467
+ if [[ -d "$rel_path" ]]; then
468
+ local child_prefix
469
+ if $is_last; then
470
+ child_prefix="${prefix} "
471
+ else
472
+ child_prefix="${prefix}│ "
473
+ fi
474
+ _print_tree "$rel_path" "$child_prefix" "$base_dir" "$max_depth" "${exclude_args[@]}"
475
+ fi
476
+ done <<< "$entries"
477
+ }
478
+
479
+ # Generic scanner: finds files in a directory pattern
480
+ # Args: PROJECT_DIR, CANDIDATE_DIRS..., FILE_PATTERNS..., MAX_DEPTH
481
+ _scan_dir_files() {
482
+ local dir="$1"; shift
483
+ local target_dir=""
484
+
485
+ # First args are candidate directory paths
486
+ local candidates=()
487
+ local max_depth=2
488
+ while [[ $# -gt 0 ]]; do
489
+ case "$1" in
490
+ --depth)
491
+ max_depth="$2"
492
+ shift 2
493
+ ;;
494
+ *)
495
+ candidates+=("$1")
496
+ shift
497
+ ;;
498
+ esac
499
+ done
500
+
501
+ for candidate in "${candidates[@]}"; do
502
+ if [[ -d "$dir/$candidate" ]]; then
503
+ target_dir="$dir/$candidate"
504
+ break
505
+ fi
506
+ done
507
+ [[ -z "$target_dir" ]] && return 0
508
+
509
+ local output=""
510
+ while IFS= read -r file_path; do
511
+ [[ -z "$file_path" ]] && continue
512
+ local rel="${file_path#$dir/}"
513
+ local name
514
+ name=$(basename "$file_path" | sed 's/\.[^.]*$//')
515
+ output+="- **${name}** (\`${rel}\`)\n"
516
+ done < <(find "$target_dir" -maxdepth "$max_depth" -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.vue" -o -name "*.svelte" \) 2>/dev/null | sort)
517
+
518
+ echo -e "$output" | head -50
519
+ }
520
+
521
+ scan_components() {
522
+ local dir="$1"
523
+ local components_dir=""
524
+
525
+ for candidate in "src/components" "src/Components" "app/components" "components"; do
526
+ if [[ -d "$dir/$candidate" ]]; then
527
+ components_dir="$dir/$candidate"
528
+ break
529
+ fi
530
+ done
531
+ [[ -z "$components_dir" ]] && return 0
532
+
533
+ local output=""
534
+ while IFS= read -r comp_dir; do
535
+ [[ -z "$comp_dir" ]] && continue
536
+ [[ "$comp_dir" == "$components_dir" ]] && continue
537
+ local name
538
+ name=$(basename "$comp_dir")
539
+ local file_count
540
+ file_count=$(find "$comp_dir" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')
541
+ if [[ "$file_count" -gt 0 ]]; then
542
+ local rel="${comp_dir#$dir/}"
543
+ output+="- **${name}** (\`${rel}/\`, ${file_count} files)\n"
544
+ fi
545
+ done < <(find "$components_dir" -maxdepth 2 -type d 2>/dev/null | sort)
546
+
547
+ echo -e "$output" | head -50
548
+ }
549
+
550
+ scan_views() {
551
+ local dir="$1"
552
+ local views_dir=""
553
+ for candidate in "src/views" "src/pages" "src/screens" "app/pages" "pages"; do
554
+ if [[ -d "$dir/$candidate" ]]; then
555
+ views_dir="$dir/$candidate"
556
+ break
557
+ fi
558
+ done
559
+ [[ -z "$views_dir" ]] && return 0
560
+
561
+ local output=""
562
+ while IFS= read -r view_path; do
563
+ [[ -z "$view_path" ]] && continue
564
+ local rel="${view_path#$dir/}"
565
+ local name
566
+ name=$(basename "$view_path" | sed 's/\.[^.]*$//')
567
+ output+="- **${name}** (\`${rel}\`)\n"
568
+ done < <(find "$views_dir" -maxdepth 3 -type f \( -name "*.vue" -o -name "*.tsx" -o -name "*.jsx" -o -name "*.ts" \) 2>/dev/null | sort)
569
+
570
+ echo -e "$output" | head -50
571
+ }
572
+
573
+ scan_stores() {
574
+ local dir="$1"
575
+ local stores_dir=""
576
+ for candidate in "src/store" "src/stores" "src/store/modules" "app/store" "store" "stores"; do
577
+ if [[ -d "$dir/$candidate" ]]; then
578
+ stores_dir="$dir/$candidate"
579
+ break
580
+ fi
581
+ done
582
+ [[ -z "$stores_dir" ]] && return 0
583
+
584
+ local output=""
585
+ while IFS= read -r store_path; do
586
+ [[ -z "$store_path" ]] && continue
587
+ local base
588
+ base=$(basename "$store_path")
589
+ [[ "$base" == "index.ts" || "$base" == "index.js" ]] && continue
590
+ local rel="${store_path#$dir/}"
591
+ local name
592
+ name=$(echo "$base" | sed 's/\.[^.]*$//')
593
+ output+="- **${name}** (\`${rel}\`)\n"
594
+ done < <(find "$stores_dir" -maxdepth 2 -type f \( -name "*.ts" -o -name "*.js" \) 2>/dev/null | sort)
595
+
596
+ echo -e "$output" | head -30
597
+ }
598
+
599
+ scan_api_services() {
600
+ local dir="$1"
601
+ local api_dir=""
602
+ for candidate in "src/api" "src/apis" "src/services" "app/api" "api" "services"; do
603
+ if [[ -d "$dir/$candidate" ]]; then
604
+ api_dir="$dir/$candidate"
605
+ break
606
+ fi
607
+ done
608
+ [[ -z "$api_dir" ]] && return 0
609
+
610
+ local output=""
611
+ while IFS= read -r api_path; do
612
+ [[ -z "$api_path" ]] && continue
613
+ local rel="${api_path#$dir/}"
614
+ local name
615
+ name=$(basename "$api_path" | sed 's/\.[^.]*$//')
616
+ output+="- **${name}** (\`${rel}\`)\n"
617
+ done < <(find "$api_dir" -maxdepth 2 -type f \( -name "*.ts" -o -name "*.js" \) 2>/dev/null | sort)
618
+
619
+ echo -e "$output" | head -30
620
+ }
621
+
622
+ scan_hooks() {
623
+ local dir="$1"
624
+ local hooks_dir=""
625
+ for candidate in "src/hooks" "src/composables" "app/hooks" "hooks" "composables"; do
626
+ if [[ -d "$dir/$candidate" ]]; then
627
+ hooks_dir="$dir/$candidate"
628
+ break
629
+ fi
630
+ done
631
+ [[ -z "$hooks_dir" ]] && return 0
632
+
633
+ local output=""
634
+ while IFS= read -r hook_path; do
635
+ [[ -z "$hook_path" ]] && continue
636
+ local rel="${hook_path#$dir/}"
637
+ local name
638
+ name=$(basename "$hook_path" | sed 's/\.[^.]*$//')
639
+ output+="- **${name}** (\`${rel}\`)\n"
640
+ done < <(find "$hooks_dir" -maxdepth 2 -type f \( -name "*.ts" -o -name "*.js" \) 2>/dev/null | sort)
641
+
642
+ echo -e "$output" | head -30
643
+ }
644
+
645
+ scan_utils() {
646
+ local dir="$1"
647
+ local utils_dir=""
648
+ for candidate in "src/utils" "src/util" "src/helpers" "src/lib" "app/utils" "utils" "helpers" "lib"; do
649
+ if [[ -d "$dir/$candidate" ]]; then
650
+ utils_dir="$dir/$candidate"
651
+ break
652
+ fi
653
+ done
654
+ [[ -z "$utils_dir" ]] && return 0
655
+
656
+ local output=""
657
+ while IFS= read -r util_path; do
658
+ [[ -z "$util_path" ]] && continue
659
+ local rel="${util_path#$dir/}"
660
+ local name
661
+ name=$(basename "$util_path" | sed 's/\.[^.]*$//')
662
+ output+="- **${name}** (\`${rel}\`)\n"
663
+ done < <(find "$utils_dir" -maxdepth 2 -type f \( -name "*.ts" -o -name "*.js" \) 2>/dev/null | sort)
664
+
665
+ echo -e "$output" | head -30
666
+ }
667
+
668
+ scan_routes() {
669
+ local dir="$1"
670
+ local router_file=""
671
+ for candidate in "src/router/index.ts" "src/router/index.js" "src/router.ts" "src/router.js" "src/routes.ts" "src/routes/index.ts"; do
672
+ if [[ -f "$dir/$candidate" ]]; then
673
+ router_file="$dir/$candidate"
674
+ break
675
+ fi
676
+ done
677
+ [[ -z "$router_file" ]] && return 0
678
+
679
+ local output=""
680
+ while IFS= read -r line; do
681
+ [[ -z "$line" ]] && continue
682
+ local path_val
683
+ path_val=$(echo "$line" | grep -oE "path:[[:space:]]*['\"][^'\"]+['\"]" | head -1 | sed "s/path:[[:space:]]*//;s/['\"]//g" || true)
684
+ if [[ -n "$path_val" ]]; then
685
+ local component=""
686
+ if echo "$line" | grep -qE "component:"; then
687
+ component=$(echo "$line" | grep -oE "import\(['\"][^'\"]+['\"]\)" | sed "s/import(['\"]//;s/['\"])//" | grep -oE "[^/]+$" | sed 's/\.[^.]*$//' || true)
688
+ fi
689
+ output+="| ${path_val} | ${component:-} |\n"
690
+ fi
691
+ done < "$router_file"
692
+
693
+ if [[ -n "$output" ]]; then
694
+ echo "| 路径 | 组件 |"
695
+ echo "|------|------|"
696
+ echo -e "$output" | head -30
697
+ fi
698
+ }
699
+
700
+ scan_style_files() {
701
+ local dir="$1"
702
+ local styles_dir=""
703
+ for candidate in "src/styles" "src/assets/styles" "src/scss" "src/css" "app/styles" "styles"; do
704
+ if [[ -d "$dir/$candidate" ]]; then
705
+ styles_dir="$dir/$candidate"
706
+ break
707
+ fi
708
+ done
709
+ [[ -z "$styles_dir" ]] && return 0
710
+
711
+ local output=""
712
+ while IFS= read -r style_path; do
713
+ [[ -z "$style_path" ]] && continue
714
+ local rel="${style_path#$dir/}"
715
+ local name
716
+ name=$(basename "$style_path")
717
+ output+="- **${name}** (\`${rel}\`)\n"
718
+ done < <(find "$styles_dir" -maxdepth 2 -type f \( -name "*.css" -o -name "*.scss" -o -name "*.less" -o -name "*.sass" \) 2>/dev/null | sort)
719
+
720
+ echo -e "$output" | head -20
721
+ }
722
+
723
+ # ── UI Theme Info ────────────────────────────────────────────────────────────
724
+
725
+ detect_ui_theme_info() {
726
+ local dir="$1"
727
+ local pkg="$dir/package.json"
728
+ [[ ! -f "$pkg" ]] && return 0
729
+
730
+ local output=""
731
+
732
+ if _has_dep "$pkg" "element-plus" &>/dev/null; then
733
+ output+="### Element Plus 主题\n\n"
734
+ local ver
735
+ ver=$(_pkg_field "$pkg" ".dependencies.element-plus")
736
+ output+="**版本**: ${ver:-未知}\n\n"
737
+
738
+ local theme_files=""
739
+ for f in "src/styles/element-override.scss" "src/styles/element-variables.scss" "src/styles/element/index.scss"; do
740
+ if [[ -f "$dir/$f" ]]; then
741
+ theme_files+="- ${f}\n"
742
+ fi
743
+ done
744
+
745
+ if [[ -n "$theme_files" ]]; then
746
+ output+="**主题覆盖文件**:\n${theme_files}\n"
747
+ fi
748
+
749
+ local var_file
750
+ var_file=$(find_first "$dir/src" "variables.scss" 2>/dev/null || true)
751
+ if [[ -n "$var_file" ]]; then
752
+ local var_count
753
+ var_count=$(grep -cE '\-\-el-' "$var_file" 2>/dev/null || echo "0")
754
+ output+="**CSS 变量定义**: \`${var_file##*/}\` (${var_count} 个 Element Plus 变量)\n"
755
+ fi
756
+ fi
757
+
758
+ if _has_dep "$pkg" "tailwindcss" &>/dev/null; then
759
+ output+="### Tailwind CSS 配置\n\n"
760
+ local ver
761
+ ver=$(_pkg_field "$pkg" ".devDependencies.tailwindcss" 2>/dev/null || _pkg_field "$pkg" ".dependencies.tailwindcss" 2>/dev/null || true)
762
+ output+="**版本**: ${ver:-未知}\n\n"
763
+ for f in "tailwind.config.js" "tailwind.config.ts" "tailwind.config.cjs"; do
764
+ if [[ -f "$dir/$f" ]]; then
765
+ output+="**配置文件**: \`${f}\`\n"
766
+ fi
767
+ done
768
+ fi
769
+
770
+ echo -e "$output"
771
+ }
772
+
773
+ # ── Dev Conventions Inference ────────────────────────────────────────────────
774
+
775
+ infer_dev_conventions() {
776
+ local dir="$1"
777
+ local pkg="$dir/package.json"
778
+ local output=""
779
+
780
+ if [[ -f "$dir/tsconfig.json" ]]; then
781
+ local strict=""
782
+ if grep -q '"strict": true' "$dir/tsconfig.json" 2>/dev/null; then
783
+ strict=" (strict mode)"
784
+ fi
785
+ output+="- **TypeScript**: 项目使用 TypeScript${strict}\n"
786
+ fi
787
+
788
+ if [[ -f "$dir/.eslintrc.js" || -f "$dir/.eslintrc.json" || -f "$dir/.eslintrc.cjs" || -f "$dir/eslint.config.js" || -f "$dir/eslint.config.ts" ]]; then
789
+ output+="- **ESLint**: 已配置代码检查\n"
790
+ fi
791
+
792
+ if [[ -f "$dir/.prettierrc" || -f "$dir/.prettierrc.js" || -f "$dir/.prettierrc.json" || -f "$dir/prettier.config.js" ]]; then
793
+ output+="- **Prettier**: 已配置代码格式化\n"
794
+ fi
795
+
796
+ if [[ -f "$dir/.husky/pre-commit" || -d "$dir/.husky" ]]; then
797
+ output+="- **Git Hooks**: 使用 Husky 管理 Git hooks\n"
798
+ fi
799
+
800
+ if [[ -f "$dir/commitlint.config.js" || -f "$dir/.commitlintrc.js" || -f "$dir/.commitlintrc.json" ]]; then
801
+ output+="- **Commitlint**: 已配置提交信息规范\n"
802
+ fi
803
+
804
+ if [[ -f "$pkg" ]] && _has_dep "$pkg" "vitest" &>/dev/null; then
805
+ output+="- **测试**: 使用 Vitest\n"
806
+ elif [[ -f "$pkg" ]] && _has_dep "$pkg" "jest" &>/dev/null; then
807
+ output+="- **测试**: 使用 Jest\n"
808
+ fi
809
+
810
+ if [[ -f "$pkg" ]] && _has_dep "$pkg" "unplugin-auto-import" "unplugin-vue-components" &>/dev/null; then
811
+ output+="- **自动导入**: 使用 unplugin 实现组件/API 自动导入\n"
812
+ fi
813
+
814
+ echo -e "$output"
815
+ }
816
+
817
+ # ── Java / Spring Detection ──────────────────────────────────────────────────
818
+
819
+ # Detect Java build tool
820
+ detect_java_build_tool() {
821
+ local dir="$1"
822
+ if [[ -f "$dir/build.gradle.kts" ]]; then
823
+ echo "Gradle (Kotlin DSL)"
824
+ elif [[ -f "$dir/build.gradle" ]]; then
825
+ echo "Gradle (Groovy DSL)"
826
+ elif [[ -f "$dir/pom.xml" ]]; then
827
+ echo "Maven"
828
+ fi
829
+ }
830
+
831
+ # Detect Java version from pom.xml or build.gradle
832
+ # Uses cross-platform grep; no grep -P (not available on macOS)
833
+ detect_java_version() {
834
+ local dir="$1"
835
+ if [[ -f "$dir/pom.xml" ]]; then
836
+ # Check <java.version> property
837
+ local ver
838
+ ver=$(grep '<java.version>' "$dir/pom.xml" 2>/dev/null | head -1 | sed 's/.*<java.version>//;s/<\/java.version>.*//' || true)
839
+ if [[ -n "$ver" ]]; then
840
+ echo "$ver"
841
+ return 0
842
+ fi
843
+ # Check maven-compiler-plugin <source>
844
+ ver=$(grep '<source>' "$dir/pom.xml" 2>/dev/null | head -1 | sed 's/.*<source>//;s/<\/source>.*//' || true)
845
+ if [[ -n "$ver" ]]; then
846
+ echo "$ver"
847
+ return 0
848
+ fi
849
+ fi
850
+ if [[ -f "$dir/build.gradle.kts" ]] || [[ -f "$dir/build.gradle" ]]; then
851
+ local gradle_file="$dir/build.gradle"
852
+ [[ -f "$dir/build.gradle.kts" ]] && gradle_file="$dir/build.gradle.kts"
853
+ local ver
854
+ ver=$(grep 'sourceCompatibility' "$gradle_file" 2>/dev/null | head -1 | sed 's/.*sourceCompatibility[[:space:]]*=[[:space:]]*//;s/[^0-9.]//g' || true)
855
+ if [[ -n "$ver" ]]; then
856
+ echo "$ver"
857
+ return 0
858
+ fi
859
+ fi
860
+ }
861
+
862
+ # Detect base package path from pom.xml groupId or first .java package declaration
863
+ detect_java_package() {
864
+ local dir="$1"
865
+ # First try: from pom.xml groupId (skip framework groupIds)
866
+ if [[ -f "$dir/pom.xml" ]]; then
867
+ local gid
868
+ gid=$(grep '<groupId>' "$dir/pom.xml" 2>/dev/null | head -1 | sed 's/.*<groupId>//;s/<\/groupId>.*//' | tr -d '[:space:]' || true)
869
+ # Skip common parent/framework groupIds
870
+ if [[ -n "$gid" ]]; then
871
+ case "$gid" in
872
+ org.springframework*|org.apache*|com.alibaba*)
873
+ # Framework groupId, skip and try next
874
+ ;;
875
+ *)
876
+ echo "$gid" | tr '.' '/'
877
+ return 0
878
+ ;;
879
+ esac
880
+ fi
881
+ fi
882
+ # Second try: from first .java file's package declaration
883
+ local first_java
884
+ first_java=$(find "$dir/src/main/java" -name "*.java" -type f 2>/dev/null | head -1 || true)
885
+ if [[ -n "$first_java" ]]; then
886
+ local pkg
887
+ pkg=$(grep '^package ' "$first_java" 2>/dev/null | head -1 | sed 's/package //;s/;//' || true)
888
+ if [[ -n "$pkg" ]]; then
889
+ echo "$pkg" | tr '.' '/'
890
+ return 0
891
+ fi
892
+ fi
893
+ }
894
+
895
+ # Detect Spring Boot/Cloud features from pom.xml and config files
896
+ detect_spring_features() {
897
+ local dir="$1"
898
+ local features=""
899
+
900
+ if [[ -f "$dir/pom.xml" ]]; then
901
+ grep -q "spring-boot" "$dir/pom.xml" 2>/dev/null && features+="Spring Boot, "
902
+ grep -q "spring-cloud-starter" "$dir/pom.xml" 2>/dev/null && features+="Spring Cloud, "
903
+ grep -q "nacos" "$dir/pom.xml" 2>/dev/null && features+="Nacos, "
904
+ grep -q "sentinel" "$dir/pom.xml" 2>/dev/null && features+="Sentinel, "
905
+ grep -q "spring-cloud-gateway" "$dir/pom.xml" 2>/dev/null && features+="Gateway, "
906
+ grep -q "openfeign" "$dir/pom.xml" 2>/dev/null && features+="OpenFeign, "
907
+ grep -q "spring-cloud-stream" "$dir/pom.xml" 2>/dev/null && features+="Cloud Stream, "
908
+ grep -q "spring-cloud-sleuth" "$dir/pom.xml" 2>/dev/null && features+="Sleuth, "
909
+ grep -q "spring-security" "$dir/pom.xml" 2>/dev/null && features+="Spring Security, "
910
+ fi
911
+
912
+ # Also check YAML config for Spring Cloud indicators
913
+ local yml_files=("$dir/src/main/resources/application.yml" "$dir/src/main/resources/application.yaml" "$dir/src/main/resources/bootstrap.yml")
914
+ for yml in "${yml_files[@]}"; do
915
+ if [[ -f "$yml" ]]; then
916
+ grep -q "nacos" "$yml" 2>/dev/null && features+="Nacos-Config, "
917
+ grep -q "sentinel" "$yml" 2>/dev/null && features+="Sentinel-Config, "
918
+ fi
919
+ done
920
+
921
+ # Remove trailing ", "
922
+ features="${features%, }"
923
+ echo "$features"
924
+ }
925
+
926
+ # Detect ORM framework from pom.xml
927
+ detect_java_orm() {
928
+ local dir="$1"
929
+ if [[ -f "$dir/pom.xml" ]]; then
930
+ if grep -q "mybatis-plus" "$dir/pom.xml" 2>/dev/null; then echo "MyBatis-Plus"; return 0; fi
931
+ if grep -q "mybatis-spring-boot" "$dir/pom.xml" 2>/dev/null; then echo "MyBatis"; return 0; fi
932
+ if grep -q "spring-boot-starter-data-jpa" "$dir/pom.xml" 2>/dev/null || grep -q "spring-data-jpa" "$dir/pom.xml" 2>/dev/null; then echo "Spring Data JPA"; return 0; fi
933
+ if grep -q "spring-boot-starter-jdbc" "$dir/pom.xml" 2>/dev/null; then echo "Spring JDBC"; return 0; fi
934
+ fi
935
+ }
936
+
937
+ # Parse Maven modules from root pom.xml <modules> section
938
+ detect_maven_modules() {
939
+ local dir="$1"
940
+ if [[ ! -f "$dir/pom.xml" ]]; then return 0; fi
941
+
942
+ # Extract module names using grep + sed (cross-platform, no grep -P)
943
+ # Note: tr -d '[:space:]' is NOT used here because it would join all lines into one string
944
+ grep '<module>' "$dir/pom.xml" 2>/dev/null | sed 's/.*<module>//;s/<\/module>.*//' | while IFS= read -r mod; do
945
+ # Trim leading/trailing whitespace only (not internal)
946
+ mod=$(echo "$mod" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
947
+ [[ -n "$mod" ]] && echo "$mod"
948
+ done
949
+ }
950
+
951
+ # Scan Java source directory tree (3 levels deep)
952
+ scan_java_structure() {
953
+ local dir="$1"
954
+ local pkg_path
955
+ pkg_path=$(detect_java_package "$dir")
956
+
957
+ local src_base="$dir/src/main/java"
958
+ if [[ -n "$pkg_path" ]] && [[ -d "$dir/src/main/java/$pkg_path" ]]; then
959
+ src_base="$dir/src/main/java/$pkg_path"
960
+ fi
961
+
962
+ [[ ! -d "$src_base" ]] && return 0
963
+
964
+ local exclude_args=()
965
+ for d in "${ATOOL_SCAN_EXCLUDE_DIRS[@]}"; do
966
+ exclude_args+=(-not -path "*/${d}/*")
967
+ done
968
+ # shellcheck disable=SC2068
969
+ _print_tree "$src_base" "" "$src_base" 3 "${exclude_args[@]}"
970
+ }
971
+
972
+ # Count Java source files by category
973
+ count_java_sources() {
974
+ local dir="$1"
975
+ local controllers services service_impls repositories mappers configs total
976
+
977
+ controllers=$(_count_files "$dir" "*Controller.java")
978
+ services=$(_count_files "$dir" "*Service.java")
979
+ service_impls=$(_count_files "$dir" "*ServiceImpl.java")
980
+ repositories=$(_count_files "$dir" "*Repository.java")
981
+ mappers=$(_count_files "$dir" "*Mapper.java")
982
+ configs=$(_count_files "$dir" "*Config.java")
983
+ total=$(_count_files "$dir" "*.java")
984
+
985
+ # Ensure all values are valid integers
986
+ controllers=${controllers:-0} ; services=${services:-0} ; service_impls=${service_impls:-0}
987
+ repositories=${repositories:-0} ; mappers=${mappers:-0} ; configs=${configs:-0}
988
+ total=${total:-0}
989
+
990
+ local rep_map=$((repositories + mappers))
991
+ echo "${total} files (Controller: ${controllers}, Service: ${services}, ServiceImpl: ${service_impls}, Repository/Mapper: ${rep_map}, Config: ${configs})"
992
+ }
993
+
994
+ # Scan Spring REST controllers and extract API endpoint summary
995
+ scan_java_controllers() {
996
+ local dir="$1"
997
+ local output=""
998
+
999
+ while IFS= read -r ctrl_file; do
1000
+ [[ -z "$ctrl_file" ]] && continue
1001
+ local name
1002
+ name=$(basename "$ctrl_file" .java)
1003
+ local rel="${ctrl_file#$dir/}"
1004
+ local base_path
1005
+ base_path=$(grep '@RequestMapping' "$ctrl_file" 2>/dev/null | head -1 | grep -oE '"[^"]+"' | tr -d '"' || echo "")
1006
+ local method_count
1007
+ method_count=$(grep -cE '@(Get|Post|Put|Delete|Patch)Mapping' "$ctrl_file" 2>/dev/null || echo "0")
1008
+ output+="- **${name}** (\`${rel}\`, base: \`${base_path}\`, ${method_count} endpoints)\n"
1009
+ done < <(find "$dir" -name "*Controller.java" -type f -not -path "*/target/*" -not -path "*/build/*" 2>/dev/null | sort | head -30)
1010
+
1011
+ echo -e "$output"
1012
+ }
1013
+
1014
+ # Scan Spring application config files for key properties
1015
+ scan_spring_config() {
1016
+ local dir="$1"
1017
+ local output=""
1018
+
1019
+ for f in "src/main/resources/application.yml" "src/main/resources/application.yaml" "src/main/resources/application.properties" "src/main/resources/bootstrap.yml"; do
1020
+ if [[ -f "$dir/$f" ]]; then
1021
+ output+="- **${f}**\n"
1022
+ # Extract port
1023
+ local port
1024
+ port=$(grep -E '^\s*port:' "$dir/$f" 2>/dev/null | head -1 | grep -oE '[0-9]+' || true)
1025
+ if [[ -n "$port" ]]; then
1026
+ output+=" - server.port: ${port}\n"
1027
+ fi
1028
+ # Extract application name
1029
+ local app_name
1030
+ app_name=$(grep -E '^\s*name:' "$dir/$f" 2>/dev/null | head -1 | sed 's/.*name:[[:space:]]*//' | tr -d ' ' || true)
1031
+ if [[ -n "$app_name" ]]; then
1032
+ output+=" - spring.application.name: ${app_name}\n"
1033
+ fi
1034
+ fi
1035
+ done
1036
+
1037
+ echo -e "$output"
1038
+ }
1039
+
1040
+ # Generate Java quick start commands (Maven/Gradle)
1041
+ detect_java_quick_start() {
1042
+ local dir="$1"
1043
+ local output=""
1044
+
1045
+ if [[ -f "$dir/pom.xml" ]]; then
1046
+ if [[ -f "$dir/mvnw" ]]; then
1047
+ output+="# 构建\n./mvnw clean package -DskipTests\n\n"
1048
+ output+="# 运行\n./mvnw spring-boot:run\n\n"
1049
+ output+="# 测试\n./mvnw test\n"
1050
+ else
1051
+ output+="# 构建\nmvn clean package -DskipTests\n\n"
1052
+ output+="# 运行\nmvn spring-boot:run\n\n"
1053
+ output+="# 测试\nmvn test\n"
1054
+ fi
1055
+ elif [[ -f "$dir/build.gradle" ]] || [[ -f "$dir/build.gradle.kts" ]]; then
1056
+ if [[ -f "$dir/gradlew" ]]; then
1057
+ output+="# 构建\n./gradlew build -x test\n\n"
1058
+ output+="# 运行\n./gradlew bootRun\n\n"
1059
+ output+="# 测试\n./gradlew test\n"
1060
+ else
1061
+ output+="# 构建\ngradle build -x test\n\n"
1062
+ output+="# 运行\ngradle bootRun\n\n"
1063
+ output+="# 测试\ngradle test\n"
1064
+ fi
1065
+ fi
1066
+
1067
+ echo -e "$output"
1068
+ }
1069
+
1070
+ # Count Java test files and compute rough coverage ratio
1071
+ count_java_test_coverage() {
1072
+ local dir="$1"
1073
+ local test_count src_count
1074
+
1075
+ test_count=$(_count_files "$dir/src/test" "*.java" 2>/dev/null || true)
1076
+ src_count=$(_count_files "$dir/src/main" "*.java" 2>/dev/null || true)
1077
+
1078
+ # Ensure valid integers (handle empty or multi-line output)
1079
+ test_count=$(echo "$test_count" | head -1 | tr -cd '0-9')
1080
+ src_count=$(echo "$src_count" | head -1 | tr -cd '0-9')
1081
+ test_count=${test_count:-0}
1082
+ src_count=${src_count:-0}
1083
+
1084
+ if [[ "$src_count" -eq 0 ]]; then
1085
+ echo "0 test files / 0 source files"
1086
+ return 0
1087
+ fi
1088
+
1089
+ # Compute percentage (integer arithmetic)
1090
+ local pct=$((test_count * 100 / src_count))
1091
+ echo "${test_count} test files / ${src_count} source files (${pct}% ratio)"
1092
+ }
1093
+
1094
+ # ── Master Orchestration ─────────────────────────────────────────────────────
1095
+
1096
+ extract_source_metadata() {
1097
+ local dir="$1"
1098
+
1099
+ # Detect project type
1100
+ local is_java=false
1101
+ if [[ -f "$dir/pom.xml" ]] || [[ -f "$dir/build.gradle" ]] || [[ -f "$dir/build.gradle.kts" ]]; then
1102
+ is_java=true
1103
+ fi
1104
+ local is_node=false
1105
+ if [[ -f "$dir/package.json" ]]; then
1106
+ is_node=true
1107
+ fi
1108
+
1109
+ # Multi-line values — write to temp files
1110
+ local tmpdir="${ATOOL_ANALYSIS_TMPDIR:-$(mktemp -d)}"
1111
+ mkdir -p "$tmpdir"
1112
+
1113
+ # ── Node.js metadata (existing) ──
1114
+ if $is_node; then
1115
+ echo "FRAMEWORK_NAME=$(detect_framework "$dir")"
1116
+ echo "FRAMEWORK_VERSION=$(detect_framework_version "$dir")"
1117
+ echo "UI_LIBRARY=$(detect_ui_library "$dir")"
1118
+ echo "UI_LIBRARY_VERSION=$(detect_ui_library_version "$dir")"
1119
+ echo "STATE_MANAGEMENT=$(detect_state_management "$dir")"
1120
+ echo "BUILDER=$(detect_builder "$dir")"
1121
+ echo "CSS_SOLUTION=$(detect_css_solution "$dir")"
1122
+ echo "ROUTER=$(detect_router "$dir")"
1123
+ echo "HTTP_CLIENT=$(detect_http_client "$dir")"
1124
+ echo "PACKAGE_MANAGER=$(detect_package_manager "$dir")"
1125
+
1126
+ # NPM scripts
1127
+ echo "SCRIPT_DEV=$(get_npm_script "$dir" "dev")"
1128
+ echo "SCRIPT_BUILD=$(get_npm_script "$dir" "build")"
1129
+ echo "SCRIPT_BUILD_PRO=$(get_npm_script "$dir" "build:pro")"
1130
+ echo "SCRIPT_BUILD_DEV=$(get_npm_script "$dir" "build:dev")"
1131
+ echo "SCRIPT_TEST=$(get_npm_script "$dir" "test")"
1132
+ echo "SCRIPT_LINT=$(get_npm_script "$dir" "lint")"
1133
+ echo "SCRIPT_PREVIEW=$(get_npm_script "$dir" "preview")"
1134
+
1135
+ scan_project_structure "$dir" > "$tmpdir/project_structure.txt"
1136
+ echo "PROJECT_STRUCTURE=__BLOCK__:$tmpdir/project_structure.txt"
1137
+
1138
+ scan_components "$dir" > "$tmpdir/component_list.txt"
1139
+ echo "COMPONENT_LIST=__BLOCK__:$tmpdir/component_list.txt"
1140
+
1141
+ scan_views "$dir" > "$tmpdir/view_list.txt"
1142
+ echo "VIEW_LIST=__BLOCK__:$tmpdir/view_list.txt"
1143
+
1144
+ scan_stores "$dir" > "$tmpdir/store_list.txt"
1145
+ echo "STORE_LIST=__BLOCK__:$tmpdir/store_list.txt"
1146
+
1147
+ scan_api_services "$dir" > "$tmpdir/api_list.txt"
1148
+ echo "API_LIST=__BLOCK__:$tmpdir/api_list.txt"
1149
+
1150
+ scan_hooks "$dir" > "$tmpdir/hook_list.txt"
1151
+ echo "HOOK_LIST=__BLOCK__:$tmpdir/hook_list.txt"
1152
+
1153
+ scan_utils "$dir" > "$tmpdir/util_list.txt"
1154
+ echo "UTIL_LIST=__BLOCK__:$tmpdir/util_list.txt"
1155
+
1156
+ scan_routes "$dir" > "$tmpdir/route_table.txt"
1157
+ echo "ROUTE_TABLE=__BLOCK__:$tmpdir/route_table.txt"
1158
+
1159
+ scan_style_files "$dir" > "$tmpdir/style_files.txt"
1160
+ echo "STYLE_FILES=__BLOCK__:$tmpdir/style_files.txt"
1161
+
1162
+ detect_ui_theme_info "$dir" > "$tmpdir/ui_theme_info.txt"
1163
+ echo "UI_THEME_INFO=__BLOCK__:$tmpdir/ui_theme_info.txt"
1164
+
1165
+ infer_dev_conventions "$dir" > "$tmpdir/dev_conventions.txt"
1166
+ echo "DEV_CONVENTIONS=__BLOCK__:$tmpdir/dev_conventions.txt"
1167
+
1168
+ _generate_quick_start "$dir" > "$tmpdir/quick_start.txt"
1169
+ echo "QUICK_START=__BLOCK__:$tmpdir/quick_start.txt"
1170
+ fi
1171
+
1172
+ # ── Java metadata (new) ──
1173
+ if $is_java; then
1174
+ echo "JAVA_BUILD_TOOL=$(detect_java_build_tool "$dir")"
1175
+ echo "JAVA_VERSION=$(detect_java_version "$dir")"
1176
+ echo "JAVA_PACKAGE=$(detect_java_package "$dir")"
1177
+ echo "SPRING_FEATURES=$(detect_spring_features "$dir")"
1178
+ echo "JAVA_ORM=$(detect_java_orm "$dir")"
1179
+ echo "JAVA_SOURCE_COUNT=$(count_java_sources "$dir")"
1180
+ echo "JAVA_TEST_COVERAGE=$(count_java_test_coverage "$dir")"
1181
+
1182
+ detect_maven_modules "$dir" > "$tmpdir/maven_modules.txt"
1183
+ echo "MAVEN_MODULES=__BLOCK__:$tmpdir/maven_modules.txt"
1184
+
1185
+ scan_java_structure "$dir" > "$tmpdir/java_structure.txt"
1186
+ echo "JAVA_STRUCTURE=__BLOCK__:$tmpdir/java_structure.txt"
1187
+
1188
+ scan_java_controllers "$dir" > "$tmpdir/java_controllers.txt"
1189
+ echo "JAVA_CONTROLLERS=__BLOCK__:$tmpdir/java_controllers.txt"
1190
+
1191
+ scan_spring_config "$dir" > "$tmpdir/spring_config.txt"
1192
+ echo "SPRING_CONFIG=__BLOCK__:$tmpdir/spring_config.txt"
1193
+
1194
+ detect_java_quick_start "$dir" > "$tmpdir/java_quick_start.txt"
1195
+ echo "JAVA_QUICK_START=__BLOCK__:$tmpdir/java_quick_start.txt"
1196
+ fi
1197
+
1198
+ # ── Common metadata ──
1199
+ echo "SOURCE_FILE_COUNT=$(count_source_files "$dir")"
1200
+ }
1201
+
1202
+ _generate_quick_start() {
1203
+ local dir="$1"
1204
+ local pkg_mgr
1205
+ pkg_mgr=$(detect_package_manager "$dir")
1206
+ [[ -z "$pkg_mgr" ]] && pkg_mgr="npm"
1207
+
1208
+ local output=""
1209
+
1210
+ case "$pkg_mgr" in
1211
+ pnpm) output+="pnpm install\n" ;;
1212
+ yarn) output+="yarn install\n" ;;
1213
+ bun) output+="bun install\n" ;;
1214
+ *) output+="npm install\n" ;;
1215
+ esac
1216
+
1217
+ local dev_script
1218
+ dev_script=$(get_npm_script "$dir" "dev")
1219
+ if [[ -n "$dev_script" ]]; then
1220
+ output+="\n# 开发模式\n"
1221
+ case "$pkg_mgr" in
1222
+ pnpm) output+="pnpm dev\n" ;;
1223
+ yarn) output+="yarn dev\n" ;;
1224
+ bun) output+="bun run dev\n" ;;
1225
+ *) output+="npm run dev\n" ;;
1226
+ esac
1227
+ fi
1228
+
1229
+ local build_script
1230
+ build_script=$(get_npm_script "$dir" "build:pro")
1231
+ if [[ -n "$build_script" ]]; then
1232
+ output+="\n# 构建 (生产环境)\n"
1233
+ case "$pkg_mgr" in
1234
+ pnpm) output+="pnpm build:pro\n" ;;
1235
+ yarn) output+="yarn build:pro\n" ;;
1236
+ bun) output+="bun run build:pro\n" ;;
1237
+ *) output+="npm run build:pro\n" ;;
1238
+ esac
1239
+ else
1240
+ build_script=$(get_npm_script "$dir" "build")
1241
+ if [[ -n "$build_script" ]]; then
1242
+ output+="\n# 构建\n"
1243
+ case "$pkg_mgr" in
1244
+ pnpm) output+="pnpm build\n" ;;
1245
+ yarn) output+="yarn build\n" ;;
1246
+ bun) output+="bun run build\n" ;;
1247
+ *) output+="npm run build\n" ;;
1248
+ esac
1249
+ fi
1250
+ fi
1251
+
1252
+ local test_script
1253
+ test_script=$(get_npm_script "$dir" "test")
1254
+ if [[ -n "$test_script" ]]; then
1255
+ output+="\n# 测试\n"
1256
+ case "$pkg_mgr" in
1257
+ pnpm) output+="pnpm test\n" ;;
1258
+ yarn) output+="yarn test\n" ;;
1259
+ bun) output+="bun run test\n" ;;
1260
+ *) output+="npm run test\n" ;;
1261
+ esac
1262
+ fi
1263
+
1264
+ echo -e "$output"
1265
+ }