aodw-skill 0.7.3

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 (188) hide show
  1. package/.aodw/01-core/ai-interaction-rules.md +218 -0
  2. package/.aodw/01-core/ai-knowledge-rules.md +302 -0
  3. package/.aodw/01-core/ai-project-overview-rules.md +284 -0
  4. package/.aodw/01-core/aodw-constitution-summary.md +20 -0
  5. package/.aodw/01-core/aodw-constitution.md +419 -0
  6. package/.aodw/01-core/csf-thinking-framework.md +373 -0
  7. package/.aodw/01-core/git-discipline.md +226 -0
  8. package/.aodw/01-core/module-doc-rules.md +90 -0
  9. package/.aodw/02-workflow/aodw-development-stages.md +235 -0
  10. package/.aodw/02-workflow/rt-id-generation-rules.md +267 -0
  11. package/.aodw/02-workflow/rt-manager-summary.md +15 -0
  12. package/.aodw/02-workflow/rt-manager.md +399 -0
  13. package/.aodw/02-workflow/spec-full-profile-summary.md +13 -0
  14. package/.aodw/02-workflow/spec-full-profile.md +391 -0
  15. package/.aodw/02-workflow/spec-lite-profile.md +313 -0
  16. package/.aodw/02-workflow/ui-workflow-rules.md +334 -0
  17. package/.aodw/03-standards/ai-coding-rules-common.md +89 -0
  18. package/.aodw/03-standards/ai-coding-rules.md +370 -0
  19. package/.aodw/03-standards/stacks/java-springboot/ai-coding-rules-backend.md +100 -0
  20. package/.aodw/03-standards/stacks/python-fastapi/ai-coding-rules-backend.md +612 -0
  21. package/.aodw/03-standards/stacks/react-typescript/ai-coding-rules-frontend.md +291 -0
  22. package/.aodw/03-standards/stacks/vue2/ai-coding-rules-frontend.md +97 -0
  23. package/.aodw/03-standards/ui-kit/ui-kit.md +163 -0
  24. package/.aodw/04-auditors/aodw-development-auditor-rules.md +470 -0
  25. package/.aodw/04-auditors/aodw-full-auditor-rules.md +365 -0
  26. package/.aodw/04-auditors/aodw-requirement-auditor-rules.md +408 -0
  27. package/.aodw/05-tooling/ai-tools-init-rules.md +465 -0
  28. package/.aodw/06-project/ai-overview.md +116 -0
  29. package/.aodw/06-project/modules-index.yaml +11 -0
  30. package/.aodw/07-optimization/token-usage-analysis.md +253 -0
  31. package/.aodw/README.md +26 -0
  32. package/.aodw/RELEASE-CHECKLIST.md +144 -0
  33. package/.aodw/config.yaml +2 -0
  34. package/.aodw/manifest.yaml +98 -0
  35. package/.aodw/templates/SOURCE-TO-DISTRIBUTION-GUIDE.md +276 -0
  36. package/.aodw/templates/TEMPLATE-APPLICATION-GUIDE.md +246 -0
  37. package/.aodw/templates/aodw-kernel-loader-template.md +70 -0
  38. package/.aodw/templates/audit-report-template.md +232 -0
  39. package/.aodw/templates/changelog-template.md +16 -0
  40. package/.aodw/templates/checklists/coding-standards-template.md +110 -0
  41. package/.aodw/templates/csf-review-template.md +201 -0
  42. package/.aodw/templates/impact-template.md +17 -0
  43. package/.aodw/templates/invariants-template.md +12 -0
  44. package/.aodw/templates/module-readme-template.md +39 -0
  45. package/.aodw/templates/plan-lite-template.md +11 -0
  46. package/.aodw/templates/rt-decision-template.md +13 -0
  47. package/.aodw/templates/rt-intake-template.md +33 -0
  48. package/.aodw/templates/rt-meta-template.yaml +43 -0
  49. package/.aodw/templates/spec-lite-template.md +17 -0
  50. package/.aodw/templates/tests-template.md +13 -0
  51. package/.aodw/templates/tools-config/README.md +80 -0
  52. package/.aodw/templates/tools-config/backend/black.config.template.toml +6 -0
  53. package/.aodw/templates/tools-config/backend/pre-commit.config.template.yaml +16 -0
  54. package/.aodw/templates/tools-config/backend/ruff.config.template.toml +23 -0
  55. package/.aodw/templates/tools-config/frontend/eslint.config.template.json +113 -0
  56. package/.aodw/templates/tools-config/frontend/prettier.config.template.json +10 -0
  57. package/.aodw/templates/tools-config/frontend/tsconfig.paths.template.json +11 -0
  58. package/.aodw/workflow-guide.md +51 -0
  59. package/AODW_Adapters/README.md +143 -0
  60. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-check.md +7 -0
  61. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-done.md +7 -0
  62. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-full.md +7 -0
  63. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-governance.md +7 -0
  64. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-impact.md +7 -0
  65. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-init.md +7 -0
  66. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-invariants.md +7 -0
  67. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-lite.md +7 -0
  68. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-module.md +7 -0
  69. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-new.md +7 -0
  70. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-open.md +7 -0
  71. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-pause.md +7 -0
  72. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-resume.md +7 -0
  73. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-tests.md +7 -0
  74. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-upgrade.md +7 -0
  75. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw.md +35 -0
  76. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-check.md +16 -0
  77. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-done.md +16 -0
  78. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-full.md +14 -0
  79. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-governance.md +13 -0
  80. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-impact.md +13 -0
  81. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-init.md +13 -0
  82. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-invariants.md +13 -0
  83. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-lite.md +14 -0
  84. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-module.md +13 -0
  85. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-new.md +30 -0
  86. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-open.md +10 -0
  87. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-pause.md +12 -0
  88. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-resume.md +12 -0
  89. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-tests.md +13 -0
  90. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-upgrade.md +12 -0
  91. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw.md +18 -0
  92. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/claude/CLAUDE.md +17 -0
  93. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-check.md +30 -0
  94. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-done.md +52 -0
  95. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-full.md +31 -0
  96. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-governance.md +34 -0
  97. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-impact.md +25 -0
  98. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-init.md +75 -0
  99. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-invariants.md +29 -0
  100. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-lite.md +23 -0
  101. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-module.md +24 -0
  102. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-new.md +70 -0
  103. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-open.md +19 -0
  104. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-pause.md +19 -0
  105. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-resume.md +20 -0
  106. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-tests.md +26 -0
  107. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-upgrade.md +27 -0
  108. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw.md +69 -0
  109. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/deploypromote.md +20 -0
  110. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/featuretotester.md +32 -0
  111. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/deploy/feature_to_master_push_test_local.sh +390 -0
  112. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/deploy/promote_only.sh +210 -0
  113. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/deploy/rollback_prod.sh +99 -0
  114. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/rules/aodw.mdc +26 -0
  115. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-check.md +29 -0
  116. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-done.md +52 -0
  117. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-full.md +30 -0
  118. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-governance.md +33 -0
  119. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-impact.md +24 -0
  120. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-init.md +75 -0
  121. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-invariants.md +28 -0
  122. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-lite.md +22 -0
  123. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-module.md +23 -0
  124. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-new.md +92 -0
  125. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-open.md +18 -0
  126. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-pause.md +18 -0
  127. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-resume.md +19 -0
  128. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-tests.md +25 -0
  129. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-upgrade.md +26 -0
  130. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw.md +68 -0
  131. package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/GEMINI.md +17 -0
  132. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-analyze.md +15 -0
  133. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-complete.md +15 -0
  134. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-control.md +14 -0
  135. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-decide.md +16 -0
  136. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-governance.md +7 -0
  137. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-implement.md +16 -0
  138. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-init.md +7 -0
  139. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-intake.md +15 -0
  140. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-open.md +7 -0
  141. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-simplified.md +107 -0
  142. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-verify.md +14 -0
  143. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-analyze.md +24 -0
  144. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-complete.md +23 -0
  145. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-control.md +21 -0
  146. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-decide.md +26 -0
  147. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-governance.md +13 -0
  148. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-implement.md +21 -0
  149. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-init.md +13 -0
  150. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-intake.md +28 -0
  151. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-open.md +10 -0
  152. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-verify.md +20 -0
  153. package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw.md +18 -0
  154. package/AODW_Adapters/antigravity/.agent/rules/aodw.md +74 -0
  155. package/AODW_Adapters/claude/CLAUDE.md +70 -0
  156. package/AODW_Adapters/cursor/.cursor/commands/README.md +37 -0
  157. package/AODW_Adapters/cursor/.cursor/rules/aodw.mdc +77 -0
  158. package/AODW_Adapters/gemini/.agent/rules/aodw-analyze.md +15 -0
  159. package/AODW_Adapters/gemini/.agent/rules/aodw-complete.md +15 -0
  160. package/AODW_Adapters/gemini/.agent/rules/aodw-control.md +14 -0
  161. package/AODW_Adapters/gemini/.agent/rules/aodw-decide.md +16 -0
  162. package/AODW_Adapters/gemini/.agent/rules/aodw-governance.md +33 -0
  163. package/AODW_Adapters/gemini/.agent/rules/aodw-implement.md +16 -0
  164. package/AODW_Adapters/gemini/.agent/rules/aodw-init.md +75 -0
  165. package/AODW_Adapters/gemini/.agent/rules/aodw-intake.md +15 -0
  166. package/AODW_Adapters/gemini/.agent/rules/aodw-open.md +18 -0
  167. package/AODW_Adapters/gemini/.agent/rules/aodw-verify.md +14 -0
  168. package/AODW_Adapters/gemini/.agent/rules/aodw.md +70 -0
  169. package/AODW_Adapters/gemini/GEMINI.md +17 -0
  170. package/AODW_Adapters/general/.github/copilot-instructions.md +34 -0
  171. package/AODW_Adapters/general/AGENTS.md +70 -0
  172. package/README.md +118 -0
  173. package/bin/aodw.js +627 -0
  174. package/bin/commands/init-overview.js +801 -0
  175. package/bin/commands/init-tools.js +811 -0
  176. package/bin/commands/new.js +235 -0
  177. package/bin/commands/serve.js +79 -0
  178. package/bin/processors/index.js +109 -0
  179. package/bin/update-adapters-from-template.js +89 -0
  180. package/bin/utils/config.js +56 -0
  181. package/docs/README.md +26 -0
  182. package/docs/adapter-evaluation.md +55 -0
  183. package/docs/backend-guidelines.md +335 -0
  184. package/docs/frontend-guidelines.md +266 -0
  185. package/docs/installation-variants.md +88 -0
  186. package/docs/migration-guide-0.2.0.md +250 -0
  187. package/docs/platform-matrix.md +83 -0
  188. package/package.json +40 -0
@@ -0,0 +1,811 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { execSync } from 'child_process';
4
+ import chalk from 'chalk';
5
+ import yaml from 'js-yaml';
6
+ import inquirer from 'inquirer';
7
+
8
+ const CORE_DIR = process.env.AODW_CORE_DIR || '.aodw';
9
+ const PACKAGE_NAME = process.env.AODW_PACKAGE_NAME || 'aodw';
10
+ const TOOLS_STATUS_FILE = `${CORE_DIR}/tools-status.yaml`;
11
+
12
+ // 获取模板目录路径(支持开发环境和发布环境)
13
+ function getTemplatesDir() {
14
+ const cwd = process.cwd();
15
+ // 先尝试当前项目的核心目录(用户项目中的模板)
16
+ const localTemplates = path.join(cwd, `${CORE_DIR}/templates/tools-config`);
17
+ if (fs.existsSync(localTemplates)) {
18
+ return localTemplates;
19
+ }
20
+ // 如果不存在,尝试 CLI 包内的模板(发布后的模板)
21
+ // 注意:CLI 包内的模板路径是相对于 CLI 源码目录的
22
+ // 路径:cli/.aodw/templates/tools-config(开发环境)
23
+ // 或:node_modules/<package>/.aodw/templates/tools-config(发布后)
24
+ const cliTemplates = path.join(__dirname, '../../.aodw/templates/tools-config');
25
+ if (fs.existsSync(cliTemplates)) {
26
+ return cliTemplates;
27
+ }
28
+ // 尝试发布后的路径(node_modules)
29
+ const nodeModulesTemplates = path.join(cwd, `node_modules/${PACKAGE_NAME}/.aodw/templates/tools-config`);
30
+ if (fs.existsSync(nodeModulesTemplates)) {
31
+ return nodeModulesTemplates;
32
+ }
33
+ // 如果都不存在,返回本地路径(让错误更明显)
34
+ return localTemplates;
35
+ }
36
+
37
+ // 检测项目类型
38
+ function detectProjectType() {
39
+ const cwd = process.cwd();
40
+ let hasFrontend = false;
41
+ let hasBackend = false;
42
+
43
+ // 检查前端特征
44
+ if (
45
+ fs.existsSync(path.join(cwd, 'frontend')) ||
46
+ fs.existsSync(path.join(cwd, 'src/pages')) ||
47
+ fs.existsSync(path.join(cwd, 'src/features')) ||
48
+ (fs.existsSync(path.join(cwd, 'package.json')) &&
49
+ fs.existsSync(path.join(cwd, 'tsconfig.json')))
50
+ ) {
51
+ hasFrontend = true;
52
+ }
53
+
54
+ // 检查后端特征
55
+ if (
56
+ fs.existsSync(path.join(cwd, 'backend')) ||
57
+ fs.existsSync(path.join(cwd, 'app')) ||
58
+ fs.existsSync(path.join(cwd, 'api')) ||
59
+ fs.existsSync(path.join(cwd, 'pyproject.toml')) ||
60
+ fs.existsSync(path.join(cwd, 'requirements.txt'))
61
+ ) {
62
+ hasBackend = true;
63
+ }
64
+
65
+ if (hasFrontend && hasBackend) return 'fullstack';
66
+ if (hasFrontend) return 'frontend';
67
+ if (hasBackend) return 'backend';
68
+ return 'unknown';
69
+ }
70
+
71
+ // 检测工具是否安装(前端)
72
+ async function detectFrontendTool(toolName) {
73
+ try {
74
+ if (toolName === 'eslint') {
75
+ // 检查 package.json
76
+ const pkgPath = path.join(process.cwd(), 'package.json');
77
+ if (fs.existsSync(pkgPath)) {
78
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
79
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
80
+ if (deps.eslint || deps['@typescript-eslint/eslint-plugin']) {
81
+ // 尝试运行版本命令
82
+ try {
83
+ execSync('npx eslint --version', { stdio: 'ignore' });
84
+ return { installed: true };
85
+ } catch (e) {
86
+ return { installed: false, reason: '命令执行失败' };
87
+ }
88
+ }
89
+ }
90
+ return { installed: false, reason: 'package.json 中未找到依赖' };
91
+ }
92
+ if (toolName === 'prettier') {
93
+ const pkgPath = path.join(process.cwd(), 'package.json');
94
+ if (fs.existsSync(pkgPath)) {
95
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
96
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
97
+ if (deps.prettier) {
98
+ try {
99
+ execSync('npx prettier --version', { stdio: 'ignore' });
100
+ return { installed: true };
101
+ } catch (e) {
102
+ return { installed: false, reason: '命令执行失败' };
103
+ }
104
+ }
105
+ }
106
+ return { installed: false, reason: 'package.json 中未找到依赖' };
107
+ }
108
+ } catch (e) {
109
+ return { installed: false, reason: e.message };
110
+ }
111
+ return { installed: false, reason: '未知错误' };
112
+ }
113
+
114
+ // 检测工具是否安装(后端)
115
+ async function detectBackendTool(toolName) {
116
+ try {
117
+ // 尝试运行版本命令
118
+ let command;
119
+ if (toolName === 'uv') {
120
+ command = 'uv --version';
121
+ } else if (toolName === 'pip-tools') {
122
+ command = 'pip-compile --version';
123
+ } else if (toolName === 'ruff') {
124
+ command = 'ruff --version';
125
+ } else if (toolName === 'black') {
126
+ command = 'black --version';
127
+ } else if (toolName === 'pre-commit') {
128
+ command = 'pre-commit --version';
129
+ } else {
130
+ return { installed: false, reason: '未知工具' };
131
+ }
132
+
133
+ try {
134
+ execSync(command, { stdio: 'ignore' });
135
+ return { installed: true };
136
+ } catch (e) {
137
+ return { installed: false, reason: '命令执行失败,可能未安装' };
138
+ }
139
+ } catch (e) {
140
+ return { installed: false, reason: e.message };
141
+ }
142
+ }
143
+
144
+ // 检测配置文件是否存在
145
+ function detectConfigFile(configType, projectType) {
146
+ const cwd = process.cwd();
147
+ const configFiles = {
148
+ frontend: {
149
+ eslint: ['.eslintrc.json', '.eslintrc.js', '.eslintrc.yaml', 'eslint.config.js'],
150
+ prettier: ['.prettierrc.json', '.prettierrc.js', '.prettierrc.yaml', 'prettier.config.js'],
151
+ tsconfig: ['tsconfig.json'],
152
+ },
153
+ backend: {
154
+ ruff: ['pyproject.toml', 'ruff.toml'],
155
+ black: ['pyproject.toml'],
156
+ 'pre-commit': ['.pre-commit-config.yaml'],
157
+ },
158
+ };
159
+
160
+ const files = configFiles[projectType]?.[configType] || [];
161
+ for (const file of files) {
162
+ const filePath = path.join(cwd, file);
163
+ if (fs.existsSync(filePath)) {
164
+ return { exists: true, path: file };
165
+ }
166
+ }
167
+ return { exists: false, path: null };
168
+ }
169
+
170
+ // 读取工具状态
171
+ function getToolsStatus() {
172
+ const filepath = path.join(process.cwd(), TOOLS_STATUS_FILE);
173
+ if (fs.existsSync(filepath)) {
174
+ try {
175
+ return yaml.load(fs.readFileSync(filepath, 'utf8')) || {};
176
+ } catch (e) {
177
+ return {};
178
+ }
179
+ }
180
+ return {};
181
+ }
182
+
183
+ // 保存工具状态
184
+ async function saveToolsStatus(status) {
185
+ const filepath = path.join(process.cwd(), TOOLS_STATUS_FILE);
186
+ await fs.ensureDir(path.dirname(filepath));
187
+ await fs.writeFile(filepath, yaml.dump(status), 'utf8');
188
+ }
189
+
190
+ // 生成配置文件(如果不存在)
191
+ async function generateConfigFile(configType, projectType) {
192
+ const templatesDir = getTemplatesDir();
193
+
194
+ // 特殊处理 tsconfig 模板文件名
195
+ let templateFileName;
196
+ if (configType === 'tsconfig' && projectType === 'frontend') {
197
+ templateFileName = 'tsconfig.paths.template.json';
198
+ } else {
199
+ const ext = projectType === 'frontend' ? 'json' : (projectType === 'backend' && configType === 'pre-commit' ? 'yaml' : 'toml');
200
+ templateFileName = `${configType}.config.template.${ext}`;
201
+ }
202
+
203
+ const templatePath = path.join(templatesDir, projectType, templateFileName);
204
+
205
+ if (!fs.existsSync(templatePath)) {
206
+ console.log(chalk.yellow(`⚠️ 配置模板不存在: ${templatePath}`));
207
+ return false;
208
+ }
209
+
210
+ const template = fs.readFileSync(templatePath, 'utf8');
211
+ const cwd = process.cwd();
212
+
213
+ if (projectType === 'frontend') {
214
+ if (configType === 'eslint') {
215
+ const targetPath = path.join(cwd, '.eslintrc.json');
216
+ if (!fs.existsSync(targetPath)) {
217
+ fs.writeFileSync(targetPath, template);
218
+ console.log(chalk.green(`✔ 已生成 ESLint 配置文件: .eslintrc.json`));
219
+ return true;
220
+ }
221
+ } else if (configType === 'prettier') {
222
+ const targetPath = path.join(cwd, '.prettierrc.json');
223
+ if (!fs.existsSync(targetPath)) {
224
+ fs.writeFileSync(targetPath, template);
225
+ console.log(chalk.green(`✔ 已生成 Prettier 配置文件: .prettierrc.json`));
226
+ return true;
227
+ }
228
+ } else if (configType === 'tsconfig') {
229
+ const targetPath = path.join(cwd, 'tsconfig.json');
230
+ try {
231
+ const templateObj = JSON.parse(template);
232
+ if (fs.existsSync(targetPath)) {
233
+ // 合并到现有 tsconfig.json
234
+ const existing = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
235
+ const merged = {
236
+ ...existing,
237
+ compilerOptions: {
238
+ ...existing.compilerOptions,
239
+ ...templateObj.compilerOptions,
240
+ },
241
+ };
242
+ fs.writeFileSync(targetPath, JSON.stringify(merged, null, 2));
243
+ console.log(chalk.green(`✔ 已更新 tsconfig.json,添加了 path alias 配置`));
244
+ return true;
245
+ } else {
246
+ fs.writeFileSync(targetPath, JSON.stringify(templateObj, null, 2));
247
+ console.log(chalk.green(`✔ 已生成 tsconfig.json`));
248
+ return true;
249
+ }
250
+ } catch (error) {
251
+ console.error(chalk.red(`✗ 解析模板文件失败: ${error.message}`));
252
+ return false;
253
+ }
254
+ }
255
+ } else if (projectType === 'backend') {
256
+ if (configType === 'ruff' || configType === 'black') {
257
+ const targetPath = path.join(cwd, 'pyproject.toml');
258
+ if (fs.existsSync(targetPath)) {
259
+ console.log(chalk.yellow(`⚠️ pyproject.toml 已存在,需要手动合并配置`));
260
+ console.log(chalk.blue(` 参考模板: ${templatePath}`));
261
+ console.log(chalk.gray(` 或通过 AI 命令"初始化工具"进行交互式配置合并`));
262
+ return false;
263
+ } else {
264
+ // 创建新的 pyproject.toml(只包含当前工具的配置)
265
+ fs.writeFileSync(targetPath, template);
266
+ console.log(chalk.green(`✔ 已生成 pyproject.toml`));
267
+ return true;
268
+ }
269
+ } else if (configType === 'pre-commit') {
270
+ const targetPath = path.join(cwd, '.pre-commit-config.yaml');
271
+ if (!fs.existsSync(targetPath)) {
272
+ fs.writeFileSync(targetPath, template);
273
+ console.log(chalk.green(`✔ 已生成 .pre-commit-config.yaml`));
274
+ return true;
275
+ }
276
+ }
277
+ }
278
+
279
+ return false;
280
+ }
281
+
282
+ // 询问用户是否安装工具
283
+ async function askToInstall(toolName, description, installMethod) {
284
+ const { install } = await inquirer.prompt([{
285
+ type: 'confirm',
286
+ name: 'install',
287
+ message: `${toolName} 未安装。${description}\n是否立即安装?`,
288
+ default: true
289
+ }]);
290
+ return install;
291
+ }
292
+
293
+ // 安装前端工具(ESLint)
294
+ async function installESLint() {
295
+ console.log(chalk.blue('📦 正在安装 ESLint 及其插件...'));
296
+ try {
297
+ // 先尝试正常安装
298
+ execSync('npm install -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-import eslint-plugin-jsx-a11y eslint-config-prettier', {
299
+ stdio: 'inherit',
300
+ cwd: process.cwd()
301
+ });
302
+ console.log(chalk.green('✔ ESLint 安装完成\n'));
303
+ return true;
304
+ } catch (error) {
305
+ // 如果出现依赖冲突,尝试使用 --legacy-peer-deps
306
+ if (error.message.includes('ERESOLVE') || error.message.includes('could not resolve')) {
307
+ console.log(chalk.yellow('⚠️ 检测到依赖冲突,尝试使用 --legacy-peer-deps 安装...'));
308
+ try {
309
+ execSync('npm install -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-import eslint-plugin-jsx-a11y eslint-config-prettier --legacy-peer-deps', {
310
+ stdio: 'inherit',
311
+ cwd: process.cwd()
312
+ });
313
+ console.log(chalk.green('✔ ESLint 安装完成(使用 --legacy-peer-deps)\n'));
314
+ return true;
315
+ } catch (retryError) {
316
+ console.error(chalk.red(`✗ ESLint 安装失败: ${retryError.message}\n`));
317
+ console.log(chalk.yellow('💡 提示:您可以手动运行安装命令并添加 --legacy-peer-deps 或 --force 选项\n'));
318
+ return false;
319
+ }
320
+ } else {
321
+ console.error(chalk.red(`✗ ESLint 安装失败: ${error.message}\n`));
322
+ return false;
323
+ }
324
+ }
325
+ }
326
+
327
+ // 安装前端工具(Prettier)
328
+ async function installPrettier() {
329
+ console.log(chalk.blue('📦 正在安装 Prettier...'));
330
+ try {
331
+ // 先尝试正常安装
332
+ execSync('npm install -D prettier', {
333
+ stdio: 'inherit',
334
+ cwd: process.cwd()
335
+ });
336
+ console.log(chalk.green('✔ Prettier 安装完成\n'));
337
+ return true;
338
+ } catch (error) {
339
+ // 如果出现依赖冲突,尝试使用 --legacy-peer-deps
340
+ if (error.message.includes('ERESOLVE') || error.message.includes('could not resolve')) {
341
+ console.log(chalk.yellow('⚠️ 检测到依赖冲突,尝试使用 --legacy-peer-deps 安装...'));
342
+ try {
343
+ execSync('npm install -D prettier --legacy-peer-deps', {
344
+ stdio: 'inherit',
345
+ cwd: process.cwd()
346
+ });
347
+ console.log(chalk.green('✔ Prettier 安装完成(使用 --legacy-peer-deps)\n'));
348
+ return true;
349
+ } catch (retryError) {
350
+ console.error(chalk.red(`✗ Prettier 安装失败: ${retryError.message}\n`));
351
+ console.log(chalk.yellow('💡 提示:您可以手动运行 "npm install -D prettier --legacy-peer-deps" 或 "npm install -D prettier --force"\n'));
352
+ return false;
353
+ }
354
+ } else {
355
+ console.error(chalk.red(`✗ Prettier 安装失败: ${error.message}\n`));
356
+ return false;
357
+ }
358
+ }
359
+ }
360
+
361
+ // 确保 requirements-dev.in 存在
362
+ function ensureRequirementsDevIn() {
363
+ const requirementsDevInPath = path.join(process.cwd(), 'requirements-dev.in');
364
+ if (!fs.existsSync(requirementsDevInPath)) {
365
+ console.log(chalk.blue('📝 创建 requirements-dev.in 文件...'));
366
+ fs.writeFileSync(requirementsDevInPath, '# Development dependencies\n');
367
+ console.log(chalk.green('✔ requirements-dev.in 已创建\n'));
368
+ }
369
+ return requirementsDevInPath;
370
+ }
371
+
372
+ // 通过 uv + pip-tools 安装后端工具
373
+ async function installBackendToolViaPipTools(toolName, versionConstraint) {
374
+ const requirementsDevInPath = ensureRequirementsDevIn();
375
+
376
+ // 检查依赖是否已存在
377
+ const content = fs.readFileSync(requirementsDevInPath, 'utf8');
378
+ if (content.includes(toolName)) {
379
+ console.log(chalk.yellow(`⚠️ ${toolName} 已在 requirements-dev.in 中\n`));
380
+ return true;
381
+ }
382
+
383
+ // 添加依赖到 requirements-dev.in
384
+ console.log(chalk.blue(`📝 添加 ${toolName} 到 requirements-dev.in...`));
385
+ fs.appendFileSync(requirementsDevInPath, `${toolName}${versionConstraint}\n`);
386
+ console.log(chalk.green(`✔ ${toolName} 已添加到 requirements-dev.in\n`));
387
+
388
+ // 检查是否有 Makefile
389
+ const makefilePath = path.join(process.cwd(), 'Makefile');
390
+ const hasMakefile = fs.existsSync(makefilePath);
391
+
392
+ if (hasMakefile) {
393
+ // 使用 Makefile
394
+ console.log(chalk.blue('📦 编译依赖(make compile-deps)...'));
395
+ try {
396
+ execSync('make compile-deps', {
397
+ stdio: 'inherit',
398
+ cwd: process.cwd()
399
+ });
400
+ console.log(chalk.green('✔ 依赖编译完成\n'));
401
+
402
+ console.log(chalk.blue('📦 同步环境(make sync)...'));
403
+ execSync('make sync', {
404
+ stdio: 'inherit',
405
+ cwd: process.cwd()
406
+ });
407
+ console.log(chalk.green('✔ 环境同步完成\n'));
408
+ return true;
409
+ } catch (error) {
410
+ console.error(chalk.red(`✗ 依赖安装失败: ${error.message}\n`));
411
+ console.log(chalk.yellow('💡 提示:请确保已安装 uv 和 pip-tools,并配置了 Makefile\n'));
412
+ return false;
413
+ }
414
+ } else {
415
+ // 直接使用 uv pip compile 和 sync
416
+ console.log(chalk.blue('📦 编译依赖(uv pip compile)...'));
417
+ try {
418
+ execSync('uv pip compile requirements-dev.in -o requirements-dev.txt', {
419
+ stdio: 'inherit',
420
+ cwd: process.cwd()
421
+ });
422
+ console.log(chalk.green('✔ 依赖编译完成\n'));
423
+
424
+ console.log(chalk.blue('📦 同步环境(uv pip sync)...'));
425
+ execSync('uv pip sync requirements-dev.txt', {
426
+ stdio: 'inherit',
427
+ cwd: process.cwd()
428
+ });
429
+ console.log(chalk.green('✔ 环境同步完成\n'));
430
+ return true;
431
+ } catch (error) {
432
+ console.error(chalk.red(`✗ 依赖安装失败: ${error.message}\n`));
433
+ console.log(chalk.yellow('💡 提示:请确保已安装 uv 和 pip-tools\n'));
434
+ return false;
435
+ }
436
+ }
437
+ }
438
+
439
+ // 安装 pre-commit hooks
440
+ async function installPreCommitHooks() {
441
+ console.log(chalk.blue('📦 安装 pre-commit hooks...'));
442
+ try {
443
+ execSync('pre-commit install', {
444
+ stdio: 'inherit',
445
+ cwd: process.cwd()
446
+ });
447
+ console.log(chalk.green('✔ pre-commit hooks 安装完成\n'));
448
+ return true;
449
+ } catch (error) {
450
+ console.error(chalk.red(`✗ pre-commit hooks 安装失败: ${error.message}\n`));
451
+ return false;
452
+ }
453
+ }
454
+
455
+ // 主函数
456
+ export async function initTools() {
457
+ console.log(chalk.blue('🔧 AODW 工具初始化检查...\n'));
458
+
459
+ // Step 1: 检测项目类型
460
+ const projectType = detectProjectType();
461
+ if (projectType === 'unknown') {
462
+ console.log(chalk.yellow('⚠️ 无法检测项目类型,请确认项目结构'));
463
+ console.log(chalk.gray(' 前端项目应包含: frontend/ 或 src/pages/ 或 package.json + tsconfig.json'));
464
+ console.log(chalk.gray(' 后端项目应包含: backend/ 或 app/ 或 pyproject.toml'));
465
+ return;
466
+ }
467
+
468
+ console.log(chalk.blue(`📦 检测到项目类型: ${projectType}\n`));
469
+
470
+ const status = {
471
+ tools_init: {
472
+ initialized: true,
473
+ initialized_at: new Date().toISOString(),
474
+ last_updated_at: new Date().toISOString(),
475
+ initialized_by: 'cli',
476
+ project_type: projectType,
477
+ frontend: {},
478
+ backend: {},
479
+ },
480
+ };
481
+
482
+ // Step 2: 检测前端工具
483
+ if (projectType === 'frontend' || projectType === 'fullstack') {
484
+ console.log(chalk.blue('🔍 检查前端工具...\n'));
485
+
486
+ // ESLint
487
+ const eslintStatus = await detectFrontendTool('eslint');
488
+ const eslintConfig = detectConfigFile('eslint', 'frontend');
489
+ status.tools_init.frontend.eslint = {
490
+ installed: eslintStatus.installed,
491
+ configured: eslintConfig.exists,
492
+ config_file: eslintConfig.path || null,
493
+ config_source: eslintConfig.exists ? 'existing' : null,
494
+ };
495
+
496
+ if (!eslintStatus.installed) {
497
+ console.log(chalk.yellow('⚠️ 检测到 ESLint 未安装'));
498
+ const shouldInstall = await askToInstall(
499
+ 'ESLint',
500
+ 'ESLint 是必需的代码质量检查工具,用于检查代码风格和潜在问题。',
501
+ 'npm install'
502
+ );
503
+ if (shouldInstall) {
504
+ const installed = await installESLint();
505
+ if (installed) {
506
+ status.tools_init.frontend.eslint.installed = true;
507
+ }
508
+ } else {
509
+ console.log(chalk.gray(' 跳过 ESLint 安装。您稍后可以手动安装。\n'));
510
+ }
511
+ }
512
+
513
+ // 检查配置(无论是否刚安装)
514
+ if (!eslintConfig.exists && status.tools_init.frontend.eslint.installed) {
515
+ console.log(chalk.yellow('⚠️ ESLint 已安装,但配置文件不存在'));
516
+ const shouldGenerate = await askToInstall(
517
+ 'ESLint 配置文件',
518
+ '是否生成 ESLint 配置文件?',
519
+ 'generate config'
520
+ );
521
+ if (shouldGenerate) {
522
+ await generateConfigFile('eslint', 'frontend');
523
+ status.tools_init.frontend.eslint.configured = true;
524
+ }
525
+ } else if (eslintConfig.exists) {
526
+ console.log(chalk.green(`✔ ESLint 已安装并配置 (${eslintConfig.path})\n`));
527
+ }
528
+
529
+ // Prettier
530
+ const prettierStatus = await detectFrontendTool('prettier');
531
+ const prettierConfig = detectConfigFile('prettier', 'frontend');
532
+ status.tools_init.frontend.prettier = {
533
+ installed: prettierStatus.installed,
534
+ configured: prettierConfig.exists,
535
+ config_file: prettierConfig.path || null,
536
+ config_source: prettierConfig.exists ? 'existing' : null,
537
+ };
538
+
539
+ if (!prettierStatus.installed) {
540
+ console.log(chalk.yellow('⚠️ 检测到 Prettier 未安装'));
541
+ const shouldInstall = await askToInstall(
542
+ 'Prettier',
543
+ 'Prettier 是代码格式化工具,用于统一代码风格。',
544
+ 'npm install'
545
+ );
546
+ if (shouldInstall) {
547
+ const installed = await installPrettier();
548
+ if (installed) {
549
+ status.tools_init.frontend.prettier.installed = true;
550
+ }
551
+ } else {
552
+ console.log(chalk.gray(' 跳过 Prettier 安装。您稍后可以手动安装。\n'));
553
+ }
554
+ }
555
+
556
+ // 检查配置(无论是否刚安装)
557
+ if (!prettierConfig.exists && status.tools_init.frontend.prettier.installed) {
558
+ console.log(chalk.yellow('⚠️ Prettier 已安装,但配置文件不存在'));
559
+ const shouldGenerate = await askToInstall(
560
+ 'Prettier 配置文件',
561
+ '是否生成 Prettier 配置文件?',
562
+ 'generate config'
563
+ );
564
+ if (shouldGenerate) {
565
+ await generateConfigFile('prettier', 'frontend');
566
+ status.tools_init.frontend.prettier.configured = true;
567
+ }
568
+ } else if (prettierConfig.exists) {
569
+ console.log(chalk.green(`✔ Prettier 已安装并配置 (${prettierConfig.path})\n`));
570
+ }
571
+
572
+ // TypeScript Path Alias
573
+ const tsconfigPath = path.join(process.cwd(), 'tsconfig.json');
574
+ const tsconfigExists = fs.existsSync(tsconfigPath);
575
+ let tsconfigHasPaths = false;
576
+ if (tsconfigExists) {
577
+ try {
578
+ const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf8'));
579
+ tsconfigHasPaths = !!(tsconfig.compilerOptions?.paths);
580
+ } catch (e) {
581
+ // ignore
582
+ }
583
+ }
584
+
585
+ status.tools_init.frontend.typescript_path_alias = {
586
+ configured: tsconfigHasPaths,
587
+ config_file: tsconfigExists ? 'tsconfig.json' : null,
588
+ config_source: tsconfigHasPaths ? 'existing' : null,
589
+ };
590
+
591
+ if (!tsconfigHasPaths) {
592
+ console.log(chalk.yellow('⚠️ TypeScript path alias 未配置'));
593
+ await generateConfigFile('tsconfig', 'frontend');
594
+ } else {
595
+ console.log(chalk.green('✔ TypeScript path alias 已配置\n'));
596
+ }
597
+ }
598
+
599
+ // Step 3: 检测后端工具
600
+ if (projectType === 'backend' || projectType === 'fullstack') {
601
+ console.log(chalk.blue('🔍 检查后端工具...\n'));
602
+
603
+ // 依赖管理工具(uv + pip-tools)
604
+ const uvStatus = await detectBackendTool('uv');
605
+ const pipToolsStatus = await detectBackendTool('pip-tools');
606
+ const requirementsInExists = fs.existsSync(path.join(process.cwd(), 'requirements.in'));
607
+ const requirementsDevInExists = fs.existsSync(path.join(process.cwd(), 'requirements-dev.in'));
608
+ const makefileExists = fs.existsSync(path.join(process.cwd(), 'Makefile'));
609
+
610
+ status.tools_init.backend.dependency_manager = {
611
+ uv_installed: uvStatus.installed,
612
+ pip_tools_installed: pipToolsStatus.installed,
613
+ configured: requirementsInExists && (makefileExists || pipToolsStatus.installed),
614
+ requirements_in_exists: requirementsInExists,
615
+ requirements_dev_in_exists: requirementsDevInExists,
616
+ makefile_exists: makefileExists,
617
+ };
618
+
619
+ if (!uvStatus.installed) {
620
+ console.log(chalk.yellow('⚠️ 检测到 uv 未安装'));
621
+ console.log(chalk.blue(' 建议运行: curl -LsSf https://astral.sh/uv/install.sh | sh'));
622
+ console.log(chalk.gray(' 或通过 AI 命令"初始化工具"进行交互式配置\n'));
623
+ } else if (!pipToolsStatus.installed) {
624
+ console.log(chalk.yellow('⚠️ 检测到 pip-tools 未安装'));
625
+ console.log(chalk.blue(' 建议运行: uv pip install pip-tools'));
626
+ console.log(chalk.gray(' 或通过 AI 命令"初始化工具"进行交互式配置\n'));
627
+ } else if (!requirementsInExists) {
628
+ console.log(chalk.yellow('⚠️ 依赖管理未配置(缺少 requirements.in)'));
629
+ console.log(chalk.blue(' 建议创建 requirements.in 和 requirements-dev.in 文件'));
630
+ console.log(chalk.gray(' 或通过 AI 命令"初始化工具"进行交互式配置\n'));
631
+ } else {
632
+ console.log(chalk.green('✔ 依赖管理工具已配置(uv + pip-tools)\n'));
633
+ }
634
+
635
+ // Ruff
636
+ const ruffStatus = await detectBackendTool('ruff');
637
+ const ruffConfig = detectConfigFile('ruff', 'backend');
638
+ status.tools_init.backend.ruff = {
639
+ installed: ruffStatus.installed,
640
+ configured: ruffConfig.exists,
641
+ config_file: ruffConfig.path || null,
642
+ config_source: ruffConfig.exists ? 'existing' : null,
643
+ };
644
+
645
+ if (!ruffStatus.installed) {
646
+ console.log(chalk.yellow('⚠️ 检测到 Ruff 未安装'));
647
+ const shouldInstall = await askToInstall(
648
+ 'Ruff',
649
+ 'Ruff 是 Python 代码质量检查工具,用于检查代码风格、复杂度和潜在问题。',
650
+ 'uv + pip-tools'
651
+ );
652
+ if (shouldInstall) {
653
+ const installed = await installBackendToolViaPipTools('ruff', '>=0.1.0,<1.0.0');
654
+ if (installed) {
655
+ status.tools_init.backend.ruff.installed = true;
656
+ }
657
+ } else {
658
+ console.log(chalk.gray(' 跳过 Ruff 安装。您稍后可以手动安装。\n'));
659
+ }
660
+ }
661
+
662
+ // 检查配置(无论是否刚安装)
663
+ if (!ruffConfig.exists && status.tools_init.backend.ruff.installed) {
664
+ console.log(chalk.yellow('⚠️ Ruff 已安装,但配置文件不存在'));
665
+ const shouldGenerate = await askToInstall(
666
+ 'Ruff 配置文件',
667
+ '是否生成 Ruff 配置文件?',
668
+ 'generate config'
669
+ );
670
+ if (shouldGenerate) {
671
+ await generateConfigFile('ruff', 'backend');
672
+ status.tools_init.backend.ruff.configured = true;
673
+ }
674
+ } else if (ruffConfig.exists) {
675
+ console.log(chalk.green(`✔ Ruff 已安装并配置 (${ruffConfig.path})\n`));
676
+ }
677
+
678
+ // Black
679
+ const blackStatus = await detectBackendTool('black');
680
+ const blackConfig = detectConfigFile('black', 'backend');
681
+ status.tools_init.backend.black = {
682
+ installed: blackStatus.installed,
683
+ configured: blackConfig.exists,
684
+ config_file: blackConfig.path || null,
685
+ config_source: blackConfig.exists ? 'existing' : null,
686
+ };
687
+
688
+ if (!blackStatus.installed) {
689
+ console.log(chalk.yellow('⚠️ 检测到 Black 未安装'));
690
+ const shouldInstall = await askToInstall(
691
+ 'Black',
692
+ 'Black 是 Python 代码格式化工具,用于统一代码风格。',
693
+ 'uv + pip-tools'
694
+ );
695
+ if (shouldInstall) {
696
+ const installed = await installBackendToolViaPipTools('black', '>=23.0.0,<24.0.0');
697
+ if (installed) {
698
+ status.tools_init.backend.black.installed = true;
699
+ }
700
+ } else {
701
+ console.log(chalk.gray(' 跳过 Black 安装。您稍后可以手动安装。\n'));
702
+ }
703
+ }
704
+
705
+ // 检查配置(无论是否刚安装)
706
+ if (!blackConfig.exists && status.tools_init.backend.black.installed) {
707
+ console.log(chalk.yellow('⚠️ Black 已安装,但配置文件不存在'));
708
+ const shouldGenerate = await askToInstall(
709
+ 'Black 配置文件',
710
+ '是否生成 Black 配置文件?',
711
+ 'generate config'
712
+ );
713
+ if (shouldGenerate) {
714
+ await generateConfigFile('black', 'backend');
715
+ status.tools_init.backend.black.configured = true;
716
+ }
717
+ } else if (blackConfig.exists) {
718
+ console.log(chalk.green(`✔ Black 已安装并配置 (${blackConfig.path})\n`));
719
+ }
720
+
721
+ // pre-commit
722
+ const precommitStatus = await detectBackendTool('pre-commit');
723
+ const precommitConfig = detectConfigFile('pre-commit', 'backend');
724
+ let hooksInstalled = false;
725
+ if (precommitStatus.installed) {
726
+ const hooksPath = path.join(process.cwd(), '.git/hooks/pre-commit');
727
+ hooksInstalled = fs.existsSync(hooksPath);
728
+ }
729
+
730
+ status.tools_init.backend.pre_commit = {
731
+ installed: precommitStatus.installed,
732
+ configured: precommitConfig.exists,
733
+ hooks_installed: hooksInstalled,
734
+ config_file: precommitConfig.path || null,
735
+ config_source: precommitConfig.exists ? 'existing' : null,
736
+ };
737
+
738
+ if (!precommitStatus.installed) {
739
+ console.log(chalk.yellow('⚠️ 检测到 pre-commit 未安装'));
740
+ const shouldInstall = await askToInstall(
741
+ 'pre-commit',
742
+ 'pre-commit 是 Git hooks 工具,用于在提交前自动检查代码质量。',
743
+ 'uv + pip-tools'
744
+ );
745
+ if (shouldInstall) {
746
+ const installed = await installBackendToolViaPipTools('pre-commit', '>=3.0.0,<4.0.0');
747
+ if (installed) {
748
+ status.tools_init.backend.pre_commit.installed = true;
749
+ // 安装 hooks
750
+ await installPreCommitHooks();
751
+ status.tools_init.backend.pre_commit.hooks_installed = true;
752
+ }
753
+ } else {
754
+ console.log(chalk.gray(' 跳过 pre-commit 安装。您稍后可以手动安装。\n'));
755
+ }
756
+ }
757
+
758
+ // 检查配置(无论是否刚安装)
759
+ if (!precommitConfig.exists && status.tools_init.backend.pre_commit.installed) {
760
+ console.log(chalk.yellow('⚠️ pre-commit 已安装,但配置文件不存在'));
761
+ const shouldGenerate = await askToInstall(
762
+ 'pre-commit 配置文件',
763
+ '是否生成 pre-commit 配置文件?',
764
+ 'generate config'
765
+ );
766
+ if (shouldGenerate) {
767
+ await generateConfigFile('pre-commit', 'backend');
768
+ status.tools_init.backend.pre_commit.configured = true;
769
+ }
770
+ if (!hooksInstalled && status.tools_init.backend.pre_commit.installed) {
771
+ console.log(chalk.yellow('⚠️ pre-commit hooks 未安装'));
772
+ const shouldInstallHooks = await askToInstall(
773
+ 'pre-commit hooks',
774
+ 'pre-commit hooks 用于在 Git 提交前自动运行代码检查。',
775
+ 'pre-commit install'
776
+ );
777
+ if (shouldInstallHooks) {
778
+ const installed = await installPreCommitHooks();
779
+ if (installed) {
780
+ status.tools_init.backend.pre_commit.hooks_installed = true;
781
+ }
782
+ }
783
+ }
784
+ } else {
785
+ if (!hooksInstalled && status.tools_init.backend.pre_commit.installed) {
786
+ console.log(chalk.yellow('⚠️ pre-commit hooks 未安装'));
787
+ const shouldInstallHooks = await askToInstall(
788
+ 'pre-commit hooks',
789
+ 'pre-commit hooks 用于在 Git 提交前自动运行代码检查。',
790
+ 'pre-commit install'
791
+ );
792
+ if (shouldInstallHooks) {
793
+ const installed = await installPreCommitHooks();
794
+ if (installed) {
795
+ status.tools_init.backend.pre_commit.hooks_installed = true;
796
+ }
797
+ }
798
+ } else if (hooksInstalled) {
799
+ console.log(chalk.green(`✔ pre-commit 已安装并配置 (${precommitConfig.path})\n`));
800
+ }
801
+ }
802
+ }
803
+
804
+ // Step 4: 保存状态
805
+ await saveToolsStatus(status);
806
+
807
+ // Step 5: 输出总结
808
+ console.log(chalk.blue('\n📊 工具初始化检查完成'));
809
+ console.log(chalk.gray(`状态已保存到: ${TOOLS_STATUS_FILE}`));
810
+ console.log(chalk.gray('\n💡 提示: 如果工具未完全配置,可以通过 AI 命令"初始化工具"进行交互式配置'));
811
+ }