jarvis-ai-assistant 0.3.30__py3-none-any.whl → 0.7.6__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 +458 -152
- jarvis/jarvis_agent/agent_manager.py +17 -13
- jarvis/jarvis_agent/builtin_input_handler.py +2 -6
- jarvis/jarvis_agent/config_editor.py +2 -7
- jarvis/jarvis_agent/event_bus.py +82 -12
- jarvis/jarvis_agent/file_context_handler.py +329 -0
- jarvis/jarvis_agent/file_methodology_manager.py +3 -4
- jarvis/jarvis_agent/jarvis.py +628 -55
- jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
- jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
- jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
- jarvis/jarvis_agent/language_support_info.py +486 -0
- jarvis/jarvis_agent/main.py +34 -10
- jarvis/jarvis_agent/memory_manager.py +7 -16
- jarvis/jarvis_agent/methodology_share_manager.py +10 -16
- jarvis/jarvis_agent/prompt_manager.py +1 -1
- jarvis/jarvis_agent/prompts.py +193 -171
- jarvis/jarvis_agent/protocols.py +8 -12
- jarvis/jarvis_agent/run_loop.py +105 -9
- jarvis/jarvis_agent/session_manager.py +2 -3
- jarvis/jarvis_agent/share_manager.py +20 -22
- jarvis/jarvis_agent/shell_input_handler.py +1 -2
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +31 -6
- jarvis/jarvis_agent/task_manager.py +11 -27
- jarvis/jarvis_agent/tool_executor.py +2 -3
- jarvis/jarvis_agent/tool_share_manager.py +12 -24
- jarvis/jarvis_agent/utils.py +5 -1
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +786 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +575 -0
- jarvis/jarvis_c2rust/collector.py +250 -0
- jarvis/jarvis_c2rust/constants.py +26 -0
- jarvis/jarvis_c2rust/library_replacer.py +1254 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1272 -0
- jarvis/jarvis_c2rust/loaders.py +207 -0
- jarvis/jarvis_c2rust/models.py +28 -0
- jarvis/jarvis_c2rust/optimizer.py +2157 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2983 -0
- jarvis/jarvis_c2rust/utils.py +385 -0
- jarvis/jarvis_code_agent/build_validation_config.py +132 -0
- jarvis/jarvis_code_agent/code_agent.py +1371 -220
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +65 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +106 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +72 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +70 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +53 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +47 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +61 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +153 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +648 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +49 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +299 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +215 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +269 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +281 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +605 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +252 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +58 -0
- jarvis/jarvis_code_agent/lint.py +501 -8
- jarvis/jarvis_code_agent/utils.py +141 -0
- jarvis/jarvis_code_analysis/code_review.py +493 -584
- jarvis/jarvis_data/config_schema.json +128 -12
- jarvis/jarvis_git_squash/main.py +4 -5
- jarvis/jarvis_git_utils/git_commiter.py +82 -75
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -29
- jarvis/jarvis_mcp/stdio_mcp_client.py +12 -13
- jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
- jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
- jarvis/jarvis_methodology/main.py +32 -48
- jarvis/jarvis_multi_agent/__init__.py +287 -55
- jarvis/jarvis_multi_agent/main.py +36 -4
- jarvis/jarvis_platform/base.py +524 -202
- jarvis/jarvis_platform/human.py +7 -8
- jarvis/jarvis_platform/kimi.py +30 -36
- jarvis/jarvis_platform/openai.py +88 -25
- jarvis/jarvis_platform/registry.py +26 -10
- jarvis/jarvis_platform/tongyi.py +24 -25
- jarvis/jarvis_platform/yuanbao.py +32 -43
- jarvis/jarvis_platform_manager/main.py +66 -77
- jarvis/jarvis_platform_manager/service.py +8 -13
- jarvis/jarvis_rag/cli.py +53 -55
- jarvis/jarvis_rag/embedding_manager.py +13 -18
- jarvis/jarvis_rag/llm_interface.py +8 -9
- jarvis/jarvis_rag/query_rewriter.py +10 -21
- jarvis/jarvis_rag/rag_pipeline.py +24 -27
- jarvis/jarvis_rag/reranker.py +4 -5
- jarvis/jarvis_rag/retriever.py +28 -30
- jarvis/jarvis_sec/__init__.py +305 -0
- jarvis/jarvis_sec/agents.py +143 -0
- jarvis/jarvis_sec/analysis.py +276 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +139 -0
- jarvis/jarvis_sec/clustering.py +1439 -0
- jarvis/jarvis_sec/file_manager.py +427 -0
- jarvis/jarvis_sec/parsers.py +73 -0
- jarvis/jarvis_sec/prompts.py +268 -0
- jarvis/jarvis_sec/report.py +336 -0
- jarvis/jarvis_sec/review.py +453 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/utils.py +499 -0
- jarvis/jarvis_sec/verification.py +848 -0
- jarvis/jarvis_sec/workflow.py +226 -0
- jarvis/jarvis_smart_shell/main.py +38 -87
- jarvis/jarvis_stats/cli.py +2 -2
- jarvis/jarvis_stats/stats.py +8 -8
- jarvis/jarvis_stats/storage.py +15 -21
- jarvis/jarvis_stats/visualizer.py +1 -1
- jarvis/jarvis_tools/clear_memory.py +3 -20
- jarvis/jarvis_tools/cli/main.py +21 -23
- jarvis/jarvis_tools/edit_file.py +1019 -132
- jarvis/jarvis_tools/execute_script.py +83 -25
- jarvis/jarvis_tools/file_analyzer.py +6 -9
- jarvis/jarvis_tools/generate_new_tool.py +14 -21
- jarvis/jarvis_tools/lsp_client.py +1552 -0
- jarvis/jarvis_tools/methodology.py +2 -3
- jarvis/jarvis_tools/read_code.py +1736 -35
- jarvis/jarvis_tools/read_symbols.py +140 -0
- jarvis/jarvis_tools/read_webpage.py +12 -13
- jarvis/jarvis_tools/registry.py +427 -200
- jarvis/jarvis_tools/retrieve_memory.py +20 -19
- jarvis/jarvis_tools/rewrite_file.py +72 -158
- jarvis/jarvis_tools/save_memory.py +3 -15
- jarvis/jarvis_tools/search_web.py +18 -18
- jarvis/jarvis_tools/sub_agent.py +36 -43
- jarvis/jarvis_tools/sub_code_agent.py +25 -26
- jarvis/jarvis_tools/virtual_tty.py +55 -33
- jarvis/jarvis_utils/clipboard.py +7 -10
- jarvis/jarvis_utils/config.py +232 -45
- jarvis/jarvis_utils/embedding.py +8 -5
- jarvis/jarvis_utils/fzf.py +8 -8
- jarvis/jarvis_utils/git_utils.py +225 -36
- jarvis/jarvis_utils/globals.py +3 -3
- jarvis/jarvis_utils/http.py +1 -1
- jarvis/jarvis_utils/input.py +99 -48
- jarvis/jarvis_utils/jsonnet_compat.py +465 -0
- jarvis/jarvis_utils/methodology.py +52 -48
- jarvis/jarvis_utils/utils.py +819 -491
- jarvis_ai_assistant-0.7.6.dist-info/METADATA +600 -0
- jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +4 -0
- jarvis/jarvis_agent/config.py +0 -92
- jarvis/jarvis_agent/edit_file_handler.py +0 -296
- jarvis/jarvis_platform/ai8.py +0 -332
- jarvis/jarvis_tools/ask_user.py +0 -54
- jarvis_ai_assistant-0.3.30.dist-info/METADATA +0 -381
- jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
|
@@ -9,455 +9,408 @@ import typer
|
|
|
9
9
|
|
|
10
10
|
from jarvis.jarvis_agent import Agent
|
|
11
11
|
from jarvis.jarvis_code_analysis.checklists.loader import get_language_checklist
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
from jarvis.jarvis_tools.read_code import ReadCodeTool
|
|
14
|
-
|
|
15
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
14
|
+
|
|
15
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput # 保留用于语法高亮
|
|
16
16
|
from jarvis.jarvis_utils.tag import ct, ot
|
|
17
17
|
from jarvis.jarvis_utils.utils import init_env, is_context_overflow
|
|
18
18
|
|
|
19
19
|
app = typer.Typer(help="自动代码审查工具")
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
22
|
+
def _detect_languages_from_files(file_paths: List[str]) -> List[str]:
|
|
23
|
+
"""
|
|
24
|
+
Detect programming languages from a list of file paths using file extensions.
|
|
25
|
+
Returns a list of detected languages ('c_cpp', 'go', 'python', 'rust', 'java', 'javascript', 'typescript', etc.).
|
|
26
|
+
"""
|
|
27
|
+
if not file_paths:
|
|
28
|
+
return []
|
|
29
|
+
|
|
30
|
+
# Extension-based language detection
|
|
31
|
+
languages = set()
|
|
32
|
+
for file_path in file_paths:
|
|
33
|
+
file_path = file_path.lower()
|
|
34
|
+
_, ext = os.path.splitext(file_path)
|
|
35
|
+
|
|
36
|
+
# Get base name for special files without extensions
|
|
37
|
+
base_name = os.path.basename(file_path)
|
|
38
|
+
|
|
39
|
+
# C/C++
|
|
40
|
+
if ext in [
|
|
41
|
+
".c",
|
|
42
|
+
".cpp",
|
|
43
|
+
".cc",
|
|
44
|
+
".cxx",
|
|
45
|
+
".h",
|
|
46
|
+
".hpp",
|
|
47
|
+
".hxx",
|
|
48
|
+
".inl",
|
|
49
|
+
".ipp",
|
|
50
|
+
]:
|
|
51
|
+
languages.add("c_cpp")
|
|
52
|
+
|
|
53
|
+
# Go
|
|
54
|
+
elif ext in [".go"]:
|
|
55
|
+
languages.add("go")
|
|
56
|
+
|
|
57
|
+
# Python
|
|
58
|
+
elif ext in [".py", ".pyw", ".pyi", ".pyx", ".pxd"] or base_name in [
|
|
59
|
+
"requirements.txt",
|
|
60
|
+
"setup.py",
|
|
61
|
+
"pyproject.toml",
|
|
62
|
+
]:
|
|
63
|
+
languages.add("python")
|
|
64
|
+
|
|
65
|
+
# Rust
|
|
66
|
+
elif ext in [".rs", ".rlib"] or base_name in ["Cargo.toml", "Cargo.lock"]:
|
|
67
|
+
languages.add("rust")
|
|
68
|
+
|
|
69
|
+
# Java
|
|
70
|
+
elif ext in [".java", ".class", ".jar"] or base_name in [
|
|
71
|
+
"pom.xml",
|
|
72
|
+
"build.gradle",
|
|
73
|
+
]:
|
|
74
|
+
languages.add("java")
|
|
75
|
+
|
|
76
|
+
# JavaScript
|
|
77
|
+
elif ext in [".js", ".mjs", ".cjs", ".jsx"]:
|
|
78
|
+
languages.add("javascript")
|
|
79
|
+
|
|
80
|
+
# TypeScript
|
|
81
|
+
elif ext in [".ts", ".tsx", ".cts", ".mts"]:
|
|
82
|
+
languages.add("typescript")
|
|
83
|
+
|
|
84
|
+
# PHP
|
|
85
|
+
elif ext in [".php", ".phtml", ".php5", ".php7", ".phps"]:
|
|
86
|
+
languages.add("php")
|
|
87
|
+
|
|
88
|
+
# Ruby
|
|
89
|
+
elif ext in [".rb", ".rake", ".gemspec"] or base_name in [
|
|
90
|
+
"Gemfile",
|
|
91
|
+
"Rakefile",
|
|
92
|
+
]:
|
|
93
|
+
languages.add("ruby")
|
|
94
|
+
|
|
95
|
+
# Swift
|
|
96
|
+
elif ext in [".swift"]:
|
|
97
|
+
languages.add("swift")
|
|
98
|
+
|
|
99
|
+
# Kotlin
|
|
100
|
+
elif ext in [".kt", ".kts"]:
|
|
101
|
+
languages.add("kotlin")
|
|
102
|
+
|
|
103
|
+
# C#
|
|
104
|
+
elif ext in [".cs", ".csx"]:
|
|
105
|
+
languages.add("csharp")
|
|
106
|
+
|
|
107
|
+
# SQL
|
|
108
|
+
elif ext in [".sql"]:
|
|
109
|
+
languages.add("sql")
|
|
110
|
+
|
|
111
|
+
# Shell/Bash
|
|
112
|
+
elif (
|
|
113
|
+
ext in [".sh", ".bash"]
|
|
114
|
+
or base_name.startswith(".bash")
|
|
115
|
+
or base_name.startswith(".zsh")
|
|
116
|
+
):
|
|
117
|
+
languages.add("shell")
|
|
118
|
+
|
|
119
|
+
# HTML/CSS
|
|
120
|
+
elif ext in [".html", ".htm", ".xhtml"]:
|
|
121
|
+
languages.add("html")
|
|
122
|
+
elif ext in [".css", ".scss", ".sass", ".less"]:
|
|
123
|
+
languages.add("css")
|
|
124
|
+
|
|
125
|
+
# XML/JSON/YAML (config files)
|
|
126
|
+
elif ext in [
|
|
127
|
+
".xml",
|
|
128
|
+
".xsd",
|
|
129
|
+
".dtd",
|
|
130
|
+
".tld",
|
|
131
|
+
".jsp",
|
|
132
|
+
".jspx",
|
|
133
|
+
".tag",
|
|
134
|
+
".tagx",
|
|
135
|
+
]:
|
|
136
|
+
languages.add("xml")
|
|
137
|
+
elif ext in [".json", ".jsonl", ".json5"]:
|
|
138
|
+
languages.add("json")
|
|
139
|
+
elif ext in [".yaml", ".yml"]:
|
|
140
|
+
languages.add("yaml")
|
|
141
|
+
|
|
142
|
+
# Markdown/Documentation
|
|
143
|
+
elif ext in [".md", ".markdown", ".rst", ".adoc"]:
|
|
144
|
+
languages.add("markdown")
|
|
145
|
+
|
|
146
|
+
# Docker
|
|
147
|
+
elif ext in [".dockerfile"] or base_name in [
|
|
148
|
+
"Dockerfile",
|
|
149
|
+
"docker-compose.yml",
|
|
150
|
+
"docker-compose.yaml",
|
|
151
|
+
]:
|
|
152
|
+
languages.add("docker")
|
|
153
|
+
|
|
154
|
+
# Terraform
|
|
155
|
+
elif ext in [".tf", ".tfvars"]:
|
|
156
|
+
languages.add("terraform")
|
|
157
|
+
|
|
158
|
+
# Makefile
|
|
159
|
+
elif ext in [".mk"] or base_name == "Makefile":
|
|
160
|
+
languages.add("makefile")
|
|
161
|
+
|
|
162
|
+
# Map to our primary language groups for checklist purposes
|
|
163
|
+
primary_languages = set()
|
|
164
|
+
language_mapping = {
|
|
165
|
+
"c_cpp": "c_cpp",
|
|
166
|
+
"go": "go",
|
|
167
|
+
"python": "python",
|
|
168
|
+
"rust": "rust",
|
|
169
|
+
"java": "java",
|
|
170
|
+
"javascript": "javascript",
|
|
171
|
+
"typescript": "typescript",
|
|
172
|
+
"php": "php",
|
|
173
|
+
"ruby": "ruby",
|
|
174
|
+
"swift": "swift",
|
|
175
|
+
"kotlin": "kotlin",
|
|
176
|
+
"csharp": "csharp",
|
|
177
|
+
"sql": "sql",
|
|
178
|
+
"shell": "shell",
|
|
179
|
+
"html": "html",
|
|
180
|
+
"css": "css",
|
|
181
|
+
"xml": "xml",
|
|
182
|
+
"json": "json",
|
|
183
|
+
"yaml": "yaml",
|
|
184
|
+
"markdown": "docs",
|
|
185
|
+
"docker": "docker",
|
|
186
|
+
"terraform": "terraform",
|
|
187
|
+
"makefile": "devops",
|
|
58
188
|
}
|
|
59
189
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
190
|
+
# Map detected languages to primary language groups
|
|
191
|
+
for lang in languages:
|
|
192
|
+
primary_lang = language_mapping.get(lang)
|
|
193
|
+
if primary_lang:
|
|
194
|
+
# Only keep languages we have checklists for
|
|
195
|
+
if primary_lang in [
|
|
196
|
+
"c_cpp",
|
|
197
|
+
"go",
|
|
198
|
+
"python",
|
|
199
|
+
"rust",
|
|
200
|
+
"java",
|
|
201
|
+
"javascript",
|
|
202
|
+
"typescript",
|
|
203
|
+
"csharp",
|
|
204
|
+
"swift",
|
|
205
|
+
"php",
|
|
206
|
+
"shell",
|
|
207
|
+
"sql",
|
|
208
|
+
"ruby",
|
|
209
|
+
"kotlin",
|
|
210
|
+
"html",
|
|
211
|
+
"css",
|
|
212
|
+
"xml",
|
|
213
|
+
"json",
|
|
214
|
+
"yaml",
|
|
215
|
+
"docker",
|
|
216
|
+
"terraform",
|
|
217
|
+
"docs",
|
|
218
|
+
"markdown",
|
|
219
|
+
"devops",
|
|
220
|
+
"makefile",
|
|
88
221
|
]:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
# Go
|
|
92
|
-
elif ext in [".go"]:
|
|
93
|
-
languages.add("go")
|
|
222
|
+
primary_languages.add(primary_lang)
|
|
94
223
|
|
|
95
|
-
|
|
96
|
-
elif ext in [".py", ".pyw", ".pyi", ".pyx", ".pxd"] or base_name in [
|
|
97
|
-
"requirements.txt",
|
|
98
|
-
"setup.py",
|
|
99
|
-
"pyproject.toml",
|
|
100
|
-
]:
|
|
101
|
-
languages.add("python")
|
|
224
|
+
return list(primary_languages)
|
|
102
225
|
|
|
103
|
-
# Rust
|
|
104
|
-
elif ext in [".rs", ".rlib"] or base_name in ["Cargo.toml", "Cargo.lock"]:
|
|
105
|
-
languages.add("rust")
|
|
106
226
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
]:
|
|
112
|
-
languages.add("java")
|
|
227
|
+
def _get_language_checklist(language: str) -> str:
|
|
228
|
+
"""Get the checklist for a specific language."""
|
|
229
|
+
checklist = get_language_checklist(language)
|
|
230
|
+
return checklist if checklist else ""
|
|
113
231
|
|
|
114
|
-
# JavaScript
|
|
115
|
-
elif ext in [".js", ".mjs", ".cjs", ".jsx"]:
|
|
116
|
-
languages.add("javascript")
|
|
117
232
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
233
|
+
def execute_code_review(
|
|
234
|
+
args: Dict[str, Any], agent: Optional["Agent"] = None
|
|
235
|
+
) -> Dict[str, Any]:
|
|
236
|
+
"""
|
|
237
|
+
纯CLI Agent执行入口:根据审查类型获取差异、构建审查上下文并通过Agent生成报告。
|
|
238
|
+
不注册为Tool,不通过ToolRegistry。
|
|
239
|
+
"""
|
|
240
|
+
try:
|
|
241
|
+
review_type = args.get("review_type", "current").strip()
|
|
242
|
+
root_dir = args.get("root_dir", ".")
|
|
121
243
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
languages.add("php")
|
|
244
|
+
# Store current directory
|
|
245
|
+
original_dir = os.getcwd()
|
|
125
246
|
|
|
126
|
-
# Ruby
|
|
127
|
-
elif ext in [".rb", ".rake", ".gemspec"] or base_name in [
|
|
128
|
-
"Gemfile",
|
|
129
|
-
"Rakefile",
|
|
130
|
-
]:
|
|
131
|
-
languages.add("ruby")
|
|
132
|
-
|
|
133
|
-
# Swift
|
|
134
|
-
elif ext in [".swift"]:
|
|
135
|
-
languages.add("swift")
|
|
136
|
-
|
|
137
|
-
# Kotlin
|
|
138
|
-
elif ext in [".kt", ".kts"]:
|
|
139
|
-
languages.add("kotlin")
|
|
140
|
-
|
|
141
|
-
# C#
|
|
142
|
-
elif ext in [".cs", ".csx"]:
|
|
143
|
-
languages.add("csharp")
|
|
144
|
-
|
|
145
|
-
# SQL
|
|
146
|
-
elif ext in [".sql"]:
|
|
147
|
-
languages.add("sql")
|
|
148
|
-
|
|
149
|
-
# Shell/Bash
|
|
150
|
-
elif (
|
|
151
|
-
ext in [".sh", ".bash"]
|
|
152
|
-
or base_name.startswith(".bash")
|
|
153
|
-
or base_name.startswith(".zsh")
|
|
154
|
-
):
|
|
155
|
-
languages.add("shell")
|
|
156
|
-
|
|
157
|
-
# HTML/CSS
|
|
158
|
-
elif ext in [".html", ".htm", ".xhtml"]:
|
|
159
|
-
languages.add("html")
|
|
160
|
-
elif ext in [".css", ".scss", ".sass", ".less"]:
|
|
161
|
-
languages.add("css")
|
|
162
|
-
|
|
163
|
-
# XML/JSON/YAML (config files)
|
|
164
|
-
elif ext in [
|
|
165
|
-
".xml",
|
|
166
|
-
".xsd",
|
|
167
|
-
".dtd",
|
|
168
|
-
".tld",
|
|
169
|
-
".jsp",
|
|
170
|
-
".jspx",
|
|
171
|
-
".tag",
|
|
172
|
-
".tagx",
|
|
173
|
-
]:
|
|
174
|
-
languages.add("xml")
|
|
175
|
-
elif ext in [".json", ".jsonl", ".json5"]:
|
|
176
|
-
languages.add("json")
|
|
177
|
-
elif ext in [".yaml", ".yml"]:
|
|
178
|
-
languages.add("yaml")
|
|
179
|
-
|
|
180
|
-
# Markdown/Documentation
|
|
181
|
-
elif ext in [".md", ".markdown", ".rst", ".adoc"]:
|
|
182
|
-
languages.add("markdown")
|
|
183
|
-
|
|
184
|
-
# Docker
|
|
185
|
-
elif ext in [".dockerfile"] or base_name in [
|
|
186
|
-
"Dockerfile",
|
|
187
|
-
"docker-compose.yml",
|
|
188
|
-
"docker-compose.yaml",
|
|
189
|
-
]:
|
|
190
|
-
languages.add("docker")
|
|
191
|
-
|
|
192
|
-
# Terraform
|
|
193
|
-
elif ext in [".tf", ".tfvars"]:
|
|
194
|
-
languages.add("terraform")
|
|
195
|
-
|
|
196
|
-
# Makefile
|
|
197
|
-
elif ext in [".mk"] or base_name == "Makefile":
|
|
198
|
-
languages.add("makefile")
|
|
199
|
-
|
|
200
|
-
# Map to our primary language groups for checklist purposes
|
|
201
|
-
primary_languages = set()
|
|
202
|
-
language_mapping = {
|
|
203
|
-
"c_cpp": "c_cpp",
|
|
204
|
-
"go": "go",
|
|
205
|
-
"python": "python",
|
|
206
|
-
"rust": "rust",
|
|
207
|
-
"java": "java",
|
|
208
|
-
"javascript": "javascript",
|
|
209
|
-
"typescript": "typescript",
|
|
210
|
-
"php": "php",
|
|
211
|
-
"ruby": "ruby",
|
|
212
|
-
"swift": "swift",
|
|
213
|
-
"kotlin": "kotlin",
|
|
214
|
-
"csharp": "csharp",
|
|
215
|
-
"sql": "sql",
|
|
216
|
-
"shell": "shell",
|
|
217
|
-
"html": "html",
|
|
218
|
-
"css": "css",
|
|
219
|
-
"xml": "xml",
|
|
220
|
-
"json": "json",
|
|
221
|
-
"yaml": "yaml",
|
|
222
|
-
"markdown": "docs",
|
|
223
|
-
"docker": "docker",
|
|
224
|
-
"terraform": "terraform",
|
|
225
|
-
"makefile": "devops",
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
# Map detected languages to primary language groups
|
|
229
|
-
for lang in languages:
|
|
230
|
-
primary_lang = language_mapping.get(lang)
|
|
231
|
-
if primary_lang:
|
|
232
|
-
# Only keep languages we have checklists for
|
|
233
|
-
if primary_lang in [
|
|
234
|
-
"c_cpp",
|
|
235
|
-
"go",
|
|
236
|
-
"python",
|
|
237
|
-
"rust",
|
|
238
|
-
"java",
|
|
239
|
-
"javascript",
|
|
240
|
-
"typescript",
|
|
241
|
-
"csharp",
|
|
242
|
-
"swift",
|
|
243
|
-
"php",
|
|
244
|
-
"shell",
|
|
245
|
-
"sql",
|
|
246
|
-
"ruby",
|
|
247
|
-
"kotlin",
|
|
248
|
-
"html",
|
|
249
|
-
"css",
|
|
250
|
-
"xml",
|
|
251
|
-
"json",
|
|
252
|
-
"yaml",
|
|
253
|
-
"docker",
|
|
254
|
-
"terraform",
|
|
255
|
-
"docs",
|
|
256
|
-
"markdown",
|
|
257
|
-
"devops",
|
|
258
|
-
"makefile",
|
|
259
|
-
]:
|
|
260
|
-
primary_languages.add(primary_lang)
|
|
261
|
-
|
|
262
|
-
return list(primary_languages)
|
|
263
|
-
|
|
264
|
-
def _get_language_checklist(self, language: str) -> str:
|
|
265
|
-
"""Get the checklist for a specific language."""
|
|
266
|
-
checklist = get_language_checklist(language)
|
|
267
|
-
return checklist if checklist else ""
|
|
268
|
-
|
|
269
|
-
def execute(
|
|
270
|
-
self, args: Dict[str, Any], agent: Optional["Agent"] = None
|
|
271
|
-
) -> Dict[str, Any]:
|
|
272
247
|
try:
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
#
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
#
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
# Extract changed files using git command
|
|
404
|
-
files_cmd = "git diff --name-only HEAD"
|
|
405
|
-
try:
|
|
406
|
-
files_output = subprocess.check_output(
|
|
407
|
-
files_cmd, shell=True, text=True
|
|
408
|
-
)
|
|
409
|
-
file_paths = [
|
|
410
|
-
f.strip() for f in files_output.split("\n") if f.strip()
|
|
411
|
-
]
|
|
412
|
-
except subprocess.CalledProcessError:
|
|
413
|
-
# Fallback to regex extraction if git command fails
|
|
414
|
-
file_pattern = r"diff --git a/.*?\s+b/(.*?)(\n|$)"
|
|
415
|
-
files = re.findall(file_pattern, diff_output)
|
|
416
|
-
file_paths = [match[0] for match in files]
|
|
417
|
-
|
|
418
|
-
# Detect languages from the file paths
|
|
419
|
-
detected_languages = self._detect_languages_from_files(file_paths)
|
|
420
|
-
|
|
421
|
-
# Add review type and related information to the diff output
|
|
422
|
-
review_info = f"""
|
|
248
|
+
# Change to root_dir
|
|
249
|
+
os.chdir(root_dir)
|
|
250
|
+
|
|
251
|
+
# Variables to store file paths and diff output
|
|
252
|
+
file_paths: List[str] = []
|
|
253
|
+
diff_output = ""
|
|
254
|
+
|
|
255
|
+
# Build git diff command based on review type
|
|
256
|
+
|
|
257
|
+
if review_type == "commit":
|
|
258
|
+
if "commit_sha" not in args:
|
|
259
|
+
return {
|
|
260
|
+
"success": False,
|
|
261
|
+
"stdout": {},
|
|
262
|
+
"stderr": "commit_sha is required for commit review type",
|
|
263
|
+
}
|
|
264
|
+
commit_sha = args["commit_sha"].strip()
|
|
265
|
+
diff_cmd = f"git show {commit_sha} | cat -"
|
|
266
|
+
|
|
267
|
+
# Execute git command and get diff output
|
|
268
|
+
diff_output = subprocess.check_output(
|
|
269
|
+
diff_cmd,
|
|
270
|
+
shell=True,
|
|
271
|
+
text=True,
|
|
272
|
+
encoding="utf-8",
|
|
273
|
+
errors="replace",
|
|
274
|
+
)
|
|
275
|
+
if not diff_output:
|
|
276
|
+
return {
|
|
277
|
+
"success": False,
|
|
278
|
+
"stdout": {},
|
|
279
|
+
"stderr": "No changes to review",
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
# Extract changed files using git command
|
|
283
|
+
files_cmd = f"git show --name-only --pretty=format: {commit_sha}"
|
|
284
|
+
try:
|
|
285
|
+
files_output = subprocess.check_output(files_cmd, shell=True, text=True)
|
|
286
|
+
# Filter out empty lines without using grep
|
|
287
|
+
file_paths = [f.strip() for f in files_output.split("\n") if f.strip()]
|
|
288
|
+
except subprocess.CalledProcessError:
|
|
289
|
+
# Fallback to regex extraction if git command fails
|
|
290
|
+
file_pattern = r"diff --git a/.*?\s+b/(.*?)(\n|$)"
|
|
291
|
+
files = re.findall(file_pattern, diff_output)
|
|
292
|
+
file_paths = [match[0] for match in files]
|
|
293
|
+
|
|
294
|
+
elif review_type == "range":
|
|
295
|
+
if "start_commit" not in args or "end_commit" not in args:
|
|
296
|
+
return {
|
|
297
|
+
"success": False,
|
|
298
|
+
"stdout": {},
|
|
299
|
+
"stderr": "start_commit and end_commit are required for range review type",
|
|
300
|
+
}
|
|
301
|
+
start_commit = args["start_commit"].strip()
|
|
302
|
+
end_commit = args["end_commit"].strip()
|
|
303
|
+
diff_cmd = f"git diff {start_commit}..{end_commit} | cat -"
|
|
304
|
+
|
|
305
|
+
# Execute git command and get diff output
|
|
306
|
+
diff_output = subprocess.check_output(
|
|
307
|
+
diff_cmd,
|
|
308
|
+
shell=True,
|
|
309
|
+
text=True,
|
|
310
|
+
encoding="utf-8",
|
|
311
|
+
errors="replace",
|
|
312
|
+
)
|
|
313
|
+
if not diff_output:
|
|
314
|
+
return {
|
|
315
|
+
"success": False,
|
|
316
|
+
"stdout": {},
|
|
317
|
+
"stderr": "No changes to review",
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
# Extract changed files using git command
|
|
321
|
+
files_cmd = f"git diff --name-only {start_commit}..{end_commit}"
|
|
322
|
+
try:
|
|
323
|
+
files_output = subprocess.check_output(files_cmd, shell=True, text=True)
|
|
324
|
+
file_paths = [f.strip() for f in files_output.split("\n") if f.strip()]
|
|
325
|
+
except subprocess.CalledProcessError:
|
|
326
|
+
# Fallback to regex extraction if git command fails
|
|
327
|
+
file_pattern = r"diff --git a/.*?\s+b/(.*?)(\n|$)"
|
|
328
|
+
files = re.findall(file_pattern, diff_output)
|
|
329
|
+
file_paths = [match[0] for match in files]
|
|
330
|
+
|
|
331
|
+
elif review_type == "file":
|
|
332
|
+
if "file_path" not in args:
|
|
333
|
+
return {
|
|
334
|
+
"success": False,
|
|
335
|
+
"stdout": {},
|
|
336
|
+
"stderr": "file_path is required for file review type",
|
|
337
|
+
}
|
|
338
|
+
file_path = args["file_path"].strip()
|
|
339
|
+
file_paths = [file_path]
|
|
340
|
+
diff_output = ReadCodeTool().execute({"files": [{"path": file_path}]})["stdout"]
|
|
341
|
+
|
|
342
|
+
else: # current changes
|
|
343
|
+
diff_cmd = "git diff HEAD | cat -"
|
|
344
|
+
|
|
345
|
+
# Execute git command and get diff output
|
|
346
|
+
diff_output = subprocess.check_output(
|
|
347
|
+
diff_cmd,
|
|
348
|
+
shell=True,
|
|
349
|
+
text=True,
|
|
350
|
+
encoding="utf-8",
|
|
351
|
+
errors="replace",
|
|
352
|
+
)
|
|
353
|
+
if not diff_output:
|
|
354
|
+
return {
|
|
355
|
+
"success": False,
|
|
356
|
+
"stdout": {},
|
|
357
|
+
"stderr": "No changes to review",
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
# Extract changed files using git command
|
|
361
|
+
files_cmd = "git diff --name-only HEAD"
|
|
362
|
+
try:
|
|
363
|
+
files_output = subprocess.check_output(files_cmd, shell=True, text=True)
|
|
364
|
+
file_paths = [f.strip() for f in files_output.split("\n") if f.strip()]
|
|
365
|
+
except subprocess.CalledProcessError:
|
|
366
|
+
# Fallback to regex extraction if git command fails
|
|
367
|
+
file_pattern = r"diff --git a/.*?\s+b/(.*?)(\n|$)"
|
|
368
|
+
files = re.findall(file_pattern, diff_output)
|
|
369
|
+
file_paths = [match[0] for match in files]
|
|
370
|
+
|
|
371
|
+
# Detect languages from the file paths
|
|
372
|
+
detected_languages = _detect_languages_from_files(file_paths)
|
|
373
|
+
|
|
374
|
+
# Add review type and related information to the diff output
|
|
375
|
+
review_info = f"""
|
|
423
376
|
----- 代码审查信息 -----
|
|
424
377
|
审查类型: {review_type}"""
|
|
425
378
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
379
|
+
# Add specific information based on review type
|
|
380
|
+
if review_type == "commit":
|
|
381
|
+
review_info += f"\n提交SHA: {args['commit_sha']}"
|
|
382
|
+
elif review_type == "range":
|
|
383
|
+
review_info += f"\n起始提交: {args['start_commit']}\n结束提交: {args['end_commit']}"
|
|
384
|
+
elif review_type == "file":
|
|
385
|
+
review_info += f"\n文件路径: {args['file_path']}"
|
|
386
|
+
else: # current changes
|
|
387
|
+
review_info += "\n当前未提交修改"
|
|
388
|
+
|
|
389
|
+
# Add file list
|
|
390
|
+
if file_paths:
|
|
391
|
+
review_info += "\n\n----- 变更文件列表 -----"
|
|
392
|
+
for i, path in enumerate(file_paths, 1):
|
|
393
|
+
review_info += f"\n{i}. {path}"
|
|
394
|
+
|
|
395
|
+
# Add language-specific checklists
|
|
396
|
+
if detected_languages:
|
|
397
|
+
review_info += "\n\n----- 检测到的编程语言 -----"
|
|
398
|
+
review_info += f"\n检测到的语言: {', '.join(detected_languages)}"
|
|
399
|
+
|
|
400
|
+
review_info += "\n\n----- 语言特定审查清单 -----"
|
|
401
|
+
for lang in detected_languages:
|
|
402
|
+
checklist = _get_language_checklist(lang)
|
|
403
|
+
if checklist:
|
|
404
|
+
review_info += f"\n{checklist}"
|
|
405
|
+
|
|
406
|
+
review_info += "\n------------------------\n\n"
|
|
407
|
+
|
|
408
|
+
# Combine review info with diff output
|
|
409
|
+
diff_output = review_info + diff_output
|
|
410
|
+
|
|
411
|
+
PrettyOutput.print(diff_output, OutputType.CODE, lang="diff") # 保留语法高亮
|
|
412
|
+
|
|
413
|
+
system_prompt = """<code_review_guide>
|
|
461
414
|
<role>
|
|
462
415
|
你是一位精益求精的首席代码审查专家,拥有多年企业级代码审计经验。你需要对所有代码变更进行极其全面、严谨且深入的审查,确保代码质量达到最高标准。
|
|
463
416
|
</role>
|
|
@@ -585,47 +538,17 @@ class CodeReviewTool:
|
|
|
585
538
|
|
|
586
539
|
我将分析上传的代码差异文件,进行全面的代码审查。
|
|
587
540
|
</code_review_guide>"""
|
|
588
|
-
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
589
541
|
|
|
590
|
-
|
|
591
|
-
|
|
542
|
+
# Get model_group from args (thinking mode removed)
|
|
543
|
+
model_group = args.get("model_group")
|
|
592
544
|
|
|
593
|
-
# Get model_group from args (thinking mode removed)
|
|
594
|
-
model_group = args.get("model_group")
|
|
595
545
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
platform_name = get_normal_platform_name(model_group)
|
|
603
|
-
model_name = get_normal_model_name(model_group)
|
|
604
|
-
|
|
605
|
-
# If no explicit parameters, try to get from existing agent
|
|
606
|
-
calling_agent = agent or get_agent(current_agent_name)
|
|
607
|
-
if (
|
|
608
|
-
not platform_name
|
|
609
|
-
and calling_agent
|
|
610
|
-
and hasattr(calling_agent, "model")
|
|
611
|
-
and calling_agent.model
|
|
612
|
-
):
|
|
613
|
-
platform_name = calling_agent.model.platform_name()
|
|
614
|
-
model_name = calling_agent.model.name()
|
|
615
|
-
|
|
616
|
-
# Create a new platform instance
|
|
617
|
-
review_model = None
|
|
618
|
-
if platform_name:
|
|
619
|
-
review_model = PlatformRegistry().create_platform(platform_name)
|
|
620
|
-
if review_model and model_name:
|
|
621
|
-
review_model.set_model_name(model_name)
|
|
622
|
-
if model_group:
|
|
623
|
-
review_model.model_group = model_group
|
|
624
|
-
|
|
625
|
-
agent = Agent(
|
|
626
|
-
system_prompt=system_prompt,
|
|
627
|
-
name="Code Review Agent",
|
|
628
|
-
summary_prompt=f"""<code_review_report>
|
|
546
|
+
agent = Agent(
|
|
547
|
+
system_prompt=system_prompt,
|
|
548
|
+
name="Code Review Agent",
|
|
549
|
+
model_group=model_group,
|
|
550
|
+
use_methodology=False,
|
|
551
|
+
summary_prompt=f"""<code_review_report>
|
|
629
552
|
<overview>
|
|
630
553
|
# 整体评估
|
|
631
554
|
[提供对整体代码质量、架构和主要关注点的简明概述,总结主要发现]
|
|
@@ -689,29 +612,23 @@ class CodeReviewTool:
|
|
|
689
612
|
{ot("REPORT")}
|
|
690
613
|
[在此处插入完整MARKDOWN格式的审查报告]
|
|
691
614
|
{ct("REPORT")}""",
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
)
|
|
615
|
+
auto_complete=args.get("auto_complete", False),
|
|
616
|
+
)
|
|
695
617
|
|
|
696
|
-
|
|
697
|
-
if review_model:
|
|
698
|
-
agent.model = review_model
|
|
618
|
+
# Agent将基于传入的 model_group 自动初始化模型,无需手动注入
|
|
699
619
|
|
|
700
|
-
|
|
701
|
-
|
|
620
|
+
# Determine if we need to split the diff due to size
|
|
621
|
+
max_diff_size = 100 * 1024 * 1024 # Limit to 100MB
|
|
702
622
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
diff_output[:max_diff_size]
|
|
710
|
-
+ "\n\n[diff content truncated due to size limitations...]"
|
|
711
|
-
)
|
|
623
|
+
if len(diff_output) > max_diff_size:
|
|
624
|
+
print(f"⚠️ 代码差异内容总大小超过限制 ({len(diff_output)} > {max_diff_size} 字节),将截断内容")
|
|
625
|
+
diff_output = (
|
|
626
|
+
diff_output[:max_diff_size]
|
|
627
|
+
+ "\n\n[diff content truncated due to size limitations...]"
|
|
628
|
+
)
|
|
712
629
|
|
|
713
|
-
|
|
714
|
-
|
|
630
|
+
# Prepare the user prompt for code review
|
|
631
|
+
user_prompt = f"""请对以下代码变更进行全面审查。
|
|
715
632
|
|
|
716
633
|
代码信息:
|
|
717
634
|
- 审查类型: {review_type}
|
|
@@ -720,45 +637,44 @@ class CodeReviewTool:
|
|
|
720
637
|
|
|
721
638
|
请根据SCRIPPPS框架和语言特定的审查清单进行分析,提供详细的代码审查报告。"""
|
|
722
639
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
)
|
|
727
|
-
|
|
728
|
-
temp_file.write(diff_output)
|
|
729
|
-
temp_file.flush()
|
|
640
|
+
# Write the full diff output to a temporary file for uploading
|
|
641
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".diff", delete=False) as temp_file:
|
|
642
|
+
temp_file_path = temp_file.name
|
|
643
|
+
temp_file.write(diff_output)
|
|
644
|
+
temp_file.flush()
|
|
730
645
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
646
|
+
try:
|
|
647
|
+
# Check if content is too large
|
|
648
|
+
platform = agent.model if agent and agent.model else None
|
|
649
|
+
is_large_content = is_context_overflow(
|
|
650
|
+
diff_output, model_group, platform
|
|
651
|
+
)
|
|
736
652
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
653
|
+
# Upload the file to the agent's model
|
|
654
|
+
if is_large_content:
|
|
655
|
+
if not agent.model or not agent.model.support_upload_files():
|
|
656
|
+
return {
|
|
657
|
+
"success": False,
|
|
658
|
+
"stdout": "",
|
|
659
|
+
"stderr": "代码差异太大,无法处理",
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
upload_success = agent.model.upload_files([temp_file_path])
|
|
663
|
+
if upload_success:
|
|
664
|
+
pass
|
|
665
|
+
else:
|
|
666
|
+
return {
|
|
667
|
+
"success": False,
|
|
668
|
+
"stdout": "",
|
|
669
|
+
"stderr": "上传代码差异文件失败",
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
# Prepare the prompt based on upload status
|
|
673
|
+
if is_large_content:
|
|
674
|
+
# When file is uploaded, reference it in the prompt
|
|
675
|
+
complete_prompt = (
|
|
676
|
+
user_prompt
|
|
677
|
+
+ f"""
|
|
762
678
|
|
|
763
679
|
我已上传了一个包含代码差异的文件。该文件包含:
|
|
764
680
|
- 审查类型: {review_type}
|
|
@@ -766,39 +682,36 @@ class CodeReviewTool:
|
|
|
766
682
|
- 检测到的编程语言: {', '.join(detected_languages) if detected_languages else '未检测到特定语言'}
|
|
767
683
|
|
|
768
684
|
请基于上传的代码差异文件进行全面审查,并生成详细的代码审查报告。"""
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
finally:
|
|
781
|
-
# Clean up the temporary file
|
|
782
|
-
if os.path.exists(temp_file_path):
|
|
783
|
-
try:
|
|
784
|
-
os.unlink(temp_file_path)
|
|
785
|
-
except Exception:
|
|
786
|
-
PrettyOutput.print(
|
|
787
|
-
f"临时文件 {temp_file_path} 未能删除",
|
|
788
|
-
OutputType.WARNING,
|
|
789
|
-
)
|
|
790
|
-
|
|
791
|
-
return {"success": True, "stdout": result, "stderr": ""}
|
|
685
|
+
)
|
|
686
|
+
# Run the agent with the prompt
|
|
687
|
+
result = agent.run(complete_prompt)
|
|
688
|
+
else:
|
|
689
|
+
complete_prompt = (
|
|
690
|
+
user_prompt
|
|
691
|
+
+ "\n\n代码差异内容:\n```diff\n"
|
|
692
|
+
+ diff_output
|
|
693
|
+
+ "\n```"
|
|
694
|
+
)
|
|
695
|
+
result = agent.run(complete_prompt)
|
|
792
696
|
finally:
|
|
793
|
-
#
|
|
794
|
-
os.
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
697
|
+
# Clean up the temporary file
|
|
698
|
+
if os.path.exists(temp_file_path):
|
|
699
|
+
try:
|
|
700
|
+
os.unlink(temp_file_path)
|
|
701
|
+
except Exception:
|
|
702
|
+
print(f"⚠️ 临时文件 {temp_file_path} 未能删除")
|
|
703
|
+
|
|
704
|
+
return {"success": True, "stdout": result, "stderr": ""}
|
|
705
|
+
finally:
|
|
706
|
+
# Always restore original directory
|
|
707
|
+
os.chdir(original_dir)
|
|
708
|
+
|
|
709
|
+
except Exception as e:
|
|
710
|
+
return {
|
|
711
|
+
"success": False,
|
|
712
|
+
"stdout": {},
|
|
713
|
+
"stderr": f"Review failed: {str(e)}",
|
|
714
|
+
}
|
|
802
715
|
|
|
803
716
|
|
|
804
717
|
def extract_code_report(result: str) -> str:
|
|
@@ -812,52 +725,50 @@ def extract_code_report(result: str) -> str:
|
|
|
812
725
|
def review_commit(
|
|
813
726
|
commit: str = typer.Argument(..., help="要审查的提交SHA"),
|
|
814
727
|
root_dir: str = typer.Option(".", "--root-dir", help="代码库根目录路径"),
|
|
815
|
-
|
|
816
728
|
model_group: Optional[str] = typer.Option(
|
|
817
729
|
None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
|
|
818
730
|
),
|
|
731
|
+
auto_complete: bool = typer.Option(False, "--auto-complete/--no-auto-complete", help="是否自动完成"),
|
|
819
732
|
):
|
|
820
733
|
"""审查指定的提交"""
|
|
821
|
-
tool = CodeReviewTool()
|
|
822
734
|
tool_args = {
|
|
823
735
|
"review_type": "commit",
|
|
824
736
|
"commit_sha": commit,
|
|
825
737
|
"root_dir": root_dir,
|
|
826
|
-
|
|
827
738
|
"model_group": model_group,
|
|
739
|
+
"auto_complete": auto_complete,
|
|
828
740
|
}
|
|
829
|
-
result =
|
|
741
|
+
result = execute_code_review(tool_args)
|
|
830
742
|
if result["success"]:
|
|
831
|
-
|
|
743
|
+
print("✅ 自动代码审查结果:")
|
|
832
744
|
report = extract_code_report(result["stdout"])
|
|
833
|
-
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
|
745
|
+
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown") # 保留语法高亮
|
|
834
746
|
else:
|
|
835
|
-
|
|
747
|
+
print(f"⚠️ {result['stderr']}")
|
|
836
748
|
|
|
837
749
|
|
|
838
750
|
@app.command("current")
|
|
839
751
|
def review_current(
|
|
840
752
|
root_dir: str = typer.Option(".", "--root-dir", help="代码库根目录路径"),
|
|
841
|
-
|
|
842
753
|
model_group: Optional[str] = typer.Option(
|
|
843
754
|
None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
|
|
844
755
|
),
|
|
756
|
+
auto_complete: bool = typer.Option(False, "--auto-complete/--no-auto-complete", help="是否自动完成"),
|
|
845
757
|
):
|
|
846
758
|
"""审查当前的变更"""
|
|
847
|
-
tool = CodeReviewTool()
|
|
848
759
|
tool_args = {
|
|
849
760
|
"review_type": "current",
|
|
850
761
|
"root_dir": root_dir,
|
|
851
|
-
|
|
852
762
|
"model_group": model_group,
|
|
763
|
+
"auto_complete": auto_complete,
|
|
853
764
|
}
|
|
854
|
-
result =
|
|
765
|
+
result = execute_code_review(tool_args)
|
|
855
766
|
if result["success"]:
|
|
856
|
-
|
|
767
|
+
print("✅ 自动代码审查结果:")
|
|
857
768
|
report = extract_code_report(result["stdout"])
|
|
858
|
-
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
|
769
|
+
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown") # 保留语法高亮
|
|
859
770
|
else:
|
|
860
|
-
|
|
771
|
+
print(f"⚠️ {result['stderr']}")
|
|
861
772
|
|
|
862
773
|
|
|
863
774
|
@app.command("range")
|
|
@@ -865,60 +776,58 @@ def review_range(
|
|
|
865
776
|
start_commit: str = typer.Argument(..., help="起始提交SHA"),
|
|
866
777
|
end_commit: str = typer.Argument(..., help="结束提交SHA"),
|
|
867
778
|
root_dir: str = typer.Option(".", "--root-dir", help="代码库根目录路径"),
|
|
868
|
-
|
|
869
779
|
model_group: Optional[str] = typer.Option(
|
|
870
780
|
None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
|
|
871
781
|
),
|
|
782
|
+
auto_complete: bool = typer.Option(False, "--auto-complete/--no-auto-complete", help="是否自动完成"),
|
|
872
783
|
):
|
|
873
784
|
"""审查提交范围"""
|
|
874
|
-
tool = CodeReviewTool()
|
|
875
785
|
tool_args = {
|
|
876
786
|
"review_type": "range",
|
|
877
787
|
"start_commit": start_commit,
|
|
878
788
|
"end_commit": end_commit,
|
|
879
789
|
"root_dir": root_dir,
|
|
880
|
-
|
|
881
790
|
"model_group": model_group,
|
|
791
|
+
"auto_complete": auto_complete,
|
|
882
792
|
}
|
|
883
|
-
result =
|
|
793
|
+
result = execute_code_review(tool_args)
|
|
884
794
|
if result["success"]:
|
|
885
|
-
|
|
795
|
+
print("✅ 自动代码审查结果:")
|
|
886
796
|
report = extract_code_report(result["stdout"])
|
|
887
|
-
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
|
797
|
+
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown") # 保留语法高亮
|
|
888
798
|
else:
|
|
889
|
-
|
|
799
|
+
print(f"⚠️ {result['stderr']}")
|
|
890
800
|
|
|
891
801
|
|
|
892
802
|
@app.command("file")
|
|
893
803
|
def review_file(
|
|
894
804
|
file: str = typer.Argument(..., help="要审查的文件路径"),
|
|
895
805
|
root_dir: str = typer.Option(".", "--root-dir", help="代码库根目录路径"),
|
|
896
|
-
|
|
897
806
|
model_group: Optional[str] = typer.Option(
|
|
898
807
|
None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
|
|
899
808
|
),
|
|
809
|
+
auto_complete: bool = typer.Option(False, "--auto-complete/--no-auto-complete", help="是否自动完成"),
|
|
900
810
|
):
|
|
901
811
|
"""审查指定的文件"""
|
|
902
|
-
tool = CodeReviewTool()
|
|
903
812
|
tool_args = {
|
|
904
813
|
"review_type": "file",
|
|
905
814
|
"file_path": file,
|
|
906
815
|
"root_dir": root_dir,
|
|
907
|
-
|
|
908
816
|
"model_group": model_group,
|
|
817
|
+
"auto_complete": auto_complete,
|
|
909
818
|
}
|
|
910
|
-
result =
|
|
819
|
+
result = execute_code_review(tool_args)
|
|
911
820
|
if result["success"]:
|
|
912
|
-
|
|
821
|
+
print("✅ 自动代码审查结果:")
|
|
913
822
|
report = extract_code_report(result["stdout"])
|
|
914
|
-
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
|
823
|
+
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown") # 保留语法高亮
|
|
915
824
|
else:
|
|
916
|
-
|
|
825
|
+
print(f"⚠️ {result['stderr']}")
|
|
917
826
|
|
|
918
827
|
|
|
919
828
|
def cli():
|
|
920
829
|
"""Typer application entry point"""
|
|
921
|
-
init_env("
|
|
830
|
+
init_env("")
|
|
922
831
|
app()
|
|
923
832
|
|
|
924
833
|
|
|
@@ -928,4 +837,4 @@ def main():
|
|
|
928
837
|
|
|
929
838
|
|
|
930
839
|
if __name__ == "__main__":
|
|
931
|
-
main()
|
|
840
|
+
main()
|