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