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
@@ -15,17 +15,18 @@ from __future__ import annotations
15
15
 
16
16
  import os
17
17
  from pathlib import Path
18
- from typing import Optional, List
18
+ from typing import List
19
+ from typing import Optional
19
20
 
20
21
  import typer
21
- from jarvis.jarvis_c2rust.scanner import run_scan as _run_scan
22
+ from jarvis.jarvis_utils.output import PrettyOutput
23
+
22
24
  from jarvis.jarvis_c2rust.library_replacer import (
23
25
  apply_library_replacement as _apply_library_replacement,
24
26
  )
27
+ from jarvis.jarvis_c2rust.llm_module_agent import execute_llm_plan as _execute_llm_plan
28
+ from jarvis.jarvis_c2rust.scanner import run_scan as _run_scan
25
29
  from jarvis.jarvis_utils.utils import init_env
26
- from jarvis.jarvis_c2rust.llm_module_agent import (
27
- execute_llm_plan as _execute_llm_plan,
28
- )
29
30
 
30
31
 
31
32
  def _check_optimize_completed(crate_dir: Path) -> bool:
@@ -35,22 +36,24 @@ def _check_optimize_completed(crate_dir: Path) -> bool:
35
36
  特别是 clippy_elimination:如果有告警,必须完成;如果没有告警,可以跳过。
36
37
  """
37
38
  import json
39
+
38
40
  from jarvis.jarvis_c2rust.constants import C2RUST_DIRNAME
39
-
41
+
40
42
  progress_path = crate_dir / C2RUST_DIRNAME / "optimize_progress.json"
41
43
  if not progress_path.exists():
42
44
  # 如果没有进度文件,说明还没开始,不算完成
43
45
  return False
44
-
46
+
45
47
  try:
46
48
  with progress_path.open("r", encoding="utf-8") as f:
47
49
  progress = json.load(f)
48
-
50
+
49
51
  steps_completed = set(progress.get("steps_completed", []))
50
-
52
+
51
53
  # 检查是否有 clippy 告警
52
54
  # 直接调用 optimizer 模块中的函数(虽然是私有函数,但我们需要它来检查)
53
55
  import subprocess
56
+
54
57
  try:
55
58
  res = subprocess.run(
56
59
  ["cargo", "clippy", "--", "-W", "clippy::all"],
@@ -61,22 +64,30 @@ def _check_optimize_completed(crate_dir: Path) -> bool:
61
64
  )
62
65
  stderr_output = (res.stderr or "").strip()
63
66
  stdout_output = (res.stdout or "").strip()
64
- output = (stderr_output + "\n" + stdout_output).strip() if (stderr_output and stdout_output) else (stderr_output or stdout_output or "").strip()
67
+ output = (
68
+ (stderr_output + "\n" + stdout_output).strip()
69
+ if (stderr_output and stdout_output)
70
+ else (stderr_output or stdout_output or "").strip()
71
+ )
65
72
  output_lower = output.lower()
66
- has_warnings = "warning:" in output_lower or "warn(" in output_lower or ("clippy::" in output_lower and res.returncode != 0)
73
+ has_warnings = (
74
+ "warning:" in output_lower
75
+ or "warn(" in output_lower
76
+ or ("clippy::" in output_lower and res.returncode != 0)
77
+ )
67
78
  except Exception:
68
79
  # 如果检查失败,保守地认为有告警(需要完成)
69
80
  has_warnings = True
70
-
81
+
71
82
  # 如果有告警,clippy_elimination 必须在 steps_completed 中
72
83
  if has_warnings:
73
84
  if "clippy_elimination" not in steps_completed:
74
85
  return False
75
-
86
+
76
87
  # 检查其他必要的步骤(根据 enable_* 选项,但这里我们假设都启用了)
77
88
  # 注意:这里我们只检查 clippy_elimination,其他步骤(unsafe_cleanup, visibility_opt, doc_opt)
78
89
  # 可能因为 enable_* 选项而未执行,所以不强制要求
79
-
90
+
80
91
  return True
81
92
  except Exception:
82
93
  # 如果读取失败,保守地认为未完成
@@ -85,6 +96,7 @@ def _check_optimize_completed(crate_dir: Path) -> bool:
85
96
 
86
97
  app = typer.Typer(help="C2Rust 命令行工具")
87
98
 
99
+
88
100
  # 显式定义根回调,确保为命令组而非单函数入口
89
101
  @app.callback()
90
102
  def _root():
@@ -92,7 +104,7 @@ def _root():
92
104
  C2Rust 命令行工具
93
105
  """
94
106
  # 设置环境变量,标识当前运行在 c2rust 环境中
95
- os.environ["JARVIS_C2RUST_ENABLED"] = "1"
107
+ os.environ["c2rust_enabled"] = "1"
96
108
  # 不做任何处理,仅作为命令组的占位,使 'scan' 作为子命令出现
97
109
  init_env("")
98
110
  pass
@@ -104,15 +116,21 @@ def _load_config() -> dict:
104
116
  返回包含 root_symbols、disabled_libraries 和 additional_notes 的字典。
105
117
  """
106
118
  import json
107
- from jarvis.jarvis_c2rust.constants import CONFIG_JSON, C2RUST_DIRNAME
108
-
119
+
120
+ from jarvis.jarvis_c2rust.constants import C2RUST_DIRNAME
121
+ from jarvis.jarvis_c2rust.constants import CONFIG_JSON
122
+
109
123
  data_dir = Path(".") / C2RUST_DIRNAME
110
124
  config_path = data_dir / CONFIG_JSON
111
- default_config = {"root_symbols": [], "disabled_libraries": [], "additional_notes": ""}
112
-
125
+ default_config = {
126
+ "root_symbols": [],
127
+ "disabled_libraries": [],
128
+ "additional_notes": "",
129
+ }
130
+
113
131
  if not config_path.exists():
114
132
  return default_config
115
-
133
+
116
134
  try:
117
135
  with config_path.open("r", encoding="utf-8") as f:
118
136
  config = json.load(f)
@@ -128,12 +146,11 @@ def _load_config() -> dict:
128
146
  return default_config
129
147
 
130
148
 
131
- RUN_STATE_JSON = "run_state.json"
132
-
133
-
134
149
  def _get_run_state_path() -> Path:
135
150
  """获取 run 状态文件路径"""
136
151
  from jarvis.jarvis_c2rust.constants import C2RUST_DIRNAME
152
+ from jarvis.jarvis_c2rust.constants import RUN_STATE_JSON
153
+
137
154
  data_dir = Path(".") / C2RUST_DIRNAME
138
155
  return data_dir / RUN_STATE_JSON
139
156
 
@@ -141,7 +158,7 @@ def _get_run_state_path() -> Path:
141
158
  def _load_run_state() -> dict:
142
159
  """加载 run 状态文件"""
143
160
  import json
144
-
161
+
145
162
  state_path = _get_run_state_path()
146
163
  default_state = {
147
164
  "scan": {"completed": False, "timestamp": None},
@@ -150,10 +167,10 @@ def _load_run_state() -> dict:
150
167
  "transpile": {"completed": False, "timestamp": None},
151
168
  "optimize": {"completed": False, "timestamp": None},
152
169
  }
153
-
170
+
154
171
  if not state_path.exists():
155
172
  return default_state
156
-
173
+
157
174
  try:
158
175
  with state_path.open("r", encoding="utf-8") as f:
159
176
  state = json.load(f)
@@ -172,27 +189,31 @@ def _save_run_state(stage: str, completed: bool = True) -> None:
172
189
  """保存 run 状态文件"""
173
190
  import json
174
191
  import time
175
-
192
+
176
193
  state_path = _get_run_state_path()
177
194
  state = _load_run_state()
178
-
195
+
179
196
  state[stage] = {
180
197
  "completed": completed,
181
- "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime()) if completed else None,
198
+ "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime())
199
+ if completed
200
+ else None,
182
201
  }
183
-
202
+
184
203
  try:
185
204
  state_path.parent.mkdir(parents=True, exist_ok=True)
186
205
  with state_path.open("w", encoding="utf-8") as f:
187
206
  json.dump(state, f, ensure_ascii=False, indent=2)
188
207
  except Exception as e:
189
- typer.secho(f"[c2rust-run] 保存状态文件失败: {e}", fg=typer.colors.YELLOW, err=True)
208
+ PrettyOutput.auto_print(f"⚠️ [c2rust-run] 保存状态文件失败: {e}")
190
209
 
191
210
 
192
211
  @app.command("config")
193
212
  def config(
194
213
  files: Optional[List[Path]] = typer.Option(
195
- None, "--files", help="头文件(.h/.hh/.hpp/.hxx)或函数名列表文件(每行一个函数名,忽略空行与以#开头的注释)"
214
+ None,
215
+ "--files",
216
+ help="头文件(.h/.hh/.hpp/.hxx)或函数名列表文件(每行一个函数名,忽略空行与以#开头的注释)",
196
217
  ),
197
218
  root_list_syms: Optional[str] = typer.Option(
198
219
  None, "--root-list-syms", help="根符号列表内联(逗号分隔)"
@@ -203,58 +224,60 @@ def config(
203
224
  additional_notes: Optional[str] = typer.Option(
204
225
  None, "--additional-notes", help="附加说明(将在所有 agent 的提示词中追加)"
205
226
  ),
206
- show: bool = typer.Option(
207
- False, "--show", help="显示当前配置内容"
208
- ),
209
- clear: bool = typer.Option(
210
- False, "--clear", help="清空配置(重置为默认值)"
211
- ),
227
+ show: bool = typer.Option(False, "--show", help="显示当前配置内容"),
228
+ clear: bool = typer.Option(False, "--clear", help="清空配置(重置为默认值)"),
212
229
  ) -> None:
213
230
  """
214
231
  管理转译配置文件(.jarvis/c2rust/config.json)。
215
-
232
+
216
233
  可以设置根符号列表(root_symbols)、禁用库列表(disabled_libraries)和附加说明(additional_notes)。
217
234
  这些配置会被 transpile 命令自动读取和使用。
218
-
235
+
219
236
  示例:
220
237
  # 从头文件自动提取函数名并设置根符号列表
221
238
  jarvis-c2rust config --files bzlib.h
222
-
239
+
223
240
  # 从多个头文件提取函数名
224
241
  jarvis-c2rust config --files a.h b.hpp c.hxx
225
-
242
+
226
243
  # 从函数名列表文件设置根符号列表
227
244
  jarvis-c2rust config --files roots.txt
228
-
245
+
229
246
  # 从命令行设置根符号列表
230
247
  jarvis-c2rust config --root-list-syms "func1,func2,func3"
231
-
248
+
232
249
  # 设置禁用库列表
233
250
  jarvis-c2rust config --disabled-libs "libc,libm"
234
-
251
+
235
252
  # 设置附加说明(将在所有 agent 的提示词中追加)
236
253
  jarvis-c2rust config --additional-notes "注意:所有函数必须处理错误情况,避免 panic"
237
-
254
+
238
255
  # 同时设置多个参数
239
256
  jarvis-c2rust config --files bzlib.h --disabled-libs "libc" --additional-notes "特殊要求说明"
240
-
257
+
241
258
  # 查看当前配置
242
259
  jarvis-c2rust config --show
243
-
260
+
244
261
  # 清空配置
245
262
  jarvis-c2rust config --clear
246
263
  """
247
264
  import json
248
- from jarvis.jarvis_c2rust.constants import CONFIG_JSON, C2RUST_DIRNAME
249
-
265
+
266
+ from jarvis.jarvis_c2rust.constants import C2RUST_DIRNAME
267
+ from jarvis.jarvis_c2rust.constants import CONFIG_JSON
268
+
250
269
  data_dir = Path(".") / C2RUST_DIRNAME
251
270
  config_path = data_dir / CONFIG_JSON
252
271
  data_dir.mkdir(parents=True, exist_ok=True)
253
-
272
+
254
273
  # 读取现有配置
255
- default_config = {"root_symbols": [], "disabled_libraries": [], "additional_notes": ""}
274
+ default_config = {
275
+ "root_symbols": [],
276
+ "disabled_libraries": [],
277
+ "additional_notes": "",
278
+ }
256
279
  current_config = default_config.copy()
257
-
280
+
258
281
  if config_path.exists():
259
282
  try:
260
283
  with config_path.open("r", encoding="utf-8") as f:
@@ -262,79 +285,115 @@ def config(
262
285
  if not isinstance(current_config, dict):
263
286
  current_config = default_config.copy()
264
287
  except Exception as e:
265
- typer.secho(f"[c2rust-config] 读取现有配置失败: {e},将使用默认值", fg=typer.colors.YELLOW)
288
+ PrettyOutput.auto_print(
289
+ f"⚠️ [c2rust-config] 读取现有配置失败: {e},将使用默认值"
290
+ )
266
291
  current_config = default_config.copy()
267
-
292
+
268
293
  # 如果只是查看配置
269
294
  if show:
270
- typer.secho(f"[c2rust-config] 当前配置文件: {config_path}", fg=typer.colors.BLUE)
271
- typer.secho(json.dumps(current_config, ensure_ascii=False, indent=2), fg=typer.colors.CYAN)
295
+ PrettyOutput.auto_print(f"📋 [c2rust-config] 当前配置文件: {config_path}")
296
+ PrettyOutput.auto_print(
297
+ json.dumps(current_config, ensure_ascii=False, indent=2)
298
+ )
272
299
  return
273
-
300
+
274
301
  # 如果清空配置
275
302
  if clear:
276
303
  current_config = default_config.copy()
277
304
  with config_path.open("w", encoding="utf-8") as f:
278
305
  json.dump(current_config, f, ensure_ascii=False, indent=2)
279
- typer.secho(f"[c2rust-config] 配置已清空: {config_path}", fg=typer.colors.GREEN)
306
+ PrettyOutput.auto_print(f"[c2rust-config] 配置已清空: {config_path}")
280
307
  return
281
-
308
+
282
309
  # 读取根符号列表(从现有配置开始,以便追加而不是替换)
283
310
  root_symbols: List[str] = list(current_config.get("root_symbols", []))
284
311
  header_exts = {".h", ".hh", ".hpp", ".hxx"}
285
-
312
+
286
313
  if files:
287
314
  for file_path in files:
288
315
  try:
289
316
  file_path = Path(file_path).resolve()
290
317
  if not file_path.exists():
291
- typer.secho(f"[c2rust-config] 警告: 文件不存在,跳过: {file_path}", fg=typer.colors.YELLOW)
318
+ PrettyOutput.auto_print(
319
+ f"⚠️ [c2rust-config] 警告: 文件不存在,跳过: {file_path}"
320
+ )
292
321
  continue
293
-
322
+
294
323
  # 检查是否是头文件
295
324
  if file_path.suffix.lower() in header_exts:
296
325
  # 从头文件提取函数名
297
- typer.secho(f"[c2rust-config] 从头文件提取函数名: {file_path}", fg=typer.colors.BLUE)
326
+ PrettyOutput.auto_print(
327
+ f"📋 [c2rust-config] 从头文件提取函数名: {file_path}"
328
+ )
298
329
  try:
299
- from jarvis.jarvis_c2rust.collector import collect_function_names as _collect_fn_names
300
330
  # 使用临时文件存储提取的函数名
301
331
  import tempfile
302
- with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False, encoding='utf-8') as tmp:
332
+
333
+ from jarvis.jarvis_c2rust.collector import (
334
+ collect_function_names as _collect_fn_names,
335
+ )
336
+
337
+ with tempfile.NamedTemporaryFile(
338
+ mode="w", suffix=".txt", delete=False, encoding="utf-8"
339
+ ) as tmp:
303
340
  tmp_path = Path(tmp.name)
304
- _collect_fn_names(files=[file_path], out_path=tmp_path, compile_commands_root=None)
341
+ _collect_fn_names(
342
+ files=[file_path],
343
+ out_path=tmp_path,
344
+ compile_commands_root=None,
345
+ )
305
346
  # 读取提取的函数名
306
347
  txt = tmp_path.read_text(encoding="utf-8")
307
- collected = [ln.strip() for ln in txt.splitlines() if ln.strip()]
348
+ collected = [
349
+ ln.strip() for ln in txt.splitlines() if ln.strip()
350
+ ]
308
351
  root_symbols.extend(collected)
309
- typer.secho(f"[c2rust-config] 从头文件 {file_path.name} 提取了 {len(collected)} 个函数名", fg=typer.colors.GREEN)
352
+ PrettyOutput.auto_print(
353
+ f"✅ [c2rust-config] 从头文件 {file_path.name} 提取了 {len(collected)} 个函数名"
354
+ )
310
355
  # 清理临时文件
311
356
  try:
312
357
  tmp_path.unlink()
313
358
  except Exception:
314
359
  pass
315
360
  except Exception as e:
316
- typer.secho(f"[c2rust-config] 从头文件提取函数名失败: {file_path}: {e}", fg=typer.colors.RED, err=True)
361
+ PrettyOutput.auto_print(
362
+ f"❌ [c2rust-config] 从头文件提取函数名失败: {file_path}: {e}"
363
+ )
317
364
  raise typer.Exit(code=1)
318
365
  else:
319
366
  # 读取函数名列表文件(每行一个函数名)
320
367
  txt = file_path.read_text(encoding="utf-8")
321
- collected = [ln.strip() for ln in txt.splitlines() if ln.strip() and not ln.strip().startswith("#")]
368
+ collected = [
369
+ ln.strip()
370
+ for ln in txt.splitlines()
371
+ if ln.strip() and not ln.strip().startswith("#")
372
+ ]
322
373
  root_symbols.extend(collected)
323
- typer.secho(f"[c2rust-config] 从文件 {file_path.name} 读取了 {len(collected)} 个根符号", fg=typer.colors.BLUE)
374
+ PrettyOutput.auto_print(
375
+ f"📋 [c2rust-config] 从文件 {file_path.name} 读取了 {len(collected)} 个根符号"
376
+ )
324
377
  except typer.Exit:
325
378
  raise
326
379
  except Exception as e:
327
- typer.secho(f"[c2rust-config] 处理文件失败: {file_path}: {e}", fg=typer.colors.RED, err=True)
380
+ PrettyOutput.auto_print(
381
+ f"❌ [c2rust-config] 处理文件失败: {file_path}: {e}"
382
+ )
328
383
  raise typer.Exit(code=1)
329
-
384
+
330
385
  # 标记是否处理了 root_list_syms,以便即使结果为空也更新配置
331
386
  processed_root_list_syms = False
332
387
  if isinstance(root_list_syms, str) and root_list_syms.strip():
333
- parts = [s.strip() for s in root_list_syms.replace("\n", ",").split(",") if s.strip()]
388
+ parts = [
389
+ s.strip() for s in root_list_syms.replace("\n", ",").split(",") if s.strip()
390
+ ]
334
391
  root_symbols.extend(parts)
335
392
  processed_root_list_syms = True
336
- typer.secho(f"[c2rust-config] 从命令行读取根符号: {len(parts)} 个", fg=typer.colors.BLUE)
337
-
393
+ PrettyOutput.auto_print(
394
+ f"📋 [c2rust-config] 从命令行读取根符号: {len(parts)} 个"
395
+ )
396
+
338
397
  # 去重根符号列表(如果处理了 files 或 root_list_syms,或者 root_symbols 非空,则更新配置)
339
398
  if files or processed_root_list_syms or root_symbols:
340
399
  try:
@@ -342,36 +401,53 @@ def config(
342
401
  except Exception:
343
402
  root_symbols = sorted(list(set(root_symbols)))
344
403
  current_config["root_symbols"] = root_symbols
345
- typer.secho(f"[c2rust-config] 已设置根符号列表: {len(root_symbols)} 个", fg=typer.colors.GREEN)
346
-
404
+ PrettyOutput.auto_print(
405
+ f"✅ [c2rust-config] 已设置根符号列表: {len(root_symbols)} 个"
406
+ )
407
+
347
408
  # 读取禁用库列表
348
409
  if isinstance(disabled_libs, str) and disabled_libs.strip():
349
- disabled_list = [s.strip() for s in disabled_libs.replace("\n", ",").split(",") if s.strip()]
410
+ disabled_list = [
411
+ s.strip() for s in disabled_libs.replace("\n", ",").split(",") if s.strip()
412
+ ]
350
413
  if disabled_list:
351
414
  current_config["disabled_libraries"] = disabled_list
352
- typer.secho(f"[c2rust-config] 已设置禁用库列表: {', '.join(disabled_list)}", fg=typer.colors.GREEN)
353
-
415
+ PrettyOutput.auto_print(
416
+ f"✅ [c2rust-config] 已设置禁用库列表: {', '.join(disabled_list)}"
417
+ )
418
+
354
419
  # 读取附加说明
355
420
  if isinstance(additional_notes, str):
356
421
  current_config["additional_notes"] = additional_notes.strip()
357
422
  if additional_notes.strip():
358
- typer.secho(f"[c2rust-config] 已设置附加说明: {len(additional_notes.strip())} 字符", fg=typer.colors.GREEN)
423
+ PrettyOutput.auto_print(
424
+ f"✅ [c2rust-config] 已设置附加说明: {len(additional_notes.strip())} 字符"
425
+ )
359
426
  else:
360
- typer.secho("[c2rust-config] 已清空附加说明", fg=typer.colors.GREEN)
361
-
427
+ PrettyOutput.auto_print("[c2rust-config] 已清空附加说明")
428
+
362
429
  # 如果没有提供任何参数,提示用户
363
- if not files and not root_list_syms and not disabled_libs and additional_notes is None:
364
- typer.secho("[c2rust-config] 未提供任何参数,使用 --show 查看当前配置,或使用 --help 查看帮助", fg=typer.colors.YELLOW)
430
+ if (
431
+ not files
432
+ and not root_list_syms
433
+ and not disabled_libs
434
+ and additional_notes is None
435
+ ):
436
+ PrettyOutput.auto_print(
437
+ "⚠️ [c2rust-config] 未提供任何参数,使用 --show 查看当前配置,或使用 --help 查看帮助"
438
+ )
365
439
  return
366
-
440
+
367
441
  # 保存配置
368
442
  try:
369
443
  with config_path.open("w", encoding="utf-8") as f:
370
444
  json.dump(current_config, f, ensure_ascii=False, indent=2)
371
- typer.secho(f"[c2rust-config] 配置已保存: {config_path}", fg=typer.colors.GREEN)
372
- typer.secho(json.dumps(current_config, ensure_ascii=False, indent=2), fg=typer.colors.CYAN)
445
+ PrettyOutput.auto_print(f"[c2rust-config] 配置已保存: {config_path}")
446
+ PrettyOutput.auto_print(
447
+ json.dumps(current_config, ensure_ascii=False, indent=2)
448
+ )
373
449
  except Exception as e:
374
- typer.secho(f"[c2rust-config] 保存配置失败: {e}", fg=typer.colors.RED, err=True)
450
+ PrettyOutput.auto_print(f"[c2rust-config] 保存配置失败: {e}")
375
451
  raise typer.Exit(code=1)
376
452
 
377
453
 
@@ -384,7 +460,10 @@ def run(
384
460
  help="用于 LLM 相关阶段(lib-replace/prepare/transpile/optimize)的模型组",
385
461
  ),
386
462
  max_retries: int = typer.Option(
387
- 0, "-m", "--max-retries", help="transpile 构建/修复与审查的最大重试次数(0 表示不限制)"
463
+ 0,
464
+ "-m",
465
+ "--max-retries",
466
+ help="transpile 构建/修复与审查的最大重试次数(0 表示不限制)",
388
467
  ),
389
468
  interactive: bool = typer.Option(
390
469
  False,
@@ -403,7 +482,7 @@ def run(
403
482
  支持断点续跑:根据状态文件(.jarvis/c2rust/run_state.json)自动跳过已完成的阶段。
404
483
 
405
484
  约束:
406
-
485
+
407
486
  - 根符号列表和禁用库列表从配置文件(.jarvis/c2rust/config.json)读取
408
487
  使用 jarvis-c2rust config 命令设置这些配置(例如:jarvis-c2rust config --files bzlib.h)
409
488
 
@@ -413,7 +492,7 @@ def run(
413
492
 
414
493
  - optimize 阶段采用默认优化配置,自动检测 crate 根目录并进行保守优化(unsafe 清理、结构优化、可见性优化、文档补充)
415
494
  """
416
-
495
+
417
496
  try:
418
497
  # 加载状态文件
419
498
  if reset:
@@ -421,55 +500,76 @@ def run(
421
500
  state_path = _get_run_state_path()
422
501
  if state_path.exists():
423
502
  state_path.unlink()
424
- typer.secho("[c2rust-run] 已重置状态,将从头开始执行", fg=typer.colors.YELLOW)
503
+ PrettyOutput.auto_print("⚠️ [c2rust-run] 已重置状态,将从头开始执行")
425
504
  state = _load_run_state()
426
505
  else:
427
506
  state = _load_run_state()
428
507
  # 显示当前状态
429
- completed_stages = [s for s, info in state.items() if info.get("completed", False)]
508
+ completed_stages = [
509
+ s for s, info in state.items() if info.get("completed", False)
510
+ ]
430
511
  if completed_stages:
431
- typer.secho(f"[c2rust-run] 检测到已完成阶段: {', '.join(completed_stages)},将从断点继续", fg=typer.colors.CYAN)
432
-
512
+ PrettyOutput.auto_print(
513
+ f"🚀 [c2rust-run] 检测到已完成阶段: {', '.join(completed_stages)},将从断点继续"
514
+ )
515
+
433
516
  # Step 1: scan
434
517
  if not state.get("scan", {}).get("completed", False):
435
- typer.secho("[c2rust-run] scan: 开始", fg=typer.colors.BLUE)
436
- _run_scan(dot=None, only_dot=False, subgraphs_dir=None, only_subgraphs=False, png=False, non_interactive=True)
437
- typer.secho("[c2rust-run] scan: 完成", fg=typer.colors.GREEN)
518
+ PrettyOutput.auto_print("🚀 [c2rust-run] scan: 开始")
519
+ _run_scan(
520
+ dot=None,
521
+ only_dot=False,
522
+ subgraphs_dir=None,
523
+ only_subgraphs=False,
524
+ png=False,
525
+ non_interactive=True,
526
+ )
527
+ PrettyOutput.auto_print("✅ [c2rust-run] scan: 完成")
438
528
  # 保存状态(因为直接调用 _run_scan 函数,需要手动保存状态)
439
529
  _save_run_state("scan", completed=True)
440
530
  else:
441
- typer.secho("[c2rust-run] scan: 已完成,跳过", fg=typer.colors.CYAN)
531
+ PrettyOutput.auto_print("🚀 [c2rust-run] scan: 已完成,跳过")
442
532
 
443
533
  # Step 2: lib-replace(从配置文件读取根列表和禁用库列表)
444
534
  if not state.get("lib_replace", {}).get("completed", False):
445
535
  # 从配置文件读取基础配置
446
536
  config = _load_config()
447
537
  root_names: List[str] = list(config.get("root_symbols", []))
448
- disabled_list: Optional[List[str]] = config.get("disabled_libraries", []) or None
449
-
538
+ disabled_list: Optional[List[str]] = (
539
+ config.get("disabled_libraries", []) or None
540
+ )
541
+
450
542
  # 去重并校验(允许为空时回退为自动根集)
451
543
  if root_names:
452
544
  try:
453
545
  root_names = list(dict.fromkeys(root_names))
454
546
  except Exception:
455
547
  root_names = sorted(list(set(root_names)))
456
-
548
+
457
549
  candidates_list: Optional[List[str]] = root_names if root_names else None
458
550
  if not candidates_list:
459
- typer.secho("[c2rust-run] lib-replace: 根列表为空,将回退为自动检测的根集合(基于扫描结果)", fg=typer.colors.YELLOW)
460
-
551
+ PrettyOutput.auto_print(
552
+ "⚠️ [c2rust-run] lib-replace: 根列表为空,将回退为自动检测的根集合(基于扫描结果)"
553
+ )
554
+
461
555
  if disabled_list:
462
- typer.secho(f"[c2rust-run] lib-replace: 从配置文件读取禁用库: {', '.join(disabled_list)}", fg=typer.colors.BLUE)
556
+ PrettyOutput.auto_print(
557
+ f"📋 [c2rust-run] lib-replace: 从配置文件读取禁用库: {', '.join(disabled_list)}"
558
+ )
463
559
 
464
560
  # 执行 lib-replace(默认库 std)
465
561
  library = "std"
466
- root_count_str = str(len(candidates_list)) if candidates_list is not None else "auto"
467
- typer.secho(f"[c2rust-run] lib-replace: 开始(库: {library},根数: {root_count_str})", fg=typer.colors.BLUE)
562
+ root_count_str = (
563
+ str(len(candidates_list)) if candidates_list is not None else "auto"
564
+ )
565
+ PrettyOutput.auto_print(
566
+ f"🚀 [c2rust-run] lib-replace: 开始(库: {library},根数: {root_count_str})"
567
+ )
468
568
  ret = _apply_library_replacement(
469
569
  db_path=Path("."),
470
570
  library_name=library,
471
571
  llm_group=llm_group,
472
- candidates=candidates_list, # None 表示自动检测全部根
572
+ candidates=candidates_list, # None 表示自动检测全部根
473
573
  out_symbols_path=None,
474
574
  out_mapping_path=None,
475
575
  max_funcs=None,
@@ -477,34 +577,42 @@ def run(
477
577
  non_interactive=not interactive,
478
578
  )
479
579
  try:
480
- order_msg = f"\n[c2rust-run] lib-replace: 转译顺序: {ret['order']}" if 'order' in ret else ""
481
- typer.secho(
482
- f"[c2rust-run] lib-replace: 替代映射: {ret['mapping']}\n"
483
- f"[c2rust-run] lib-replace: 新符号表: {ret['symbols']}"
484
- + order_msg,
485
- fg=typer.colors.GREEN,
580
+ order_msg = (
581
+ f"\n[c2rust-run] lib-replace: 转译顺序: {ret['order']}"
582
+ if "order" in ret
583
+ else ""
584
+ )
585
+ PrettyOutput.auto_print(
586
+ f"✅ [c2rust-run] lib-replace: 替代映射: {ret['mapping']}\n"
587
+ f"✅ [c2rust-run] lib-replace: 新符号表: {ret['symbols']}"
588
+ + order_msg
486
589
  )
487
590
  except Exception as _e:
488
- typer.secho(f"[c2rust-run] lib-replace: 结果输出时发生非致命错误: {_e}", fg=typer.colors.YELLOW, err=True)
591
+ PrettyOutput.auto_print(
592
+ f"⚠️ [c2rust-run] lib-replace: 结果输出时发生非致命错误: {_e}"
593
+ )
489
594
  # 保存状态(因为直接调用 _apply_library_replacement 函数,需要手动保存状态)
490
595
  _save_run_state("lib_replace", completed=True)
491
596
  else:
492
- typer.secho("[c2rust-run] lib-replace: 已完成,跳过", fg=typer.colors.CYAN)
597
+ PrettyOutput.auto_print("🚀 [c2rust-run] lib-replace: 已完成,跳过")
493
598
 
494
599
  # Step 3: prepare
495
600
  if not state.get("prepare", {}).get("completed", False):
496
- typer.secho("[c2rust-run] prepare: 开始", fg=typer.colors.BLUE)
497
- _execute_llm_plan(apply=True, llm_group=llm_group, non_interactive=not interactive)
498
- typer.secho("[c2rust-run] prepare: 完成", fg=typer.colors.GREEN)
601
+ PrettyOutput.auto_print("🚀 [c2rust-run] prepare: 开始")
602
+ _execute_llm_plan(
603
+ apply=True, llm_group=llm_group, non_interactive=not interactive
604
+ )
605
+ PrettyOutput.auto_print("✅ [c2rust-run] prepare: 完成")
499
606
  # 保存状态(因为直接调用 _execute_llm_plan 函数,需要手动保存状态)
500
607
  _save_run_state("prepare", completed=True)
501
608
  else:
502
- typer.secho("[c2rust-run] prepare: 已完成,跳过", fg=typer.colors.CYAN)
609
+ PrettyOutput.auto_print("🚀 [c2rust-run] prepare: 已完成,跳过")
503
610
 
504
611
  # Step 4: transpile
505
612
  if not state.get("transpile", {}).get("completed", False):
506
- typer.secho("[c2rust-run] transpile: 开始", fg=typer.colors.BLUE)
613
+ PrettyOutput.auto_print("🚀 [c2rust-run] transpile: 开始")
507
614
  from jarvis.jarvis_c2rust.transpiler import run_transpile as _run_transpile
615
+
508
616
  # 从配置文件读取配置(transpile 内部会自动读取)
509
617
  _run_transpile(
510
618
  project_root=Path("."),
@@ -515,23 +623,33 @@ def run(
515
623
  root_symbols=None, # 从配置文件恢复
516
624
  non_interactive=not interactive,
517
625
  )
518
- typer.secho("[c2rust-run] transpile: 完成", fg=typer.colors.GREEN)
626
+ PrettyOutput.auto_print("[c2rust-run] transpile: 完成")
519
627
  # 保存状态(因为直接调用 _run_transpile 函数,需要手动保存状态)
520
628
  _save_run_state("transpile", completed=True)
521
629
  else:
522
- typer.secho("[c2rust-run] transpile: 已完成,跳过", fg=typer.colors.CYAN)
630
+ PrettyOutput.auto_print("🚀 [c2rust-run] transpile: 已完成,跳过")
523
631
 
524
632
  # Step 5: optimize
525
633
  if not state.get("optimize", {}).get("completed", False):
526
634
  try:
527
- typer.secho("[c2rust-run] optimize: 开始", fg=typer.colors.BLUE)
528
- from jarvis.jarvis_c2rust.optimizer import optimize_project as _optimize_project
635
+ PrettyOutput.auto_print("🚀 [c2rust-run] optimize: 开始")
636
+ from jarvis.jarvis_c2rust.optimizer import (
637
+ optimize_project as _optimize_project,
638
+ )
529
639
  from jarvis.jarvis_c2rust.utils import default_crate_dir
640
+
530
641
  # 使用与 transpile 相同的逻辑确定项目根目录和 crate 目录
531
642
  project_root = Path(".")
532
643
  crate_dir = default_crate_dir(project_root)
533
- typer.secho(f"[c2rust-run] optimize: 使用项目根目录: {project_root}, crate 目录: {crate_dir}", fg=typer.colors.CYAN)
534
- res = _optimize_project(project_root=project_root, crate_dir=crate_dir, llm_group=llm_group, non_interactive=not interactive)
644
+ PrettyOutput.auto_print(
645
+ f"📋 [c2rust-run] optimize: 使用项目根目录: {project_root}, crate 目录: {crate_dir}"
646
+ )
647
+ res = _optimize_project(
648
+ project_root=project_root,
649
+ crate_dir=crate_dir,
650
+ llm_group=llm_group,
651
+ non_interactive=not interactive,
652
+ )
535
653
  summary = (
536
654
  f"[c2rust-run] optimize: 结果摘要:\n"
537
655
  f" files_scanned: {res.get('files_scanned')}\n"
@@ -541,35 +659,36 @@ def run(
541
659
  f" docs_added: {res.get('docs_added')}\n"
542
660
  f" cargo_checks: {res.get('cargo_checks')}\n"
543
661
  )
544
- typer.secho(summary, fg=typer.colors.GREEN)
545
-
662
+ PrettyOutput.auto_print(summary)
663
+
546
664
  # 检查优化是否真正完成(所有步骤都完成,包括 clippy 告警修复)
547
665
  optimize_truly_completed = _check_optimize_completed(crate_dir)
548
666
  if optimize_truly_completed:
549
- typer.secho("[c2rust-run] optimize: 完成", fg=typer.colors.GREEN)
667
+ PrettyOutput.auto_print("[c2rust-run] optimize: 完成")
550
668
  # 保存状态(因为直接调用 _optimize_project 函数,需要手动保存状态)
551
669
  _save_run_state("optimize", completed=True)
552
670
  else:
553
- typer.secho("[c2rust-run] optimize: 部分步骤未完成(如 clippy 告警未完全修复),下次将继续", fg=typer.colors.YELLOW)
671
+ PrettyOutput.auto_print(
672
+ "⚠️ [c2rust-run] optimize: 部分步骤未完成(如 clippy 告警未完全修复),下次将继续"
673
+ )
554
674
  # 不保存状态,下次恢复时会继续执行优化
555
675
  except Exception as _e:
556
- typer.secho(f"[c2rust-run] optimize: 错误: {_e}", fg=typer.colors.RED, err=True)
676
+ PrettyOutput.auto_print(f"[c2rust-run] optimize: 错误: {_e}")
557
677
  raise
558
678
  else:
559
- typer.secho("[c2rust-run] optimize: 已完成,跳过", fg=typer.colors.CYAN)
560
-
679
+ PrettyOutput.auto_print("🚀 [c2rust-run] optimize: 已完成,跳过")
680
+
561
681
  # 所有阶段完成
562
- typer.secho("[c2rust-run] 所有阶段已完成!", fg=typer.colors.GREEN)
682
+ PrettyOutput.auto_print("🎉 [c2rust-run] 所有阶段已完成!")
563
683
  except Exception as e:
564
- typer.secho(f"[c2rust-run] 错误: {e}", fg=typer.colors.RED, err=True)
684
+ PrettyOutput.auto_print(f"[c2rust-run] 错误: {e}")
565
685
  raise typer.Exit(code=1)
566
686
 
567
687
 
568
-
569
688
  def main() -> None:
570
689
  """主入口"""
571
690
  app()
572
691
 
573
692
 
574
693
  if __name__ == "__main__":
575
- main()
694
+ main()