mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-05-21 23:46:50 +00:00
feat: add sandbox and local impl
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
from .local_sandbox_provider import LocalSandboxProvider
|
||||
|
||||
__all__ = ["LocalSandboxProvider"]
|
||||
@@ -0,0 +1,116 @@
|
||||
import fnmatch
|
||||
from pathlib import Path
|
||||
|
||||
IGNORE_PATTERNS = [
|
||||
# Version Control
|
||||
".git",
|
||||
".svn",
|
||||
".hg",
|
||||
".bzr",
|
||||
# Dependencies
|
||||
"node_modules",
|
||||
"__pycache__",
|
||||
".venv",
|
||||
"venv",
|
||||
".env",
|
||||
"env",
|
||||
".tox",
|
||||
".nox",
|
||||
".eggs",
|
||||
"*.egg-info",
|
||||
"site-packages",
|
||||
# Build outputs
|
||||
"dist",
|
||||
"build",
|
||||
".next",
|
||||
".nuxt",
|
||||
".output",
|
||||
".turbo",
|
||||
"target",
|
||||
"out",
|
||||
# IDE & Editor
|
||||
".idea",
|
||||
".vscode",
|
||||
"*.swp",
|
||||
"*.swo",
|
||||
"*~",
|
||||
".project",
|
||||
".classpath",
|
||||
".settings",
|
||||
# OS generated
|
||||
".DS_Store",
|
||||
"Thumbs.db",
|
||||
"desktop.ini",
|
||||
"*.lnk",
|
||||
# Logs & temp files
|
||||
"*.log",
|
||||
"*.tmp",
|
||||
"*.temp",
|
||||
"*.bak",
|
||||
"*.cache",
|
||||
".cache",
|
||||
"logs",
|
||||
# Coverage & test artifacts
|
||||
".coverage",
|
||||
"coverage",
|
||||
".nyc_output",
|
||||
"htmlcov",
|
||||
".pytest_cache",
|
||||
".mypy_cache",
|
||||
".ruff_cache",
|
||||
]
|
||||
|
||||
|
||||
def _should_ignore(name: str) -> bool:
|
||||
"""Check if a file/directory name matches any ignore pattern."""
|
||||
for pattern in IGNORE_PATTERNS:
|
||||
if fnmatch.fnmatch(name, pattern):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def list_dir(path: str, max_depth: int = 2) -> list[str]:
|
||||
"""
|
||||
List files and directories up to max_depth levels deep.
|
||||
|
||||
Args:
|
||||
path: The root directory path to list.
|
||||
max_depth: Maximum depth to traverse (default: 2).
|
||||
1 = only direct children, 2 = children + grandchildren, etc.
|
||||
|
||||
Returns:
|
||||
A list of absolute paths for files and directories,
|
||||
excluding items matching IGNORE_PATTERNS.
|
||||
"""
|
||||
result: list[str] = []
|
||||
root_path = Path(path).resolve()
|
||||
|
||||
if not root_path.is_dir():
|
||||
return result
|
||||
|
||||
def _traverse(current_path: Path, current_depth: int) -> None:
|
||||
"""Recursively traverse directories up to max_depth."""
|
||||
if current_depth > max_depth:
|
||||
return
|
||||
|
||||
try:
|
||||
for item in current_path.iterdir():
|
||||
if _should_ignore(item.name):
|
||||
continue
|
||||
|
||||
post_fix = "/" if item.is_dir() else ""
|
||||
result.append(str(item.resolve()) + post_fix)
|
||||
|
||||
# Recurse into subdirectories if not at max depth
|
||||
if item.is_dir() and current_depth < max_depth:
|
||||
_traverse(item, current_depth + 1)
|
||||
except PermissionError:
|
||||
pass
|
||||
|
||||
_traverse(root_path, 1)
|
||||
|
||||
return sorted(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\n".join(list_dir("/Users/Henry/Desktop", max_depth=2)))
|
||||
@@ -0,0 +1,46 @@
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from src.sandbox.local.list_dir import list_dir
|
||||
from src.sandbox.sandbox import Sandbox
|
||||
|
||||
|
||||
class LocalSandbox(Sandbox):
|
||||
def __init__(self, id: str):
|
||||
super().__init__(id)
|
||||
|
||||
def execute_command(self, command: str) -> str:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
executable="/bin/zsh",
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
)
|
||||
output = result.stdout
|
||||
if result.stderr:
|
||||
output += f"\nStd Error:\n{result.stderr}" if output else result.stderr
|
||||
if result.returncode != 0:
|
||||
output += f"\nExit Code: {result.returncode}"
|
||||
return output if output else "(no output)"
|
||||
|
||||
def list_dir(self, path: str, max_depth=2) -> list[str]:
|
||||
return list_dir(path, max_depth)
|
||||
|
||||
def read_file(self, path: str) -> str:
|
||||
with open(path, "r") as f:
|
||||
return f.read()
|
||||
|
||||
def write_file(self, path: str, content: str, append: bool = False) -> None:
|
||||
dir_path = os.path.dirname(path)
|
||||
if dir_path:
|
||||
os.makedirs(dir_path, exist_ok=True)
|
||||
mode = "a" if append else "w"
|
||||
with open(path, mode) as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sandbox = LocalSandbox("test")
|
||||
print(sandbox.list_dir("/Users/Henry/mnt"))
|
||||
@@ -0,0 +1,21 @@
|
||||
from src.sandbox.local.local_sandbox import LocalSandbox
|
||||
from src.sandbox.sandbox import Sandbox
|
||||
from src.sandbox.sandbox_provider import SandboxProvider
|
||||
|
||||
_singleton: LocalSandbox | None = None
|
||||
|
||||
|
||||
class LocalSandboxProvider(SandboxProvider):
|
||||
def acquire(self) -> Sandbox:
|
||||
global _singleton
|
||||
if _singleton is None:
|
||||
_singleton = LocalSandbox("local")
|
||||
return _singleton.id
|
||||
|
||||
def get(self, sandbox_id: str) -> None:
|
||||
if _singleton is None:
|
||||
self.acquire()
|
||||
return _singleton
|
||||
|
||||
def release(self, sandbox_id: str) -> None:
|
||||
pass
|
||||
Reference in New Issue
Block a user