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,469 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""优化器进度管理模块。"""
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
from typing import Dict
|
|
8
|
+
from typing import List
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from typing import Set
|
|
11
|
+
from typing import cast
|
|
12
|
+
|
|
13
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
14
|
+
|
|
15
|
+
from jarvis.jarvis_c2rust.optimizer_options import OptimizeOptions
|
|
16
|
+
from jarvis.jarvis_c2rust.optimizer_utils import git_head_commit
|
|
17
|
+
from jarvis.jarvis_c2rust.optimizer_utils import git_reset_hard
|
|
18
|
+
from jarvis.jarvis_c2rust.optimizer_utils import git_toplevel
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ProgressManager:
|
|
22
|
+
"""进度管理器,负责加载、保存进度和 Git 管理。"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
crate_dir: Path,
|
|
27
|
+
options: OptimizeOptions,
|
|
28
|
+
progress_path: Path,
|
|
29
|
+
):
|
|
30
|
+
self.crate_dir = crate_dir
|
|
31
|
+
self.options = options
|
|
32
|
+
self.progress_path = progress_path
|
|
33
|
+
self.processed: Set[str] = set()
|
|
34
|
+
self.steps_completed: Set[str] = set()
|
|
35
|
+
self._step_commits: Dict[str, str] = {}
|
|
36
|
+
self._last_snapshot_commit: Optional[str] = None
|
|
37
|
+
self._agent_before_commits: Dict[str, Optional[str]] = {}
|
|
38
|
+
|
|
39
|
+
def load_or_reset_progress(self) -> None:
|
|
40
|
+
"""加载或重置进度。"""
|
|
41
|
+
if self.options.reset_progress:
|
|
42
|
+
try:
|
|
43
|
+
self.progress_path.write_text(
|
|
44
|
+
json.dumps(
|
|
45
|
+
{"processed": [], "steps_completed": []},
|
|
46
|
+
ensure_ascii=False,
|
|
47
|
+
indent=2,
|
|
48
|
+
),
|
|
49
|
+
encoding="utf-8",
|
|
50
|
+
)
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|
|
53
|
+
self.processed = set()
|
|
54
|
+
if not hasattr(self, "steps_completed"):
|
|
55
|
+
self.steps_completed = set()
|
|
56
|
+
if not hasattr(self, "_step_commits"):
|
|
57
|
+
self._step_commits = {}
|
|
58
|
+
return
|
|
59
|
+
try:
|
|
60
|
+
if self.progress_path.exists():
|
|
61
|
+
obj = json.loads(self.progress_path.read_text(encoding="utf-8"))
|
|
62
|
+
if isinstance(obj, dict):
|
|
63
|
+
arr = obj.get("processed") or []
|
|
64
|
+
if isinstance(arr, list):
|
|
65
|
+
self.processed = {str(x) for x in arr if isinstance(x, str)}
|
|
66
|
+
else:
|
|
67
|
+
self.processed = set()
|
|
68
|
+
# 加载已完成的步骤
|
|
69
|
+
steps = obj.get("steps_completed") or []
|
|
70
|
+
if isinstance(steps, list):
|
|
71
|
+
self.steps_completed = {
|
|
72
|
+
str(x) for x in steps if isinstance(x, str)
|
|
73
|
+
}
|
|
74
|
+
else:
|
|
75
|
+
self.steps_completed = set()
|
|
76
|
+
# 加载步骤的 commit id
|
|
77
|
+
step_commits = obj.get("step_commits") or {}
|
|
78
|
+
if isinstance(step_commits, dict):
|
|
79
|
+
self._step_commits = {
|
|
80
|
+
str(k): str(v)
|
|
81
|
+
for k, v in step_commits.items()
|
|
82
|
+
if isinstance(k, str) and isinstance(v, str)
|
|
83
|
+
}
|
|
84
|
+
else:
|
|
85
|
+
self._step_commits = {}
|
|
86
|
+
|
|
87
|
+
# 恢复时,reset 到最后一个步骤的 commit id
|
|
88
|
+
if self.options.resume and self._step_commits:
|
|
89
|
+
last_commit = None
|
|
90
|
+
# 按照步骤顺序找到最后一个已完成步骤的 commit
|
|
91
|
+
step_order = [
|
|
92
|
+
"clippy_elimination",
|
|
93
|
+
"unsafe_cleanup",
|
|
94
|
+
"visibility_opt",
|
|
95
|
+
"doc_opt",
|
|
96
|
+
]
|
|
97
|
+
for step in reversed(step_order):
|
|
98
|
+
if (
|
|
99
|
+
step in self.steps_completed
|
|
100
|
+
and step in self._step_commits
|
|
101
|
+
):
|
|
102
|
+
last_commit = self._step_commits[step]
|
|
103
|
+
break
|
|
104
|
+
|
|
105
|
+
if last_commit:
|
|
106
|
+
current_commit = self.get_crate_commit_hash()
|
|
107
|
+
if current_commit != last_commit:
|
|
108
|
+
PrettyOutput.auto_print(
|
|
109
|
+
f"🔧 [c2rust-optimizer][resume] 检测到代码状态不一致,正在 reset 到最后一个步骤的 commit: {last_commit}",
|
|
110
|
+
)
|
|
111
|
+
if self.reset_to_commit(last_commit):
|
|
112
|
+
PrettyOutput.auto_print(
|
|
113
|
+
f"✅ [c2rust-optimizer][resume] 已 reset 到 commit: {last_commit}",
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
PrettyOutput.auto_print(
|
|
117
|
+
"⚠️ [c2rust-optimizer][resume] reset 失败,继续使用当前代码状态",
|
|
118
|
+
)
|
|
119
|
+
else:
|
|
120
|
+
PrettyOutput.auto_print(
|
|
121
|
+
"ℹ️ [c2rust-optimizer][resume] 代码状态一致,无需 reset",
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
self.processed = set()
|
|
125
|
+
self.steps_completed = set()
|
|
126
|
+
self._step_commits = {}
|
|
127
|
+
else:
|
|
128
|
+
self.processed = set()
|
|
129
|
+
self.steps_completed = set()
|
|
130
|
+
self._step_commits = {}
|
|
131
|
+
except Exception:
|
|
132
|
+
self.processed = set()
|
|
133
|
+
self.steps_completed = set()
|
|
134
|
+
self._step_commits = {}
|
|
135
|
+
|
|
136
|
+
def get_crate_commit_hash(self) -> Optional[str]:
|
|
137
|
+
"""获取 crate 目录的当前 commit id。"""
|
|
138
|
+
try:
|
|
139
|
+
repo_root = git_toplevel(self.crate_dir)
|
|
140
|
+
if repo_root is None:
|
|
141
|
+
return None
|
|
142
|
+
return git_head_commit(repo_root)
|
|
143
|
+
except Exception:
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
def reset_to_commit(self, commit_hash: str) -> bool:
|
|
147
|
+
"""回退 crate 目录到指定的 commit。"""
|
|
148
|
+
try:
|
|
149
|
+
repo_root = git_toplevel(self.crate_dir)
|
|
150
|
+
if repo_root is None:
|
|
151
|
+
return False
|
|
152
|
+
return git_reset_hard(repo_root, commit_hash)
|
|
153
|
+
except Exception:
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
def snapshot_commit(self) -> None:
|
|
157
|
+
"""
|
|
158
|
+
在启用 git_guard 时记录当前 HEAD commit(仅记录,不提交未暂存更改)。
|
|
159
|
+
统一在仓库根目录执行 git 命令,避免子目录导致的意外。
|
|
160
|
+
"""
|
|
161
|
+
if not self.options.git_guard:
|
|
162
|
+
return
|
|
163
|
+
try:
|
|
164
|
+
repo_root = git_toplevel(self.crate_dir)
|
|
165
|
+
if repo_root is None:
|
|
166
|
+
return
|
|
167
|
+
head = git_head_commit(repo_root)
|
|
168
|
+
if head:
|
|
169
|
+
self._last_snapshot_commit = head
|
|
170
|
+
except Exception:
|
|
171
|
+
# 忽略快照失败,不阻塞流程
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
def reset_to_snapshot(self) -> bool:
|
|
175
|
+
"""
|
|
176
|
+
在启用 git_guard 且存在快照时,将工作区 reset --hard 回快照。
|
|
177
|
+
统一在仓库根目录执行 git 命令,避免子目录导致的意外。
|
|
178
|
+
返回是否成功执行 reset。
|
|
179
|
+
"""
|
|
180
|
+
if not self.options.git_guard:
|
|
181
|
+
return False
|
|
182
|
+
snap = getattr(self, "_last_snapshot_commit", None)
|
|
183
|
+
if not snap:
|
|
184
|
+
return False
|
|
185
|
+
repo_root = git_toplevel(self.crate_dir)
|
|
186
|
+
if repo_root is None:
|
|
187
|
+
return False
|
|
188
|
+
ok = git_reset_hard(repo_root, snap)
|
|
189
|
+
return ok
|
|
190
|
+
|
|
191
|
+
def save_progress_for_batch(self, files: List[Path]) -> None:
|
|
192
|
+
"""保存文件处理进度。"""
|
|
193
|
+
try:
|
|
194
|
+
rels = []
|
|
195
|
+
for p in files:
|
|
196
|
+
try:
|
|
197
|
+
rel = p.resolve().relative_to(self.crate_dir.resolve()).as_posix()
|
|
198
|
+
except Exception:
|
|
199
|
+
rel = str(p)
|
|
200
|
+
rels.append(rel)
|
|
201
|
+
self.processed.update(rels)
|
|
202
|
+
|
|
203
|
+
# 获取当前 commit id 并记录
|
|
204
|
+
current_commit = self.get_crate_commit_hash()
|
|
205
|
+
|
|
206
|
+
data: Dict[str, Any] = {
|
|
207
|
+
"processed": sorted(self.processed),
|
|
208
|
+
"steps_completed": sorted(self.steps_completed),
|
|
209
|
+
}
|
|
210
|
+
if current_commit:
|
|
211
|
+
data["last_commit"] = current_commit
|
|
212
|
+
PrettyOutput.auto_print(
|
|
213
|
+
f"ℹ️ [c2rust-optimizer][progress] 已记录当前 commit: {current_commit}",
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
self.progress_path.write_text(
|
|
217
|
+
json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
218
|
+
)
|
|
219
|
+
except Exception:
|
|
220
|
+
pass
|
|
221
|
+
|
|
222
|
+
def save_fix_progress(
|
|
223
|
+
self, step_name: str, fix_key: str, files: Optional[List[Path]] = None
|
|
224
|
+
) -> None:
|
|
225
|
+
"""
|
|
226
|
+
保存单个修复的进度(包括 commit id)。
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
step_name: 步骤名称(如 "clippy_elimination", "unsafe_cleanup")
|
|
230
|
+
fix_key: 修复的唯一标识(如 "warning-1", "file_path.rs")
|
|
231
|
+
files: 修改的文件列表(可选)
|
|
232
|
+
"""
|
|
233
|
+
try:
|
|
234
|
+
# 获取当前 commit id
|
|
235
|
+
current_commit = self.get_crate_commit_hash()
|
|
236
|
+
if not current_commit:
|
|
237
|
+
PrettyOutput.auto_print(
|
|
238
|
+
"⚠️ [c2rust-optimizer][progress] 无法获取 commit id,跳过进度记录",
|
|
239
|
+
)
|
|
240
|
+
return
|
|
241
|
+
|
|
242
|
+
# 加载现有进度
|
|
243
|
+
if self.progress_path.exists():
|
|
244
|
+
try:
|
|
245
|
+
obj = json.loads(self.progress_path.read_text(encoding="utf-8"))
|
|
246
|
+
except Exception:
|
|
247
|
+
obj = {}
|
|
248
|
+
else:
|
|
249
|
+
obj = {}
|
|
250
|
+
|
|
251
|
+
# 初始化修复进度结构
|
|
252
|
+
if "fix_progress" not in obj:
|
|
253
|
+
obj["fix_progress"] = {}
|
|
254
|
+
if step_name not in obj["fix_progress"]:
|
|
255
|
+
obj["fix_progress"][step_name] = {}
|
|
256
|
+
|
|
257
|
+
# 记录修复进度
|
|
258
|
+
obj["fix_progress"][step_name][fix_key] = {
|
|
259
|
+
"commit": current_commit,
|
|
260
|
+
"timestamp": None, # 可以添加时间戳如果需要
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
# 更新已处理的文件列表
|
|
264
|
+
if files:
|
|
265
|
+
rels = []
|
|
266
|
+
for p in files:
|
|
267
|
+
try:
|
|
268
|
+
rel = (
|
|
269
|
+
p.resolve().relative_to(self.crate_dir.resolve()).as_posix()
|
|
270
|
+
)
|
|
271
|
+
except Exception:
|
|
272
|
+
rel = str(p)
|
|
273
|
+
rels.append(rel)
|
|
274
|
+
self.processed.update(rels)
|
|
275
|
+
obj["processed"] = sorted(self.processed)
|
|
276
|
+
|
|
277
|
+
# 更新 last_commit
|
|
278
|
+
obj["last_commit"] = current_commit
|
|
279
|
+
|
|
280
|
+
# 保存进度
|
|
281
|
+
self.progress_path.write_text(
|
|
282
|
+
json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
283
|
+
)
|
|
284
|
+
PrettyOutput.auto_print(
|
|
285
|
+
f"ℹ️ [c2rust-optimizer][progress] 已记录修复进度: {step_name}/{fix_key} -> commit {current_commit[:8]}"
|
|
286
|
+
)
|
|
287
|
+
except Exception as e:
|
|
288
|
+
PrettyOutput.auto_print(
|
|
289
|
+
f"⚠️ ⚠️ [c2rust-optimizer] 保存修复进度失败(非致命): {e}"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
def save_step_progress(self, step_name: str, files: List[Path]) -> None:
|
|
293
|
+
"""保存步骤进度:标记步骤完成并更新文件列表。"""
|
|
294
|
+
try:
|
|
295
|
+
# 标记步骤为已完成
|
|
296
|
+
self.steps_completed.add(step_name)
|
|
297
|
+
# 更新已处理的文件列表
|
|
298
|
+
rels = []
|
|
299
|
+
for p in files:
|
|
300
|
+
try:
|
|
301
|
+
rel = p.resolve().relative_to(self.crate_dir.resolve()).as_posix()
|
|
302
|
+
except Exception:
|
|
303
|
+
rel = str(p)
|
|
304
|
+
rels.append(rel)
|
|
305
|
+
self.processed.update(rels)
|
|
306
|
+
|
|
307
|
+
# 获取当前 commit id 并记录
|
|
308
|
+
current_commit = self.get_crate_commit_hash()
|
|
309
|
+
|
|
310
|
+
# 保存进度
|
|
311
|
+
data: Dict[str, Any] = {
|
|
312
|
+
"processed": sorted(self.processed),
|
|
313
|
+
"steps_completed": sorted(self.steps_completed),
|
|
314
|
+
}
|
|
315
|
+
if current_commit:
|
|
316
|
+
# 记录每个步骤的 commit id
|
|
317
|
+
step_commits = getattr(self, "_step_commits", {})
|
|
318
|
+
step_commits[step_name] = current_commit
|
|
319
|
+
self._step_commits = step_commits
|
|
320
|
+
data["step_commits"] = cast(Dict[str, str], step_commits)
|
|
321
|
+
data["last_commit"] = current_commit
|
|
322
|
+
PrettyOutput.auto_print(
|
|
323
|
+
f"ℹ️ [c2rust-optimizer][progress] 已记录步骤 '{step_name}' 的 commit: {current_commit}",
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
self.progress_path.write_text(
|
|
327
|
+
json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
328
|
+
)
|
|
329
|
+
PrettyOutput.auto_print(
|
|
330
|
+
"ℹ️ [c2rust-optimizer] 步骤进度已保存",
|
|
331
|
+
)
|
|
332
|
+
except Exception as e:
|
|
333
|
+
PrettyOutput.auto_print(
|
|
334
|
+
f"⚠️ [c2rust-optimizer] 保存步骤进度失败(非致命): {e}",
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
def on_before_tool_call(self, agent: Any, current_response=None, **kwargs) -> None:
|
|
338
|
+
"""
|
|
339
|
+
工具调用前的事件处理器,用于记录工具调用前的 commit id。
|
|
340
|
+
|
|
341
|
+
在每次工具调用前记录当前的 commit,以便在工具调用后检测到问题时能够回退。
|
|
342
|
+
"""
|
|
343
|
+
try:
|
|
344
|
+
# 只关注可能修改代码的工具
|
|
345
|
+
# 注意:在 BEFORE_TOOL_CALL 时,工具还未执行,无法获取工具名称
|
|
346
|
+
# 但我们可以在 AFTER_TOOL_CALL 时检查工具名称,这里先记录 commit
|
|
347
|
+
agent_id = id(agent)
|
|
348
|
+
agent_key = f"agent_{agent_id}"
|
|
349
|
+
current_commit = self.get_crate_commit_hash()
|
|
350
|
+
if current_commit:
|
|
351
|
+
# 记录工具调用前的 commit(如果之前没有记录,或者 commit 已变化)
|
|
352
|
+
if (
|
|
353
|
+
agent_key not in self._agent_before_commits
|
|
354
|
+
or self._agent_before_commits[agent_key] != current_commit
|
|
355
|
+
):
|
|
356
|
+
self._agent_before_commits[agent_key] = current_commit
|
|
357
|
+
except Exception as e:
|
|
358
|
+
# 事件处理器异常不应影响主流程
|
|
359
|
+
PrettyOutput.auto_print(
|
|
360
|
+
f"⚠️ ⚠️ [c2rust-optimizer][test-detection] BEFORE_TOOL_CALL 事件处理器异常: {e}"
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
def on_after_tool_call(
|
|
364
|
+
self,
|
|
365
|
+
agent: Any,
|
|
366
|
+
current_response=None,
|
|
367
|
+
need_return=None,
|
|
368
|
+
tool_prompt=None,
|
|
369
|
+
**kwargs,
|
|
370
|
+
) -> None:
|
|
371
|
+
"""
|
|
372
|
+
工具调用后的事件处理器,用于细粒度检测测试代码删除。
|
|
373
|
+
|
|
374
|
+
在每次工具调用后立即检测,如果检测到测试代码被错误删除,立即回退。
|
|
375
|
+
"""
|
|
376
|
+
try:
|
|
377
|
+
# 只检测编辑文件的工具调用
|
|
378
|
+
last_tool = (
|
|
379
|
+
agent.get_user_data("__last_executed_tool__")
|
|
380
|
+
if hasattr(agent, "get_user_data")
|
|
381
|
+
else None
|
|
382
|
+
)
|
|
383
|
+
if not last_tool:
|
|
384
|
+
return
|
|
385
|
+
|
|
386
|
+
# 只关注可能修改代码的工具
|
|
387
|
+
edit_tools = {
|
|
388
|
+
"edit_file",
|
|
389
|
+
"apply_patch",
|
|
390
|
+
}
|
|
391
|
+
if last_tool not in edit_tools:
|
|
392
|
+
return
|
|
393
|
+
|
|
394
|
+
# 获取该 Agent 对应的工具调用前的 commit id
|
|
395
|
+
agent_id = id(agent)
|
|
396
|
+
agent_key = f"agent_{agent_id}"
|
|
397
|
+
before_commit = self._agent_before_commits.get(agent_key)
|
|
398
|
+
|
|
399
|
+
# 如果没有 commit 信息,无法检测
|
|
400
|
+
if not before_commit:
|
|
401
|
+
return
|
|
402
|
+
|
|
403
|
+
# 检测测试代码删除
|
|
404
|
+
from jarvis.jarvis_c2rust.utils import ask_llm_about_test_deletion
|
|
405
|
+
from jarvis.jarvis_c2rust.utils import detect_test_deletion
|
|
406
|
+
|
|
407
|
+
detection_result = detect_test_deletion("[c2rust-optimizer]")
|
|
408
|
+
if not detection_result:
|
|
409
|
+
# 没有检测到删除,更新 commit 记录
|
|
410
|
+
current_commit = self.get_crate_commit_hash()
|
|
411
|
+
if current_commit and current_commit != before_commit:
|
|
412
|
+
self._agent_before_commits[agent_key] = current_commit
|
|
413
|
+
return
|
|
414
|
+
|
|
415
|
+
PrettyOutput.auto_print(
|
|
416
|
+
"⚠️ ⚠️ [c2rust-optimizer][test-detection] 检测到可能错误删除了测试代码标记(工具调用后检测)"
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
# 询问 LLM 是否合理
|
|
420
|
+
need_reset = ask_llm_about_test_deletion(
|
|
421
|
+
detection_result, agent, "[c2rust-optimizer]"
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
if need_reset:
|
|
425
|
+
PrettyOutput.auto_print(
|
|
426
|
+
f"❌ ❌ [c2rust-optimizer][test-detection] LLM 确认删除不合理,正在回退到 commit: {before_commit}"
|
|
427
|
+
)
|
|
428
|
+
if self.reset_to_commit(before_commit):
|
|
429
|
+
PrettyOutput.auto_print(
|
|
430
|
+
"✅ ✅ [c2rust-optimizer][test-detection] 已回退到之前的 commit(工具调用后检测)"
|
|
431
|
+
)
|
|
432
|
+
# 回退后,保持之前的 commit 记录
|
|
433
|
+
self._agent_before_commits[agent_key] = before_commit
|
|
434
|
+
# 在 agent 的 session 中添加提示,告知修改被撤销
|
|
435
|
+
if hasattr(agent, "session") and hasattr(agent.session, "prompt"):
|
|
436
|
+
agent.session.prompt += "\n\n⚠️ 修改被撤销:检测到测试代码被错误删除,已回退到之前的版本。\n"
|
|
437
|
+
else:
|
|
438
|
+
PrettyOutput.auto_print(
|
|
439
|
+
"❌ ❌ [c2rust-optimizer][test-detection] 回退失败"
|
|
440
|
+
)
|
|
441
|
+
else:
|
|
442
|
+
# LLM 认为删除合理,更新 commit 记录
|
|
443
|
+
current_commit = self.get_crate_commit_hash()
|
|
444
|
+
if current_commit and current_commit != before_commit:
|
|
445
|
+
self._agent_before_commits[agent_key] = current_commit
|
|
446
|
+
except Exception as e:
|
|
447
|
+
# 事件处理器异常不应影响主流程
|
|
448
|
+
PrettyOutput.auto_print(
|
|
449
|
+
f"⚠️ ⚠️ [c2rust-optimizer][test-detection] AFTER_TOOL_CALL 事件处理器异常: {e}"
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
def check_and_handle_test_deletion(
|
|
453
|
+
self, before_commit: Optional[str], agent: Any
|
|
454
|
+
) -> bool:
|
|
455
|
+
"""
|
|
456
|
+
检测并处理测试代码删除。
|
|
457
|
+
|
|
458
|
+
参数:
|
|
459
|
+
before_commit: agent 运行前的 commit hash
|
|
460
|
+
agent: 代码优化或修复的 agent 实例,使用其 model 进行询问
|
|
461
|
+
|
|
462
|
+
返回:
|
|
463
|
+
bool: 如果检测到问题且已回退,返回 True;否则返回 False
|
|
464
|
+
"""
|
|
465
|
+
from jarvis.jarvis_c2rust.utils import check_and_handle_test_deletion
|
|
466
|
+
|
|
467
|
+
return check_and_handle_test_deletion(
|
|
468
|
+
before_commit, agent, self.reset_to_commit, "[c2rust-optimizer]"
|
|
469
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""优化器报告管理模块。"""
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
from dataclasses import asdict
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from jarvis.jarvis_c2rust.optimizer_options import OptimizeStats
|
|
9
|
+
from jarvis.jarvis_c2rust.optimizer_utils import write_file
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_report_display_path(
|
|
13
|
+
report_path: Path, project_root: Path, crate_dir: Path
|
|
14
|
+
) -> str:
|
|
15
|
+
"""
|
|
16
|
+
获取报告文件的显示路径(优先使用相对路径)。
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
report_path: 报告文件的绝对路径
|
|
20
|
+
project_root: 项目根目录
|
|
21
|
+
crate_dir: crate 根目录
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
显示路径字符串
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
return str(report_path.relative_to(project_root))
|
|
28
|
+
except ValueError:
|
|
29
|
+
try:
|
|
30
|
+
return str(report_path.relative_to(crate_dir))
|
|
31
|
+
except ValueError:
|
|
32
|
+
try:
|
|
33
|
+
return str(report_path.relative_to(Path.cwd()))
|
|
34
|
+
except ValueError:
|
|
35
|
+
return str(report_path)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def write_final_report(report_path: Path, stats: OptimizeStats) -> None:
|
|
39
|
+
"""
|
|
40
|
+
写入最终优化报告。
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
report_path: 报告文件路径
|
|
44
|
+
stats: 优化统计信息
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
write_file(
|
|
48
|
+
report_path,
|
|
49
|
+
json.dumps(asdict(stats), ensure_ascii=False, indent=2),
|
|
50
|
+
)
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|