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