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,469 @@
1
+ # -*- coding: utf-8 -*-
2
+ """优化器进度管理模块。"""
3
+
4
+ import json
5
+ from pathlib import Path
6
+ from typing import Any
7
+ from typing import Dict
8
+ from typing import List
9
+ from typing import Optional
10
+ from typing import Set
11
+ from typing import cast
12
+
13
+ from jarvis.jarvis_utils.output import PrettyOutput
14
+
15
+ from jarvis.jarvis_c2rust.optimizer_options import OptimizeOptions
16
+ from jarvis.jarvis_c2rust.optimizer_utils import git_head_commit
17
+ from jarvis.jarvis_c2rust.optimizer_utils import git_reset_hard
18
+ from jarvis.jarvis_c2rust.optimizer_utils import git_toplevel
19
+
20
+
21
+ class ProgressManager:
22
+ """进度管理器,负责加载、保存进度和 Git 管理。"""
23
+
24
+ def __init__(
25
+ self,
26
+ crate_dir: Path,
27
+ options: OptimizeOptions,
28
+ progress_path: Path,
29
+ ):
30
+ self.crate_dir = crate_dir
31
+ self.options = options
32
+ self.progress_path = progress_path
33
+ self.processed: Set[str] = set()
34
+ self.steps_completed: Set[str] = set()
35
+ self._step_commits: Dict[str, str] = {}
36
+ self._last_snapshot_commit: Optional[str] = None
37
+ self._agent_before_commits: Dict[str, Optional[str]] = {}
38
+
39
+ def load_or_reset_progress(self) -> None:
40
+ """加载或重置进度。"""
41
+ if self.options.reset_progress:
42
+ try:
43
+ self.progress_path.write_text(
44
+ json.dumps(
45
+ {"processed": [], "steps_completed": []},
46
+ ensure_ascii=False,
47
+ indent=2,
48
+ ),
49
+ encoding="utf-8",
50
+ )
51
+ except Exception:
52
+ pass
53
+ self.processed = set()
54
+ if not hasattr(self, "steps_completed"):
55
+ self.steps_completed = set()
56
+ if not hasattr(self, "_step_commits"):
57
+ self._step_commits = {}
58
+ return
59
+ try:
60
+ if self.progress_path.exists():
61
+ obj = json.loads(self.progress_path.read_text(encoding="utf-8"))
62
+ if isinstance(obj, dict):
63
+ arr = obj.get("processed") or []
64
+ if isinstance(arr, list):
65
+ self.processed = {str(x) for x in arr if isinstance(x, str)}
66
+ else:
67
+ self.processed = set()
68
+ # 加载已完成的步骤
69
+ steps = obj.get("steps_completed") or []
70
+ if isinstance(steps, list):
71
+ self.steps_completed = {
72
+ str(x) for x in steps if isinstance(x, str)
73
+ }
74
+ else:
75
+ self.steps_completed = set()
76
+ # 加载步骤的 commit id
77
+ step_commits = obj.get("step_commits") or {}
78
+ if isinstance(step_commits, dict):
79
+ self._step_commits = {
80
+ str(k): str(v)
81
+ for k, v in step_commits.items()
82
+ if isinstance(k, str) and isinstance(v, str)
83
+ }
84
+ else:
85
+ self._step_commits = {}
86
+
87
+ # 恢复时,reset 到最后一个步骤的 commit id
88
+ if self.options.resume and self._step_commits:
89
+ last_commit = None
90
+ # 按照步骤顺序找到最后一个已完成步骤的 commit
91
+ step_order = [
92
+ "clippy_elimination",
93
+ "unsafe_cleanup",
94
+ "visibility_opt",
95
+ "doc_opt",
96
+ ]
97
+ for step in reversed(step_order):
98
+ if (
99
+ step in self.steps_completed
100
+ and step in self._step_commits
101
+ ):
102
+ last_commit = self._step_commits[step]
103
+ break
104
+
105
+ if last_commit:
106
+ current_commit = self.get_crate_commit_hash()
107
+ if current_commit != last_commit:
108
+ PrettyOutput.auto_print(
109
+ f"🔧 [c2rust-optimizer][resume] 检测到代码状态不一致,正在 reset 到最后一个步骤的 commit: {last_commit}",
110
+ )
111
+ if self.reset_to_commit(last_commit):
112
+ PrettyOutput.auto_print(
113
+ f"✅ [c2rust-optimizer][resume] 已 reset 到 commit: {last_commit}",
114
+ )
115
+ else:
116
+ PrettyOutput.auto_print(
117
+ "⚠️ [c2rust-optimizer][resume] reset 失败,继续使用当前代码状态",
118
+ )
119
+ else:
120
+ PrettyOutput.auto_print(
121
+ "ℹ️ [c2rust-optimizer][resume] 代码状态一致,无需 reset",
122
+ )
123
+ else:
124
+ self.processed = set()
125
+ self.steps_completed = set()
126
+ self._step_commits = {}
127
+ else:
128
+ self.processed = set()
129
+ self.steps_completed = set()
130
+ self._step_commits = {}
131
+ except Exception:
132
+ self.processed = set()
133
+ self.steps_completed = set()
134
+ self._step_commits = {}
135
+
136
+ def get_crate_commit_hash(self) -> Optional[str]:
137
+ """获取 crate 目录的当前 commit id。"""
138
+ try:
139
+ repo_root = git_toplevel(self.crate_dir)
140
+ if repo_root is None:
141
+ return None
142
+ return git_head_commit(repo_root)
143
+ except Exception:
144
+ return None
145
+
146
+ def reset_to_commit(self, commit_hash: str) -> bool:
147
+ """回退 crate 目录到指定的 commit。"""
148
+ try:
149
+ repo_root = git_toplevel(self.crate_dir)
150
+ if repo_root is None:
151
+ return False
152
+ return git_reset_hard(repo_root, commit_hash)
153
+ except Exception:
154
+ return False
155
+
156
+ def snapshot_commit(self) -> None:
157
+ """
158
+ 在启用 git_guard 时记录当前 HEAD commit(仅记录,不提交未暂存更改)。
159
+ 统一在仓库根目录执行 git 命令,避免子目录导致的意外。
160
+ """
161
+ if not self.options.git_guard:
162
+ return
163
+ try:
164
+ repo_root = git_toplevel(self.crate_dir)
165
+ if repo_root is None:
166
+ return
167
+ head = git_head_commit(repo_root)
168
+ if head:
169
+ self._last_snapshot_commit = head
170
+ except Exception:
171
+ # 忽略快照失败,不阻塞流程
172
+ pass
173
+
174
+ def reset_to_snapshot(self) -> bool:
175
+ """
176
+ 在启用 git_guard 且存在快照时,将工作区 reset --hard 回快照。
177
+ 统一在仓库根目录执行 git 命令,避免子目录导致的意外。
178
+ 返回是否成功执行 reset。
179
+ """
180
+ if not self.options.git_guard:
181
+ return False
182
+ snap = getattr(self, "_last_snapshot_commit", None)
183
+ if not snap:
184
+ return False
185
+ repo_root = git_toplevel(self.crate_dir)
186
+ if repo_root is None:
187
+ return False
188
+ ok = git_reset_hard(repo_root, snap)
189
+ return ok
190
+
191
+ def save_progress_for_batch(self, files: List[Path]) -> None:
192
+ """保存文件处理进度。"""
193
+ try:
194
+ rels = []
195
+ for p in files:
196
+ try:
197
+ rel = p.resolve().relative_to(self.crate_dir.resolve()).as_posix()
198
+ except Exception:
199
+ rel = str(p)
200
+ rels.append(rel)
201
+ self.processed.update(rels)
202
+
203
+ # 获取当前 commit id 并记录
204
+ current_commit = self.get_crate_commit_hash()
205
+
206
+ data: Dict[str, Any] = {
207
+ "processed": sorted(self.processed),
208
+ "steps_completed": sorted(self.steps_completed),
209
+ }
210
+ if current_commit:
211
+ data["last_commit"] = current_commit
212
+ PrettyOutput.auto_print(
213
+ f"ℹ️ [c2rust-optimizer][progress] 已记录当前 commit: {current_commit}",
214
+ )
215
+
216
+ self.progress_path.write_text(
217
+ json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
218
+ )
219
+ except Exception:
220
+ pass
221
+
222
+ def save_fix_progress(
223
+ self, step_name: str, fix_key: str, files: Optional[List[Path]] = None
224
+ ) -> None:
225
+ """
226
+ 保存单个修复的进度(包括 commit id)。
227
+
228
+ Args:
229
+ step_name: 步骤名称(如 "clippy_elimination", "unsafe_cleanup")
230
+ fix_key: 修复的唯一标识(如 "warning-1", "file_path.rs")
231
+ files: 修改的文件列表(可选)
232
+ """
233
+ try:
234
+ # 获取当前 commit id
235
+ current_commit = self.get_crate_commit_hash()
236
+ if not current_commit:
237
+ PrettyOutput.auto_print(
238
+ "⚠️ [c2rust-optimizer][progress] 无法获取 commit id,跳过进度记录",
239
+ )
240
+ return
241
+
242
+ # 加载现有进度
243
+ if self.progress_path.exists():
244
+ try:
245
+ obj = json.loads(self.progress_path.read_text(encoding="utf-8"))
246
+ except Exception:
247
+ obj = {}
248
+ else:
249
+ obj = {}
250
+
251
+ # 初始化修复进度结构
252
+ if "fix_progress" not in obj:
253
+ obj["fix_progress"] = {}
254
+ if step_name not in obj["fix_progress"]:
255
+ obj["fix_progress"][step_name] = {}
256
+
257
+ # 记录修复进度
258
+ obj["fix_progress"][step_name][fix_key] = {
259
+ "commit": current_commit,
260
+ "timestamp": None, # 可以添加时间戳如果需要
261
+ }
262
+
263
+ # 更新已处理的文件列表
264
+ if files:
265
+ rels = []
266
+ for p in files:
267
+ try:
268
+ rel = (
269
+ p.resolve().relative_to(self.crate_dir.resolve()).as_posix()
270
+ )
271
+ except Exception:
272
+ rel = str(p)
273
+ rels.append(rel)
274
+ self.processed.update(rels)
275
+ obj["processed"] = sorted(self.processed)
276
+
277
+ # 更新 last_commit
278
+ obj["last_commit"] = current_commit
279
+
280
+ # 保存进度
281
+ self.progress_path.write_text(
282
+ json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8"
283
+ )
284
+ PrettyOutput.auto_print(
285
+ f"ℹ️ [c2rust-optimizer][progress] 已记录修复进度: {step_name}/{fix_key} -> commit {current_commit[:8]}"
286
+ )
287
+ except Exception as e:
288
+ PrettyOutput.auto_print(
289
+ f"⚠️ ⚠️ [c2rust-optimizer] 保存修复进度失败(非致命): {e}"
290
+ )
291
+
292
+ def save_step_progress(self, step_name: str, files: List[Path]) -> None:
293
+ """保存步骤进度:标记步骤完成并更新文件列表。"""
294
+ try:
295
+ # 标记步骤为已完成
296
+ self.steps_completed.add(step_name)
297
+ # 更新已处理的文件列表
298
+ rels = []
299
+ for p in files:
300
+ try:
301
+ rel = p.resolve().relative_to(self.crate_dir.resolve()).as_posix()
302
+ except Exception:
303
+ rel = str(p)
304
+ rels.append(rel)
305
+ self.processed.update(rels)
306
+
307
+ # 获取当前 commit id 并记录
308
+ current_commit = self.get_crate_commit_hash()
309
+
310
+ # 保存进度
311
+ data: Dict[str, Any] = {
312
+ "processed": sorted(self.processed),
313
+ "steps_completed": sorted(self.steps_completed),
314
+ }
315
+ if current_commit:
316
+ # 记录每个步骤的 commit id
317
+ step_commits = getattr(self, "_step_commits", {})
318
+ step_commits[step_name] = current_commit
319
+ self._step_commits = step_commits
320
+ data["step_commits"] = cast(Dict[str, str], step_commits)
321
+ data["last_commit"] = current_commit
322
+ PrettyOutput.auto_print(
323
+ f"ℹ️ [c2rust-optimizer][progress] 已记录步骤 '{step_name}' 的 commit: {current_commit}",
324
+ )
325
+
326
+ self.progress_path.write_text(
327
+ json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
328
+ )
329
+ PrettyOutput.auto_print(
330
+ "ℹ️ [c2rust-optimizer] 步骤进度已保存",
331
+ )
332
+ except Exception as e:
333
+ PrettyOutput.auto_print(
334
+ f"⚠️ [c2rust-optimizer] 保存步骤进度失败(非致命): {e}",
335
+ )
336
+
337
+ def on_before_tool_call(self, agent: Any, current_response=None, **kwargs) -> None:
338
+ """
339
+ 工具调用前的事件处理器,用于记录工具调用前的 commit id。
340
+
341
+ 在每次工具调用前记录当前的 commit,以便在工具调用后检测到问题时能够回退。
342
+ """
343
+ try:
344
+ # 只关注可能修改代码的工具
345
+ # 注意:在 BEFORE_TOOL_CALL 时,工具还未执行,无法获取工具名称
346
+ # 但我们可以在 AFTER_TOOL_CALL 时检查工具名称,这里先记录 commit
347
+ agent_id = id(agent)
348
+ agent_key = f"agent_{agent_id}"
349
+ current_commit = self.get_crate_commit_hash()
350
+ if current_commit:
351
+ # 记录工具调用前的 commit(如果之前没有记录,或者 commit 已变化)
352
+ if (
353
+ agent_key not in self._agent_before_commits
354
+ or self._agent_before_commits[agent_key] != current_commit
355
+ ):
356
+ self._agent_before_commits[agent_key] = current_commit
357
+ except Exception as e:
358
+ # 事件处理器异常不应影响主流程
359
+ PrettyOutput.auto_print(
360
+ f"⚠️ ⚠️ [c2rust-optimizer][test-detection] BEFORE_TOOL_CALL 事件处理器异常: {e}"
361
+ )
362
+
363
+ def on_after_tool_call(
364
+ self,
365
+ agent: Any,
366
+ current_response=None,
367
+ need_return=None,
368
+ tool_prompt=None,
369
+ **kwargs,
370
+ ) -> None:
371
+ """
372
+ 工具调用后的事件处理器,用于细粒度检测测试代码删除。
373
+
374
+ 在每次工具调用后立即检测,如果检测到测试代码被错误删除,立即回退。
375
+ """
376
+ try:
377
+ # 只检测编辑文件的工具调用
378
+ last_tool = (
379
+ agent.get_user_data("__last_executed_tool__")
380
+ if hasattr(agent, "get_user_data")
381
+ else None
382
+ )
383
+ if not last_tool:
384
+ return
385
+
386
+ # 只关注可能修改代码的工具
387
+ edit_tools = {
388
+ "edit_file",
389
+ "apply_patch",
390
+ }
391
+ if last_tool not in edit_tools:
392
+ return
393
+
394
+ # 获取该 Agent 对应的工具调用前的 commit id
395
+ agent_id = id(agent)
396
+ agent_key = f"agent_{agent_id}"
397
+ before_commit = self._agent_before_commits.get(agent_key)
398
+
399
+ # 如果没有 commit 信息,无法检测
400
+ if not before_commit:
401
+ return
402
+
403
+ # 检测测试代码删除
404
+ from jarvis.jarvis_c2rust.utils import ask_llm_about_test_deletion
405
+ from jarvis.jarvis_c2rust.utils import detect_test_deletion
406
+
407
+ detection_result = detect_test_deletion("[c2rust-optimizer]")
408
+ if not detection_result:
409
+ # 没有检测到删除,更新 commit 记录
410
+ current_commit = self.get_crate_commit_hash()
411
+ if current_commit and current_commit != before_commit:
412
+ self._agent_before_commits[agent_key] = current_commit
413
+ return
414
+
415
+ PrettyOutput.auto_print(
416
+ "⚠️ ⚠️ [c2rust-optimizer][test-detection] 检测到可能错误删除了测试代码标记(工具调用后检测)"
417
+ )
418
+
419
+ # 询问 LLM 是否合理
420
+ need_reset = ask_llm_about_test_deletion(
421
+ detection_result, agent, "[c2rust-optimizer]"
422
+ )
423
+
424
+ if need_reset:
425
+ PrettyOutput.auto_print(
426
+ f"❌ ❌ [c2rust-optimizer][test-detection] LLM 确认删除不合理,正在回退到 commit: {before_commit}"
427
+ )
428
+ if self.reset_to_commit(before_commit):
429
+ PrettyOutput.auto_print(
430
+ "✅ ✅ [c2rust-optimizer][test-detection] 已回退到之前的 commit(工具调用后检测)"
431
+ )
432
+ # 回退后,保持之前的 commit 记录
433
+ self._agent_before_commits[agent_key] = before_commit
434
+ # 在 agent 的 session 中添加提示,告知修改被撤销
435
+ if hasattr(agent, "session") and hasattr(agent.session, "prompt"):
436
+ agent.session.prompt += "\n\n⚠️ 修改被撤销:检测到测试代码被错误删除,已回退到之前的版本。\n"
437
+ else:
438
+ PrettyOutput.auto_print(
439
+ "❌ ❌ [c2rust-optimizer][test-detection] 回退失败"
440
+ )
441
+ else:
442
+ # LLM 认为删除合理,更新 commit 记录
443
+ current_commit = self.get_crate_commit_hash()
444
+ if current_commit and current_commit != before_commit:
445
+ self._agent_before_commits[agent_key] = current_commit
446
+ except Exception as e:
447
+ # 事件处理器异常不应影响主流程
448
+ PrettyOutput.auto_print(
449
+ f"⚠️ ⚠️ [c2rust-optimizer][test-detection] AFTER_TOOL_CALL 事件处理器异常: {e}"
450
+ )
451
+
452
+ def check_and_handle_test_deletion(
453
+ self, before_commit: Optional[str], agent: Any
454
+ ) -> bool:
455
+ """
456
+ 检测并处理测试代码删除。
457
+
458
+ 参数:
459
+ before_commit: agent 运行前的 commit hash
460
+ agent: 代码优化或修复的 agent 实例,使用其 model 进行询问
461
+
462
+ 返回:
463
+ bool: 如果检测到问题且已回退,返回 True;否则返回 False
464
+ """
465
+ from jarvis.jarvis_c2rust.utils import check_and_handle_test_deletion
466
+
467
+ return check_and_handle_test_deletion(
468
+ before_commit, agent, self.reset_to_commit, "[c2rust-optimizer]"
469
+ )
@@ -0,0 +1,52 @@
1
+ # -*- coding: utf-8 -*-
2
+ """优化器报告管理模块。"""
3
+
4
+ import json
5
+ from dataclasses import asdict
6
+ from pathlib import Path
7
+
8
+ from jarvis.jarvis_c2rust.optimizer_options import OptimizeStats
9
+ from jarvis.jarvis_c2rust.optimizer_utils import write_file
10
+
11
+
12
+ def get_report_display_path(
13
+ report_path: Path, project_root: Path, crate_dir: Path
14
+ ) -> str:
15
+ """
16
+ 获取报告文件的显示路径(优先使用相对路径)。
17
+
18
+ Args:
19
+ report_path: 报告文件的绝对路径
20
+ project_root: 项目根目录
21
+ crate_dir: crate 根目录
22
+
23
+ Returns:
24
+ 显示路径字符串
25
+ """
26
+ try:
27
+ return str(report_path.relative_to(project_root))
28
+ except ValueError:
29
+ try:
30
+ return str(report_path.relative_to(crate_dir))
31
+ except ValueError:
32
+ try:
33
+ return str(report_path.relative_to(Path.cwd()))
34
+ except ValueError:
35
+ return str(report_path)
36
+
37
+
38
+ def write_final_report(report_path: Path, stats: OptimizeStats) -> None:
39
+ """
40
+ 写入最终优化报告。
41
+
42
+ Args:
43
+ report_path: 报告文件路径
44
+ stats: 优化统计信息
45
+ """
46
+ try:
47
+ write_file(
48
+ report_path,
49
+ json.dumps(asdict(stats), ensure_ascii=False, indent=2),
50
+ )
51
+ except Exception:
52
+ pass