agent-Specialization/modules/terminal_ops/container.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

92 lines
3.2 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 ContainerMixin:
"""TerminalOperator container 能力 mixin。"""
def _resolve_active_container_session(self) -> Optional[SimpleNamespace]:
"""
若已存在活动终端且在容器内运行,返回一个临时的容器句柄,
以便 run_command 复用同一个容器环境。
"""
manager = self._terminal_manager
if not manager:
return None
active_name = getattr(manager, "active_terminal", None)
if not active_name:
return None
terminal = manager.terminals.get(active_name) if getattr(manager, "terminals", None) else None
if not terminal or not getattr(terminal, "using_container", False):
return None
container_name = getattr(terminal, "sandbox_container_name", None)
if not container_name:
return None
try:
mount_path = (terminal.sandbox_options.get("mount_path") or "/workspace").rstrip("/") or "/workspace"
except Exception:
mount_path = "/workspace"
return SimpleNamespace(mode="docker", container_name=container_name, mount_path=mount_path)
def _will_use_container(self, session_override: Optional["ContainerHandle"]) -> bool:
"""根据会话/回退策略判断此次执行是否在容器中进行。"""
if session_override:
return getattr(session_override, "mode", None) == "docker"
if self.container_session:
return getattr(self.container_session, "mode", None) == "docker"
# 未绑定容器会话时会使用工具箱容器(同样是 Docker
return True
def _get_toolbox(self) -> ToolboxContainer:
if self._toolbox is None:
self._toolbox = ToolboxContainer(
project_path=str(self.project_path),
idle_timeout=TOOLBOX_TERMINAL_IDLE_SECONDS,
container_session=self.container_session,
)
return self._toolbox