jarvis-ai-assistant 0.1.125__py3-none-any.whl → 0.1.126__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 (44) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +116 -116
  3. jarvis/jarvis_code_agent/code_agent.py +96 -100
  4. jarvis/jarvis_code_agent/patch.py +39 -47
  5. jarvis/jarvis_code_agent/shell_input_handler.py +22 -0
  6. jarvis/jarvis_codebase/main.py +83 -84
  7. jarvis/jarvis_dev/main.py +691 -713
  8. jarvis/jarvis_lsp/base.py +0 -12
  9. jarvis/jarvis_lsp/cpp.py +0 -9
  10. jarvis/jarvis_lsp/go.py +0 -9
  11. jarvis/jarvis_lsp/python.py +0 -28
  12. jarvis/jarvis_lsp/registry.py +0 -1
  13. jarvis/jarvis_lsp/rust.py +0 -9
  14. jarvis/jarvis_multi_agent/__init__.py +52 -52
  15. jarvis/jarvis_tools/ask_codebase.py +6 -6
  16. jarvis/jarvis_tools/ask_user.py +2 -2
  17. jarvis/jarvis_tools/base.py +4 -4
  18. jarvis/jarvis_tools/chdir.py +8 -8
  19. jarvis/jarvis_tools/code_review.py +6 -6
  20. jarvis/jarvis_tools/create_code_agent.py +4 -4
  21. jarvis/jarvis_tools/create_sub_agent.py +7 -7
  22. jarvis/jarvis_tools/execute_shell.py +54 -21
  23. jarvis/jarvis_tools/execute_shell_script.py +3 -3
  24. jarvis/jarvis_tools/file_operation.py +36 -8
  25. jarvis/jarvis_tools/git_commiter.py +16 -16
  26. jarvis/jarvis_tools/lsp_find_definition.py +7 -7
  27. jarvis/jarvis_tools/lsp_prepare_rename.py +7 -7
  28. jarvis/jarvis_tools/methodology.py +6 -6
  29. jarvis/jarvis_tools/rag.py +5 -5
  30. jarvis/jarvis_tools/read_webpage.py +2 -2
  31. jarvis/jarvis_tools/registry.py +139 -139
  32. jarvis/jarvis_tools/search_web.py +5 -5
  33. jarvis/jarvis_tools/select_code_files.py +3 -3
  34. jarvis/jarvis_tools/tool_generator.py +33 -34
  35. jarvis/jarvis_utils/methodology.py +5 -5
  36. {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/METADATA +31 -17
  37. jarvis_ai_assistant-0.1.126.dist-info/RECORD +74 -0
  38. {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/WHEEL +1 -1
  39. jarvis/jarvis_tools/lsp_validate_edit.py +0 -141
  40. jarvis/jarvis_tools/read_code.py +0 -192
  41. jarvis_ai_assistant-0.1.125.dist-info/RECORD +0 -75
  42. {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/LICENSE +0 -0
  43. {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/entry_points.txt +0 -0
  44. {jarvis_ai_assistant-0.1.125.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/top_level.txt +0 -0
jarvis/jarvis_lsp/base.py CHANGED
@@ -125,18 +125,6 @@ class BaseLSP(ABC):
125
125
  """
126
126
  return None
127
127
 
128
- @abstractmethod
129
- def validate_edit(self, file_path: str, edit: Dict[str, Any]) -> bool:
130
- """Validate if proposed edit is syntactically correct.
131
-
132
- Args:
133
- file_path: Path to the file
134
- edit: Edit operation in LSP format
135
-
136
- Returns:
137
- bool: True if edit is valid
138
- """
139
- return False
140
128
 
141
129
  def shutdown(self):
142
130
  """Shutdown LSP server cleanly."""
jarvis/jarvis_lsp/cpp.py CHANGED
@@ -114,15 +114,6 @@ class CPPLSP(BaseLSP):
114
114
  })
115
115
  return result
116
116
 
117
- def validate_edit(self, file_path: str, edit: Dict[str, Any]) -> bool:
118
- # Send workspace/willRenameFiles request to check validity
119
- result = self._send_request("workspace/willRenameFiles", {
120
- "files": [{
121
- "oldUri": f"file://{file_path}",
122
- "newUri": f"file://{file_path}.tmp"
123
- }]
124
- })
125
- return bool(result)
126
117
 
127
118
  def shutdown(self):
128
119
  if self.clangd_process:
jarvis/jarvis_lsp/go.py CHANGED
@@ -120,15 +120,6 @@ class GoLSP(BaseLSP):
120
120
  })
121
121
  return result
122
122
 
123
- def validate_edit(self, file_path: str, edit: Dict[str, Any]) -> bool:
124
- # Send workspace/willRenameFiles request to check validity
125
- result = self._send_request("workspace/willRenameFiles", {
126
- "files": [{
127
- "oldUri": f"file://{file_path}",
128
- "newUri": f"file://{file_path}.tmp"
129
- }]
130
- })
131
- return bool(result)
132
123
 
133
124
  def shutdown(self):
134
125
  if self.gopls_process:
@@ -100,34 +100,6 @@ class PythonLSP(BaseLSP):
100
100
  return None
101
101
  return None
102
102
 
103
- def validate_edit(self, file_path: str, edit: Dict[str, Any]) -> bool:
104
- try:
105
- # Simple syntax check of the edited content
106
- content = ""
107
- with open(file_path, 'r') as f:
108
- content = f.read()
109
-
110
- # Apply edit
111
- start = edit["range"]["start"]
112
- end = edit["range"]["end"]
113
- new_text = edit["newText"]
114
-
115
- lines = content.splitlines(True)
116
- before = "".join(lines[:start["line"]])
117
- after = "".join(lines[end["line"] + 1:])
118
- current_line = lines[start["line"]]
119
-
120
- edited_line = (current_line[:start["character"]] +
121
- new_text +
122
- current_line[end["character"]:])
123
-
124
- new_content = before + edited_line + after
125
-
126
- # Check if new content is valid Python
127
- jedi.Script(code=new_content)
128
- return True
129
- except Exception:
130
- return False
131
103
 
132
104
  def shutdown(self):
133
105
  self.script_cache.clear()
@@ -14,7 +14,6 @@ REQUIRED_METHODS = [
14
14
  ('get_document_symbols', ['file_path']),
15
15
  ('get_diagnostics', ['file_path']),
16
16
  ('prepare_rename', ['file_path', 'position']),
17
- ('validate_edit', ['file_path', 'edit']),
18
17
  ('shutdown', [])
19
18
  ]
20
19
 
jarvis/jarvis_lsp/rust.py CHANGED
@@ -122,15 +122,6 @@ class RustLSP(BaseLSP):
122
122
  })
123
123
  return result
124
124
 
125
- def validate_edit(self, file_path: str, edit: Dict[str, Any]) -> bool:
126
- # Send workspace/willRenameFiles request to check validity
127
- result = self._send_request("workspace/willRenameFiles", {
128
- "files": [{
129
- "oldUri": f"file://{file_path}",
130
- "newUri": f"file://{file_path}.tmp"
131
- }]
132
- })
133
- return bool(result)
134
125
 
135
126
  def shutdown(self):
136
127
  if self.analyzer_process:
@@ -32,65 +32,65 @@ class MultiAgent(OutputHandler):
32
32
 
33
33
  def prompt(self) -> str:
34
34
  return f"""
35
- # 🤖 Message Handling System
36
- You are part of a multi-agent system that communicates through structured messages.
37
-
38
- # 🎯 Core Rules
39
- ## Critical Action Rules
40
- - Execute ONLY ONE action per turn:
41
- - Either use ONE tool (file_operation, ask_user, etc.)
42
- - OR send ONE message to another agent
43
- - NEVER combine both in same turn
44
-
45
- ## Message Flow Control
46
- - Wait for response after sending message
47
- - Process response before next action
48
- - Never send multiple messages at once
49
- - Never combine messages with tool calls
50
-
51
- # 📝 Message Format
35
+ # 🤖 多智能体消息处理系统
36
+ 您是多智能体系统的一部分,通过结构化消息进行通信。
37
+
38
+ # 🎯 核心规则
39
+ ## 关键操作规则
40
+ - 每轮只能执行一个操作:
41
+ - 要么使用一个工具(文件操作、询问用户等)
42
+ - 要么发送一条消息给其他智能体
43
+ - 切勿在同一轮中同时进行这两种操作
44
+
45
+ ## 消息流控制
46
+ - 发送消息后等待响应
47
+ - 处理响应后再进行下一步操作
48
+ - 切勿同时发送多条消息
49
+ - 切勿将消息与工具调用混合使用
50
+
51
+ # 📝 消息格式
52
52
  ```
53
53
  <SEND_MESSAGE>
54
- to: agent_name # Target agent name
54
+ to: 智能体名称 # 目标智能体名称
55
55
  content: |
56
- message_content # Message content
57
- use multiple lines # If needed
58
- with proper indentation
56
+ 消息内容 # 消息内容
57
+ 可使用多行 # 如果需要
58
+ 保持正确的缩进
59
59
  </SEND_MESSAGE>
60
60
  ```
61
61
 
62
- # 🔄 Action Sequence
63
- 1. Choose Most Important Action
64
- - Evaluate priority
65
- - Select ONE action
66
- - Execute action
62
+ # 🔄 操作顺序
63
+ 1. 选择最重要的操作
64
+ - 评估优先级
65
+ - 选择一个操作
66
+ - 执行该操作
67
67
 
68
- 2. Wait for Response
69
- - Process result/response
70
- - Plan next action
71
- - Wait for next turn
68
+ 2. 等待响应
69
+ - 处理结果/响应
70
+ - 计划下一步操作
71
+ - 等待下一轮
72
72
 
73
- 3. Handle Responses
74
- - Process incoming messages
75
- - Reply to sender when needed
76
- - Continue task based on response
73
+ 3. 处理响应
74
+ - 处理收到的消息
75
+ - 需要时回复发送者
76
+ - 根据响应继续任务
77
77
 
78
- # 👥 Available Agents
78
+ # 👥 可用智能体
79
79
  {chr(10).join([f"- {c.name}: {c.description}" for c in self.agents_config])}
80
80
 
81
- # ❗ Important Rules
82
- 1. ONE action per turn only
83
- 2. Wait for responses
84
- 3. Process before next action
85
- 4. Reply to messages
86
- 5. Forward task if needed
87
-
88
- # 💡 Tips
89
- - First action will be executed
90
- - Additional actions will be ignored
91
- - Always process responses first
92
- - Send message to continue task if needed
93
- - Handle and reply to received messages
81
+ # ❗ 重要规则
82
+ 1. 每轮只能执行一个操作
83
+ 2. 等待响应
84
+ 3. 处理后再进行下一步
85
+ 4. 回复消息
86
+ 5. 需要时转发任务
87
+
88
+ # 💡 提示
89
+ - 第一个操作将被执行
90
+ - 额外的操作将被忽略
91
+ - 总是先处理响应
92
+ - 需要时发送消息以继续任务
93
+ - 处理并回复收到的消息
94
94
  """
95
95
 
96
96
  def can_handle(self, response: str) -> bool:
@@ -161,10 +161,10 @@ from: {last_agent}
161
161
  content: {msg['content']}
162
162
  """
163
163
  if msg['to'] not in self.agents:
164
- PrettyOutput.print(f"没有找到{msg['to']},重试...", OutputType.WARNING)
165
- msg = self.agents[last_agent].run(f"The agent {msg['to']} is not found, agent list: {self.agents.keys()}")
164
+ PrettyOutput.print(f"未找到智能体 {msg['to']},正在重试...", OutputType.WARNING)
165
+ msg = self.agents[last_agent].run(f"未找到智能体 {msg['to']},可用智能体列表: {self.agents.keys()}")
166
166
  continue
167
- PrettyOutput.print(f"{last_agent} 发送消息给 {msg['to']}...", OutputType.INFO)
167
+ PrettyOutput.print(f"{last_agent} 正在向 {msg['to']} 发送消息...", OutputType.INFO)
168
168
  last_agent = self.agents[msg['to']].name
169
169
  msg = self.agents[msg['to']].run(prompt)
170
- return ""
170
+ return ""
@@ -5,20 +5,20 @@ from jarvis.jarvis_utils.git_utils import find_git_root
5
5
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
6
6
 
7
7
  class AskCodebaseTool:
8
- """Tool for intelligent codebase querying and analysis using CodeBase"""
9
-
8
+ """用于智能代码库查询和分析的工具"""
9
+
10
10
  name = "ask_codebase"
11
- description = "Ask questions about the codebase and get detailed analysis"
11
+ description = "查询代码库问题并获取详细分析"
12
12
  parameters = {
13
13
  "type": "object",
14
14
  "properties": {
15
15
  "question": {
16
16
  "type": "string",
17
- "description": "Question about the codebase"
17
+ "description": "关于代码库的问题"
18
18
  },
19
19
  "top_k": {
20
20
  "type": "integer",
21
- "description": "Number of most relevant files to analyze (optional)",
21
+ "description": "要分析的最相关文件数量(可选)",
22
22
  "default": 20
23
23
  }
24
24
  },
@@ -98,4 +98,4 @@ def main():
98
98
 
99
99
 
100
100
  if __name__ == "__main__":
101
- main()
101
+ main()
@@ -5,13 +5,13 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
5
5
 
6
6
  class AskUserTool:
7
7
  name="ask_user"
8
- description="""Ask the user when information needed to complete the task is missing or when critical decision information is lacking. Users can input multiple lines of text, ending with an empty line. Use cases: 1. Need user to provide more information to complete the task; 2. Need user to make critical decisions; 3. Need user to confirm important operations; 4. Need user to provide additional information"""
8
+ description="""当完成任务所需的信息缺失或关键决策信息不足时,向用户提问。用户可以输入多行文本,以空行结束。使用场景:1. 需要用户提供更多信息以完成任务;2. 需要用户做出关键决策;3. 需要用户确认重要操作;4. 需要用户提供额外信息"""
9
9
  parameters={
10
10
  "type": "object",
11
11
  "properties": {
12
12
  "question": {
13
13
  "type": "string",
14
- "description": "The question to ask the user"
14
+ "description": "要向用户提出的问题"
15
15
  }
16
16
  },
17
17
  "required": ["question"]
@@ -7,7 +7,7 @@ class Tool:
7
7
  """
8
8
  初始化工具对象
9
9
 
10
- Args:
10
+ 参数:
11
11
  name (str): 工具名称
12
12
  description (str): 工具描述
13
13
  parameters (Dict): 工具参数定义
@@ -28,10 +28,10 @@ class Tool:
28
28
  """
29
29
  执行工具函数
30
30
 
31
- Args:
31
+ 参数:
32
32
  arguments (Dict): 工具执行所需的参数
33
33
 
34
- Returns:
34
+ 返回:
35
35
  Dict[str, Any]: 工具执行结果
36
36
  """
37
- return self.func(arguments)
37
+ return self.func(arguments)
@@ -3,13 +3,13 @@ import os
3
3
 
4
4
  class ChdirTool:
5
5
  name = "chdir"
6
- description = "Change current working directory"
6
+ description = "更改当前工作目录"
7
7
  parameters = {
8
8
  "type": "object",
9
9
  "properties": {
10
10
  "path": {
11
11
  "type": "string",
12
- "description": "Directory path to switch to, supports both relative and absolute paths"
12
+ "description": "要切换到的目录路径,支持相对路径和绝对路径"
13
13
  }
14
14
  },
15
15
  "required": ["path"]
@@ -45,7 +45,7 @@ class ChdirTool:
45
45
  return {
46
46
  "success": False,
47
47
  "stdout": "",
48
- "stderr": f"Directory does not exist: {path}"
48
+ "stderr": f"目录不存在: {path}"
49
49
  }
50
50
 
51
51
  # Ensure the path points to a directory, not a file
@@ -53,7 +53,7 @@ class ChdirTool:
53
53
  return {
54
54
  "success": False,
55
55
  "stdout": "",
56
- "stderr": f"The path is not a directory: {path}"
56
+ "stderr": f"路径不是目录: {path}"
57
57
  }
58
58
 
59
59
  # Capture current directory and attempt to change to new path
@@ -62,7 +62,7 @@ class ChdirTool:
62
62
 
63
63
  return {
64
64
  "success": True,
65
- "stdout": f"Changed working directory:\nFrom: {old_path}\nTo: {path}",
65
+ "stdout": f"成功切换工作目录:\n原目录: {old_path}\n新目录: {path}",
66
66
  "stderr": ""
67
67
  }
68
68
 
@@ -71,12 +71,12 @@ class ChdirTool:
71
71
  return {
72
72
  "success": False,
73
73
  "stdout": "",
74
- "stderr": f"No permission to access directory: {path}"
74
+ "stderr": f"无权限访问目录: {path}"
75
75
  }
76
76
  # Catch-all for any other unexpected errors during directory change
77
77
  except Exception as e:
78
78
  return {
79
79
  "success": False,
80
80
  "stdout": "",
81
- "stderr": f"Failed to switch directory: {str(e)}"
82
- }
81
+ "stderr": f"切换目录失败: {str(e)}"
82
+ }
@@ -10,27 +10,27 @@ from jarvis.jarvis_utils.utils import init_env
10
10
 
11
11
  class CodeReviewTool:
12
12
  name = "code_review"
13
- description = "Autonomous code review agent for code changes analysis"
13
+ description = "自动代码审查工具,用于分析代码变更"
14
14
  parameters = {
15
15
  "type": "object",
16
16
  "properties": {
17
17
  "review_type": {
18
18
  "type": "string",
19
- "description": "Type of review: 'commit' for specific commit, 'current' for current changes, 'range' for commit range",
19
+ "description": "审查类型:'commit' 审查特定提交,'current' 审查当前变更,'range' 审查提交范围",
20
20
  "enum": ["commit", "current", "range"],
21
21
  "default": "current"
22
22
  },
23
23
  "commit_sha": {
24
24
  "type": "string",
25
- "description": "Target commit SHA to analyze (required for review_type='commit')"
25
+ "description": "要分析的提交SHAreview_type='commit'时必填)"
26
26
  },
27
27
  "start_commit": {
28
28
  "type": "string",
29
- "description": "Start commit SHA (required for review_type='range')"
29
+ "description": "起始提交SHAreview_type='range'时必填)"
30
30
  },
31
31
  "end_commit": {
32
32
  "type": "string",
33
- "description": "End commit SHA (required for review_type='range')"
33
+ "description": "结束提交SHAreview_type='range'时必填)"
34
34
  }
35
35
  },
36
36
  "required": []
@@ -243,4 +243,4 @@ def main():
243
243
  PrettyOutput.print(result["stderr"], OutputType.WARNING)
244
244
 
245
245
  if __name__ == "__main__":
246
- main()
246
+ main()
@@ -6,12 +6,12 @@ from jarvis.jarvis_utils.git_utils import get_latest_commit_hash, has_uncommitte
6
6
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
7
7
 
8
8
  class CreateCodeAgentTool:
9
- """Tool for managing the code development workflow."""
9
+ """用于管理代码开发工作流的工具"""
10
10
 
11
11
  name = "create_code_agent"
12
- description = "Technical code implementation and development process management"
12
+ description = "技术代码实现和开发过程管理工具"
13
13
  parameters = {
14
- "requirement": "Technical specifications for code implementation"
14
+ "requirement": "代码实现的技术规范"
15
15
  }
16
16
 
17
17
 
@@ -109,4 +109,4 @@ def main():
109
109
  PrettyOutput.print(result["stderr"], OutputType.WARNING)
110
110
 
111
111
  if __name__ == "__main__":
112
- main()
112
+ main()
@@ -8,32 +8,32 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
8
8
 
9
9
  class SubAgentTool:
10
10
  name = "create_sub_agent"
11
- description = "Create a sub-agent to handle specific tasks, the sub-agent will generate a task summary report"
11
+ description = "创建子代理以处理特定任务,子代理将生成任务总结报告"
12
12
  parameters = {
13
13
  "type": "object",
14
14
  "properties": {
15
15
  "agent_name": {
16
16
  "type": "string",
17
- "description": "Sub-agent name"
17
+ "description": "子代理名称"
18
18
  },
19
19
  "task": {
20
20
  "type": "string",
21
- "description": "Specific task to complete"
21
+ "description": "要完成的特定任务"
22
22
  },
23
23
  "context": {
24
24
  "type": "string",
25
- "description": "Context information related to the task",
25
+ "description": "与任务相关的上下文信息",
26
26
  "default": ""
27
27
  },
28
28
  "goal": {
29
29
  "type": "string",
30
- "description": "Completion goal of the task",
30
+ "description": "任务的完成目标",
31
31
  "default": ""
32
32
  },
33
33
  "files": {
34
34
  "type": "array",
35
35
  "items": {"type": "string"},
36
- "description": "Related file path list, used for file question answering and processing",
36
+ "description": "相关文件路径列表,用于文件问答和处理",
37
37
  "default": []
38
38
  }
39
39
  },
@@ -83,4 +83,4 @@ class SubAgentTool:
83
83
  "success": False,
84
84
  "stdout": "",
85
85
  "stderr": f"Sub-agent execution failed: {str(e)}"
86
- }
86
+ }
@@ -1,57 +1,89 @@
1
+ # Shell command execution module
2
+ #
3
+ # Provides functionality to execute shell commands safely with:
4
+ # - Command escaping
5
+ # - Output capturing
6
+ # - Temporary file management
7
+ # - Error handling
1
8
  from typing import Dict, Any
2
9
  import os
3
10
  import tempfile
4
11
  from pathlib import Path
5
-
6
12
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
7
-
8
-
9
-
10
-
11
13
  class ShellTool:
14
+ """Shell command execution tool
15
+
16
+ Attributes:
17
+ name: Tool identifier used in API
18
+ description: Tool description for API documentation
19
+ parameters: JSON schema for command parameters
20
+ """
12
21
  name = "execute_shell"
13
- description = """Execute shell command and return result"""
14
-
22
+ description = "执行Shell命令并返回结果"
15
23
  parameters = {
16
24
  "type": "object",
17
25
  "properties": {
18
26
  "command": {
19
27
  "type": "string",
20
- "description": "Shell command to execute"
28
+ "description": "要执行的Shell命令"
21
29
  }
22
30
  },
23
31
  "required": ["command"]
24
32
  }
25
-
26
-
27
33
  def _escape_command(self, cmd: str) -> str:
28
- """Escape special characters in command"""
34
+ """Escape special characters in command to prevent shell injection
35
+
36
+ Args:
37
+ cmd: Raw command string
38
+
39
+ Returns:
40
+ Escaped command string with single quotes properly handled
41
+ """
29
42
  return cmd.replace("'", "'\"'\"'")
30
-
31
43
  def execute(self, args: Dict) -> Dict[str, Any]:
32
- """Execute shell command"""
44
+ """Execute shell command and capture output
45
+
46
+ Steps:
47
+ 1. Validate and clean input command
48
+ 2. Create temporary file for output capture
49
+ 3. Execute command with output redirection
50
+ 4. Read and process output file
51
+ 5. Clean up temporary resources
52
+ 6. Return structured results
53
+
54
+ Args:
55
+ args: Dictionary containing 'command' parameter
56
+
57
+ Returns:
58
+ Dictionary with:
59
+ - success: Boolean indicating command execution status
60
+ - stdout: Command output
61
+ - stderr: Error message if execution failed
62
+ """
33
63
  try:
64
+ # Get and clean command input
34
65
  command = args["command"].strip()
35
66
 
36
- # Generate temporary file name
67
+ # Generate temporary file name using process ID for uniqueness
37
68
  output_file = os.path.join(tempfile.gettempdir(), f"jarvis_shell_{os.getpid()}.log")
38
69
 
39
- # Escape special characters in command
70
+ # Escape special characters in command to prevent injection
40
71
  escaped_command = self._escape_command(command)
41
72
 
42
- # Modify command to use script
73
+ # Use script command to capture both stdout and stderr
43
74
  tee_command = f"script -q -c '{escaped_command}' {output_file}"
44
75
 
76
+ # Log command execution
45
77
  PrettyOutput.print(f"执行命令: {command}", OutputType.INFO)
46
78
 
47
- # Execute command
79
+ # Execute command and capture return code
48
80
  return_code = os.system(tee_command)
49
81
 
50
- # Read output file
82
+ # Read and process output file
51
83
  try:
52
84
  with open(output_file, 'r', encoding='utf-8', errors='replace') as f:
53
85
  output = f.read()
54
- # Remove header and footer added by script
86
+ # Remove header and footer added by script command
55
87
  if output:
56
88
  lines = output.splitlines()
57
89
  if len(lines) > 2:
@@ -62,6 +94,7 @@ class ShellTool:
62
94
  # Clean up temporary file
63
95
  Path(output_file).unlink(missing_ok=True)
64
96
 
97
+ # Return successful result
65
98
  return {
66
99
  "success": True,
67
100
  "stdout": output,
@@ -69,7 +102,7 @@ class ShellTool:
69
102
  }
70
103
 
71
104
  except Exception as e:
72
- # Ensure temporary file is cleaned up
105
+ # Ensure temporary file is cleaned up even if error occurs
73
106
  if 'output_file' in locals():
74
107
  Path(output_file).unlink(missing_ok=True)
75
108
  PrettyOutput.print(str(e), OutputType.ERROR)
@@ -77,4 +110,4 @@ class ShellTool:
77
110
  "success": False,
78
111
  "stdout": "",
79
112
  "stderr": str(e)
80
- }
113
+ }
@@ -8,13 +8,13 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
8
8
 
9
9
  class ShellScriptTool:
10
10
  name = "execute_shell_script"
11
- description = """Execute shell script file and return result"""
11
+ description = "执行Shell脚本文件并返回结果"
12
12
  parameters = {
13
13
  "type": "object",
14
14
  "properties": {
15
15
  "script_content": {
16
16
  "type": "string",
17
- "description": "Content of the shell script to execute"
17
+ "description": "要执行的Shell脚本内容"
18
18
  }
19
19
  },
20
20
  "required": ["script_content"]
@@ -55,4 +55,4 @@ class ShellScriptTool:
55
55
  "success": False,
56
56
  "stdout": "",
57
57
  "stderr": str(e)
58
- }
58
+ }