agent-Specialization/modules/terminal_ops/command.py
JOJO f661dc6456 refactor(server,modules,utils,frontend): split oversized modules into packages and fix regressions
- Split server/chat.py, server/status.py, server/tasks.py into sub-packages
- Split utils/context_manager.py, utils/conversation_manager.py into mixin packages
- Split modules/file_manager.py, persistent_terminal.py, terminal_ops.py, mcp_client_manager.py into packages
- Split core/main_terminal_parts/context.py into base + mixins
- Split static/src/app/methods/{ui,message,upload,taskPolling,conversation} into sub-modules
- Fix flattened method exports, dynamic import paths, missing cross-module imports
- Add missing permission/network/execution mode constants and _PERMISSION_MODE_LABEL
- Update AGENTS.md, CLAUDE.md and project memories to reflect new structure
2026-06-20 15:54:48 +08:00

116 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# modules/terminal_ops.py - 终端操作模块修复Python命令检测
import os
import sys
import asyncio
import subprocess
import shutil
import time
import signal
import re
from pathlib import Path
from typing import Dict, Optional, Tuple, TYPE_CHECKING
from types import SimpleNamespace
try:
from config import (
TERMINAL_COMMAND_TIMEOUT,
FORBIDDEN_COMMANDS,
OUTPUT_FORMATS,
MAX_RUN_COMMAND_CHARS,
TOOLBOX_TERMINAL_IDLE_SECONDS,
HOST_SANDBOX_NETWORK_PERMISSION,
)
except ImportError:
project_root = Path(__file__).resolve().parents[1]
if str(project_root) not in sys.path:
sys.path.insert(0, str(project_root))
from config import (
TERMINAL_COMMAND_TIMEOUT,
FORBIDDEN_COMMANDS,
OUTPUT_FORMATS,
MAX_RUN_COMMAND_CHARS,
TOOLBOX_TERMINAL_IDLE_SECONDS,
HOST_SANDBOX_NETWORK_PERMISSION,
)
from modules.toolbox_container import ToolboxContainer
from modules.host_sandbox_runner import (
HostSandboxError,
NETWORK_PERMISSION_RESTRICTED,
build_host_sandbox_plan,
build_host_sandbox_readonly_plan,
host_sandbox_enabled,
)
if TYPE_CHECKING:
from modules.user_container_manager import ContainerHandle
from modules.terminal_manager import TerminalManager
class CommandMixin:
"""TerminalOperator command 能力 mixin。"""
def _validate_command(self, command: str) -> Tuple[bool, str]:
"""验证命令安全性"""
# 检查禁止的命令
for forbidden in FORBIDDEN_COMMANDS:
if forbidden in command.lower():
return False, f"用户不允许执行包含“{forbidden}”的指令"
# 检查危险的命令模式
dangerous_patterns = [
"sudo",
"chmod 777",
"rm -rf",
"> /dev/",
"fork bomb"
]
for pattern in dangerous_patterns:
if pattern in command.lower():
return False, f"用户不允许执行包含“{pattern}”的指令"
return True, ""
@staticmethod
def _clamp_timeout(requested: Optional[int], default: int, max_limit: int) -> int:
"""对timeout进行默认化与上限夹紧。"""
if not requested or requested <= 0:
return default
return min(int(requested), max_limit)
def _resolve_work_path(self, working_dir: Optional[str]) -> Path:
if working_dir:
work_path = (self.project_path / working_dir).resolve()
work_path.relative_to(self.project_path)
return work_path
return self.project_path
def _format_toolbox_output(self, payload: Dict) -> Dict:
success = bool(payload.get("success"))
output_text = payload.get("output", "") or ""
# 去掉常见的交互式shell警告
noisy_lines = (
"bash: cannot set terminal process group",
"bash: no job control in this shell",
)
filtered = []
for line in output_text.splitlines():
if any(noise in line for noise in noisy_lines):
continue
filtered.append(line)
output_text = "\n".join(filtered)
result = {
"success": success,
"output": output_text,
"return_code": 0 if success else -1
}
if not success:
result["error"] = payload.get("error") or payload.get("message", "命令执行失败")
if "message" in payload:
result["message"] = payload["message"]
if "status" in payload:
result["status"] = payload["status"]
if "truncated" in payload:
result["truncated"] = payload["truncated"]
return result