feat: 增加shell操作
This commit is contained in:
parent
99e7de9efd
commit
22a4b8a4bb
|
|
@ -1,7 +1,7 @@
|
|||
# 配置文件
|
||||
app:
|
||||
secret_key: ${APP_SECRET_KEY}
|
||||
debug: false
|
||||
debug: true
|
||||
host: 0.0.0.0
|
||||
port: 8000
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from luxx.config import config
|
|||
engine = create_engine(
|
||||
config.database_url,
|
||||
connect_args={"check_same_thread": False} if "sqlite" in config.database_url else {},
|
||||
echo=config.debug
|
||||
echo=False
|
||||
)
|
||||
|
||||
# Create session factory
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@ from luxx.tools.builtin import crawler
|
|||
from luxx.tools.builtin import code
|
||||
from luxx.tools.builtin import data
|
||||
from luxx.tools.builtin import file
|
||||
from luxx.tools.builtin import shell
|
||||
|
||||
__all__ = ["crawler", "code", "data", "file"]
|
||||
__all__ = ["crawler", "code", "data", "file", "shell"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
"""Shell command execution tool"""
|
||||
import subprocess
|
||||
from typing import Dict, Any
|
||||
|
||||
from luxx.tools.factory import tool
|
||||
from luxx.tools.core import ToolContext, CommandPermission
|
||||
from luxx.config import config
|
||||
from pathlib import Path
|
||||
|
||||
def get_workspace_from_context(context: ToolContext) -> str:
|
||||
"""Get workspace from context, auto-create if needed"""
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
if context.workspace:
|
||||
return context.workspace
|
||||
if context.user_id is not None:
|
||||
workspace_root = Path(config.workspace_root).resolve()
|
||||
user_hash = hashlib.sha256(str(context.user_id).encode()).hexdigest()[:16]
|
||||
user_workspace = workspace_root / user_hash
|
||||
if config.workspace_auto_create and not user_workspace.exists():
|
||||
user_workspace.mkdir(parents=True, exist_ok=True)
|
||||
return str(user_workspace)
|
||||
return None
|
||||
|
||||
|
||||
@tool(
|
||||
name="shell_exec",
|
||||
description="Execute a shell command in the user's workspace directory",
|
||||
parameters={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "Shell command to execute"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "integer",
|
||||
"description": "Timeout in seconds (default 30)",
|
||||
"default": 30
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string",
|
||||
"description": "Working directory relative to workspace (default: workspace root)",
|
||||
"default": "."
|
||||
}
|
||||
},
|
||||
"required": ["command"]
|
||||
},
|
||||
required_params=["command"],
|
||||
category="shell",
|
||||
required_permission=CommandPermission.EXECUTE
|
||||
)
|
||||
def shell_exec(arguments: Dict[str, Any], context: ToolContext = None):
|
||||
"""
|
||||
Execute a shell command in the user's workspace.
|
||||
|
||||
Args:
|
||||
command: Shell command to execute
|
||||
timeout: Timeout in seconds (default 30)
|
||||
cwd: Working directory relative to workspace (default: workspace root)
|
||||
|
||||
Returns:
|
||||
{"stdout": str, "stderr": str, "returncode": int}
|
||||
"""
|
||||
workspace = get_workspace_from_context(context)
|
||||
|
||||
if not workspace:
|
||||
return {"error": "Workspace not configured"}
|
||||
|
||||
command = arguments.get("command", "")
|
||||
timeout = arguments.get("timeout", 30)
|
||||
cwd_rel = arguments.get("cwd", ".")
|
||||
|
||||
# Build working directory
|
||||
|
||||
|
||||
workspace_path = Path(workspace).resolve()
|
||||
cwd_path = (workspace_path / cwd_rel).resolve()
|
||||
|
||||
# Security check: ensure cwd is within workspace
|
||||
if not cwd_path.is_relative_to(workspace_path):
|
||||
return {"error": "Working directory is outside workspace"}
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
shell=True,
|
||||
cwd=str(cwd_path),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=min(timeout, 120) # Max 2 minutes
|
||||
)
|
||||
|
||||
return {
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr,
|
||||
"returncode": result.returncode,
|
||||
"command": command,
|
||||
"cwd": str(cwd_path.relative_to(workspace_path))
|
||||
}
|
||||
except subprocess.TimeoutExpired:
|
||||
return {"error": f"Command timed out after {timeout} seconds"}
|
||||
except Exception as e:
|
||||
return {"error": f"Execution error: {str(e)}"}
|
||||
Loading…
Reference in New Issue