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
@@ -0,0 +1,336 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 模块管理模块
4
+ """
5
+
6
+ import re
7
+ from pathlib import Path
8
+ from typing import Optional
9
+
10
+ from jarvis.jarvis_utils.output import PrettyOutput
11
+
12
+
13
+ class ModuleManager:
14
+ """模块管理器"""
15
+
16
+ def __init__(self, crate_dir: Path) -> None:
17
+ self.crate_dir = crate_dir
18
+
19
+ def ensure_cargo_toml_bin(
20
+ self, bin_path: str, bin_name: Optional[str] = None
21
+ ) -> None:
22
+ """
23
+ 在 Cargo.toml 中确保存在 [[bin]] 配置。
24
+ - bin_path: 二进制文件的路径,相对于 crate 根目录(如 "src/bin/main.rs" 或 "src/bin/app.rs")
25
+ - bin_name: 二进制名称,如果为 None 则从 bin_path 推导
26
+ """
27
+ try:
28
+ cargo_path = (self.crate_dir / "Cargo.toml").resolve()
29
+ if not cargo_path.exists():
30
+ # 如果 Cargo.toml 不存在,创建最小配置
31
+ pkg_name = self.crate_dir.name
32
+ content = (
33
+ f'[package]\nname = "{pkg_name}"\nversion = "0.1.0"\nedition = "2021"\n\n'
34
+ '[lib]\npath = "src/lib.rs"\n\n'
35
+ )
36
+ cargo_path.write_text(content, encoding="utf-8")
37
+ PrettyOutput.auto_print(
38
+ f"✅ [c2rust-transpiler][cargo] 已创建 Cargo.toml: {cargo_path}"
39
+ )
40
+
41
+ # 读取现有内容
42
+ txt = cargo_path.read_text(encoding="utf-8", errors="replace")
43
+
44
+ # 从 bin_path 推导 bin_name
45
+ if bin_name is None:
46
+ # 从路径中提取文件名(去掉 .rs 后缀)
47
+ bin_path_clean = bin_path.replace("\\", "/")
48
+ if bin_path_clean.startswith("src/bin/"):
49
+ bin_name = bin_path_clean[len("src/bin/") :]
50
+ if bin_name.endswith(".rs"):
51
+ bin_name = bin_name[:-3]
52
+ else:
53
+ # 如果路径不是 src/bin/ 格式,使用默认名称
54
+ bin_name = self.crate_dir.name
55
+
56
+ # 检查是否已存在相同的 [[bin]] 配置
57
+ # 匹配 [[bin]] 块,查找 name 和 path
58
+ bin_pattern = re.compile(
59
+ r"\[\[bin\]\]\s*\n(?:[^\[]*(?:\n[^\[]*)*?)(?=\[\[bin\]\]|\[\[|\[|$)",
60
+ re.MULTILINE,
61
+ )
62
+ existing_bins = bin_pattern.findall(txt)
63
+
64
+ # 检查是否已存在相同 path 的 bin
65
+ for bin_block in existing_bins:
66
+ # 检查 path 字段
67
+ path_match = re.search(r'path\s*=\s*["\']([^"\']+)["\']', bin_block)
68
+ if path_match and path_match.group(1) == bin_path:
69
+ # 已存在相同路径的 bin 配置
70
+ return
71
+ # 检查 name 字段
72
+ name_match = re.search(r'name\s*=\s*["\']([^"\']+)["\']', bin_block)
73
+ if name_match and name_match.group(1) == bin_name:
74
+ # 已存在相同名称的 bin,检查路径是否相同
75
+ if path_match and path_match.group(1) == bin_path:
76
+ # 完全相同的配置,无需添加
77
+ return
78
+ # 名称相同但路径不同,可能需要更新,但为了安全起见,我们仍然添加新的配置
79
+ # (因为可能存在多个同名但不同路径的 bin)
80
+
81
+ # 添加 [[bin]] 配置
82
+ bin_config = f'\n[[bin]]\nname = "{bin_name}"\npath = "{bin_path}"\n'
83
+
84
+ # 在文件末尾添加(如果已有其他配置,在适当位置插入)
85
+ # 优先在 [lib] 之后添加,如果不存在则在 [dependencies] 之前添加
86
+ lib_match = re.search(r"(?m)^\s*\[lib\]\s*$", txt)
87
+ deps_match = re.search(r"(?m)^\s*\[dependencies\]\s*$", txt)
88
+
89
+ if lib_match:
90
+ # 在 [lib] 块之后添加
91
+ insert_pos = txt.find("\n", lib_match.end())
92
+ if insert_pos == -1:
93
+ insert_pos = len(txt)
94
+ # 找到 [lib] 块的结束位置
95
+ next_section = re.search(r"(?m)^\s*\[", txt[insert_pos:])
96
+ if next_section:
97
+ insert_pos = insert_pos + next_section.start()
98
+ new_txt = txt[:insert_pos] + bin_config + txt[insert_pos:]
99
+ elif deps_match:
100
+ # 在 [dependencies] 之前添加
101
+ insert_pos = deps_match.start()
102
+ new_txt = txt[:insert_pos] + bin_config + txt[insert_pos:]
103
+ else:
104
+ # 在文件末尾添加
105
+ new_txt = txt.rstrip() + bin_config
106
+
107
+ cargo_path.write_text(new_txt, encoding="utf-8")
108
+ PrettyOutput.auto_print(
109
+ f"✅ [c2rust-transpiler][cargo] 已在 Cargo.toml 中添加 [[bin]] 配置: name={bin_name}, path={bin_path}"
110
+ )
111
+ except Exception as e:
112
+ PrettyOutput.auto_print(
113
+ f"⚠️ [c2rust-transpiler][cargo] 更新 Cargo.toml 失败: {e}"
114
+ )
115
+
116
+ def ensure_top_level_pub_mod(self, mod_name: str) -> None:
117
+ """
118
+ 在 src/lib.rs 中确保存在 `pub mod <mod_name>;`
119
+ - 如已存在 `pub mod`,不做改动
120
+ - 如存在 `mod <mod_name>;`,升级为 `pub mod <mod_name>;`
121
+ - 如都不存在,则在文件末尾追加一行 `pub mod <mod_name>;`
122
+ - 最小改动,不覆盖其他内容
123
+ """
124
+ try:
125
+ if not mod_name or mod_name in ("lib", "main", "mod", "bin"):
126
+ return
127
+ lib_rs = (self.crate_dir / "src" / "lib.rs").resolve()
128
+ lib_rs.parent.mkdir(parents=True, exist_ok=True)
129
+ if not lib_rs.exists():
130
+ try:
131
+ lib_rs.write_text(
132
+ "// Auto-generated by c2rust transpiler\n", encoding="utf-8"
133
+ )
134
+ PrettyOutput.auto_print(
135
+ f"✅ [c2rust-transpiler][mod] 已创建 src/lib.rs: {lib_rs}"
136
+ )
137
+ except Exception:
138
+ return
139
+ txt = lib_rs.read_text(encoding="utf-8", errors="replace")
140
+ pub_pat = re.compile(rf"(?m)^\s*pub\s+mod\s+{re.escape(mod_name)}\s*;\s*$")
141
+ mod_pat = re.compile(rf"(?m)^\s*mod\s+{re.escape(mod_name)}\s*;\s*$")
142
+ if pub_pat.search(txt):
143
+ return
144
+ if mod_pat.search(txt):
145
+ # 升级为 pub mod(保留原缩进)
146
+ def _repl(m):
147
+ line = m.group(0)
148
+ match = re.match(r"^(\s*)", line)
149
+ ws = match.group(1) if match else ""
150
+ return f"{ws}pub mod {mod_name};"
151
+
152
+ new_txt = mod_pat.sub(_repl, txt, count=1)
153
+ else:
154
+ new_txt = txt.rstrip() + f"\npub mod {mod_name};\n"
155
+ lib_rs.write_text(new_txt, encoding="utf-8")
156
+ PrettyOutput.auto_print(
157
+ f"✅ [c2rust-transpiler][mod] updated src/lib.rs: ensured pub mod {mod_name}"
158
+ )
159
+ except Exception:
160
+ # 保持稳健,失败不阻塞主流程
161
+ pass
162
+
163
+ def ensure_mod_rs_decl(self, dir_path: Path, child_mod: str) -> None:
164
+ """
165
+ 在 dir_path/mod.rs 中确保存在 `pub mod <child_mod>;`
166
+ - 如存在 `mod <child_mod>;` 则升级为 `pub mod <child_mod>;`
167
+ - 如均不存在则在文件末尾追加 `pub mod <child_mod>;`
168
+ - 最小改动,不覆盖其他内容
169
+ """
170
+ try:
171
+ if not child_mod or child_mod in ("lib", "main", "mod", "bin"):
172
+ return
173
+ mod_rs = (dir_path / "mod.rs").resolve()
174
+ mod_rs.parent.mkdir(parents=True, exist_ok=True)
175
+ if not mod_rs.exists():
176
+ try:
177
+ mod_rs.write_text(
178
+ "// Auto-generated by c2rust transpiler\n", encoding="utf-8"
179
+ )
180
+ PrettyOutput.auto_print(
181
+ f"✅ [c2rust-transpiler][mod] 已创建 {mod_rs}"
182
+ )
183
+ except Exception:
184
+ return
185
+ txt = mod_rs.read_text(encoding="utf-8", errors="replace")
186
+ pub_pat = re.compile(rf"(?m)^\s*pub\s+mod\s+{re.escape(child_mod)}\s*;\s*$")
187
+ mod_pat = re.compile(rf"(?m)^\s*mod\s+{re.escape(child_mod)}\s*;\s*$")
188
+ if pub_pat.search(txt):
189
+ return
190
+ if mod_pat.search(txt):
191
+ # 升级为 pub mod(保留原缩进)
192
+ def _repl(m):
193
+ line = m.group(0)
194
+ match = re.match(r"^(\s*)", line)
195
+ ws = match.group(1) if match else ""
196
+ return f"{ws}pub mod {child_mod};"
197
+
198
+ new_txt = mod_pat.sub(_repl, txt, count=1)
199
+ else:
200
+ new_txt = txt.rstrip() + f"\npub mod {child_mod};\n"
201
+ mod_rs.write_text(new_txt, encoding="utf-8")
202
+ PrettyOutput.auto_print(
203
+ f"✅ [c2rust-transpiler][mod] updated {mod_rs}: ensured pub mod {child_mod}"
204
+ )
205
+ except Exception:
206
+ pass
207
+
208
+ def ensure_mod_chain_for_module(self, module: str) -> None:
209
+ """
210
+ 根据目标模块文件,补齐从该文件所在目录向上的 mod.rs 声明链:
211
+ - 对于 src/foo/bar.rs:在 src/foo/mod.rs 确保 `pub mod bar;`
212
+ 并在上层 src/mod.rs(不修改)改为在 src/lib.rs 确保 `pub mod foo;`(已由顶层函数处理)
213
+ - 对于 src/foo/bar/mod.rs:在 src/foo/mod.rs 确保 `pub mod bar;`
214
+ - 对多级目录,逐级在上层 mod.rs 确保对子目录的 `pub mod <child>;`
215
+ """
216
+ try:
217
+ mp = Path(module)
218
+ base = mp
219
+ if not mp.is_absolute():
220
+ base = (self.crate_dir / module).resolve()
221
+ crate_root = self.crate_dir.resolve()
222
+ # 必须在 crate/src 下
223
+ rel = base.relative_to(crate_root)
224
+ rel_s = str(rel).replace("\\", "/")
225
+ if not rel_s.startswith("src/"):
226
+ return
227
+ # 计算起始目录与首个子模块名
228
+ inside = rel_s[len("src/") :].strip("/")
229
+ if not inside:
230
+ return
231
+ parts = [p for p in inside.split("/") if p] # 过滤空字符串
232
+ # 特殊处理:如果路径包含 bin/,不要生成 mod 声明
233
+ if "bin" in parts:
234
+ return
235
+ if parts[-1].endswith(".rs"):
236
+ if parts[-1] in ("lib.rs", "main.rs"):
237
+ return
238
+ child = parts[-1][:-3] # 去掉 .rs
239
+ # 过滤掉 "mod" 和 "bin" 关键字
240
+ if child in ("mod", "bin"):
241
+ return
242
+ if len(parts) > 1:
243
+ start_dir = crate_root / "src" / "/".join(parts[:-1])
244
+ else:
245
+ start_dir = crate_root / "src"
246
+ # 确保 start_dir 在 crate/src 下
247
+ try:
248
+ start_dir_rel = start_dir.relative_to(crate_root)
249
+ if not str(start_dir_rel).replace("\\", "/").startswith("src/"):
250
+ return
251
+ except ValueError:
252
+ return
253
+ # 在当前目录的 mod.rs 确保 pub mod <child>
254
+ if start_dir.name != "src":
255
+ self.ensure_mod_rs_decl(start_dir, child)
256
+ # 向上逐级确保父目录对当前目录的 pub mod 声明
257
+ cur_dir = start_dir
258
+ else:
259
+ # 末尾为目录(mod.rs 情况):确保父目录对该目录 pub mod
260
+ if parts:
261
+ cur_dir = crate_root / "src" / "/".join(parts)
262
+ # 确保 cur_dir 在 crate/src 下
263
+ try:
264
+ cur_dir_rel = cur_dir.relative_to(crate_root)
265
+ if not str(cur_dir_rel).replace("\\", "/").startswith("src/"):
266
+ return
267
+ except ValueError:
268
+ return
269
+ else:
270
+ return
271
+ # 逐级向上到 src 根(不修改 src/mod.rs,顶层由 lib.rs 公开)
272
+ while True:
273
+ parent = cur_dir.parent
274
+ if not parent.exists():
275
+ break
276
+ # 确保不超过 crate 根目录
277
+ try:
278
+ parent.relative_to(crate_root)
279
+ except ValueError:
280
+ # parent 不在 crate_root 下,停止向上遍历
281
+ break
282
+ if parent.name == "src":
283
+ # 顶层由 _ensure_top_level_pub_mod 负责
284
+ break
285
+ # 在 parent/mod.rs 确保 pub mod <cur_dir.name>
286
+ # 确保 parent 在 crate/src 下
287
+ # 过滤掉 "mod" 和 "bin" 关键字
288
+ if cur_dir.name in ("mod", "bin"):
289
+ cur_dir = parent
290
+ continue
291
+ try:
292
+ parent_rel = parent.relative_to(crate_root)
293
+ if str(parent_rel).replace("\\", "/").startswith("src/"):
294
+ self.ensure_mod_rs_decl(parent, cur_dir.name)
295
+ except (ValueError, Exception):
296
+ # parent 不在 crate/src 下,跳过
297
+ break
298
+ cur_dir = parent
299
+ except Exception:
300
+ pass
301
+
302
+ def module_file_to_crate_path(self, module: str) -> str:
303
+ """
304
+ 将模块文件路径转换为 crate 路径前缀:
305
+ - src/lib.rs -> crate
306
+ - src/foo/mod.rs -> crate::foo
307
+ - src/foo/bar.rs -> crate::foo::bar
308
+ 支持绝对路径:若 module 为绝对路径且位于 crate 根目录下,会自动转换为相对路径再解析;
309
+ 其它(无法解析为 crate/src 下的路径)统一返回 'crate'
310
+ """
311
+ mod = str(module).strip()
312
+ # 若传入绝对路径且在 crate_dir 下,转换为相对路径以便后续按 src/ 前缀解析
313
+ try:
314
+ mp = Path(mod)
315
+ if mp.is_absolute():
316
+ try:
317
+ rel = mp.resolve().relative_to(self.crate_dir.resolve())
318
+ mod = str(rel).replace("\\", "/")
319
+ except Exception:
320
+ # 绝对路径不在 crate_dir 下,保持原样
321
+ pass
322
+ except Exception:
323
+ pass
324
+ # 规范化 ./ 前缀
325
+ if mod.startswith("./"):
326
+ mod = mod[2:]
327
+ # 仅处理位于 src/ 下的模块文件
328
+ if not mod.startswith("src/"):
329
+ return "crate"
330
+ p = mod[len("src/") :]
331
+ if p.endswith("mod.rs"):
332
+ p = p[: -len("mod.rs")]
333
+ elif p.endswith(".rs"):
334
+ p = p[: -len(".rs")]
335
+ p = p.strip("/")
336
+ return "crate" if not p else "crate::" + p.replace("/", "::")