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
jarvis/jarvis_c2rust/utils.py
CHANGED
|
@@ -2,18 +2,28 @@
|
|
|
2
2
|
"""
|
|
3
3
|
C2Rust 转译器工具函数
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from __future__ import annotations
|
|
6
7
|
|
|
7
8
|
import json
|
|
8
9
|
import re
|
|
10
|
+
import subprocess
|
|
9
11
|
from pathlib import Path
|
|
10
|
-
from typing import Any
|
|
12
|
+
from typing import Any
|
|
13
|
+
from typing import Callable
|
|
14
|
+
from typing import Dict
|
|
15
|
+
from typing import List
|
|
16
|
+
from typing import Optional
|
|
17
|
+
from typing import Tuple
|
|
11
18
|
|
|
12
|
-
import
|
|
19
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
13
20
|
|
|
14
|
-
from jarvis.jarvis_c2rust.constants import C2RUST_DIRNAME
|
|
21
|
+
from jarvis.jarvis_c2rust.constants import C2RUST_DIRNAME
|
|
22
|
+
from jarvis.jarvis_c2rust.constants import ORDER_JSONL
|
|
15
23
|
from jarvis.jarvis_c2rust.scanner import compute_translation_order_jsonl
|
|
16
|
-
from jarvis.jarvis_utils.
|
|
24
|
+
from jarvis.jarvis_utils.config import get_max_input_token_count
|
|
25
|
+
from jarvis.jarvis_utils.git_utils import get_diff
|
|
26
|
+
from jarvis.jarvis_utils.git_utils import get_diff_file_list
|
|
17
27
|
from jarvis.jarvis_utils.jsonnet_compat import loads as json5_loads
|
|
18
28
|
|
|
19
29
|
|
|
@@ -21,7 +31,7 @@ def ensure_order_file(project_root: Path) -> Path:
|
|
|
21
31
|
"""确保 translation_order.jsonl 存在且包含有效步骤;仅基于 symbols.jsonl 生成,不使用任何回退。"""
|
|
22
32
|
data_dir = project_root / C2RUST_DIRNAME
|
|
23
33
|
order_path = data_dir / ORDER_JSONL
|
|
24
|
-
|
|
34
|
+
PrettyOutput.auto_print(f"📋 [c2rust-transpiler][order] 目标顺序文件: {order_path}")
|
|
25
35
|
|
|
26
36
|
def _has_steps(p: Path) -> bool:
|
|
27
37
|
try:
|
|
@@ -31,13 +41,19 @@ def ensure_order_file(project_root: Path) -> Path:
|
|
|
31
41
|
return False
|
|
32
42
|
|
|
33
43
|
# 已存在则校验是否有步骤
|
|
34
|
-
|
|
44
|
+
PrettyOutput.auto_print(
|
|
45
|
+
f"🔍 [c2rust-transpiler][order] 检查现有顺序文件有效性: {order_path}"
|
|
46
|
+
)
|
|
35
47
|
if order_path.exists():
|
|
36
48
|
if _has_steps(order_path):
|
|
37
|
-
|
|
49
|
+
PrettyOutput.auto_print(
|
|
50
|
+
f"✅ [c2rust-transpiler][order] 现有顺序文件有效,将使用 {order_path}"
|
|
51
|
+
)
|
|
38
52
|
return order_path
|
|
39
53
|
# 为空或不可读:基于标准路径重新计算(仅 symbols.jsonl)
|
|
40
|
-
|
|
54
|
+
PrettyOutput.auto_print(
|
|
55
|
+
"⚠️ [c2rust-transpiler][order] 现有顺序文件为空/无效,正基于 symbols.jsonl 重新计算"
|
|
56
|
+
)
|
|
41
57
|
try:
|
|
42
58
|
compute_translation_order_jsonl(data_dir, out_path=order_path)
|
|
43
59
|
except Exception as e:
|
|
@@ -50,13 +66,17 @@ def ensure_order_file(project_root: Path) -> Path:
|
|
|
50
66
|
except Exception as e:
|
|
51
67
|
raise RuntimeError(f"计算翻译顺序失败: {e}")
|
|
52
68
|
|
|
53
|
-
|
|
69
|
+
PrettyOutput.auto_print(
|
|
70
|
+
f"📋 [c2rust-transpiler][order] 已生成顺序文件: {order_path} (exists={order_path.exists()})"
|
|
71
|
+
)
|
|
54
72
|
if not order_path.exists():
|
|
55
73
|
raise FileNotFoundError(f"计算后未找到 translation_order.jsonl: {order_path}")
|
|
56
74
|
|
|
57
75
|
# 最终校验:若仍无有效步骤,直接报错并提示先执行 scan 或检查 symbols.jsonl
|
|
58
76
|
if not _has_steps(order_path):
|
|
59
|
-
raise RuntimeError(
|
|
77
|
+
raise RuntimeError(
|
|
78
|
+
"translation_order.jsonl 无有效步骤。请先执行 'jarvis-c2rust scan' 生成 symbols.jsonl 并重试。"
|
|
79
|
+
)
|
|
60
80
|
|
|
61
81
|
return order_path
|
|
62
82
|
|
|
@@ -84,7 +104,11 @@ def iter_order_steps(order_jsonl: Path) -> List[List[int]]:
|
|
|
84
104
|
if isinstance(ids, list) and ids:
|
|
85
105
|
# 新格式:仅支持 ids
|
|
86
106
|
try:
|
|
87
|
-
ids_int = [
|
|
107
|
+
ids_int = [
|
|
108
|
+
int(x)
|
|
109
|
+
for x in ids
|
|
110
|
+
if isinstance(x, (int, str)) and str(x).strip()
|
|
111
|
+
]
|
|
88
112
|
except Exception:
|
|
89
113
|
ids_int = []
|
|
90
114
|
if ids_int:
|
|
@@ -138,13 +162,17 @@ def write_json(path: Path, obj: Any) -> None:
|
|
|
138
162
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
139
163
|
# 使用临时文件确保原子性
|
|
140
164
|
temp_path = path.with_suffix(path.suffix + ".tmp")
|
|
141
|
-
temp_path.write_text(
|
|
165
|
+
temp_path.write_text(
|
|
166
|
+
json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
167
|
+
)
|
|
142
168
|
# 原子性重命名
|
|
143
169
|
temp_path.replace(path)
|
|
144
170
|
except Exception:
|
|
145
171
|
# 如果原子写入失败,回退到直接写入
|
|
146
172
|
try:
|
|
147
|
-
path.write_text(
|
|
173
|
+
path.write_text(
|
|
174
|
+
json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
175
|
+
)
|
|
148
176
|
except Exception:
|
|
149
177
|
pass
|
|
150
178
|
|
|
@@ -185,10 +213,10 @@ def extract_json_from_summary(text: str) -> Tuple[Dict[str, Any], Optional[str]]
|
|
|
185
213
|
def detect_test_deletion(log_prefix: str = "[c2rust]") -> Optional[Dict[str, Any]]:
|
|
186
214
|
"""
|
|
187
215
|
检测是否错误删除了 #[test] 或 #[cfg(test)]。
|
|
188
|
-
|
|
216
|
+
|
|
189
217
|
参数:
|
|
190
218
|
log_prefix: 日志前缀(如 "[c2rust-transpiler]" 或 "[c2rust-optimizer]")
|
|
191
|
-
|
|
219
|
+
|
|
192
220
|
返回:
|
|
193
221
|
如果检测到删除,返回包含 'diff', 'files', 'deleted_tests' 的字典;否则返回 None
|
|
194
222
|
"""
|
|
@@ -196,90 +224,98 @@ def detect_test_deletion(log_prefix: str = "[c2rust]") -> Optional[Dict[str, Any
|
|
|
196
224
|
diff = get_diff()
|
|
197
225
|
if not diff:
|
|
198
226
|
return None
|
|
199
|
-
|
|
227
|
+
|
|
200
228
|
# 检查 diff 中是否包含删除的 #[test] 或 #[cfg(test)]
|
|
201
229
|
test_patterns = [
|
|
202
|
-
r
|
|
203
|
-
r
|
|
204
|
-
r
|
|
230
|
+
r"^-\s*#\[test\]",
|
|
231
|
+
r"^-\s*#\[cfg\(test\)\]",
|
|
232
|
+
r"^-\s*#\[cfg\(test\)",
|
|
205
233
|
]
|
|
206
|
-
|
|
234
|
+
|
|
207
235
|
deleted_tests = []
|
|
208
|
-
lines = diff.split(
|
|
236
|
+
lines = diff.split("\n")
|
|
209
237
|
current_file = None
|
|
210
|
-
|
|
238
|
+
|
|
211
239
|
for i, line in enumerate(lines):
|
|
212
240
|
# 检测文件路径
|
|
213
|
-
if
|
|
241
|
+
if (
|
|
242
|
+
line.startswith("diff --git")
|
|
243
|
+
or line.startswith("---")
|
|
244
|
+
or line.startswith("+++")
|
|
245
|
+
):
|
|
214
246
|
# 尝试从 diff 行中提取文件名
|
|
215
|
-
if line.startswith(
|
|
247
|
+
if line.startswith("---"):
|
|
216
248
|
parts = line.split()
|
|
217
249
|
if len(parts) > 1:
|
|
218
|
-
current_file = parts[1].lstrip(
|
|
219
|
-
elif line.startswith(
|
|
250
|
+
current_file = parts[1].lstrip("a/").lstrip("b/")
|
|
251
|
+
elif line.startswith("+++"):
|
|
220
252
|
parts = line.split()
|
|
221
253
|
if len(parts) > 1:
|
|
222
|
-
current_file = parts[1].lstrip(
|
|
254
|
+
current_file = parts[1].lstrip("a/").lstrip("b/")
|
|
223
255
|
continue
|
|
224
|
-
|
|
256
|
+
|
|
225
257
|
# 检查是否匹配删除的测试标记
|
|
226
258
|
for pattern in test_patterns:
|
|
227
259
|
if re.search(pattern, line, re.IGNORECASE):
|
|
228
260
|
# 检查上下文,确认是删除而不是修改
|
|
229
|
-
if i > 0 and lines[i-1].startswith(
|
|
261
|
+
if i > 0 and lines[i - 1].startswith("-"):
|
|
230
262
|
# 可能是删除的一部分
|
|
231
|
-
deleted_tests.append(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
263
|
+
deleted_tests.append(
|
|
264
|
+
{
|
|
265
|
+
"file": current_file or "unknown",
|
|
266
|
+
"line": line,
|
|
267
|
+
"line_number": i + 1,
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
elif not (i < len(lines) - 1 and lines[i + 1].startswith("+")):
|
|
237
271
|
# 下一行不是添加,说明是删除
|
|
238
|
-
deleted_tests.append(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
272
|
+
deleted_tests.append(
|
|
273
|
+
{
|
|
274
|
+
"file": current_file or "unknown",
|
|
275
|
+
"line": line,
|
|
276
|
+
"line_number": i + 1,
|
|
277
|
+
}
|
|
278
|
+
)
|
|
243
279
|
break
|
|
244
|
-
|
|
280
|
+
|
|
245
281
|
if deleted_tests:
|
|
246
282
|
modified_files = get_diff_file_list()
|
|
247
283
|
return {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
284
|
+
"diff": diff,
|
|
285
|
+
"files": modified_files,
|
|
286
|
+
"deleted_tests": deleted_tests,
|
|
251
287
|
}
|
|
252
288
|
return None
|
|
253
289
|
except Exception as e:
|
|
254
|
-
|
|
290
|
+
PrettyOutput.auto_print(
|
|
291
|
+
f"⚠️ {log_prefix}[test-detection] 检测测试删除时发生异常: {e}"
|
|
292
|
+
)
|
|
255
293
|
return None
|
|
256
294
|
|
|
257
295
|
|
|
258
296
|
def ask_llm_about_test_deletion(
|
|
259
|
-
detection_result: Dict[str, Any],
|
|
260
|
-
agent: Any,
|
|
261
|
-
log_prefix: str = "[c2rust]"
|
|
297
|
+
detection_result: Dict[str, Any], agent: Any, log_prefix: str = "[c2rust]"
|
|
262
298
|
) -> bool:
|
|
263
299
|
"""
|
|
264
300
|
询问 LLM 是否错误删除了测试代码。
|
|
265
|
-
|
|
301
|
+
|
|
266
302
|
参数:
|
|
267
303
|
detection_result: 检测结果字典,包含 'diff', 'files', 'deleted_tests'
|
|
268
304
|
agent: 代码生成或修复的 agent 实例,使用其 model 进行询问
|
|
269
305
|
log_prefix: 日志前缀(如 "[c2rust-transpiler]" 或 "[c2rust-optimizer]")
|
|
270
|
-
|
|
306
|
+
|
|
271
307
|
返回:
|
|
272
308
|
bool: 如果 LLM 认为删除不合理返回 True(需要回退),否则返回 False
|
|
273
309
|
"""
|
|
274
|
-
if not agent or not hasattr(agent,
|
|
310
|
+
if not agent or not hasattr(agent, "model"):
|
|
275
311
|
# 如果没有 agent 或 agent 没有 model,默认认为有问题(保守策略)
|
|
276
312
|
return True
|
|
277
|
-
|
|
313
|
+
|
|
278
314
|
try:
|
|
279
|
-
deleted_tests = detection_result.get(
|
|
280
|
-
diff = detection_result.get(
|
|
281
|
-
files = detection_result.get(
|
|
282
|
-
|
|
315
|
+
deleted_tests = detection_result.get("deleted_tests", [])
|
|
316
|
+
diff = detection_result.get("diff", "")
|
|
317
|
+
files = detection_result.get("files", [])
|
|
318
|
+
|
|
283
319
|
# 构建预览(限制长度)
|
|
284
320
|
preview_lines = []
|
|
285
321
|
preview_lines.append("检测到可能错误删除了测试代码标记:")
|
|
@@ -289,17 +325,17 @@ def ask_llm_about_test_deletion(
|
|
|
289
325
|
preview_lines.append(f" 行: {item.get('line', '')}")
|
|
290
326
|
if len(deleted_tests) > 10:
|
|
291
327
|
preview_lines.append(f"... 还有 {len(deleted_tests) - 10} 个删除的测试标记")
|
|
292
|
-
|
|
328
|
+
|
|
293
329
|
# 限制 diff 长度
|
|
294
330
|
diff_preview = diff[:5000] if len(diff) > 5000 else diff
|
|
295
331
|
if len(diff) > 5000:
|
|
296
332
|
diff_preview += "\n... (diff 内容过长,已截断)"
|
|
297
|
-
|
|
333
|
+
|
|
298
334
|
prompt = f"""检测到代码变更中可能错误删除了测试代码标记(#[test] 或 #[cfg(test)]),请判断是否合理:
|
|
299
335
|
|
|
300
336
|
删除的测试标记统计:
|
|
301
337
|
- 删除的测试标记数量: {len(deleted_tests)}
|
|
302
|
-
- 涉及的文件: {
|
|
338
|
+
- 涉及的文件: {", ".join(files[:5])}{" ..." if len(files) > 5 else ""}
|
|
303
339
|
|
|
304
340
|
删除的测试标记详情:
|
|
305
341
|
{chr(10).join(preview_lines)}
|
|
@@ -318,25 +354,29 @@ def ask_llm_about_test_deletion(
|
|
|
318
354
|
|
|
319
355
|
请严格按照协议格式回答,不要添加其他内容。
|
|
320
356
|
"""
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
357
|
+
|
|
358
|
+
PrettyOutput.auto_print(
|
|
359
|
+
f"🤔 {log_prefix}[test-detection] 正在询问 LLM 判断测试代码删除是否合理..."
|
|
360
|
+
)
|
|
361
|
+
response = agent.model.chat_until_success(prompt)
|
|
324
362
|
response_str = str(response or "")
|
|
325
|
-
|
|
363
|
+
|
|
326
364
|
# 使用确定的协议标记解析回答
|
|
327
365
|
if "<!!!NO!!!>" in response_str:
|
|
328
|
-
|
|
366
|
+
PrettyOutput.auto_print("❌ LLM 确认:测试代码删除不合理,需要回退")
|
|
329
367
|
return True # 需要回退
|
|
330
368
|
elif "<!!!YES!!!>" in response_str:
|
|
331
|
-
|
|
369
|
+
PrettyOutput.auto_print("✅ LLM 确认:测试代码删除合理")
|
|
332
370
|
return False # 不需要回退
|
|
333
371
|
else:
|
|
334
372
|
# 如果无法找到协议标记,默认认为有问题(保守策略)
|
|
335
|
-
|
|
373
|
+
PrettyOutput.auto_print(
|
|
374
|
+
f"⚠️ 无法找到协议标记,默认认为有问题。回答内容: {response_str[:200]}"
|
|
375
|
+
)
|
|
336
376
|
return True # 保守策略:默认回退
|
|
337
377
|
except Exception as e:
|
|
338
378
|
# 如果询问失败,默认认为有问题(保守策略)
|
|
339
|
-
|
|
379
|
+
PrettyOutput.auto_print(f"⚠️ 询问 LLM 失败: {str(e)},默认认为有问题")
|
|
340
380
|
return True # 保守策略:默认回退
|
|
341
381
|
|
|
342
382
|
|
|
@@ -344,42 +384,192 @@ def check_and_handle_test_deletion(
|
|
|
344
384
|
before_commit: Optional[str],
|
|
345
385
|
agent: Any,
|
|
346
386
|
reset_to_commit_fn: Callable[[str], bool],
|
|
347
|
-
log_prefix: str = "[c2rust]"
|
|
387
|
+
log_prefix: str = "[c2rust]",
|
|
348
388
|
) -> bool:
|
|
349
389
|
"""
|
|
350
390
|
检测并处理测试代码删除。
|
|
351
|
-
|
|
391
|
+
|
|
352
392
|
参数:
|
|
353
393
|
before_commit: agent 运行前的 commit hash
|
|
354
394
|
agent: 代码生成或修复的 agent 实例,使用其 model 进行询问
|
|
355
395
|
reset_to_commit_fn: 回退到指定 commit 的函数,接受 commit hash 作为参数,返回是否成功
|
|
356
396
|
log_prefix: 日志前缀(如 "[c2rust-transpiler]" 或 "[c2rust-optimizer]")
|
|
357
|
-
|
|
397
|
+
|
|
358
398
|
返回:
|
|
359
399
|
bool: 如果检测到问题且已回退,返回 True;否则返回 False
|
|
360
400
|
"""
|
|
361
401
|
if not before_commit:
|
|
362
402
|
# 没有记录 commit,无法回退
|
|
363
403
|
return False
|
|
364
|
-
|
|
404
|
+
|
|
365
405
|
detection_result = detect_test_deletion(log_prefix)
|
|
366
406
|
if not detection_result:
|
|
367
407
|
# 没有检测到删除
|
|
368
408
|
return False
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
409
|
+
|
|
410
|
+
PrettyOutput.auto_print(
|
|
411
|
+
f"⚠️ {log_prefix}[test-detection] 检测到可能错误删除了测试代码标记"
|
|
412
|
+
)
|
|
413
|
+
|
|
372
414
|
# 询问 LLM(使用传入的 agent 的 model)
|
|
373
415
|
need_reset = ask_llm_about_test_deletion(detection_result, agent, log_prefix)
|
|
374
|
-
|
|
416
|
+
|
|
375
417
|
if need_reset:
|
|
376
|
-
|
|
418
|
+
PrettyOutput.auto_print(
|
|
419
|
+
f"❌ {log_prefix}[test-detection] LLM 确认删除不合理,正在回退到 commit: {before_commit}"
|
|
420
|
+
)
|
|
377
421
|
if reset_to_commit_fn(before_commit):
|
|
378
|
-
|
|
422
|
+
PrettyOutput.auto_print(
|
|
423
|
+
f"✅ {log_prefix}[test-detection] 已回退到之前的 commit"
|
|
424
|
+
)
|
|
379
425
|
return True
|
|
380
426
|
else:
|
|
381
|
-
|
|
427
|
+
PrettyOutput.auto_print(f"❌ {log_prefix}[test-detection] 回退失败")
|
|
382
428
|
return False
|
|
383
|
-
|
|
429
|
+
|
|
384
430
|
return False
|
|
385
431
|
|
|
432
|
+
|
|
433
|
+
def extract_files_from_git_diff(git_diff: str) -> List[str]:
|
|
434
|
+
"""
|
|
435
|
+
从 git diff 字符串中提取所有修改的文件列表。
|
|
436
|
+
|
|
437
|
+
参数:
|
|
438
|
+
git_diff: git diff 内容
|
|
439
|
+
|
|
440
|
+
返回:
|
|
441
|
+
List[str]: 修改的文件路径列表(去重)
|
|
442
|
+
"""
|
|
443
|
+
if not git_diff or not git_diff.strip():
|
|
444
|
+
return []
|
|
445
|
+
|
|
446
|
+
files = set()
|
|
447
|
+
# 匹配 "diff --git a/path b/path" 格式
|
|
448
|
+
# git diff 标准格式:diff --git a/path b/path
|
|
449
|
+
pattern = r"^diff --git a/([^\s]+) b/([^\s]+)$"
|
|
450
|
+
for line in git_diff.split("\n"):
|
|
451
|
+
match = re.match(pattern, line)
|
|
452
|
+
if match:
|
|
453
|
+
# 通常 a/path 和 b/path 相同,但处理重命名时可能不同
|
|
454
|
+
file_a = match.group(1)
|
|
455
|
+
file_b = match.group(2)
|
|
456
|
+
# 优先使用 b 路径(新路径),如果不同则都添加
|
|
457
|
+
files.add(file_b)
|
|
458
|
+
if file_a != file_b:
|
|
459
|
+
files.add(file_a)
|
|
460
|
+
|
|
461
|
+
return sorted(list(files))
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def get_modified_files_from_git(
|
|
465
|
+
base_commit: Optional[str], crate_dir: Optional[Path]
|
|
466
|
+
) -> List[str]:
|
|
467
|
+
"""
|
|
468
|
+
使用 git 命令获取修改的文件列表。
|
|
469
|
+
|
|
470
|
+
参数:
|
|
471
|
+
base_commit: 基准 commit(如果为 None,则与 HEAD 比较)
|
|
472
|
+
crate_dir: crate 根目录(如果为 None,则使用当前目录)
|
|
473
|
+
|
|
474
|
+
返回:
|
|
475
|
+
List[str]: 修改的文件路径列表
|
|
476
|
+
"""
|
|
477
|
+
if not crate_dir:
|
|
478
|
+
return []
|
|
479
|
+
|
|
480
|
+
try:
|
|
481
|
+
# 构建 git diff 命令
|
|
482
|
+
if base_commit:
|
|
483
|
+
cmd = ["git", "diff", "--name-only", base_commit]
|
|
484
|
+
else:
|
|
485
|
+
cmd = ["git", "diff", "--name-only", "HEAD"]
|
|
486
|
+
|
|
487
|
+
result = subprocess.run(
|
|
488
|
+
cmd,
|
|
489
|
+
cwd=crate_dir,
|
|
490
|
+
capture_output=True,
|
|
491
|
+
text=True,
|
|
492
|
+
check=False,
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
if result.returncode == 0:
|
|
496
|
+
files = [f.strip() for f in result.stdout.splitlines() if f.strip()]
|
|
497
|
+
return sorted(files)
|
|
498
|
+
else:
|
|
499
|
+
# 如果命令失败,返回空列表
|
|
500
|
+
return []
|
|
501
|
+
except Exception:
|
|
502
|
+
# 如果出现任何异常,返回空列表
|
|
503
|
+
return []
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def truncate_git_diff_with_context_limit(
|
|
507
|
+
git_diff: str,
|
|
508
|
+
agent: Optional[Any] = None,
|
|
509
|
+
llm_group: Optional[str] = None,
|
|
510
|
+
token_ratio: float = 0.3,
|
|
511
|
+
base_commit: Optional[str] = None,
|
|
512
|
+
crate_dir: Optional[Path] = None,
|
|
513
|
+
) -> str:
|
|
514
|
+
"""
|
|
515
|
+
限制 git diff 的长度,避免上下文过大。
|
|
516
|
+
|
|
517
|
+
参数:
|
|
518
|
+
git_diff: 原始的 git diff 内容
|
|
519
|
+
agent: 可选的 agent 实例,用于获取剩余 token 数量(更准确,考虑对话历史)
|
|
520
|
+
llm_group: 可选的 LLM 组名称,用于获取输入窗口限制(当 agent 不可用时使用)
|
|
521
|
+
token_ratio: token 使用比例(默认 0.3,即 30%)
|
|
522
|
+
base_commit: 可选的基准 commit,如果提供则使用 git 命令获取文件列表
|
|
523
|
+
crate_dir: 可选的 crate 根目录,如果提供则使用 git 命令获取文件列表
|
|
524
|
+
|
|
525
|
+
返回:
|
|
526
|
+
str: 限制长度后的 git diff(如果超出限制则截断并添加提示和文件列表)
|
|
527
|
+
"""
|
|
528
|
+
if not git_diff or not git_diff.strip():
|
|
529
|
+
return git_diff
|
|
530
|
+
|
|
531
|
+
max_diff_chars = None
|
|
532
|
+
|
|
533
|
+
# 优先尝试使用 agent 获取剩余 token(更准确,包含对话历史)
|
|
534
|
+
if agent:
|
|
535
|
+
try:
|
|
536
|
+
remaining_tokens = agent.get_remaining_token_count()
|
|
537
|
+
if remaining_tokens > 0:
|
|
538
|
+
# 使用剩余 token 的指定比例作为字符限制(1 token ≈ 4字符)
|
|
539
|
+
max_diff_chars = int(remaining_tokens * token_ratio * 4)
|
|
540
|
+
if max_diff_chars <= 0:
|
|
541
|
+
max_diff_chars = None
|
|
542
|
+
except Exception:
|
|
543
|
+
pass
|
|
544
|
+
|
|
545
|
+
# 回退方案:使用输入窗口的指定比例转换为字符数
|
|
546
|
+
if max_diff_chars is None:
|
|
547
|
+
try:
|
|
548
|
+
max_input_tokens = get_max_input_token_count(llm_group)
|
|
549
|
+
max_diff_chars = int(max_input_tokens * token_ratio * 4)
|
|
550
|
+
except Exception:
|
|
551
|
+
# 如果获取失败,使用默认值(约 10000 字符)
|
|
552
|
+
max_diff_chars = 10000
|
|
553
|
+
|
|
554
|
+
# 应用长度限制
|
|
555
|
+
if len(git_diff) > max_diff_chars:
|
|
556
|
+
# 优先使用 git 命令获取文件列表(更可靠)
|
|
557
|
+
if base_commit is not None and crate_dir:
|
|
558
|
+
modified_files = get_modified_files_from_git(base_commit, crate_dir)
|
|
559
|
+
else:
|
|
560
|
+
# 回退到从 diff 内容中提取
|
|
561
|
+
modified_files = extract_files_from_git_diff(git_diff)
|
|
562
|
+
|
|
563
|
+
truncated_diff = git_diff[:max_diff_chars] + "\n... (差异内容过长,已截断)"
|
|
564
|
+
|
|
565
|
+
# 如果有修改的文件,添加文件列表
|
|
566
|
+
if modified_files:
|
|
567
|
+
truncated_diff += "\n\n**修改的文件列表(共 {} 个文件):**\n".format(
|
|
568
|
+
len(modified_files)
|
|
569
|
+
)
|
|
570
|
+
for file_path in modified_files:
|
|
571
|
+
truncated_diff += f" - {file_path}\n"
|
|
572
|
+
|
|
573
|
+
return truncated_diff
|
|
574
|
+
|
|
575
|
+
return git_diff
|