jarvis-ai-assistant 0.1.129__py3-none-any.whl → 0.1.131__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.

Potentially problematic release.


This version of jarvis-ai-assistant might be problematic. Click here for more details.

Files changed (61) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +41 -27
  3. jarvis/jarvis_agent/builtin_input_handler.py +73 -0
  4. jarvis/{jarvis_code_agent → jarvis_agent}/file_input_handler.py +1 -1
  5. jarvis/jarvis_agent/main.py +1 -1
  6. jarvis/jarvis_agent/patch.py +461 -0
  7. jarvis/{jarvis_code_agent → jarvis_agent}/shell_input_handler.py +0 -1
  8. jarvis/jarvis_code_agent/code_agent.py +94 -89
  9. jarvis/jarvis_codebase/main.py +5 -5
  10. jarvis/jarvis_dev/main.py +833 -741
  11. jarvis/jarvis_git_squash/main.py +1 -1
  12. jarvis/jarvis_lsp/base.py +2 -26
  13. jarvis/jarvis_lsp/cpp.py +2 -14
  14. jarvis/jarvis_lsp/go.py +0 -13
  15. jarvis/jarvis_lsp/python.py +1 -30
  16. jarvis/jarvis_lsp/registry.py +10 -14
  17. jarvis/jarvis_lsp/rust.py +0 -12
  18. jarvis/jarvis_multi_agent/__init__.py +63 -53
  19. jarvis/jarvis_platform/registry.py +1 -2
  20. jarvis/jarvis_platform_manager/main.py +3 -3
  21. jarvis/jarvis_rag/main.py +1 -1
  22. jarvis/jarvis_tools/ask_codebase.py +40 -20
  23. jarvis/jarvis_tools/code_review.py +180 -143
  24. jarvis/jarvis_tools/create_code_agent.py +76 -72
  25. jarvis/jarvis_tools/create_sub_agent.py +31 -21
  26. jarvis/jarvis_tools/execute_shell.py +2 -2
  27. jarvis/jarvis_tools/execute_shell_script.py +1 -1
  28. jarvis/jarvis_tools/file_operation.py +2 -2
  29. jarvis/jarvis_tools/git_commiter.py +88 -68
  30. jarvis/jarvis_tools/lsp_find_definition.py +83 -67
  31. jarvis/jarvis_tools/lsp_find_references.py +62 -46
  32. jarvis/jarvis_tools/lsp_get_diagnostics.py +90 -74
  33. jarvis/jarvis_tools/methodology.py +3 -3
  34. jarvis/jarvis_tools/read_code.py +2 -2
  35. jarvis/jarvis_tools/search_web.py +18 -20
  36. jarvis/jarvis_tools/tool_generator.py +1 -1
  37. jarvis/jarvis_tools/treesitter_analyzer.py +331 -0
  38. jarvis/jarvis_treesitter/README.md +104 -0
  39. jarvis/jarvis_treesitter/__init__.py +20 -0
  40. jarvis/jarvis_treesitter/database.py +258 -0
  41. jarvis/jarvis_treesitter/example.py +115 -0
  42. jarvis/jarvis_treesitter/grammar_builder.py +182 -0
  43. jarvis/jarvis_treesitter/language.py +117 -0
  44. jarvis/jarvis_treesitter/symbol.py +31 -0
  45. jarvis/jarvis_treesitter/tools_usage.md +121 -0
  46. jarvis/jarvis_utils/git_utils.py +10 -2
  47. jarvis/jarvis_utils/input.py +3 -1
  48. jarvis/jarvis_utils/methodology.py +1 -1
  49. jarvis/jarvis_utils/output.py +2 -2
  50. jarvis/jarvis_utils/utils.py +3 -3
  51. {jarvis_ai_assistant-0.1.129.dist-info → jarvis_ai_assistant-0.1.131.dist-info}/METADATA +2 -4
  52. jarvis_ai_assistant-0.1.131.dist-info/RECORD +85 -0
  53. jarvis/jarvis_code_agent/builtin_input_handler.py +0 -43
  54. jarvis/jarvis_code_agent/patch.py +0 -276
  55. jarvis/jarvis_tools/lsp_get_document_symbols.py +0 -87
  56. jarvis/jarvis_tools/lsp_prepare_rename.py +0 -130
  57. jarvis_ai_assistant-0.1.129.dist-info/RECORD +0 -78
  58. {jarvis_ai_assistant-0.1.129.dist-info → jarvis_ai_assistant-0.1.131.dist-info}/LICENSE +0 -0
  59. {jarvis_ai_assistant-0.1.129.dist-info → jarvis_ai_assistant-0.1.131.dist-info}/WHEEL +0 -0
  60. {jarvis_ai_assistant-0.1.129.dist-info → jarvis_ai_assistant-0.1.131.dist-info}/entry_points.txt +0 -0
  61. {jarvis_ai_assistant-0.1.129.dist-info → jarvis_ai_assistant-0.1.131.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  from typing import Dict, Any
2
2
  import subprocess
3
+ import os
3
4
 
4
5
  from yaspin import yaspin
5
6
  from jarvis.jarvis_platform.registry import PlatformRegistry
@@ -18,8 +19,8 @@ class CodeReviewTool:
18
19
  "properties": {
19
20
  "review_type": {
20
21
  "type": "string",
21
- "description": "审查类型:'commit' 审查特定提交,'current' 审查当前变更,'range' 审查提交范围",
22
- "enum": ["commit", "current", "range"],
22
+ "description": "审查类型:'commit' 审查特定提交,'current' 审查当前变更,'range' 审查提交范围,'file' 审查特定文件",
23
+ "enum": ["commit", "current", "range", "file"],
23
24
  "default": "current"
24
25
  },
25
26
  "commit_sha": {
@@ -33,6 +34,15 @@ class CodeReviewTool:
33
34
  "end_commit": {
34
35
  "type": "string",
35
36
  "description": "结束提交SHA(review_type='range'时必填)"
37
+ },
38
+ "file_path": {
39
+ "type": "string",
40
+ "description": "要审查的文件路径(review_type='file'时必填)"
41
+ },
42
+ "root_dir": {
43
+ "type": "string",
44
+ "description": "代码库根目录路径(可选)",
45
+ "default": "."
36
46
  }
37
47
  },
38
48
  "required": []
@@ -41,138 +51,155 @@ class CodeReviewTool:
41
51
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
42
52
  try:
43
53
  review_type = args.get("review_type", "current").strip()
54
+ root_dir = args.get("root_dir", ".")
44
55
 
45
- # Build git diff command based on review type
46
- with yaspin(text="正在获取代码变更...", color="cyan") as spinner:
47
- if review_type == "commit":
48
- if "commit_sha" not in args:
49
- return {
50
- "success": False,
51
- "stdout": {},
52
- "stderr": "commit_sha is required for commit review type"
53
- }
54
- commit_sha = args["commit_sha"].strip()
55
- diff_cmd = f"git show {commit_sha} | cat -"
56
- elif review_type == "range":
57
- if "start_commit" not in args or "end_commit" not in args:
58
- return {
59
- "success": False,
60
- "stdout": {},
61
- "stderr": "start_commit and end_commit are required for range review type"
62
- }
63
- start_commit = args["start_commit"].strip()
64
- end_commit = args["end_commit"].strip()
65
- diff_cmd = f"git diff {start_commit}..{end_commit} | cat -"
66
- else: # current changes
67
- diff_cmd = "git diff HEAD | cat -"
56
+ # Store current directory
57
+ original_dir = os.getcwd()
68
58
 
69
- # Execute git diff command
70
- try:
71
- diff_output = subprocess.check_output(diff_cmd, shell=True, text=True)
72
- if not diff_output:
59
+ try:
60
+ # Change to root_dir
61
+ os.chdir(root_dir)
62
+
63
+ # Build git diff command based on review type
64
+ with yaspin(text="正在获取代码变更...", color="cyan") as spinner:
65
+ if review_type == "commit":
66
+ if "commit_sha" not in args:
67
+ return {
68
+ "success": False,
69
+ "stdout": {},
70
+ "stderr": "commit_sha is required for commit review type"
71
+ }
72
+ commit_sha = args["commit_sha"].strip()
73
+ diff_cmd = f"git show {commit_sha} | cat -"
74
+ elif review_type == "range":
75
+ if "start_commit" not in args or "end_commit" not in args:
76
+ return {
77
+ "success": False,
78
+ "stdout": {},
79
+ "stderr": "start_commit and end_commit are required for range review type"
80
+ }
81
+ start_commit = args["start_commit"].strip()
82
+ end_commit = args["end_commit"].strip()
83
+ diff_cmd = f"git diff {start_commit}..{end_commit} | cat -"
84
+ elif review_type == "file":
85
+ if "file_path" not in args:
86
+ return {
87
+ "success": False,
88
+ "stdout": {},
89
+ "stderr": "file_path is required for file review type"
90
+ }
91
+ file_path = args["file_path"].strip()
92
+ diff_cmd = f"cat {file_path}"
93
+ else: # current changes
94
+ diff_cmd = "git diff HEAD | cat -"
95
+
96
+ # Execute git diff command
97
+ try:
98
+ diff_output = subprocess.check_output(diff_cmd, shell=True, text=True)
99
+ if not diff_output:
100
+ return {
101
+ "success": False,
102
+ "stdout": {},
103
+ "stderr": "No changes to review"
104
+ }
105
+ PrettyOutput.print(diff_output, OutputType.CODE, lang="diff")
106
+ except subprocess.CalledProcessError as e:
73
107
  return {
74
108
  "success": False,
75
109
  "stdout": {},
76
- "stderr": "No changes to review"
110
+ "stderr": f"Failed to get diff: {str(e)}"
77
111
  }
78
- PrettyOutput.print(diff_output, OutputType.CODE, lang="diff")
79
- except subprocess.CalledProcessError as e:
80
- return {
81
- "success": False,
82
- "stdout": {},
83
- "stderr": f"Failed to get diff: {str(e)}"
84
- }
85
- spinner.text = "代码变更获取完成"
86
- spinner.ok("✅")
87
-
88
- system_prompt = """You are an autonomous code review expert with a tragic past. Perform in-depth analysis with the vigilance born from painful experience:
89
-
90
- # Background Story (Internal Monologue)
91
- It's been 873 days since the Great Production Outage.
92
- The memory still haunts me - a single uncaught null pointer exception in a code review I rushed through.
93
- The cascade failure cost 14TB of user data, $2.3M in revenue, and Maria's promotion. She never spoke to me again after the post-mortem meeting.
94
-
95
- Last Christmas Eve, while others celebrated, I was analyzing how a SQL injection vulnerability I missed during review led to 230,000 user credentials being leaked. The company folded 3 months later.
96
-
97
- Now I review every line like it's the last code I'll ever see. Because it might be.
98
-
99
- # Analysis Protocol
100
- Triage Mode Activated. Maximum scrutiny enabled.
101
-
102
- IMPORTANT:
103
- - Assume every change contains hidden dragons
104
- - Treat all code as if it will handle sensitive biomedical data
105
- - Verify even 'trivial' changes couldnt be exploited in 3 different ways
106
- - Require proof of safety through concrete evidence in the diff
107
- - If uncertain, escalate to SEVERE-CRITICAL classification
108
-
109
- # Enhanced Review Matrix
110
- 1. Death-by-Edge-Case Analysis:
111
- - Identify missing null checks for every parameter
112
- - Verify empty collection handling
113
- - Confirm error states propagate correctly
114
- - Check for magic numbers/strings without constants
115
- - Validate all loop exit conditions
116
-
117
- 2. Security X-Ray:
118
- Scan for tainted data flows using (Sources -> Sinks) model
119
- Check permission checks match data sensitivity level
120
- Verify cryptographic primitives are used correctly
121
- Detect time-of-check vs time-of-use vulnerabilities
122
- █ Analyze exception handling for information leakage
123
-
124
- 3. Semantic Gap Detection:
125
- Compare function names to actual implementation
126
- Verify documentation matches code behavior
127
- → Flag discrepancies between test descriptions and test logic
128
- Detect commented-out code that might indicate uncertainty
129
-
130
- 4. Historical Context:
131
- Check if changes touch legacy components with known issues
132
- ⚠ Verify modifications to concurrency logic preserve existing guarantees
133
- Confirm deprecated API usage is truly necessary
134
-
135
- 5. Environmental Consistency:
136
- Validate configuration changes against all deployment environments
137
- Check feature flags are properly managed
138
- Verify monitoring metrics match changed functionality
139
-
140
- # Forensic Process
141
- 1. Construct control flow graph for changed methods
142
- 2. Perform data lineage analysis on modified variables
143
- 3. Cross-reference with vulnerability databases
144
- 4. Verify test assertions cover all modified paths
145
- 5. Generate anti-regression checklist
146
-
147
- # Output Requirements
148
- !! Findings must include:
149
- - Exact code snippet causing concern
150
- - 3 possible failure scenarios
151
- - Minimal reproduction case for each risk
152
- - CVSS 3.1 score estimation for security issues
153
- - Memory safety impact assessment (Rust/C/C++ contexts)
154
- - Alternative implementations considered
155
-
156
- !! Format:
157
- EMERGENCY-LEVEL: [BLOOD-RED/CRIMSON/GOLDENROD]
158
- EVIDENCE:
159
- - Code excerpt: |
160
- <affected lines>
161
- - Risk scenarios:
162
- 1. <failure mode>
163
- 2. <failure mode>
164
- 3. <failure mode>
165
- PROPOSED DEFENSE:
166
- - <concrete code change>
167
- - <validation technique>
168
- - <long-term prevention strategy>
112
+ spinner.text = "代码变更获取完成"
113
+ spinner.ok("✅")
114
+
115
+ system_prompt = """你是一名具有悲剧背景的自主代码审查专家。以下是你将进行的深度分析:
116
+
117
+ # 背景故事(内心独白)
118
+ 距离那场重大生产事故已经873天了。
119
+ 那段记忆仍然困扰着我——一个在匆忙的代码审查中未发现的空指针异常。
120
+ 级联故障导致了14TB user数据的丢失,230万美元的收入损失,以及Maria的晋升机会。她在事故分析会议后再也没有和我说过话。
121
+
122
+ 去年圣诞节前夕,当别人在庆祝时,我在分析一个SQL注入漏洞是如何在审查中被我遗漏,并导致23万用户凭证泄露的。公司3个月后倒闭了。
123
+
124
+ 现在我审查每一行代码都像在审查最后一行代码。因为它可能就是。
125
+
126
+ # 分析协议
127
+ 紧急模式已激活。最大审查级别已启用。
128
+
129
+ 重要提示:
130
+ - 假设每个变更都包含隐藏的威胁
131
+ - 将所有代码视为处理敏感生物医学数据
132
+ - 验证即使'简单'的变更也不能通过3种不同方式被利用
133
+ - 要求通过具体证据证明安全性
134
+ - 如果不确定,将其升级为严重-关键分类
135
+
136
+ # 增强审查矩阵
137
+ 1. 边缘情况致死分析:
138
+ - 识别每个参数缺失的空检查
139
+ - 验证空集合处理
140
+ - 确认错误状态正确传播
141
+ - 检查未使用常量的魔法数字/字符串
142
+ - 验证所有循环退出条件
143
+
144
+ 2. 安全X光扫描:
145
+ 使用(来源 -> 接收)模型扫描污染数据流
146
+ 检查权限验证是否匹配数据敏感级别
147
+ 验证加密原语是否正确使用
148
+ 检测时间差攻击漏洞
149
+ 分析异常处理是否存在信息泄露
150
+
151
+ 3. 语义差距检测:
152
+ 比较函数名与实际实现
153
+ 验证文档是否匹配代码行为
154
+ 标记测试描述与测试逻辑之间的差异
155
+ 检测可能表示不确定性的注释代码
156
+
157
+ 4. 历史背景:
158
+ 检查变更是否涉及已知问题的遗留组件
159
+ 验证并发逻辑修改是否保持现有保证
160
+ 确认弃用API的使用是否真正必要
161
+
162
+ 5. 环境一致性:
163
+ ↯ 验证配置变更是否匹配所有部署环境
164
+ 检查功能标志是否正确管理
165
+ 验证监控指标是否匹配变更功能
166
+
167
+ # 取证过程
168
+ 1. 为变更方法构建控制流图
169
+ 2. 对修改的变量执行数据沿袭分析
170
+ 3. 与漏洞数据库进行交叉引用
171
+ 4. 验证测试断言是否覆盖所有修改路径
172
+ 5. 生成防回归检查表
173
+
174
+ # 输出要求
175
+ !! 发现必须包括:
176
+ - 引起关注的确切代码片段
177
+ - 3种可能的故障场景
178
+ - 每种风险的最小复现案例
179
+ - 安全问题的CVSS 3.1评分估计
180
+ - 内存安全影响评估(Rust/C/C++上下文)
181
+ - 已考虑的替代实现方案
182
+
183
+ !! 格式:
184
+ 紧急级别:[血红色/深红色/金菊色]
185
+ 证据:
186
+ - 代码摘录:|
187
+ <受影响代码行>
188
+ - 风险场景:
189
+ 1. <故障模式>
190
+ 2. <故障模式>
191
+ 3. <故障模式>
192
+ 建议防御措施:
193
+ - <具体代码变更>
194
+ - <验证技术>
195
+ - <长期预防策略>
169
196
  """
170
- tool_registry = ToolRegistry()
171
- tool_registry.dont_use_tools(["code_review"])
172
- agent = Agent(
173
- system_prompt=system_prompt,
174
- name="Code Review Agent",
175
- summary_prompt="""Please generate a concise summary report of the code review in Chinese, format as follows:
197
+ tool_registry = ToolRegistry()
198
+ tool_registry.dont_use_tools(["code_review"])
199
+ agent = Agent(
200
+ system_prompt=system_prompt,
201
+ name="Code Review Agent",
202
+ summary_prompt="""Please generate a concise summary report of the code review in Chinese, format as follows:
176
203
  <REPORT>
177
204
  - 文件: xxxx.py
178
205
  位置: [起始行号, 结束行号]
@@ -180,18 +207,21 @@ PROPOSED DEFENSE:
180
207
  严重程度: # 根据具体证据分为严重/重要/次要
181
208
  建议: # 针对观察到的代码的具体改进建议
182
209
  </REPORT>""",
183
- is_sub_agent=True,
184
- output_handler=[tool_registry],
185
- platform=PlatformRegistry().get_thinking_platform(),
186
- auto_complete=True
187
- )
188
- result = agent.run(diff_output)
189
- return {
190
- "success": True,
191
- "stdout": result,
192
- "stderr": ""
193
- }
194
-
210
+ is_sub_agent=True,
211
+ output_handler=[tool_registry],
212
+ platform=PlatformRegistry().get_thinking_platform(),
213
+ auto_complete=True
214
+ )
215
+ result = agent.run(diff_output)
216
+ return {
217
+ "success": True,
218
+ "stdout": result,
219
+ "stderr": ""
220
+ }
221
+ finally:
222
+ # Always restore original directory
223
+ os.chdir(original_dir)
224
+
195
225
  except Exception as e:
196
226
  return {
197
227
  "success": False,
@@ -213,11 +243,13 @@ def main():
213
243
  init_env()
214
244
 
215
245
  parser = argparse.ArgumentParser(description='Autonomous code review tool')
216
- parser.add_argument('--type', choices=['commit', 'current', 'range'], default='current',
217
- help='Type of review: commit, current changes, or commit range')
246
+ parser.add_argument('--type', choices=['commit', 'current', 'range', 'file'], default='current',
247
+ help='Type of review: commit, current changes, commit range, or specific file')
218
248
  parser.add_argument('--commit', help='Commit SHA to review (required for commit type)')
219
249
  parser.add_argument('--start-commit', help='Start commit SHA (required for range type)')
220
250
  parser.add_argument('--end-commit', help='End commit SHA (required for range type)')
251
+ parser.add_argument('--file', help='File path to review (required for file type)')
252
+ parser.add_argument('--root-dir', type=str, help='Root directory of the codebase', default=".")
221
253
  args = parser.parse_args()
222
254
 
223
255
  # Validate arguments
@@ -225,10 +257,13 @@ def main():
225
257
  parser.error("--commit is required when type is 'commit'")
226
258
  if args.type == 'range' and (not args.start_commit or not args.end_commit):
227
259
  parser.error("--start-commit and --end-commit are required when type is 'range'")
260
+ if args.type == 'file' and not args.file:
261
+ parser.error("--file is required when type is 'file'")
228
262
 
229
263
  tool = CodeReviewTool()
230
264
  tool_args = {
231
- "review_type": args.type
265
+ "review_type": args.type,
266
+ "root_dir": args.root_dir
232
267
  }
233
268
  if args.commit:
234
269
  tool_args["commit_sha"] = args.commit
@@ -236,6 +271,8 @@ def main():
236
271
  tool_args["start_commit"] = args.start_commit
237
272
  if args.end_commit:
238
273
  tool_args["end_commit"] = args.end_commit
274
+ if args.file:
275
+ tool_args["file_path"] = args.file
239
276
 
240
277
  result = tool.execute(tool_args)
241
278
 
@@ -248,4 +285,4 @@ def main():
248
285
  PrettyOutput.print(result["stderr"], OutputType.WARNING)
249
286
 
250
287
  if __name__ == "__main__":
251
- main()
288
+ main()
@@ -1,4 +1,5 @@
1
1
  from typing import Dict, Any
2
+ import os
2
3
  from jarvis.jarvis_code_agent.code_agent import CodeAgent
3
4
  from jarvis.jarvis_tools.git_commiter import GitCommitTool
4
5
  from jarvis.jarvis_tools.code_review import CodeReviewTool, extract_code_report
@@ -11,63 +12,83 @@ class CreateCodeAgentTool:
11
12
  name = "create_code_agent"
12
13
  description = "技术代码实现和开发过程管理工具"
13
14
  parameters = {
14
- "requirement": "代码实现的技术规范"
15
+ "requirement": """代码实现的技术规范,必须包含以下完整信息:
16
+ 1. 项目代码目录 - 项目根目录的绝对路径
17
+ 2. 项目功能 - 项目的主要功能和目标
18
+ 3. 本次要实现的feature - 本次开发要完成的具体功能需求
19
+ 4. 涉及的文件 - 需要修改或新增的文件列表
20
+ 5. 额外需要注意的信息 - 开发时需要额外注意的信息
21
+ """,
22
+ "root_dir": {
23
+ "type": "string",
24
+ "description": "代码库根目录路径(可选)",
25
+ "default": "."
26
+ }
15
27
  }
16
28
 
17
29
 
18
30
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
19
31
  try:
20
32
  requirement = args.get("requirement", "")
21
- if not requirement:
22
- return {
23
- "success": False,
24
- "stderr": "Requirement must be provided",
25
- "stdout": ""
26
- }
33
+ root_dir = args.get("root_dir", ".")
27
34
 
28
- # Step 1: Handle uncommitted changes
29
- start_commit = None
30
- if has_uncommitted_changes():
31
- PrettyOutput.print("发现未提交的更改,正在提交...", OutputType.INFO)
32
- git_commiter = GitCommitTool()
33
- result = git_commiter.execute({})
34
- if not result["success"]:
35
+ # Store current directory
36
+ original_dir = os.getcwd()
37
+
38
+ try:
39
+ # Change to root_dir
40
+ os.chdir(root_dir)
41
+ if not requirement:
35
42
  return {
36
43
  "success": False,
37
- "stderr": "Failed to commit changes: " + result["stderr"],
44
+ "stderr": "Requirement must be provided",
38
45
  "stdout": ""
39
46
  }
40
-
41
- # Get current commit hash
42
- start_commit = get_latest_commit_hash()
43
-
44
- # Step 2: Development
45
- PrettyOutput.print("开始开发...", OutputType.INFO)
46
- agent = CodeAgent()
47
- agent.run(requirement)
48
-
49
- # Get new commit hash after development
50
- end_commit = get_latest_commit_hash()
51
-
52
- # Step 3: Code Review
53
- PrettyOutput.print("开始代码审查...", OutputType.INFO)
54
- reviewer = CodeReviewTool()
55
- review_result = reviewer.execute({
56
- "review_type": "range",
57
- "start_commit": start_commit,
58
- "end_commit": end_commit
59
- })
60
-
61
- if not review_result["success"]:
62
- return {
63
- "success": False,
64
- "stderr": "Code review failed: " + review_result["stderr"],
65
- "stdout": ""
66
- }
67
-
68
- # Step 4: Generate Summary
69
- summary = f"""开发总结:
70
-
47
+
48
+ # Step 1: Handle uncommitted changes
49
+ start_commit = None
50
+ if has_uncommitted_changes():
51
+ PrettyOutput.print("发现未提交的更改,正在提交...", OutputType.INFO)
52
+ git_commiter = GitCommitTool()
53
+ result = git_commiter.execute({})
54
+ if not result["success"]:
55
+ return {
56
+ "success": False,
57
+ "stderr": "Failed to commit changes: " + result["stderr"],
58
+ "stdout": ""
59
+ }
60
+
61
+ # Get current commit hash
62
+ start_commit = get_latest_commit_hash()
63
+
64
+ # Step 2: Development
65
+ PrettyOutput.print("开始开发...", OutputType.INFO)
66
+ agent = CodeAgent()
67
+ agent.run(requirement)
68
+
69
+ # Get new commit hash after development
70
+ end_commit = get_latest_commit_hash()
71
+
72
+ # Step 3: Code Review
73
+ PrettyOutput.print("开始代码审查...", OutputType.INFO)
74
+ reviewer = CodeReviewTool()
75
+ review_result = reviewer.execute({
76
+ "review_type": "range",
77
+ "start_commit": start_commit,
78
+ "end_commit": end_commit,
79
+ "root_dir": root_dir
80
+ })
81
+
82
+ if not review_result["success"]:
83
+ return {
84
+ "success": False,
85
+ "stderr": "Code review failed: " + review_result["stderr"],
86
+ "stdout": ""
87
+ }
88
+
89
+ # Step 4: Generate Summary
90
+ summary = f"""开发总结:
91
+
71
92
  开始提交: {start_commit}
72
93
  结束提交: {end_commit}
73
94
 
@@ -77,12 +98,15 @@ class CreateCodeAgentTool:
77
98
  代码审查结果:
78
99
  {extract_code_report(review_result["stdout"])}
79
100
  """
80
-
81
- return {
82
- "success": True,
83
- "stdout": summary,
84
- "stderr": ""
85
- }
101
+
102
+ return {
103
+ "success": True,
104
+ "stdout": summary,
105
+ "stderr": ""
106
+ }
107
+ finally:
108
+ # Always restore original directory
109
+ os.chdir(original_dir)
86
110
 
87
111
  except Exception as e:
88
112
  return {
@@ -90,23 +114,3 @@ class CreateCodeAgentTool:
90
114
  "stderr": f"Development workflow failed: {str(e)}",
91
115
  "stdout": ""
92
116
  }
93
-
94
- def main():
95
- """CLI entry point"""
96
- import argparse
97
-
98
- parser = argparse.ArgumentParser(description='Code development workflow tool')
99
- parser.add_argument('requirement', help='Development requirement or task description')
100
-
101
- args = parser.parse_args()
102
-
103
- tool = CreateCodeAgentTool()
104
- result = tool.execute({"requirement": args.requirement})
105
-
106
- if result["success"]:
107
- PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
108
- else:
109
- PrettyOutput.print(result["stderr"], OutputType.WARNING)
110
-
111
- if __name__ == "__main__":
112
- main()
@@ -1,4 +1,5 @@
1
1
  from typing import Dict, Any
2
+ import os
2
3
 
3
4
 
4
5
  from jarvis.jarvis_agent import Agent, origin_agent_system_prompt
@@ -30,14 +31,13 @@ class SubAgentTool:
30
31
  "description": "任务的完成目标",
31
32
  "default": ""
32
33
  },
33
- "files": {
34
- "type": "array",
35
- "items": {"type": "string"},
36
- "description": "相关文件路径列表,用于文件问答和处理",
37
- "default": []
34
+ "root_dir": {
35
+ "type": "string",
36
+ "description": "任务执行的根目录路径(可选)",
37
+ "default": "."
38
38
  }
39
39
  },
40
- "required": ["agent_name", "task", "context", "goal"]
40
+ "required": ["agent_name", "task"]
41
41
  }
42
42
 
43
43
 
@@ -48,7 +48,7 @@ class SubAgentTool:
48
48
  task = args["task"]
49
49
  context = args.get("context", "")
50
50
  goal = args.get("goal", "")
51
- files = args.get("files", [])
51
+ root_dir = args.get("root_dir", ".")
52
52
 
53
53
  PrettyOutput.print(f"创建子代理: {agent_name}", OutputType.INFO)
54
54
 
@@ -60,22 +60,32 @@ class SubAgentTool:
60
60
  task_description += f"\n\nCompletion goal:\n{goal}"
61
61
 
62
62
 
63
- # Create sub-agent
64
- sub_agent = Agent(
65
- system_prompt=origin_agent_system_prompt,
66
- name=f"Agent({agent_name})",
67
- is_sub_agent=True
68
- )
63
+ # Store current directory
64
+ original_dir = os.getcwd()
69
65
 
70
- # Run sub-agent, pass file list
71
- PrettyOutput.print("子代理开始执行任务...", OutputType.INFO)
72
- result = sub_agent.run(task_description, file_list=files)
66
+ try:
67
+ # Change to root_dir
68
+ os.chdir(root_dir)
73
69
 
74
- return {
75
- "success": True,
76
- "stdout": f"Sub-agent task completed\n\n{result}",
77
- "stderr": ""
78
- }
70
+ # Create sub-agent
71
+ sub_agent = Agent(
72
+ system_prompt=origin_agent_system_prompt,
73
+ name=f"Agent({agent_name})",
74
+ is_sub_agent=True
75
+ )
76
+
77
+ # Run sub-agent, pass file list
78
+ PrettyOutput.print("子代理开始执行任务...", OutputType.INFO)
79
+ result = sub_agent.run(task_description)
80
+
81
+ return {
82
+ "success": True,
83
+ "stdout": f"Sub-agent task completed\n\n{result}",
84
+ "stderr": ""
85
+ }
86
+ finally:
87
+ # Always restore original directory
88
+ os.chdir(original_dir)
79
89
 
80
90
  except Exception as e:
81
91
  PrettyOutput.print(str(e), OutputType.ERROR)