agent-Specialization/modules/file_manager/base.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

103 lines
3.8 KiB
Python

# modules/file_manager.py - 文件管理模块(添加行编辑功能)
import os
import shutil
from pathlib import Path
import re
from bisect import bisect_right
from typing import Any, Optional, Dict, List, Set, Tuple, TYPE_CHECKING
from datetime import datetime
try:
from config import (
MAX_FILE_SIZE,
FORBIDDEN_PATHS,
FORBIDDEN_ROOT_PATHS,
OUTPUT_FORMATS,
READ_TOOL_MAX_FILE_SIZE,
PROJECT_MAX_STORAGE_BYTES,
TERMINAL_SANDBOX_MODE,
LINUX_SAFETY,
)
except ImportError: # 兼容全局环境中存在同名包的情况
import sys
from pathlib import Path
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 (
MAX_FILE_SIZE,
FORBIDDEN_PATHS,
FORBIDDEN_ROOT_PATHS,
OUTPUT_FORMATS,
READ_TOOL_MAX_FILE_SIZE,
PROJECT_MAX_STORAGE_BYTES,
TERMINAL_SANDBOX_MODE,
LINUX_SAFETY,
)
from modules.container_file_proxy import ContainerFileProxy
from modules.host_sandbox_policy import get_macos_writable_paths, get_macos_readable_paths
from utils.logger import setup_logger
if TYPE_CHECKING:
from modules.user_container_manager import ContainerHandle
# 临时禁用长度检查
DISABLE_LENGTH_CHECK = True
logger = setup_logger(__name__)
class FileManagerBase:
"""FileManager 基础类,包含初始化与容器访问。"""
def __init__(self, project_path: str, container_session: Optional["ContainerHandle"] = None, data_dir: Optional[str] = None):
self.project_path = Path(project_path).resolve()
self.container_session: Optional["ContainerHandle"] = None
self._container_proxy: Optional[ContainerFileProxy] = None
self._data_dir: Optional[str] = data_dir
self.set_container_session(container_session)
def _load_personalization_config(self) -> Optional[Dict]:
"""加载个性化配置"""
if not self._data_dir:
return None
try:
from modules.personalization_manager import load_personalization_config
return load_personalization_config(self._data_dir)
except Exception:
return None
def set_container_session(self, container_session: Optional["ContainerHandle"]):
self.container_session = container_session
if (
container_session
and container_session.mode == "docker"
and container_session.container_name
):
if self._container_proxy is None:
self._container_proxy = ContainerFileProxy(container_session)
else:
self._container_proxy.update_session(container_session)
else:
self._container_proxy = None
def _use_container(self) -> bool:
return self._container_proxy is not None and self._container_proxy.is_available()
def _container_call(self, action: str, payload: Dict) -> Dict:
if not self._use_container():
return {
"success": False,
"error": "容器未就绪,无法执行文件操作"
}
return self._container_proxy.run(action, payload)
def _is_docker_mode(self) -> bool:
if self.container_session and getattr(self.container_session, "mode", None) is not None:
return getattr(self.container_session, "mode", None) == "docker"
return (TERMINAL_SANDBOX_MODE or "").lower() == "docker" or bool(LINUX_SAFETY)
def _is_host_mode(self) -> bool:
if self.container_session and getattr(self.container_session, "mode", None) is not None:
return getattr(self.container_session, "mode", None) != "docker"
return (TERMINAL_SANDBOX_MODE or "").lower() == "host"