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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +567 -222
  3. jarvis/jarvis_agent/agent_manager.py +19 -12
  4. jarvis/jarvis_agent/builtin_input_handler.py +79 -11
  5. jarvis/jarvis_agent/config_editor.py +7 -2
  6. jarvis/jarvis_agent/event_bus.py +24 -13
  7. jarvis/jarvis_agent/events.py +19 -1
  8. jarvis/jarvis_agent/file_context_handler.py +67 -64
  9. jarvis/jarvis_agent/file_methodology_manager.py +38 -24
  10. jarvis/jarvis_agent/jarvis.py +186 -114
  11. jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
  12. jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
  13. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
  14. jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
  15. jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
  16. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
  17. jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
  18. jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
  19. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
  20. jarvis/jarvis_agent/language_support_info.py +250 -219
  21. jarvis/jarvis_agent/main.py +19 -23
  22. jarvis/jarvis_agent/memory_manager.py +9 -6
  23. jarvis/jarvis_agent/methodology_share_manager.py +21 -15
  24. jarvis/jarvis_agent/output_handler.py +4 -2
  25. jarvis/jarvis_agent/prompt_builder.py +7 -6
  26. jarvis/jarvis_agent/prompt_manager.py +113 -8
  27. jarvis/jarvis_agent/prompts.py +317 -85
  28. jarvis/jarvis_agent/protocols.py +5 -2
  29. jarvis/jarvis_agent/run_loop.py +192 -32
  30. jarvis/jarvis_agent/session_manager.py +7 -3
  31. jarvis/jarvis_agent/share_manager.py +23 -13
  32. jarvis/jarvis_agent/shell_input_handler.py +12 -8
  33. jarvis/jarvis_agent/stdio_redirect.py +25 -26
  34. jarvis/jarvis_agent/task_analyzer.py +29 -23
  35. jarvis/jarvis_agent/task_list.py +869 -0
  36. jarvis/jarvis_agent/task_manager.py +26 -23
  37. jarvis/jarvis_agent/tool_executor.py +6 -5
  38. jarvis/jarvis_agent/tool_share_manager.py +24 -14
  39. jarvis/jarvis_agent/user_interaction.py +3 -3
  40. jarvis/jarvis_agent/utils.py +9 -1
  41. jarvis/jarvis_agent/web_bridge.py +37 -17
  42. jarvis/jarvis_agent/web_output_sink.py +5 -2
  43. jarvis/jarvis_agent/web_server.py +165 -36
  44. jarvis/jarvis_c2rust/__init__.py +1 -1
  45. jarvis/jarvis_c2rust/cli.py +260 -141
  46. jarvis/jarvis_c2rust/collector.py +37 -18
  47. jarvis/jarvis_c2rust/constants.py +60 -0
  48. jarvis/jarvis_c2rust/library_replacer.py +242 -1010
  49. jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
  50. jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
  51. jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
  52. jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
  53. jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
  54. jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
  55. jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
  56. jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
  57. jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
  58. jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
  59. jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
  60. jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
  61. jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
  62. jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
  63. jarvis/jarvis_c2rust/loaders.py +28 -10
  64. jarvis/jarvis_c2rust/models.py +5 -2
  65. jarvis/jarvis_c2rust/optimizer.py +192 -1974
  66. jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
  67. jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
  68. jarvis/jarvis_c2rust/optimizer_config.py +49 -0
  69. jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
  70. jarvis/jarvis_c2rust/optimizer_options.py +48 -0
  71. jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
  72. jarvis/jarvis_c2rust/optimizer_report.py +52 -0
  73. jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
  74. jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
  75. jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
  76. jarvis/jarvis_c2rust/scanner.py +229 -166
  77. jarvis/jarvis_c2rust/transpiler.py +531 -2732
  78. jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
  79. jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
  80. jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
  81. jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
  82. jarvis/jarvis_c2rust/transpiler_config.py +178 -0
  83. jarvis/jarvis_c2rust/transpiler_context.py +122 -0
  84. jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
  85. jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
  86. jarvis/jarvis_c2rust/transpiler_git.py +163 -0
  87. jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
  88. jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
  89. jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
  90. jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
  91. jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
  92. jarvis/jarvis_c2rust/utils.py +269 -79
  93. jarvis/jarvis_code_agent/after_change.py +233 -0
  94. jarvis/jarvis_code_agent/build_validation_config.py +37 -30
  95. jarvis/jarvis_code_agent/builtin_rules.py +68 -0
  96. jarvis/jarvis_code_agent/code_agent.py +976 -1517
  97. jarvis/jarvis_code_agent/code_agent_build.py +227 -0
  98. jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
  99. jarvis/jarvis_code_agent/code_agent_git.py +525 -0
  100. jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
  101. jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
  102. jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
  103. jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
  104. jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
  105. jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
  106. jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
  107. jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
  108. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
  109. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
  110. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
  111. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
  112. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
  113. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
  114. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
  115. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
  116. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
  117. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
  118. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
  119. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
  120. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
  121. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
  122. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
  123. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
  124. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
  125. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
  126. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
  127. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
  128. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
  129. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
  130. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
  131. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
  132. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
  133. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
  134. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
  135. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
  136. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
  137. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
  138. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
  139. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
  140. jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
  141. jarvis/jarvis_code_agent/lint.py +223 -524
  142. jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
  143. jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
  144. jarvis/jarvis_code_agent/rules/code_review.md +115 -0
  145. jarvis/jarvis_code_agent/rules/documentation.md +165 -0
  146. jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
  147. jarvis/jarvis_code_agent/rules/performance.md +158 -0
  148. jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
  149. jarvis/jarvis_code_agent/rules/security.md +160 -0
  150. jarvis/jarvis_code_agent/rules/tdd.md +78 -0
  151. jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
  152. jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
  153. jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
  154. jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
  155. jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
  156. jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
  157. jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
  158. jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
  159. jarvis/jarvis_code_agent/utils.py +36 -26
  160. jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
  161. jarvis/jarvis_code_analysis/code_review.py +64 -33
  162. jarvis/jarvis_data/config_schema.json +285 -192
  163. jarvis/jarvis_git_squash/main.py +8 -6
  164. jarvis/jarvis_git_utils/git_commiter.py +53 -76
  165. jarvis/jarvis_mcp/__init__.py +5 -2
  166. jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
  167. jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
  168. jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
  169. jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
  170. jarvis/jarvis_methodology/main.py +48 -39
  171. jarvis/jarvis_multi_agent/__init__.py +56 -23
  172. jarvis/jarvis_multi_agent/main.py +15 -18
  173. jarvis/jarvis_platform/base.py +179 -111
  174. jarvis/jarvis_platform/human.py +27 -16
  175. jarvis/jarvis_platform/kimi.py +52 -45
  176. jarvis/jarvis_platform/openai.py +101 -40
  177. jarvis/jarvis_platform/registry.py +51 -33
  178. jarvis/jarvis_platform/tongyi.py +68 -38
  179. jarvis/jarvis_platform/yuanbao.py +59 -43
  180. jarvis/jarvis_platform_manager/main.py +68 -76
  181. jarvis/jarvis_platform_manager/service.py +24 -14
  182. jarvis/jarvis_rag/README_CONFIG.md +314 -0
  183. jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
  184. jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
  185. jarvis/jarvis_rag/__init__.py +57 -4
  186. jarvis/jarvis_rag/cache.py +3 -1
  187. jarvis/jarvis_rag/cli.py +48 -68
  188. jarvis/jarvis_rag/embedding_interface.py +39 -0
  189. jarvis/jarvis_rag/embedding_manager.py +7 -230
  190. jarvis/jarvis_rag/embeddings/__init__.py +41 -0
  191. jarvis/jarvis_rag/embeddings/base.py +114 -0
  192. jarvis/jarvis_rag/embeddings/cohere.py +66 -0
  193. jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
  194. jarvis/jarvis_rag/embeddings/local.py +260 -0
  195. jarvis/jarvis_rag/embeddings/openai.py +62 -0
  196. jarvis/jarvis_rag/embeddings/registry.py +293 -0
  197. jarvis/jarvis_rag/llm_interface.py +8 -6
  198. jarvis/jarvis_rag/query_rewriter.py +8 -9
  199. jarvis/jarvis_rag/rag_pipeline.py +61 -52
  200. jarvis/jarvis_rag/reranker.py +7 -75
  201. jarvis/jarvis_rag/reranker_interface.py +32 -0
  202. jarvis/jarvis_rag/rerankers/__init__.py +41 -0
  203. jarvis/jarvis_rag/rerankers/base.py +109 -0
  204. jarvis/jarvis_rag/rerankers/cohere.py +67 -0
  205. jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
  206. jarvis/jarvis_rag/rerankers/jina.py +79 -0
  207. jarvis/jarvis_rag/rerankers/local.py +89 -0
  208. jarvis/jarvis_rag/rerankers/registry.py +293 -0
  209. jarvis/jarvis_rag/retriever.py +58 -43
  210. jarvis/jarvis_sec/__init__.py +66 -141
  211. jarvis/jarvis_sec/agents.py +21 -17
  212. jarvis/jarvis_sec/analysis.py +80 -33
  213. jarvis/jarvis_sec/checkers/__init__.py +7 -13
  214. jarvis/jarvis_sec/checkers/c_checker.py +356 -164
  215. jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
  216. jarvis/jarvis_sec/cli.py +43 -21
  217. jarvis/jarvis_sec/clustering.py +430 -272
  218. jarvis/jarvis_sec/file_manager.py +99 -55
  219. jarvis/jarvis_sec/parsers.py +9 -6
  220. jarvis/jarvis_sec/prompts.py +4 -3
  221. jarvis/jarvis_sec/report.py +44 -22
  222. jarvis/jarvis_sec/review.py +180 -107
  223. jarvis/jarvis_sec/status.py +50 -41
  224. jarvis/jarvis_sec/types.py +3 -0
  225. jarvis/jarvis_sec/utils.py +160 -83
  226. jarvis/jarvis_sec/verification.py +411 -181
  227. jarvis/jarvis_sec/workflow.py +132 -21
  228. jarvis/jarvis_smart_shell/main.py +28 -41
  229. jarvis/jarvis_stats/cli.py +14 -12
  230. jarvis/jarvis_stats/stats.py +28 -19
  231. jarvis/jarvis_stats/storage.py +14 -8
  232. jarvis/jarvis_stats/visualizer.py +12 -7
  233. jarvis/jarvis_tools/base.py +5 -2
  234. jarvis/jarvis_tools/clear_memory.py +13 -9
  235. jarvis/jarvis_tools/cli/main.py +23 -18
  236. jarvis/jarvis_tools/edit_file.py +572 -873
  237. jarvis/jarvis_tools/execute_script.py +10 -7
  238. jarvis/jarvis_tools/file_analyzer.py +7 -8
  239. jarvis/jarvis_tools/meta_agent.py +287 -0
  240. jarvis/jarvis_tools/methodology.py +5 -3
  241. jarvis/jarvis_tools/read_code.py +305 -1438
  242. jarvis/jarvis_tools/read_symbols.py +50 -17
  243. jarvis/jarvis_tools/read_webpage.py +19 -18
  244. jarvis/jarvis_tools/registry.py +435 -156
  245. jarvis/jarvis_tools/retrieve_memory.py +16 -11
  246. jarvis/jarvis_tools/save_memory.py +8 -6
  247. jarvis/jarvis_tools/search_web.py +31 -31
  248. jarvis/jarvis_tools/sub_agent.py +32 -28
  249. jarvis/jarvis_tools/sub_code_agent.py +44 -60
  250. jarvis/jarvis_tools/task_list_manager.py +1811 -0
  251. jarvis/jarvis_tools/virtual_tty.py +29 -19
  252. jarvis/jarvis_utils/__init__.py +4 -0
  253. jarvis/jarvis_utils/builtin_replace_map.py +2 -1
  254. jarvis/jarvis_utils/clipboard.py +9 -8
  255. jarvis/jarvis_utils/collections.py +331 -0
  256. jarvis/jarvis_utils/config.py +699 -194
  257. jarvis/jarvis_utils/dialogue_recorder.py +294 -0
  258. jarvis/jarvis_utils/embedding.py +6 -3
  259. jarvis/jarvis_utils/file_processors.py +7 -1
  260. jarvis/jarvis_utils/fzf.py +9 -3
  261. jarvis/jarvis_utils/git_utils.py +71 -42
  262. jarvis/jarvis_utils/globals.py +116 -32
  263. jarvis/jarvis_utils/http.py +6 -2
  264. jarvis/jarvis_utils/input.py +318 -83
  265. jarvis/jarvis_utils/jsonnet_compat.py +119 -104
  266. jarvis/jarvis_utils/methodology.py +37 -28
  267. jarvis/jarvis_utils/output.py +201 -44
  268. jarvis/jarvis_utils/utils.py +986 -628
  269. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
  270. jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
  271. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
  272. jarvis/jarvis_tools/generate_new_tool.py +0 -205
  273. jarvis/jarvis_tools/lsp_client.py +0 -1552
  274. jarvis/jarvis_tools/rewrite_file.py +0 -105
  275. jarvis_ai_assistant-0.7.16.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,134 @@
1
+ # -*- coding: utf-8 -*-
2
+ """库替换器的输出写入模块。"""
3
+
4
+ import json
5
+ import time
6
+ from pathlib import Path
7
+ from typing import Any, Dict, List, Set, Tuple
8
+
9
+
10
+ def write_output_symbols(
11
+ all_records: List[Dict[str, Any]],
12
+ pruned_funcs: Set[int],
13
+ selected_roots: List[Tuple[int, Dict[str, Any]]],
14
+ out_symbols_path: Path,
15
+ out_symbols_prune_path: Path,
16
+ ) -> List[Dict[str, Any]]:
17
+ """写出新符号表,返回替代映射列表"""
18
+ now_ts = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime())
19
+ kept_ids: Set[int] = set()
20
+ for rec in all_records:
21
+ rec_id = rec.get("id")
22
+ if rec_id is None:
23
+ continue
24
+ fid = int(rec_id)
25
+ cat = rec.get("category") or ""
26
+ if cat == "function":
27
+ if fid in pruned_funcs:
28
+ continue
29
+ kept_ids.add(fid)
30
+ else:
31
+ kept_ids.add(fid)
32
+
33
+ sel_root_ids = set(fid for fid, _ in selected_roots)
34
+ replacements: List[Dict[str, Any]] = []
35
+
36
+ with (
37
+ open(out_symbols_path, "w", encoding="utf-8") as fo,
38
+ open(out_symbols_prune_path, "w", encoding="utf-8") as fo2,
39
+ ):
40
+ for rec in all_records:
41
+ rec_id = rec.get("id")
42
+ if rec_id is None:
43
+ continue
44
+ fid = int(rec_id)
45
+ if fid not in kept_ids:
46
+ continue
47
+
48
+ rec_out = dict(rec)
49
+ if (rec.get("category") or "") == "function" and fid in sel_root_ids:
50
+ # 以库级替代为语义:不要求具体 API;将根 ref 设置为库占位符(支持多库组合)
51
+ conf = 0.0
52
+ api = ""
53
+ apis = None
54
+ libraries_out: List[str] = []
55
+ notes_out: str = ""
56
+ lib_single: str = ""
57
+ is_entry = False
58
+ for rf, rres in selected_roots:
59
+ if rf == fid:
60
+ api = str(rres.get("api") or rres.get("function") or "")
61
+ apis = rres.get("apis")
62
+ libs_val = rres.get("libraries")
63
+ if isinstance(libs_val, list):
64
+ libraries_out = [str(x) for x in libs_val if str(x)]
65
+ lib_single = str(rres.get("library") or "").strip()
66
+ try:
67
+ conf = float(rres.get("confidence") or 0.0)
68
+ except Exception:
69
+ conf = 0.0
70
+ notes_val = rres.get("notes")
71
+ if isinstance(notes_val, str):
72
+ notes_out = notes_val
73
+ is_entry = bool(rres.get("is_entry_function", False))
74
+ break
75
+ # 入口函数保护:不修改 ref 字段(保留原值,需要转译),但保留替代信息供转译参考
76
+ if not is_entry:
77
+ # 非入口函数:修改 ref 为库占位符
78
+ if libraries_out:
79
+ lib_markers = [f"lib::{lb}" for lb in libraries_out]
80
+ elif lib_single:
81
+ lib_markers = [f"lib::{lib_single}"]
82
+ else:
83
+ lib_markers = []
84
+ rec_out["ref"] = lib_markers
85
+ # 入口函数:保持 ref 不变(不修改),但后续仍会保存 lib_replacement 元数据
86
+ try:
87
+ rec_out["updated_at"] = now_ts
88
+ except Exception:
89
+ pass
90
+ # 保存库替代元数据到符号表,供后续转译阶段作为上下文使用
91
+ try:
92
+ meta_apis = (
93
+ apis if isinstance(apis, list) else ([api] if api else [])
94
+ )
95
+ lib_primary = libraries_out[0] if libraries_out else lib_single
96
+ rec_out["lib_replacement"] = {
97
+ "libraries": libraries_out,
98
+ "library": lib_primary or "",
99
+ "apis": meta_apis,
100
+ "api": api,
101
+ "confidence": float(conf)
102
+ if isinstance(conf, (int, float))
103
+ else 0.0,
104
+ "notes": notes_out,
105
+ "mode": "llm",
106
+ "is_entry_function": is_entry,
107
+ "updated_at": now_ts,
108
+ }
109
+ except Exception:
110
+ # 忽略写入元数据失败,不阻塞主流程
111
+ pass
112
+ rep_obj: Dict[str, Any] = {
113
+ "id": fid,
114
+ "name": rec.get("name") or "",
115
+ "qualified_name": rec.get("qualified_name") or "",
116
+ "library": (libraries_out[0] if libraries_out else lib_single),
117
+ "libraries": libraries_out,
118
+ "function": api,
119
+ "confidence": conf,
120
+ "mode": "llm",
121
+ "is_entry_function": is_entry,
122
+ }
123
+ if isinstance(apis, list):
124
+ rep_obj["apis"] = apis
125
+ if notes_out:
126
+ rep_obj["notes"] = notes_out
127
+ replacements.append(rep_obj)
128
+
129
+ line = json.dumps(rec_out, ensure_ascii=False) + "\n"
130
+ fo.write(line)
131
+ fo2.write(line)
132
+ # 不覆写 symbols.jsonl(保留原始扫描/整理结果作为基线)
133
+
134
+ return replacements
@@ -0,0 +1,124 @@
1
+ # -*- coding: utf-8 -*-
2
+ """库替换器的提示词构建模块。"""
3
+
4
+ from typing import Any
5
+ from typing import Dict
6
+ from typing import List
7
+ from typing import Set
8
+
9
+ from jarvis.jarvis_c2rust.constants import MAX_CHILD_SAMPLES
10
+ from jarvis.jarvis_c2rust.constants import MAX_DOT_EDGES
11
+ from jarvis.jarvis_c2rust.constants import MAX_SUBTREE_EDGES
12
+ from jarvis.jarvis_c2rust.constants import MAX_SUBTREE_NODES_META
13
+ from jarvis.jarvis_c2rust.constants import SUBTREE_SOURCE_SNIPPET_MAX_LINES
14
+ from jarvis.jarvis_c2rust.library_replacer_utils import read_source_snippet
15
+
16
+
17
+ def build_subtree_prompt(
18
+ fid: int,
19
+ desc: Set[int],
20
+ by_id: Dict[int, Dict[str, Any]],
21
+ adj_func: Dict[int, List[int]],
22
+ disabled_display: str,
23
+ additional_notes: str = "",
24
+ ) -> str:
25
+ """构建子树评估提示词"""
26
+ root_rec = by_id.get(fid, {})
27
+ root_name = root_rec.get("qualified_name") or root_rec.get("name") or f"sym_{fid}"
28
+ root_sig = root_rec.get("signature") or ""
29
+ root_lang = root_rec.get("language") or ""
30
+ root_src = read_source_snippet(root_rec)
31
+
32
+ # 子树摘要(限制长度,避免超长)
33
+ nodes_meta: List[str] = []
34
+ for nid in sorted(desc):
35
+ r = by_id.get(nid, {})
36
+ nm = r.get("qualified_name") or r.get("name") or f"sym_{nid}"
37
+ sg = r.get("signature") or ""
38
+ if sg and sg != nm:
39
+ nodes_meta.append(f"- {nm} | {sg}")
40
+ else:
41
+ nodes_meta.append(f"- {nm}")
42
+ if len(nodes_meta) > MAX_SUBTREE_NODES_META:
43
+ nodes_meta = nodes_meta[:MAX_SUBTREE_NODES_META] + [
44
+ f"...({len(desc) - MAX_SUBTREE_NODES_META} more)"
45
+ ]
46
+
47
+ # 选取部分代表性叶子/内部节点源码(最多 MAX_SOURCE_SAMPLES 个)
48
+ samples: List[str] = []
49
+ sample_ids: List[int] = [fid]
50
+ for ch in adj_func.get(fid, [])[:MAX_CHILD_SAMPLES]:
51
+ sample_ids.append(ch)
52
+ for sid in sample_ids:
53
+ rec = by_id.get(sid, {})
54
+ nm = rec.get("qualified_name") or rec.get("name") or f"sym_{sid}"
55
+ sg = rec.get("signature") or ""
56
+ src = read_source_snippet(rec, max_lines=SUBTREE_SOURCE_SNIPPET_MAX_LINES)
57
+ samples.append(f"--- BEGIN {nm} ---\n{sg}\n{src}\n--- END {nm} ---")
58
+
59
+ # 构建依赖图(子树内的调用有向边)
60
+ def _label(nid: int) -> str:
61
+ r = by_id.get(nid, {})
62
+ return r.get("qualified_name") or r.get("name") or f"sym_{nid}"
63
+
64
+ edges_list: List[str] = []
65
+ for u in sorted(desc):
66
+ for v in adj_func.get(u, []):
67
+ if v in desc:
68
+ edges_list.append(f"{_label(u)} -> {_label(v)}")
69
+ edges_text: str
70
+ if len(edges_list) > MAX_SUBTREE_EDGES:
71
+ edges_text = "\n".join(
72
+ edges_list[:MAX_SUBTREE_EDGES]
73
+ + [f"...({len(edges_list) - MAX_SUBTREE_EDGES} more edges)"]
74
+ )
75
+ else:
76
+ edges_text = "\n".join(edges_list)
77
+
78
+ # 适度提供 DOT(边数不大时),便于大模型直观看图
79
+ dot_text = ""
80
+ if len(edges_list) <= MAX_DOT_EDGES:
81
+ dot_lines: List[str] = ["digraph subtree {", " rankdir=LR;"]
82
+ for u in sorted(desc):
83
+ for v in adj_func.get(u, []):
84
+ if v in desc:
85
+ dot_lines.append(f' "{_label(u)}" -> "{_label(v)}";')
86
+ dot_lines.append("}")
87
+ dot_text = "\n".join(dot_lines)
88
+
89
+ disabled_hint = (
90
+ f"重要约束:禁止使用以下库(若这些库为唯一可行选项则判定为不可替代):{disabled_display}\n"
91
+ if disabled_display
92
+ else ""
93
+ )
94
+
95
+ return (
96
+ "请评估以下 C/C++ 函数子树是否可以由一个或多个成熟的 Rust 库整体替代(语义等价或更强)。"
97
+ "允许库内多个 API 协同,允许多个库组合;如果必须依赖尚不成熟/冷门库或非 Rust 库,则判定为不可替代。"
98
+ "如果当前调用的函数无法使用 crate 直接提供的功能而需要封装或者改造,则认为不可替代。\n"
99
+ f"{disabled_hint}"
100
+ "输出格式:仅输出一个 <SUMMARY> 块,块内直接包含 JSON 对象(不需要额外的标签),字段: replaceable(bool), libraries(list[str]), confidence(float 0..1),"
101
+ "可选字段: library(str,首选主库), api(str) 或 apis(list), notes(str: 简述如何由这些库协作实现的思路)。\n\n"
102
+ f"根函数(被评估子树的根): {root_name}\n"
103
+ f"签名: {root_sig}\n"
104
+ f"语言: {root_lang}\n"
105
+ "根函数源码片段(可能截断):\n"
106
+ f"{root_src}\n\n"
107
+ f"子树规模: {len(desc)} 个函数\n"
108
+ "子树函数列表(名称|签名):\n" + "\n".join(nodes_meta) + "\n\n"
109
+ "依赖图(调用边,caller -> callee):\n"
110
+ f"{edges_text}\n\n"
111
+ + (
112
+ f"DOT 表示(边数较少时提供):\n```dot\n{dot_text}\n```\n\n"
113
+ if dot_text
114
+ else ""
115
+ )
116
+ + "代表性源码样本(部分节点,可能截断,仅供辅助判断):\n"
117
+ + "\n".join(samples)
118
+ + "\n"
119
+ + (
120
+ f"\n【附加说明(用户自定义)】\n{additional_notes}\n"
121
+ if additional_notes
122
+ else ""
123
+ )
124
+ )
@@ -0,0 +1,188 @@
1
+ # -*- coding: utf-8 -*-
2
+ """库替换器的工具函数。"""
3
+
4
+ import json
5
+ import os
6
+ import re
7
+ from pathlib import Path
8
+ from typing import List
9
+ from typing import Optional
10
+
11
+ from jarvis.jarvis_c2rust.constants import CONFIG_JSON
12
+ from jarvis.jarvis_c2rust.constants import DEFAULT_MAPPING_OUTPUT
13
+ from jarvis.jarvis_c2rust.constants import DEFAULT_SOURCE_SNIPPET_MAX_LINES
14
+ from jarvis.jarvis_c2rust.constants import DEFAULT_SYMBOLS_OUTPUT
15
+ from jarvis.jarvis_c2rust.constants import ORDER_ALIAS_OUTPUT
16
+ from jarvis.jarvis_c2rust.constants import ORDER_PRUNE_OUTPUT
17
+ from jarvis.jarvis_c2rust.constants import SYMBOLS_PRUNE_OUTPUT
18
+
19
+
20
+ def resolve_symbols_jsonl_path(hint: Path) -> Path:
21
+ """解析symbols.jsonl路径"""
22
+ p = Path(hint)
23
+ if p.is_file() and p.suffix.lower() == ".jsonl":
24
+ return p
25
+ if p.is_dir():
26
+ return p / ".jarvis" / "c2rust" / "symbols.jsonl"
27
+ return Path(".") / ".jarvis" / "c2rust" / "symbols.jsonl"
28
+
29
+
30
+ def setup_output_paths(
31
+ data_dir: Path,
32
+ out_symbols_path: Optional[Path],
33
+ out_mapping_path: Optional[Path],
34
+ ) -> tuple[Path, Path, Path, Path, Path]:
35
+ """设置输出路径,返回(符号表路径, 映射路径, 兼容符号表路径, 顺序路径, 别名顺序路径)"""
36
+ if out_symbols_path is None:
37
+ out_symbols_path = data_dir / DEFAULT_SYMBOLS_OUTPUT
38
+ else:
39
+ out_symbols_path = Path(out_symbols_path)
40
+ if out_mapping_path is None:
41
+ out_mapping_path = data_dir / DEFAULT_MAPPING_OUTPUT
42
+ else:
43
+ out_mapping_path = Path(out_mapping_path)
44
+
45
+ # 兼容输出
46
+ out_symbols_prune_path = data_dir / SYMBOLS_PRUNE_OUTPUT
47
+ order_prune_path = data_dir / ORDER_PRUNE_OUTPUT
48
+ alias_order_path = data_dir / ORDER_ALIAS_OUTPUT
49
+
50
+ return (
51
+ out_symbols_path,
52
+ out_mapping_path,
53
+ out_symbols_prune_path,
54
+ order_prune_path,
55
+ alias_order_path,
56
+ )
57
+
58
+
59
+ def read_source_snippet(
60
+ rec: dict, max_lines: int = DEFAULT_SOURCE_SNIPPET_MAX_LINES
61
+ ) -> str:
62
+ """读取源码片段"""
63
+ path = rec.get("file") or ""
64
+ try:
65
+ if not path:
66
+ return ""
67
+ p = Path(path)
68
+ if not p.exists():
69
+ return ""
70
+ sl = int(rec.get("start_line") or 1)
71
+ el = int(rec.get("end_line") or sl)
72
+ if el < sl:
73
+ el = sl
74
+ lines = p.read_text(encoding="utf-8", errors="replace").splitlines()
75
+ start_idx = max(sl - 1, 0)
76
+ end_idx = min(el, len(lines))
77
+ snippet_lines = lines[start_idx:end_idx]
78
+ if len(snippet_lines) > max_lines:
79
+ snippet_lines = snippet_lines[:max_lines]
80
+ return "\n".join(snippet_lines)
81
+ except Exception:
82
+ return ""
83
+
84
+
85
+ def normalize_disabled_libraries(
86
+ disabled_libraries: Optional[List[str]],
87
+ ) -> tuple[List[str], str]:
88
+ """规范化禁用库列表,返回(规范化列表, 显示字符串)"""
89
+ disabled_norm: List[str] = []
90
+ disabled_display: str = ""
91
+ if isinstance(disabled_libraries, list):
92
+ disabled_norm = [
93
+ str(x).strip().lower() for x in disabled_libraries if str(x).strip()
94
+ ]
95
+ disabled_display = ", ".join(
96
+ [str(x).strip() for x in disabled_libraries if str(x).strip()]
97
+ )
98
+ return disabled_norm, disabled_display
99
+
100
+
101
+ def load_additional_notes(data_dir: Path) -> str:
102
+ """从配置文件加载附加说明"""
103
+ try:
104
+ config_path = data_dir / CONFIG_JSON
105
+ if config_path.exists():
106
+ with config_path.open("r", encoding="utf-8") as f:
107
+ config = json.load(f)
108
+ if isinstance(config, dict):
109
+ return str(config.get("additional_notes", "") or "").strip()
110
+ except Exception:
111
+ pass
112
+ return ""
113
+
114
+
115
+ def normalize_list(items: Optional[List[str]]) -> List[str]:
116
+ """规范化列表,去重并排序"""
117
+ if not isinstance(items, list):
118
+ return []
119
+ vals: List[str] = []
120
+ for x in items:
121
+ try:
122
+ s = str(x).strip()
123
+ except Exception:
124
+ continue
125
+ if s:
126
+ vals.append(s)
127
+ # 去重并排序
128
+ try:
129
+ vals = sorted(set(vals))
130
+ except Exception:
131
+ # 如果排序失败,至少去重(保留顺序)
132
+ vals = list(dict.fromkeys(vals))
133
+ return vals
134
+
135
+
136
+ def normalize_list_lower(items: Optional[List[str]]) -> List[str]:
137
+ """规范化列表并转为小写(先转小写,再去重并排序)"""
138
+ if not isinstance(items, list):
139
+ return []
140
+ # 先转小写,然后规范化
141
+ lower_items = []
142
+ for x in items:
143
+ try:
144
+ s = str(x).strip().lower()
145
+ except Exception:
146
+ continue
147
+ if s:
148
+ lower_items.append(s)
149
+ # 去重并排序
150
+ try:
151
+ return sorted(set(lower_items))
152
+ except Exception:
153
+ # 如果排序失败,至少去重(保留顺序)
154
+ return list(dict.fromkeys(lower_items))
155
+
156
+
157
+ def is_entry_function(rec_meta: dict) -> bool:
158
+ """判断是否为入口函数"""
159
+ nm = str(rec_meta.get("name") or "")
160
+ qn = str(rec_meta.get("qualified_name") or "")
161
+ # Configurable entry detection (avoid hard-coding 'main'):
162
+ # Honor env vars: c2rust_delay_entry_symbols / c2rust_delay_entries / C2RUST_DELAY_ENTRIES
163
+ entries_env = (
164
+ os.environ.get("c2rust_delay_entry_symbols")
165
+ or os.environ.get("c2rust_delay_entries")
166
+ or os.environ.get("C2RUST_DELAY_ENTRIES")
167
+ or ""
168
+ )
169
+ entries_set = set()
170
+ if entries_env:
171
+ try:
172
+ parts = re.split(r"[,\s;]+", entries_env.strip())
173
+ except Exception:
174
+ parts = [p.strip() for p in entries_env.replace(";", ",").split(",")]
175
+ entries_set = {p.strip().lower() for p in parts if p and p.strip()}
176
+ if entries_set:
177
+ is_entry = (
178
+ (nm.lower() in entries_set)
179
+ or (qn.lower() in entries_set)
180
+ or any(qn.lower().endswith(f"::{e}") for e in entries_set)
181
+ )
182
+ else:
183
+ is_entry = (
184
+ (nm.lower() == "main")
185
+ or (qn.lower() == "main")
186
+ or qn.lower().endswith("::main")
187
+ )
188
+ return is_entry