jarvis-ai-assistant 0.7.16__py3-none-any.whl → 1.0.2__py3-none-any.whl

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 (279) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +567 -222
  3. jarvis/jarvis_agent/agent_manager.py +19 -12
  4. jarvis/jarvis_agent/builtin_input_handler.py +79 -11
  5. jarvis/jarvis_agent/config_editor.py +7 -2
  6. jarvis/jarvis_agent/event_bus.py +24 -13
  7. jarvis/jarvis_agent/events.py +19 -1
  8. jarvis/jarvis_agent/file_context_handler.py +67 -64
  9. jarvis/jarvis_agent/file_methodology_manager.py +38 -24
  10. jarvis/jarvis_agent/jarvis.py +186 -114
  11. jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
  12. jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
  13. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
  14. jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
  15. jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
  16. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
  17. jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
  18. jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
  19. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
  20. jarvis/jarvis_agent/language_support_info.py +250 -219
  21. jarvis/jarvis_agent/main.py +19 -23
  22. jarvis/jarvis_agent/memory_manager.py +9 -6
  23. jarvis/jarvis_agent/methodology_share_manager.py +21 -15
  24. jarvis/jarvis_agent/output_handler.py +4 -2
  25. jarvis/jarvis_agent/prompt_builder.py +7 -6
  26. jarvis/jarvis_agent/prompt_manager.py +113 -8
  27. jarvis/jarvis_agent/prompts.py +317 -85
  28. jarvis/jarvis_agent/protocols.py +5 -2
  29. jarvis/jarvis_agent/run_loop.py +192 -32
  30. jarvis/jarvis_agent/session_manager.py +7 -3
  31. jarvis/jarvis_agent/share_manager.py +23 -13
  32. jarvis/jarvis_agent/shell_input_handler.py +12 -8
  33. jarvis/jarvis_agent/stdio_redirect.py +25 -26
  34. jarvis/jarvis_agent/task_analyzer.py +29 -23
  35. jarvis/jarvis_agent/task_list.py +869 -0
  36. jarvis/jarvis_agent/task_manager.py +26 -23
  37. jarvis/jarvis_agent/tool_executor.py +6 -5
  38. jarvis/jarvis_agent/tool_share_manager.py +24 -14
  39. jarvis/jarvis_agent/user_interaction.py +3 -3
  40. jarvis/jarvis_agent/utils.py +9 -1
  41. jarvis/jarvis_agent/web_bridge.py +37 -17
  42. jarvis/jarvis_agent/web_output_sink.py +5 -2
  43. jarvis/jarvis_agent/web_server.py +165 -36
  44. jarvis/jarvis_c2rust/__init__.py +1 -1
  45. jarvis/jarvis_c2rust/cli.py +260 -141
  46. jarvis/jarvis_c2rust/collector.py +37 -18
  47. jarvis/jarvis_c2rust/constants.py +60 -0
  48. jarvis/jarvis_c2rust/library_replacer.py +242 -1010
  49. jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
  50. jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
  51. jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
  52. jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
  53. jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
  54. jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
  55. jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
  56. jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
  57. jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
  58. jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
  59. jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
  60. jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
  61. jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
  62. jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
  63. jarvis/jarvis_c2rust/loaders.py +28 -10
  64. jarvis/jarvis_c2rust/models.py +5 -2
  65. jarvis/jarvis_c2rust/optimizer.py +192 -1974
  66. jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
  67. jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
  68. jarvis/jarvis_c2rust/optimizer_config.py +49 -0
  69. jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
  70. jarvis/jarvis_c2rust/optimizer_options.py +48 -0
  71. jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
  72. jarvis/jarvis_c2rust/optimizer_report.py +52 -0
  73. jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
  74. jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
  75. jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
  76. jarvis/jarvis_c2rust/scanner.py +229 -166
  77. jarvis/jarvis_c2rust/transpiler.py +531 -2732
  78. jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
  79. jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
  80. jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
  81. jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
  82. jarvis/jarvis_c2rust/transpiler_config.py +178 -0
  83. jarvis/jarvis_c2rust/transpiler_context.py +122 -0
  84. jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
  85. jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
  86. jarvis/jarvis_c2rust/transpiler_git.py +163 -0
  87. jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
  88. jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
  89. jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
  90. jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
  91. jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
  92. jarvis/jarvis_c2rust/utils.py +269 -79
  93. jarvis/jarvis_code_agent/after_change.py +233 -0
  94. jarvis/jarvis_code_agent/build_validation_config.py +37 -30
  95. jarvis/jarvis_code_agent/builtin_rules.py +68 -0
  96. jarvis/jarvis_code_agent/code_agent.py +976 -1517
  97. jarvis/jarvis_code_agent/code_agent_build.py +227 -0
  98. jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
  99. jarvis/jarvis_code_agent/code_agent_git.py +525 -0
  100. jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
  101. jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
  102. jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
  103. jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
  104. jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
  105. jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
  106. jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
  107. jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
  108. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
  109. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
  110. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
  111. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
  112. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
  113. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
  114. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
  115. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
  116. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
  117. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
  118. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
  119. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
  120. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
  121. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
  122. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
  123. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
  124. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
  125. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
  126. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
  127. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
  128. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
  129. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
  130. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
  131. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
  132. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
  133. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
  134. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
  135. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
  136. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
  137. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
  138. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
  139. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
  140. jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
  141. jarvis/jarvis_code_agent/lint.py +223 -524
  142. jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
  143. jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
  144. jarvis/jarvis_code_agent/rules/code_review.md +115 -0
  145. jarvis/jarvis_code_agent/rules/documentation.md +165 -0
  146. jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
  147. jarvis/jarvis_code_agent/rules/performance.md +158 -0
  148. jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
  149. jarvis/jarvis_code_agent/rules/security.md +160 -0
  150. jarvis/jarvis_code_agent/rules/tdd.md +78 -0
  151. jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
  152. jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
  153. jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
  154. jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
  155. jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
  156. jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
  157. jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
  158. jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
  159. jarvis/jarvis_code_agent/utils.py +36 -26
  160. jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
  161. jarvis/jarvis_code_analysis/code_review.py +64 -33
  162. jarvis/jarvis_data/config_schema.json +285 -192
  163. jarvis/jarvis_git_squash/main.py +8 -6
  164. jarvis/jarvis_git_utils/git_commiter.py +53 -76
  165. jarvis/jarvis_mcp/__init__.py +5 -2
  166. jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
  167. jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
  168. jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
  169. jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
  170. jarvis/jarvis_methodology/main.py +48 -39
  171. jarvis/jarvis_multi_agent/__init__.py +56 -23
  172. jarvis/jarvis_multi_agent/main.py +15 -18
  173. jarvis/jarvis_platform/base.py +179 -111
  174. jarvis/jarvis_platform/human.py +27 -16
  175. jarvis/jarvis_platform/kimi.py +52 -45
  176. jarvis/jarvis_platform/openai.py +101 -40
  177. jarvis/jarvis_platform/registry.py +51 -33
  178. jarvis/jarvis_platform/tongyi.py +68 -38
  179. jarvis/jarvis_platform/yuanbao.py +59 -43
  180. jarvis/jarvis_platform_manager/main.py +68 -76
  181. jarvis/jarvis_platform_manager/service.py +24 -14
  182. jarvis/jarvis_rag/README_CONFIG.md +314 -0
  183. jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
  184. jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
  185. jarvis/jarvis_rag/__init__.py +57 -4
  186. jarvis/jarvis_rag/cache.py +3 -1
  187. jarvis/jarvis_rag/cli.py +48 -68
  188. jarvis/jarvis_rag/embedding_interface.py +39 -0
  189. jarvis/jarvis_rag/embedding_manager.py +7 -230
  190. jarvis/jarvis_rag/embeddings/__init__.py +41 -0
  191. jarvis/jarvis_rag/embeddings/base.py +114 -0
  192. jarvis/jarvis_rag/embeddings/cohere.py +66 -0
  193. jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
  194. jarvis/jarvis_rag/embeddings/local.py +260 -0
  195. jarvis/jarvis_rag/embeddings/openai.py +62 -0
  196. jarvis/jarvis_rag/embeddings/registry.py +293 -0
  197. jarvis/jarvis_rag/llm_interface.py +8 -6
  198. jarvis/jarvis_rag/query_rewriter.py +8 -9
  199. jarvis/jarvis_rag/rag_pipeline.py +61 -52
  200. jarvis/jarvis_rag/reranker.py +7 -75
  201. jarvis/jarvis_rag/reranker_interface.py +32 -0
  202. jarvis/jarvis_rag/rerankers/__init__.py +41 -0
  203. jarvis/jarvis_rag/rerankers/base.py +109 -0
  204. jarvis/jarvis_rag/rerankers/cohere.py +67 -0
  205. jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
  206. jarvis/jarvis_rag/rerankers/jina.py +79 -0
  207. jarvis/jarvis_rag/rerankers/local.py +89 -0
  208. jarvis/jarvis_rag/rerankers/registry.py +293 -0
  209. jarvis/jarvis_rag/retriever.py +58 -43
  210. jarvis/jarvis_sec/__init__.py +66 -141
  211. jarvis/jarvis_sec/agents.py +21 -17
  212. jarvis/jarvis_sec/analysis.py +80 -33
  213. jarvis/jarvis_sec/checkers/__init__.py +7 -13
  214. jarvis/jarvis_sec/checkers/c_checker.py +356 -164
  215. jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
  216. jarvis/jarvis_sec/cli.py +43 -21
  217. jarvis/jarvis_sec/clustering.py +430 -272
  218. jarvis/jarvis_sec/file_manager.py +99 -55
  219. jarvis/jarvis_sec/parsers.py +9 -6
  220. jarvis/jarvis_sec/prompts.py +4 -3
  221. jarvis/jarvis_sec/report.py +44 -22
  222. jarvis/jarvis_sec/review.py +180 -107
  223. jarvis/jarvis_sec/status.py +50 -41
  224. jarvis/jarvis_sec/types.py +3 -0
  225. jarvis/jarvis_sec/utils.py +160 -83
  226. jarvis/jarvis_sec/verification.py +411 -181
  227. jarvis/jarvis_sec/workflow.py +132 -21
  228. jarvis/jarvis_smart_shell/main.py +28 -41
  229. jarvis/jarvis_stats/cli.py +14 -12
  230. jarvis/jarvis_stats/stats.py +28 -19
  231. jarvis/jarvis_stats/storage.py +14 -8
  232. jarvis/jarvis_stats/visualizer.py +12 -7
  233. jarvis/jarvis_tools/base.py +5 -2
  234. jarvis/jarvis_tools/clear_memory.py +13 -9
  235. jarvis/jarvis_tools/cli/main.py +23 -18
  236. jarvis/jarvis_tools/edit_file.py +572 -873
  237. jarvis/jarvis_tools/execute_script.py +10 -7
  238. jarvis/jarvis_tools/file_analyzer.py +7 -8
  239. jarvis/jarvis_tools/meta_agent.py +287 -0
  240. jarvis/jarvis_tools/methodology.py +5 -3
  241. jarvis/jarvis_tools/read_code.py +305 -1438
  242. jarvis/jarvis_tools/read_symbols.py +50 -17
  243. jarvis/jarvis_tools/read_webpage.py +19 -18
  244. jarvis/jarvis_tools/registry.py +435 -156
  245. jarvis/jarvis_tools/retrieve_memory.py +16 -11
  246. jarvis/jarvis_tools/save_memory.py +8 -6
  247. jarvis/jarvis_tools/search_web.py +31 -31
  248. jarvis/jarvis_tools/sub_agent.py +32 -28
  249. jarvis/jarvis_tools/sub_code_agent.py +44 -60
  250. jarvis/jarvis_tools/task_list_manager.py +1811 -0
  251. jarvis/jarvis_tools/virtual_tty.py +29 -19
  252. jarvis/jarvis_utils/__init__.py +4 -0
  253. jarvis/jarvis_utils/builtin_replace_map.py +2 -1
  254. jarvis/jarvis_utils/clipboard.py +9 -8
  255. jarvis/jarvis_utils/collections.py +331 -0
  256. jarvis/jarvis_utils/config.py +699 -194
  257. jarvis/jarvis_utils/dialogue_recorder.py +294 -0
  258. jarvis/jarvis_utils/embedding.py +6 -3
  259. jarvis/jarvis_utils/file_processors.py +7 -1
  260. jarvis/jarvis_utils/fzf.py +9 -3
  261. jarvis/jarvis_utils/git_utils.py +71 -42
  262. jarvis/jarvis_utils/globals.py +116 -32
  263. jarvis/jarvis_utils/http.py +6 -2
  264. jarvis/jarvis_utils/input.py +318 -83
  265. jarvis/jarvis_utils/jsonnet_compat.py +119 -104
  266. jarvis/jarvis_utils/methodology.py +37 -28
  267. jarvis/jarvis_utils/output.py +201 -44
  268. jarvis/jarvis_utils/utils.py +986 -628
  269. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
  270. jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
  271. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
  272. jarvis/jarvis_tools/generate_new_tool.py +0 -205
  273. jarvis/jarvis_tools/lsp_client.py +0 -1552
  274. jarvis/jarvis_tools/rewrite_file.py +0 -105
  275. jarvis_ai_assistant-0.7.16.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,3 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
1
  """
5
2
  构建系统检测器模块
6
3
 
@@ -8,118 +5,575 @@
8
5
  """
9
6
 
10
7
  import os
11
- from typing import List, Optional
8
+ import re
9
+ import subprocess
10
+
11
+ from jarvis.jarvis_utils.output import PrettyOutput
12
+
13
+ #!/usr/bin/env python3
14
+ # -*- coding: utf-8 -*-
15
+
16
+ from typing import List
17
+ from typing import Optional
18
+ from typing import Tuple
12
19
 
13
20
  from .base import BuildSystem
14
21
 
15
22
 
16
23
  class BuildSystemDetector:
17
24
  """构建系统检测器"""
18
-
25
+
19
26
  def __init__(self, project_root: str):
20
27
  self.project_root = project_root
21
-
22
- def detect(self) -> Optional[BuildSystem]:
23
- """检测项目使用的构建系统(兼容旧接口,返回第一个检测到的)
24
-
28
+
29
+ def _get_file_statistics(self) -> str:
30
+ """获取文件数量统计信息
31
+
32
+ 使用loc工具获取文件统计信息。
33
+
25
34
  Returns:
26
- 检测到的构建系统,如果无法检测则返回None
35
+ loc工具输出的原始字符串,失败时返回空字符串
27
36
  """
28
- all_systems = self.detect_all()
29
- return all_systems[0] if all_systems else None
30
-
31
- def detect_all(self) -> List[BuildSystem]:
32
- """检测所有可能的构建系统
33
-
37
+ try:
38
+ # 调用loc工具获取统计信息
39
+ result = subprocess.run(
40
+ ["loc"],
41
+ cwd=self.project_root,
42
+ capture_output=True,
43
+ text=True,
44
+ encoding="utf-8",
45
+ errors="replace",
46
+ check=False,
47
+ )
48
+
49
+ if result.returncode == 0 and result.stdout:
50
+ return result.stdout.strip()
51
+ else:
52
+ return ""
53
+ except FileNotFoundError:
54
+ # loc工具未安装,返回空字符串
55
+ PrettyOutput.auto_print("⚠️ loc工具未安装,无法获取文件统计信息")
56
+ return ""
57
+ except Exception as e:
58
+ # 其他错误,返回空字符串
59
+ PrettyOutput.auto_print(f"⚠️ 调用loc工具失败: {e}")
60
+ return ""
61
+
62
+ def _get_git_root_file_list(self, max_files: int = 100) -> str:
63
+ """获取git根目录的文件列表(限制数量)
64
+
65
+ 先识别git根目录,然后列出根目录下的文件列表。
66
+
67
+ Args:
68
+ max_files: 最大返回文件数量
69
+
34
70
  Returns:
35
- 检测到的所有构建系统列表(按优先级排序)
71
+ 文件列表的字符串表示,每行一个文件,失败时返回空字符串
36
72
  """
37
- detected = []
38
- # 按优先级检测(从最具体到最通用)
39
- detectors = [
40
- self._detect_rust,
41
- self._detect_go,
42
- self._detect_java_maven,
43
- self._detect_java_gradle,
44
- self._detect_nodejs,
45
- self._detect_python,
46
- self._detect_c_cmake,
47
- self._detect_c_makefile,
48
- ]
49
-
50
- for detector in detectors:
51
- result = detector()
52
- if result and result not in detected:
53
- detected.append(result)
54
-
55
- return detected
56
-
57
- def _detect_rust(self) -> Optional[BuildSystem]:
58
- """检测Rust项目(Cargo.toml)"""
59
- cargo_toml = os.path.join(self.project_root, "Cargo.toml")
60
- if os.path.exists(cargo_toml):
61
- return BuildSystem.RUST
62
- return None
63
-
64
- def _detect_go(self) -> Optional[BuildSystem]:
65
- """检测Go项目(go.mod)"""
66
- go_mod = os.path.join(self.project_root, "go.mod")
67
- if os.path.exists(go_mod):
68
- return BuildSystem.GO
69
- return None
70
-
71
- def _detect_java_maven(self) -> Optional[BuildSystem]:
72
- """检测Maven项目(pom.xml)"""
73
- pom_xml = os.path.join(self.project_root, "pom.xml")
74
- if os.path.exists(pom_xml):
75
- return BuildSystem.JAVA_MAVEN
76
- return None
77
-
78
- def _detect_java_gradle(self) -> Optional[BuildSystem]:
79
- """检测Gradle项目(build.gradle或build.gradle.kts)"""
80
- build_gradle = os.path.join(self.project_root, "build.gradle")
81
- build_gradle_kts = os.path.join(self.project_root, "build.gradle.kts")
82
- if os.path.exists(build_gradle) or os.path.exists(build_gradle_kts):
83
- return BuildSystem.JAVA_GRADLE
84
- return None
85
-
86
- def _detect_nodejs(self) -> Optional[BuildSystem]:
87
- """检测Node.js项目(package.json)"""
88
- package_json = os.path.join(self.project_root, "package.json")
89
- if os.path.exists(package_json):
90
- return BuildSystem.NODEJS
91
- return None
92
-
93
- def _detect_python(self) -> Optional[BuildSystem]:
94
- """检测Python项目(setup.py, pyproject.toml, requirements.txt等)"""
95
- indicators = [
96
- "setup.py",
97
- "pyproject.toml",
98
- "requirements.txt",
99
- "setup.cfg",
100
- "Pipfile",
101
- "poetry.lock",
73
+ try:
74
+ # 先识别git根目录
75
+ git_root_result = subprocess.run(
76
+ ["git", "rev-parse", "--show-toplevel"],
77
+ cwd=self.project_root,
78
+ capture_output=True,
79
+ text=True,
80
+ check=False,
81
+ )
82
+
83
+ if git_root_result.returncode != 0:
84
+ # 如果不是git仓库,尝试直接读取当前目录
85
+ git_root = self.project_root
86
+ else:
87
+ git_root = git_root_result.stdout.strip()
88
+
89
+ # 列出git根目录下的文件
90
+ file_list: List[str] = []
91
+
92
+ # 使用git ls-files获取git跟踪的文件列表
93
+ result = subprocess.run(
94
+ ["git", "ls-files"],
95
+ cwd=git_root,
96
+ capture_output=True,
97
+ text=True,
98
+ check=False,
99
+ )
100
+
101
+ if result.returncode == 0:
102
+ files = result.stdout.strip().split("\n")
103
+ # 只取根目录下的文件(不包含子目录)
104
+ for file_path in files:
105
+ if not file_path.strip():
106
+ continue
107
+ # 只取根目录下的文件(不包含路径分隔符)
108
+ if "/" not in file_path:
109
+ file_list.append(file_path)
110
+ if len(file_list) >= max_files:
111
+ break
112
+ else:
113
+ # 如果git命令失败,尝试直接读取根目录
114
+ try:
115
+ for item in os.listdir(git_root):
116
+ item_path = os.path.join(git_root, item)
117
+ if os.path.isfile(item_path) and not item.startswith("."):
118
+ file_list.append(item)
119
+ if len(file_list) >= max_files:
120
+ break
121
+ except Exception:
122
+ pass
123
+
124
+ # 返回格式化的字符串
125
+ if file_list:
126
+ return "\n".join(file_list)
127
+ else:
128
+ return ""
129
+ except Exception as e:
130
+ # 发生错误时返回空字符串
131
+ PrettyOutput.auto_print(f"⚠️ 获取git根目录文件列表失败: {e}")
132
+ return ""
133
+
134
+ def _get_supported_build_systems(self) -> List[str]:
135
+ """获取当前支持的构建系统列表
136
+
137
+ Returns:
138
+ 构建系统名称列表
139
+ """
140
+ return [
141
+ "rust (Cargo.toml)",
142
+ "go (go.mod)",
143
+ "java_maven (pom.xml)",
144
+ "java_gradle (build.gradle/build.gradle.kts)",
145
+ "nodejs (package.json)",
146
+ "python (setup.py/pyproject.toml/requirements.txt等)",
147
+ "c_cmake (CMakeLists.txt)",
148
+ "c_makefile (Makefile)",
149
+ "unknown (未知/未识别)",
102
150
  ]
103
- for indicator in indicators:
104
- if os.path.exists(os.path.join(self.project_root, indicator)):
105
- return BuildSystem.PYTHON
106
- return None
107
-
108
- def _detect_c_cmake(self) -> Optional[BuildSystem]:
109
- """检测CMake项目(CMakeLists.txt)"""
110
- cmake_lists = os.path.join(self.project_root, "CMakeLists.txt")
111
- if os.path.exists(cmake_lists):
112
- # 检查是否同时存在Makefile
113
- makefile = os.path.join(self.project_root, "Makefile")
114
- if os.path.exists(makefile):
115
- return BuildSystem.C_MAKEFILE_CMAKE
116
- return BuildSystem.C_CMAKE
117
- return None
118
-
119
- def _detect_c_makefile(self) -> Optional[BuildSystem]:
120
- """检测Makefile项目"""
121
- makefile = os.path.join(self.project_root, "Makefile")
122
- if os.path.exists(makefile):
123
- return BuildSystem.C_MAKEFILE
124
- return None
125
151
 
152
+ def detect_with_llm(self) -> Optional[List[Tuple[BuildSystem, float]]]:
153
+ """使用LLM检测构建系统(基于文件统计和文件列表)
154
+
155
+ Returns:
156
+ 检测到的构建系统列表(带概率),按概率从大到小排序,如果无法检测则返回None
157
+ 格式: [(BuildSystem, probability), ...]
158
+ """
159
+ # 检查配置文件中是否已有保存的构建系统
160
+ from jarvis.jarvis_code_agent.build_validation_config import (
161
+ BuildValidationConfig,
162
+ )
163
+
164
+ config = BuildValidationConfig(self.project_root)
165
+ saved_system = config.get_selected_build_system()
166
+ if saved_system:
167
+ try:
168
+ saved_enum = BuildSystem(saved_system)
169
+ PrettyOutput.auto_print(
170
+ f"ℹ️ 使用配置文件中保存的构建系统: {saved_system}"
171
+ )
172
+ return [(saved_enum, 1.0)]
173
+ except ValueError:
174
+ # 配置文件中保存的构建系统无效,继续检测
175
+ pass
176
+
177
+ # 获取文件统计信息
178
+ file_stats = self._get_file_statistics()
179
+
180
+ # 获取git根目录文件列表
181
+ root_files = self._get_git_root_file_list(max_files=50)
182
+
183
+ # 获取支持的构建系统列表
184
+ supported_systems = self._get_supported_build_systems()
185
+
186
+ # 构建上下文
187
+ stats_text = file_stats if file_stats else " (无统计信息)"
188
+ # 格式化文件列表,每行前面加 " - "
189
+ if root_files:
190
+ files_lines = root_files.split("\n")[:30] # 限制前30个文件
191
+ files_text = "\n".join([f" - {f}" for f in files_lines])
192
+ else:
193
+ files_text = " (无文件列表)"
194
+ systems_text = "\n".join([f" - {sys}" for sys in supported_systems])
195
+
196
+ context = f"""请根据以下信息判断项目的构建系统:
197
+
198
+ 文件数量统计(按扩展名,前20项):
199
+ {stats_text}
200
+
201
+ Git根目录文件列表(前30项):
202
+ {files_text}
203
+
204
+ 当前支持的构建系统:
205
+ {systems_text}
206
+
207
+ 请仔细分析文件统计信息和文件列表,判断项目使用的构建系统。
208
+ 对于每个可能的构建系统,请给出一个概率值(0.0-1.0之间),表示该构建系统的可能性。
209
+ 如果无法确定,可以返回 "unknown"。
210
+
211
+ 请使用以下格式回答(必须包含且仅包含以下标记,多个构建系统用换行分隔):
212
+ - 如果判断为Rust项目,回答: <BUILD_SYSTEM>rust:0.95</BUILD_SYSTEM>
213
+ - 如果判断为Go项目,回答: <BUILD_SYSTEM>go:0.90</BUILD_SYSTEM>
214
+ - 如果判断为Java Maven项目,回答: <BUILD_SYSTEM>java_maven:0.85</BUILD_SYSTEM>
215
+ - 如果判断为Java Gradle项目,回答: <BUILD_SYSTEM>java_gradle:0.80</BUILD_SYSTEM>
216
+ - 如果判断为Node.js项目,回答: <BUILD_SYSTEM>nodejs:0.75</BUILD_SYSTEM>
217
+ - 如果判断为Python项目,回答: <BUILD_SYSTEM>python:0.70</BUILD_SYSTEM>
218
+ - 如果判断为CMake项目,回答: <BUILD_SYSTEM>c_cmake:0.65</BUILD_SYSTEM>
219
+ - 如果判断为Makefile项目,回答: <BUILD_SYSTEM>c_makefile:0.60</BUILD_SYSTEM>
220
+ - 如果无法确定,回答: <BUILD_SYSTEM>unknown:0.50</BUILD_SYSTEM>
221
+
222
+ 格式说明:
223
+ - 每个构建系统一行,格式为 <BUILD_SYSTEM>系统名称:概率值</BUILD_SYSTEM>
224
+ - 概率值范围:0.0-1.0,数值越大表示可能性越高
225
+ - 可以返回多个构建系统,每个一行,按概率从高到低排序
226
+ - 示例:
227
+ <BUILD_SYSTEM>python:0.85</BUILD_SYSTEM>
228
+ <BUILD_SYSTEM>nodejs:0.30</BUILD_SYSTEM>
229
+
230
+ 请严格按照协议格式回答,不要添加其他内容。
231
+ """
232
+
233
+ try:
234
+ # 使用cheap平台进行判断
235
+ from jarvis.jarvis_platform.registry import PlatformRegistry
236
+
237
+ platform = PlatformRegistry().get_cheap_platform()
238
+
239
+ PrettyOutput.auto_print("🤖 正在使用LLM判断构建系统...")
240
+ response = platform.chat_until_success(context)
241
+
242
+ # 解析响应
243
+ detected_systems_with_prob: List[Tuple[BuildSystem, float]] = []
244
+ unknown_probabilities: List[float] = [] # 收集无效构建系统的概率
245
+
246
+ # 提取所有BUILD_SYSTEM标记
247
+ matches = re.findall(r"<BUILD_SYSTEM>(.*?)</BUILD_SYSTEM>", response)
248
+
249
+ for match in matches:
250
+ match = match.strip()
251
+ # 解析格式:系统名称:概率值
252
+ if ":" in match:
253
+ parts = match.split(":", 1)
254
+ system_str = parts[0].strip()
255
+ try:
256
+ prob_str = parts[1].strip()
257
+ probability = float(prob_str)
258
+ # 确保概率在0.0-1.0之间
259
+ probability = max(0.0, min(1.0, probability))
260
+
261
+ try:
262
+ system_enum = BuildSystem(system_str)
263
+ detected_systems_with_prob.append(
264
+ (system_enum, probability)
265
+ )
266
+ except ValueError:
267
+ # 无效的构建系统名称,转换为unknown
268
+ unknown_probabilities.append(probability)
269
+ except (ValueError, IndexError):
270
+ # 如果解析失败,尝试不带概率的格式(向后兼容)
271
+ try:
272
+ system_enum = BuildSystem(system_str)
273
+ # 默认概率为0.5
274
+ detected_systems_with_prob.append((system_enum, 0.5))
275
+ except ValueError:
276
+ # 无效的构建系统名称,转换为unknown(默认概率0.5)
277
+ unknown_probabilities.append(0.5)
278
+ else:
279
+ # 不带概率的格式(向后兼容)
280
+ try:
281
+ system_enum = BuildSystem(match)
282
+ # 默认概率为0.5
283
+ detected_systems_with_prob.append((system_enum, 0.5))
284
+ except ValueError:
285
+ # 无效的构建系统名称,转换为unknown(默认概率0.5)
286
+ unknown_probabilities.append(0.5)
287
+
288
+ # 如果有无效的构建系统,将它们合并为unknown
289
+ if unknown_probabilities:
290
+ # 使用平均概率,或者如果只有一个,直接使用
291
+ avg_prob = (
292
+ sum(unknown_probabilities) / len(unknown_probabilities)
293
+ if unknown_probabilities
294
+ else 0.5
295
+ )
296
+ # 检查是否已经有unknown,如果有则取最大概率
297
+ existing_unknown = None
298
+ for i, (sys, prob) in enumerate(detected_systems_with_prob):
299
+ if sys == BuildSystem.UNKNOWN:
300
+ existing_unknown = i
301
+ break
302
+
303
+ if existing_unknown is not None:
304
+ # 如果已有unknown,取最大概率
305
+ max_prob = max(
306
+ detected_systems_with_prob[existing_unknown][1], avg_prob
307
+ )
308
+ detected_systems_with_prob[existing_unknown] = (
309
+ BuildSystem.UNKNOWN,
310
+ max_prob,
311
+ )
312
+ else:
313
+ # 如果没有unknown,添加一个
314
+ detected_systems_with_prob.append((BuildSystem.UNKNOWN, avg_prob))
315
+
316
+ if detected_systems_with_prob:
317
+ # 按概率从大到小排序
318
+ detected_systems_with_prob.sort(key=lambda x: x[1], reverse=True)
319
+ return detected_systems_with_prob
320
+ else:
321
+ # 如果没有找到有效的构建系统,返回unknown
322
+ return [(BuildSystem.UNKNOWN, 0.5)]
323
+
324
+ except Exception as e:
325
+ PrettyOutput.auto_print(f"⚠️ LLM判断构建系统失败: {e},使用unknown")
326
+ return [(BuildSystem.UNKNOWN, 0.5)]
327
+
328
+ def detect_with_llm_and_confirm(self) -> Optional[List[BuildSystem]]:
329
+ """使用LLM检测构建系统,并让用户确认
330
+
331
+ Returns:
332
+ 用户确认后的构建系统列表,如果用户取消则返回None
333
+ """
334
+
335
+ # 检查是否处于非交互模式
336
+ def _is_non_interactive() -> bool:
337
+ try:
338
+ from jarvis.jarvis_utils.config import is_non_interactive
339
+
340
+ return bool(is_non_interactive())
341
+ except Exception:
342
+ return False
343
+
344
+ detected_systems_with_prob = self.detect_with_llm()
345
+
346
+ if not detected_systems_with_prob:
347
+ return None
348
+
349
+ # 提取构建系统列表(按概率排序)
350
+ detected_systems = [sys for sys, _ in detected_systems_with_prob]
351
+
352
+ # 非交互模式:直接选择概率最高的构建系统
353
+ if _is_non_interactive():
354
+ system, prob = detected_systems_with_prob[0]
355
+ PrettyOutput.auto_print(
356
+ f"ℹ️ 非交互模式:自动选择概率最高的构建系统: {system.value} (概率: {prob:.2%})"
357
+ )
358
+ from jarvis.jarvis_code_agent.build_validation_config import (
359
+ BuildValidationConfig,
360
+ )
361
+
362
+ config = BuildValidationConfig(self.project_root)
363
+ config.set_selected_build_system(system.value)
364
+ return detected_systems
365
+
366
+ # 如果检测到unknown,直接使用,不询问用户
367
+ if len(detected_systems) == 1 and detected_systems[0] == BuildSystem.UNKNOWN:
368
+ prob = detected_systems_with_prob[0][1]
369
+ PrettyOutput.auto_print(
370
+ f"ℹ️ LLM判断:无法确定构建系统(unknown,概率: {prob:.2%}),直接使用unknown"
371
+ )
372
+ from jarvis.jarvis_code_agent.build_validation_config import (
373
+ BuildValidationConfig,
374
+ )
375
+
376
+ config = BuildValidationConfig(self.project_root)
377
+ config.set_selected_build_system("unknown")
378
+ return detected_systems
379
+
380
+ # 显示检测结果(按概率从大到小排序)
381
+ PrettyOutput.auto_print("\n🤖 LLM判断结果(按概率从大到小排序):")
382
+ for idx, (system, prob) in enumerate(detected_systems_with_prob, start=1):
383
+ PrettyOutput.auto_print(f" {idx}. {system.value} (概率: {prob:.2%})")
384
+
385
+ # 显示检测结果
386
+ if len(detected_systems) == 1:
387
+ system, prob = detected_systems_with_prob[0]
388
+ from jarvis.jarvis_code_agent.build_validation_config import (
389
+ BuildValidationConfig,
390
+ )
391
+ from jarvis.jarvis_utils.input import user_confirm
392
+
393
+ config = BuildValidationConfig(self.project_root)
394
+
395
+ if user_confirm(
396
+ f"是否确认使用 {system.value} 作为构建系统?(概率: {prob:.2%})",
397
+ default=True,
398
+ ):
399
+ config.set_selected_build_system(system.value)
400
+ return detected_systems
401
+ else:
402
+ # 用户不确认,让用户选择(传入带概率的信息以保持排序)
403
+ return self._let_user_select_build_system_with_prob(
404
+ detected_systems_with_prob
405
+ )
406
+ else:
407
+ # 检测到多个构建系统,让用户选择(传入带概率的信息以保持排序)
408
+ return self._let_user_select_build_system_with_prob(
409
+ detected_systems_with_prob
410
+ )
411
+
412
+ def _let_user_select_build_system_with_prob(
413
+ self, detected_systems_with_prob: List[Tuple[BuildSystem, float]]
414
+ ) -> Optional[List[BuildSystem]]:
415
+ """让用户选择构建系统(带概率信息,按概率排序)
416
+
417
+ Args:
418
+ detected_systems_with_prob: 检测到的构建系统列表(带概率),已按概率排序
419
+
420
+ Returns:
421
+ 用户选择的构建系统列表,如果用户取消则返回None
422
+ """
423
+
424
+ # 检查是否处于非交互模式
425
+ def _is_non_interactive() -> bool:
426
+ try:
427
+ from jarvis.jarvis_utils.config import is_non_interactive
428
+
429
+ return bool(is_non_interactive())
430
+ except Exception:
431
+ return False
432
+
433
+ from jarvis.jarvis_code_agent.build_validation_config import (
434
+ BuildValidationConfig,
435
+ )
436
+
437
+ config = BuildValidationConfig(self.project_root)
438
+
439
+ # 非交互模式:直接选择概率最高的构建系统
440
+ if _is_non_interactive():
441
+ if detected_systems_with_prob:
442
+ selected, prob = detected_systems_with_prob[0]
443
+ PrettyOutput.auto_print(
444
+ f"ℹ️ 非交互模式:自动选择概率最高的构建系统: {selected.value} (概率: {prob:.2%})"
445
+ )
446
+ config.set_selected_build_system(selected.value)
447
+ return [selected]
448
+ else:
449
+ PrettyOutput.auto_print("ℹ️ 非交互模式:未检测到构建系统,使用unknown")
450
+ config.set_selected_build_system("unknown")
451
+ return [BuildSystem.UNKNOWN]
452
+
453
+ PrettyOutput.auto_print("\n请选择构建系统(按概率从大到小排序):")
454
+ for idx, (system, prob) in enumerate(detected_systems_with_prob, start=1):
455
+ PrettyOutput.auto_print(f" {idx}. {system.value} (概率: {prob:.2%})")
456
+ PrettyOutput.auto_print(
457
+ f" {len(detected_systems_with_prob) + 1}. 取消(使用unknown)"
458
+ )
459
+
460
+ while True:
461
+ try:
462
+ choice = input(
463
+ f"\n请选择 (1-{len(detected_systems_with_prob) + 1}): "
464
+ ).strip()
465
+ choice_num = int(choice)
466
+
467
+ if 1 <= choice_num <= len(detected_systems_with_prob):
468
+ selected, prob = detected_systems_with_prob[choice_num - 1]
469
+ # 保存用户选择
470
+ config.set_selected_build_system(selected.value)
471
+ PrettyOutput.auto_print(
472
+ f"ℹ️ 用户选择构建系统: {selected.value} (概率: {prob:.2%})"
473
+ )
474
+ return [selected]
475
+ elif choice_num == len(detected_systems_with_prob) + 1:
476
+ PrettyOutput.auto_print("ℹ️ 用户取消选择,使用unknown")
477
+ config.set_selected_build_system("unknown")
478
+ return [BuildSystem.UNKNOWN]
479
+ else:
480
+ PrettyOutput.auto_print(
481
+ f"无效选择,请输入 1-{len(detected_systems_with_prob) + 1}"
482
+ )
483
+ except ValueError:
484
+ PrettyOutput.auto_print("请输入有效的数字")
485
+ except (KeyboardInterrupt, EOFError):
486
+ PrettyOutput.auto_print("\n用户取消,使用unknown")
487
+ config.set_selected_build_system("unknown")
488
+ return [BuildSystem.UNKNOWN]
489
+
490
+ def _let_user_select_build_system(
491
+ self, detected_systems: Optional[List[BuildSystem]] = None
492
+ ) -> Optional[List[BuildSystem]]:
493
+ """让用户选择构建系统(兼容旧接口)
494
+
495
+ Args:
496
+ detected_systems: 检测到的构建系统列表,如果为None则显示所有支持的构建系统
497
+
498
+ Returns:
499
+ 用户选择的构建系统列表,如果用户取消则返回None
500
+ """
501
+
502
+ # 检查是否处于非交互模式
503
+ def _is_non_interactive() -> bool:
504
+ try:
505
+ from jarvis.jarvis_utils.config import is_non_interactive
506
+
507
+ return bool(is_non_interactive())
508
+ except Exception:
509
+ return False
510
+
511
+ from jarvis.jarvis_code_agent.build_validation_config import (
512
+ BuildValidationConfig,
513
+ )
514
+
515
+ config = BuildValidationConfig(self.project_root)
516
+
517
+ if detected_systems is None:
518
+ # 显示所有支持的构建系统
519
+ all_systems = [
520
+ BuildSystem.RUST,
521
+ BuildSystem.GO,
522
+ BuildSystem.JAVA_MAVEN,
523
+ BuildSystem.JAVA_GRADLE,
524
+ BuildSystem.NODEJS,
525
+ BuildSystem.PYTHON,
526
+ BuildSystem.C_CMAKE,
527
+ BuildSystem.C_MAKEFILE,
528
+ BuildSystem.UNKNOWN,
529
+ ]
530
+ detected_systems = all_systems
531
+
532
+ # 非交互模式:直接选择第一个构建系统(或unknown)
533
+ if _is_non_interactive():
534
+ if detected_systems and detected_systems[0] != BuildSystem.UNKNOWN:
535
+ selected_system: BuildSystem = detected_systems[0]
536
+ PrettyOutput.auto_print(
537
+ f"ℹ️ 非交互模式:自动选择构建系统: {selected_system.value}"
538
+ )
539
+ config.set_selected_build_system(selected_system.value)
540
+ return [selected_system]
541
+ else:
542
+ PrettyOutput.auto_print("ℹ️ 非交互模式:未检测到构建系统,使用unknown")
543
+ config.set_selected_build_system("unknown")
544
+ return [BuildSystem.UNKNOWN]
545
+
546
+ PrettyOutput.auto_print("\n请选择构建系统:")
547
+ for idx, system in enumerate(detected_systems, start=1):
548
+ PrettyOutput.auto_print(f" {idx}. {system.value}")
549
+ PrettyOutput.auto_print(f" {len(detected_systems) + 1}. 取消(使用unknown)")
550
+
551
+ while True:
552
+ try:
553
+ choice = input(f"\n请选择 (1-{len(detected_systems) + 1}): ").strip()
554
+ choice_num = int(choice)
555
+
556
+ if 1 <= choice_num <= len(detected_systems):
557
+ selected_build_system: BuildSystem = detected_systems[
558
+ choice_num - 1
559
+ ]
560
+ # 保存用户选择
561
+ config.set_selected_build_system(selected_build_system.value)
562
+ PrettyOutput.auto_print(
563
+ f"ℹ️ 用户选择构建系统: {selected_build_system.value}"
564
+ )
565
+ return [selected_build_system]
566
+ elif choice_num == len(detected_systems) + 1:
567
+ PrettyOutput.auto_print("ℹ️ 用户取消选择,使用unknown")
568
+ config.set_selected_build_system("unknown")
569
+ return [BuildSystem.UNKNOWN]
570
+ else:
571
+ PrettyOutput.auto_print(
572
+ f"无效选择,请输入 1-{len(detected_systems) + 1}"
573
+ )
574
+ except ValueError:
575
+ PrettyOutput.auto_print("请输入有效的数字")
576
+ except (KeyboardInterrupt, EOFError):
577
+ PrettyOutput.auto_print("\n用户取消,使用unknown")
578
+ config.set_selected_build_system("unknown")
579
+ return [BuildSystem.UNKNOWN]