atypique-api / core /workspace_manager.py
RDS777's picture
Backend v3.0 complet
8e3a425
Raw
History Blame Contribute Delete
2.3 kB
# core/workspace_manager.py
"""
Gestionnaire de l’espace de travail VORTEX.
Permet de lire, écrire, lister et exécuter des fichiers dans un dossier dédié.
"""
import os
import subprocess
import tempfile
from pathlib import Path
WORKSPACE = Path(os.environ.get("VORTEX_WORKSPACE", "/app/workspace"))
WORKSPACE.mkdir(parents=True, exist_ok=True)
class WorkspaceManager:
@staticmethod
def read_file(path: str) -> str:
"""Lit un fichier et retourne son contenu."""
full_path = WORKSPACE / path
if not full_path.exists():
return f"[Erreur] Fichier {path} introuvable."
try:
return full_path.read_text(encoding="utf-8")
except Exception as e:
return f"[Erreur] {e}"
@staticmethod
def write_file(path: str, content: str) -> str:
"""Écrit ou écrase un fichier."""
full_path = WORKSPACE / path
full_path.parent.mkdir(parents=True, exist_ok=True)
full_path.write_text(content, encoding="utf-8")
return f"✅ Fichier {path} écrit ({len(content)} caractères)."
@staticmethod
def list_files(extension: str = "") -> list:
"""Liste les fichiers du workspace (filtre optionnel par extension)."""
pattern = f"*{extension}" if extension else "*"
return [str(p.relative_to(WORKSPACE)) for p in WORKSPACE.glob(pattern) if p.is_file()]
@staticmethod
def run_file(path: str, timeout: int = 30) -> dict:
"""Exécute un fichier Python dans le workspace et retourne le résultat."""
full_path = WORKSPACE / path
if not full_path.exists():
return {"success": False, "error": f"Fichier {path} introuvable."}
try:
proc = subprocess.run(
["python3", str(full_path)],
capture_output=True,
text=True,
timeout=timeout,
cwd=str(WORKSPACE)
)
return {
"success": proc.returncode == 0,
"stdout": proc.stdout[:2000],
"stderr": proc.stderr[:500]
}
except subprocess.TimeoutExpired:
return {"success": False, "error": "Timeout"}
except Exception as e:
return {"success": False, "error": str(e)}