jarvis-ai-assistant 0.7.8__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.8.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.8.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,204 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import List
6
+ from typing import cast
7
+
8
+
9
+ from jarvis.jarvis_c2rust.models import FnRecord
10
+
11
+
12
+ def build_generate_impl_prompt(
13
+ self,
14
+ rec: FnRecord,
15
+ c_code: str,
16
+ module: str,
17
+ rust_sig: str,
18
+ unresolved: List[str],
19
+ ) -> str:
20
+ """
21
+ 从 Transpiler._build_generate_impl_prompt 提取出的实现,保持签名与逻辑完全一致。
22
+ """
23
+ symbols_path = str((self.data_dir / "symbols.jsonl").resolve())
24
+ is_root = self._is_root_symbol(rec)
25
+ requirement_lines = [
26
+ f"目标:在 {module} 中,使用 TDD 方法为 C 函数 {rec.qname or rec.name} 生成 Rust 实现。",
27
+ f"函数签名:{rust_sig}",
28
+ f"crate 目录:{self.crate_dir.resolve()}",
29
+ f"C 工程目录:{self.project_root.resolve()}",
30
+ *(
31
+ ["根符号要求:必须使用 `pub` 关键字,模块必须在 src/lib.rs 中导出"]
32
+ if is_root
33
+ else []
34
+ ),
35
+ "",
36
+ "【TDD 流程】",
37
+ "1. Red:先写测试(#[cfg(test)] mod tests),基于 C 函数行为设计测试用例",
38
+ "2. Green:编写实现使测试通过,确保与 C 语义等价",
39
+ "3. Refactor:优化代码,保持测试通过",
40
+ "",
41
+ "【核心要求】",
42
+ "- 先写测试再写实现,测试必须可编译通过",
43
+ "- 禁止使用 todo!/unimplemented!,必须实现完整功能",
44
+ "- 使用 Rust 原生类型(i32/u32、&str/String、&[T]/&mut [T]、Result<T,E>),避免 C 风格类型",
45
+ '- 禁止使用 extern "C",使用标准 Rust 调用约定',
46
+ "- 保持最小变更,避免无关重构",
47
+ "- 注释使用中文,禁止 use ...::* 通配导入",
48
+ "- 资源释放类函数(fclose/free 等)可通过 RAII 自动管理,提供空实现并在文档中说明",
49
+ *(
50
+ [f"- 禁用库:{', '.join(self.disabled_libraries)}"]
51
+ if self.disabled_libraries
52
+ else []
53
+ ),
54
+ "",
55
+ "【依赖处理】",
56
+ "- 检查依赖函数是否已实现,未实现的需一并补齐(遵循 TDD:先测试后实现)",
57
+ "- 使用 read_symbols/read_code 获取 C 源码",
58
+ "- 优先处理底层依赖,确保所有测试通过",
59
+ "",
60
+ "【工具】",
61
+ f'- read_symbols: {{"symbols_file": "{symbols_path}", "symbols": [...]}}',
62
+ "- read_code: 读取 C 源码或 Rust 模块",
63
+ "",
64
+ *([f"未转换符号:{', '.join(unresolved)}"] if unresolved else []),
65
+ "",
66
+ "C 源码:",
67
+ "<C_SOURCE>",
68
+ c_code,
69
+ "</C_SOURCE>",
70
+ "",
71
+ "签名参考:",
72
+ json.dumps(
73
+ {
74
+ "signature": getattr(rec, "signature", ""),
75
+ "params": getattr(rec, "params", None),
76
+ },
77
+ ensure_ascii=False,
78
+ indent=2,
79
+ ),
80
+ "",
81
+ "仅输出补丁,不要解释。",
82
+ ]
83
+ # 若存在库替代上下文,则附加到实现提示中,便于生成器参考(多库组合、参考API、备注等)
84
+ librep_ctx = None
85
+ try:
86
+ librep_ctx = getattr(rec, "lib_replacement", None)
87
+ except Exception:
88
+ librep_ctx = None
89
+ if isinstance(librep_ctx, dict) and librep_ctx:
90
+ requirement_lines.extend(
91
+ [
92
+ "",
93
+ "库替代上下文(若存在):",
94
+ json.dumps(librep_ctx, ensure_ascii=False, indent=2),
95
+ "",
96
+ ]
97
+ )
98
+ # 添加编译参数(如果存在)
99
+ compile_flags = self._extract_compile_flags(rec.file)
100
+ if compile_flags:
101
+ requirement_lines.extend(
102
+ [
103
+ "",
104
+ "C文件编译参数(来自 compile_commands.json):",
105
+ compile_flags,
106
+ "",
107
+ ]
108
+ )
109
+ prompt = "\n".join(requirement_lines)
110
+ return cast(str, self._append_additional_notes(prompt))
111
+
112
+
113
+ def codeagent_generate_impl(
114
+ self,
115
+ rec: FnRecord,
116
+ c_code: str,
117
+ module: str,
118
+ rust_sig: str,
119
+ unresolved: List[str],
120
+ ) -> None:
121
+ """
122
+ 从 Transpiler._codeagent_generate_impl 提取出的实现,保持逻辑一致。
123
+ """
124
+ # 构建提示词
125
+ prompt = build_generate_impl_prompt(self, rec, c_code, module, rust_sig, unresolved)
126
+
127
+ # 确保目标模块文件存在(提高补丁应用与实现落盘的确定性)
128
+ try:
129
+ mp = Path(module)
130
+ if not mp.is_absolute():
131
+ mp = (self.crate_dir / module).resolve()
132
+ mp.parent.mkdir(parents=True, exist_ok=True)
133
+ if not mp.exists():
134
+ try:
135
+ mp.write_text(
136
+ "// Auto-created by c2rust transpiler\n", encoding="utf-8"
137
+ )
138
+ from jarvis.jarvis_utils.output import PrettyOutput
139
+
140
+ PrettyOutput.auto_print(
141
+ f"✅ [c2rust-transpiler][gen] auto-created module file: {mp}",
142
+ )
143
+ except Exception:
144
+ pass
145
+ except Exception:
146
+ pass
147
+
148
+ # 由于 transpile() 开始时已切换到 crate 目录,此处无需再次切换
149
+ # 记录运行前的 commit
150
+ before_commit = self._get_crate_commit_hash()
151
+ agent = self._get_code_agent()
152
+ agent.run(
153
+ self._compose_prompt_with_context(prompt),
154
+ prefix="[c2rust-transpiler][gen]",
155
+ suffix="",
156
+ )
157
+
158
+ # 检测并处理测试代码删除
159
+ if self._check_and_handle_test_deletion(before_commit, agent):
160
+ # 如果回退了,需要重新运行 agent
161
+ from jarvis.jarvis_utils.output import PrettyOutput
162
+
163
+ PrettyOutput.auto_print(
164
+ "⚠️ [c2rust-transpiler][gen] 检测到测试代码删除问题,已回退,重新运行 agent",
165
+ )
166
+ before_commit = self._get_crate_commit_hash()
167
+ agent.run(
168
+ self._compose_prompt_with_context(prompt),
169
+ prefix="[c2rust-transpiler][gen][retry]",
170
+ suffix="",
171
+ )
172
+ # 再次检测
173
+ if self._check_and_handle_test_deletion(before_commit, agent):
174
+ PrettyOutput.auto_print(
175
+ "❌ [c2rust-transpiler][gen] 再次检测到测试代码删除问题,已回退",
176
+ )
177
+
178
+ # 如果是根符号,确保其模块在 lib.rs 中被暴露
179
+ if self._is_root_symbol(rec):
180
+ try:
181
+ mp = Path(module)
182
+ crate_root = self.crate_dir.resolve()
183
+ rel = (
184
+ mp.resolve().relative_to(crate_root)
185
+ if mp.is_absolute()
186
+ else Path(module)
187
+ )
188
+ rel_s = str(rel).replace("\\", "/")
189
+ if rel_s.startswith("./"):
190
+ rel_s = rel_s[2:]
191
+ if rel_s.startswith("src/"):
192
+ parts = rel_s[len("src/") :].strip("/").split("/")
193
+ if parts and parts[0]:
194
+ top_mod = parts[0]
195
+ # 过滤掉 "mod" 关键字和 .rs 文件
196
+ if top_mod != "mod" and not top_mod.endswith(".rs"):
197
+ self._ensure_top_level_pub_mod(top_mod)
198
+ from jarvis.jarvis_utils.output import PrettyOutput
199
+
200
+ PrettyOutput.auto_print(
201
+ f"📋 [c2rust-transpiler][gen] 根符号 {rec.qname or rec.name} 的模块 {top_mod} 已在 lib.rs 中暴露",
202
+ )
203
+ except Exception:
204
+ pass
@@ -0,0 +1,146 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 编译命令处理模块
4
+ """
5
+
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Any
9
+ from typing import Dict
10
+ from typing import List
11
+ from typing import Optional
12
+ from typing import Union
13
+
14
+ from jarvis.jarvis_utils.output import PrettyOutput
15
+
16
+
17
+ class CompileCommandsManager:
18
+ """编译命令管理器"""
19
+
20
+ def __init__(self, project_root: Path) -> None:
21
+ self.project_root = project_root
22
+ self._compile_commands_cache: Optional[List[Dict[str, Any]]] = None
23
+ self._compile_commands_path: Optional[Path] = None
24
+
25
+ def _find_compile_commands(self) -> Optional[Path]:
26
+ """
27
+ 查找 compile_commands.json 文件。
28
+ 搜索顺序:
29
+ 1. project_root / compile_commands.json
30
+ 2. project_root / build / compile_commands.json
31
+ 3. project_root 的父目录及向上查找(最多向上3层)
32
+ """
33
+ # 首先在 project_root 下查找
34
+ candidates = [
35
+ self.project_root / "compile_commands.json",
36
+ self.project_root / "build" / "compile_commands.json",
37
+ ]
38
+ # 向上查找(最多3层)
39
+ current = self.project_root.parent
40
+ for _ in range(3):
41
+ if current and current.exists():
42
+ candidates.append(current / "compile_commands.json")
43
+ current = current.parent
44
+ else:
45
+ break
46
+
47
+ for path in candidates:
48
+ if path.exists() and path.is_file():
49
+ return path.resolve()
50
+ return None
51
+
52
+ def load_compile_commands(self) -> Optional[List[Dict[str, Any]]]:
53
+ """
54
+ 加载 compile_commands.json 文件。
55
+ 如果已缓存,直接返回缓存结果。
56
+ """
57
+ if self._compile_commands_cache is not None:
58
+ return self._compile_commands_cache
59
+
60
+ compile_commands_path = self._find_compile_commands()
61
+ if compile_commands_path is None:
62
+ self._compile_commands_cache = []
63
+ self._compile_commands_path = None
64
+ return None
65
+
66
+ try:
67
+ with compile_commands_path.open("r", encoding="utf-8") as f:
68
+ data = json.load(f)
69
+ if isinstance(data, list):
70
+ self._compile_commands_cache = data
71
+ self._compile_commands_path = compile_commands_path
72
+ PrettyOutput.auto_print(
73
+ f"📋 [c2rust-transpiler][compile_commands] 已加载: {compile_commands_path} ({len(data)} 条记录)"
74
+ )
75
+ return data
76
+ except Exception as e:
77
+ PrettyOutput.auto_print(
78
+ f"❌ [c2rust-transpiler][compile_commands] 加载失败: {compile_commands_path}: {e}"
79
+ )
80
+ self._compile_commands_cache = []
81
+ self._compile_commands_path = None
82
+ return None
83
+
84
+ self._compile_commands_cache = []
85
+ self._compile_commands_path = None
86
+ return None
87
+
88
+ def extract_compile_flags(self, c_file_path: Union[str, Path]) -> Optional[str]:
89
+ """
90
+ 从 compile_commands.json 中提取指定 C 文件的编译参数。
91
+
92
+ 如果 compile_commands.json 中存在 arguments 字段,则用空格连接该数组并返回。
93
+ 如果只有 command 字段,则直接返回 command 字符串。
94
+
95
+ 返回格式:
96
+ - 如果存在 arguments:用空格连接的参数字符串,例如 "-I/usr/include -DDEBUG"
97
+ - 如果只有 command:完整的编译命令字符串,例如 "gcc -I/usr/include -DDEBUG file.c"
98
+
99
+ 如果未找到或解析失败,返回 None。
100
+ """
101
+ compile_commands = self.load_compile_commands()
102
+ if not compile_commands:
103
+ return None
104
+
105
+ # 规范化目标文件路径
106
+ try:
107
+ target_path = Path(c_file_path)
108
+ if not target_path.is_absolute():
109
+ target_path = (self.project_root / target_path).resolve()
110
+ target_path = target_path.resolve()
111
+ except Exception:
112
+ return None
113
+
114
+ # 查找匹配的编译命令
115
+ for entry in compile_commands:
116
+ if not isinstance(entry, dict):
117
+ continue # type: ignore
118
+
119
+ entry_file = entry.get("file")
120
+ if not entry_file:
121
+ continue
122
+
123
+ try:
124
+ entry_path = Path(entry_file)
125
+ if not entry_path.is_absolute() and entry.get("directory"):
126
+ directory = entry.get("directory")
127
+ if directory is not None:
128
+ entry_path = (Path(directory) / entry_path).resolve()
129
+ entry_path = entry_path.resolve()
130
+
131
+ # 路径匹配(支持相对路径和绝对路径)
132
+ if entry_path == target_path:
133
+ # 如果存在 arguments,用空格连接并返回
134
+ arguments = entry.get("arguments")
135
+ if isinstance(arguments, list):
136
+ # 过滤掉空字符串,然后用空格连接
137
+ args = [str(arg) for arg in arguments if arg]
138
+ return " ".join(args) if args else None
139
+ # 如果只有 command,直接返回 command 字符串
140
+ elif entry.get("command"):
141
+ command = entry.get("command", "")
142
+ return command if command else None
143
+ except Exception:
144
+ continue
145
+
146
+ return None
@@ -0,0 +1,178 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 配置和进度管理模块
4
+ """
5
+
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Any
9
+ from typing import Dict
10
+
11
+ from jarvis.jarvis_utils.output import PrettyOutput
12
+ from jarvis.jarvis_c2rust.constants import CONFIG_JSON
13
+ from jarvis.jarvis_c2rust.models import FnRecord
14
+ from jarvis.jarvis_c2rust.utils import read_json
15
+ from jarvis.jarvis_c2rust.utils import write_json
16
+
17
+
18
+ class ConfigManager:
19
+ """配置和进度管理器"""
20
+
21
+ def __init__(self, data_dir: Path, progress_path: Path) -> None:
22
+ self.data_dir = data_dir
23
+ self.progress_path = progress_path
24
+ self.progress: Dict[str, Any] = read_json(
25
+ self.progress_path, {"current": None, "converted": []}
26
+ )
27
+
28
+ def save_progress(self) -> None:
29
+ """保存进度,使用原子性写入"""
30
+ write_json(self.progress_path, self.progress)
31
+
32
+ def load_config(self) -> Dict[str, Any]:
33
+ """
34
+ 从独立的配置文件加载配置。
35
+ 如果配置文件不存在,尝试从 progress.json 迁移配置(向后兼容)。
36
+ """
37
+ config_path = self.data_dir / CONFIG_JSON
38
+ default_config = {
39
+ "root_symbols": [],
40
+ "disabled_libraries": [],
41
+ "additional_notes": "",
42
+ }
43
+
44
+ # 尝试从配置文件读取
45
+ if config_path.exists():
46
+ config = read_json(config_path, default_config)
47
+ if isinstance(config, dict):
48
+ # 确保包含所有必需的键(向后兼容)
49
+ if "additional_notes" not in config:
50
+ config["additional_notes"] = ""
51
+ return config
52
+
53
+ # 向后兼容:如果配置文件不存在,尝试从 progress.json 迁移
54
+ progress_config = self.progress.get("config", {})
55
+ if progress_config:
56
+ # 迁移配置到独立文件
57
+ migrated_config = {
58
+ "root_symbols": progress_config.get("root_symbols", []),
59
+ "disabled_libraries": progress_config.get("disabled_libraries", []),
60
+ "additional_notes": progress_config.get("additional_notes", ""),
61
+ }
62
+ write_json(config_path, migrated_config)
63
+ PrettyOutput.auto_print(
64
+ f"⚠️ [c2rust-transpiler][config] 已从 progress.json 迁移配置到 {config_path}"
65
+ )
66
+ return migrated_config
67
+
68
+ return default_config
69
+
70
+ def save_config(
71
+ self,
72
+ root_symbols: list,
73
+ disabled_libraries: list,
74
+ additional_notes: str,
75
+ ) -> None:
76
+ """保存配置到独立的配置文件"""
77
+ config_path = self.data_dir / CONFIG_JSON
78
+ config = {
79
+ "root_symbols": root_symbols,
80
+ "disabled_libraries": disabled_libraries,
81
+ "additional_notes": additional_notes,
82
+ }
83
+ write_json(config_path, config)
84
+
85
+ def load_order_index(
86
+ self,
87
+ order_jsonl: Path,
88
+ fn_index_by_id: Dict[int, FnRecord],
89
+ fn_name_to_id: Dict[str, int],
90
+ ) -> None:
91
+ """
92
+ 从自包含的 order.jsonl 中加载所有 records,建立:
93
+ - fn_index_by_id: id -> FnRecord
94
+ - fn_name_to_id: name/qname -> id
95
+ 若同一 id 多次出现,首次记录为准。
96
+ """
97
+ fn_index_by_id.clear()
98
+ fn_name_to_id.clear()
99
+ PrettyOutput.auto_print(
100
+ f"📊 [c2rust-transpiler][index] 正在加载翻译顺序索引: {order_jsonl}"
101
+ )
102
+ try:
103
+ with order_jsonl.open("r", encoding="utf-8") as f:
104
+ for ln in f:
105
+ ln = ln.strip()
106
+ if not ln:
107
+ continue
108
+ try:
109
+ obj = json.loads(ln)
110
+ except Exception:
111
+ continue
112
+ # 仅支持新格式:items
113
+ recs = obj.get("items")
114
+ if not isinstance(recs, list):
115
+ continue
116
+ for r in recs:
117
+ if not isinstance(r, dict):
118
+ continue
119
+ # 构建 FnRecord
120
+ try:
121
+ rec_id = r.get("id")
122
+ if rec_id is None:
123
+ continue
124
+ fid = int(rec_id)
125
+ except Exception:
126
+ continue
127
+ if fid in fn_index_by_id:
128
+ # 已收录
129
+ continue
130
+ nm = r.get("name") or ""
131
+ qn = r.get("qualified_name") or ""
132
+ fp = r.get("file") or ""
133
+ refs = r.get("ref")
134
+ if not isinstance(refs, list):
135
+ refs = []
136
+ refs = [c for c in refs if isinstance(c, str) and c]
137
+ sr = int(r.get("start_line") or 0)
138
+ sc = int(r.get("start_col") or 0)
139
+ er = int(r.get("end_line") or 0)
140
+ ec = int(r.get("end_col") or 0)
141
+ sg = r.get("signature") or ""
142
+ rt = r.get("return_type") or ""
143
+ pr = (
144
+ r.get("params")
145
+ if isinstance(r.get("params"), list)
146
+ else None
147
+ )
148
+ lr = (
149
+ r.get("lib_replacement")
150
+ if isinstance(r.get("lib_replacement"), dict)
151
+ else None
152
+ )
153
+ rec = FnRecord(
154
+ id=fid,
155
+ name=nm,
156
+ qname=qn,
157
+ file=fp,
158
+ start_line=sr,
159
+ start_col=sc,
160
+ end_line=er,
161
+ end_col=ec,
162
+ refs=refs,
163
+ signature=str(sg or ""),
164
+ return_type=str(rt or ""),
165
+ params=pr,
166
+ lib_replacement=lr,
167
+ )
168
+ fn_index_by_id[fid] = rec
169
+ if nm:
170
+ fn_name_to_id.setdefault(nm, fid)
171
+ if qn:
172
+ fn_name_to_id.setdefault(qn, fid)
173
+ except Exception:
174
+ # 若索引构建失败,保持为空,后续流程将跳过
175
+ pass
176
+ PrettyOutput.auto_print(
177
+ f"✅ [c2rust-transpiler][index] 索引构建完成: ids={len(fn_index_by_id)} names={len(fn_name_to_id)}"
178
+ )
@@ -0,0 +1,122 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 上下文收集模块
4
+ """
5
+
6
+ from pathlib import Path
7
+ from typing import Any
8
+ from typing import Dict
9
+ from typing import List
10
+
11
+ from jarvis.jarvis_c2rust.models import FnRecord
12
+
13
+
14
+ class ContextCollector:
15
+ """上下文收集器"""
16
+
17
+ def __init__(
18
+ self,
19
+ project_root: Path,
20
+ fn_index_by_id: Dict[int, FnRecord],
21
+ fn_name_to_id: Dict[str, int],
22
+ symbol_map: Any, # _SymbolMapJsonl
23
+ ) -> None:
24
+ self.project_root = project_root
25
+ self.fn_index_by_id = fn_index_by_id
26
+ self.fn_name_to_id = fn_name_to_id
27
+ self.symbol_map = symbol_map
28
+
29
+ def read_source_span(self, rec: FnRecord) -> str:
30
+ """按起止行读取源码片段(忽略列边界,尽量完整)"""
31
+ try:
32
+ p = Path(rec.file)
33
+ if not p.is_absolute():
34
+ p = (self.project_root / p).resolve()
35
+ if not p.exists():
36
+ return ""
37
+ lines = p.read_text(encoding="utf-8", errors="replace").splitlines()
38
+ s = max(1, int(rec.start_line or 1))
39
+ e = min(len(lines), max(int(rec.end_line or s), s))
40
+ chunk = "\n".join(lines[s - 1 : e])
41
+ return chunk
42
+ except Exception:
43
+ return ""
44
+
45
+ def collect_callees_context(self, rec: FnRecord) -> List[Dict[str, Any]]:
46
+ """
47
+ 生成被引用符号上下文列表(不区分函数与类型):
48
+ - 若已转译:提供 {name, qname, translated: true, rust_module, rust_symbol, ambiguous?}
49
+ - 若未转译但存在扫描记录:提供 {name, qname, translated: false, file, start_line, end_line}
50
+ - 若仅名称:提供 {name, qname, translated: false}
51
+ 注:若存在同名映射多条记录(重载/同名符号),此处标记 ambiguous=true,并选择最近一条作为提示。
52
+ """
53
+ ctx: List[Dict[str, Any]] = []
54
+ for callee in rec.refs or []:
55
+ entry: Dict[str, Any] = {"name": callee, "qname": callee}
56
+ # 已转译映射
57
+ if self.symbol_map.has_symbol(callee):
58
+ recs = self.symbol_map.get(callee)
59
+ m = recs[-1] if recs else None
60
+ entry.update(
61
+ {
62
+ "translated": True,
63
+ "rust_module": (m or {}).get("module"),
64
+ "rust_symbol": (m or {}).get("rust_symbol"),
65
+ }
66
+ )
67
+ if len(recs) > 1:
68
+ entry["ambiguous"] = True
69
+ ctx.append(entry)
70
+ continue
71
+ # 使用 order 索引按名称解析ID(函数或类型)
72
+ cid = self.fn_name_to_id.get(callee)
73
+ if cid:
74
+ crec = self.fn_index_by_id.get(cid)
75
+ if crec:
76
+ entry.update(
77
+ {
78
+ "translated": False,
79
+ "file": crec.file,
80
+ "start_line": crec.start_line,
81
+ "end_line": crec.end_line,
82
+ }
83
+ )
84
+ else:
85
+ entry.update({"translated": False})
86
+ ctx.append(entry)
87
+ return ctx
88
+
89
+ def untranslated_callee_symbols(self, rec: FnRecord) -> List[str]:
90
+ """
91
+ 返回尚未转换的被调函数符号(使用扫描记录中的名称/限定名作为键)
92
+ """
93
+ syms: List[str] = []
94
+ for callee in rec.refs or []:
95
+ if not self.symbol_map.has_symbol(callee):
96
+ syms.append(callee)
97
+ # 去重
98
+ try:
99
+ syms = list(dict.fromkeys(syms))
100
+ except Exception:
101
+ syms = sorted(list(set(syms)))
102
+ return syms
103
+
104
+ def append_additional_notes(self, prompt: str, additional_notes: str) -> str:
105
+ """
106
+ 在提示词末尾追加附加说明(如果存在)。
107
+
108
+ Args:
109
+ prompt: 原始提示词
110
+ additional_notes: 附加说明
111
+
112
+ Returns:
113
+ 追加了附加说明的提示词
114
+ """
115
+ if additional_notes and additional_notes.strip():
116
+ return (
117
+ prompt
118
+ + "\n\n"
119
+ + "【附加说明(用户自定义)】\n"
120
+ + additional_notes.strip()
121
+ )
122
+ return prompt