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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.8.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
|