import tomllib import tomli_w from pathlib import Path from typing import Dict, Any, Optional from src.models import Persona from src import paths class PersonaManager: """Manages Persona profiles across global and project-specific files.""" def __init__(self, project_root: Optional[Path] = None): self.project_root = project_root def _get_path(self, scope: str) -> Path: if scope == "global": return paths.get_global_personas_path() elif scope == "project": if not self.project_root: raise ValueError("Project root is not set, cannot resolve project scope.") return paths.get_project_personas_path(self.project_root) else: raise ValueError("Invalid scope, must be 'global' or 'project'") def load_all(self) -> Dict[str, Persona]: """Merges global and project personas into a single dictionary.""" personas = {} global_path = paths.get_global_personas_path() global_data = self._load_file(global_path) for name, data in global_data.get("personas", {}).items(): personas[name] = Persona.from_dict(name, data) if self.project_root: project_path = paths.get_project_personas_path(self.project_root) project_data = self._load_file(project_path) for name, data in project_data.get("personas", {}).items(): personas[name] = Persona.from_dict(name, data) return personas def save_persona(self, persona: Persona, scope: str = "project") -> None: path = self._get_path(scope) data = self._load_file(path) if "personas" not in data: data["personas"] = {} data["personas"][persona.name] = persona.to_dict() self._save_file(path, data) def get_persona_scope(self, name: str) -> str: """Returns the scope ('global' or 'project') of a persona by name.""" if self.project_root: project_path = paths.get_project_personas_path(self.project_root) project_data = self._load_file(project_path) if name in project_data.get("personas", {}): return "project" global_path = paths.get_global_personas_path() global_data = self._load_file(global_path) if name in global_data.get("personas", {}): return "global" return "project" def delete_persona(self, name: str, scope: str = "project") -> None: path = self._get_path(scope) data = self._load_file(path) if "personas" in data and name in data["personas"]: del data["personas"][name] self._save_file(path, data) def _load_file(self, path: Path) -> Dict[str, Any]: if not path.exists(): return {} try: with open(path, "rb") as f: return tomllib.load(f) except Exception: return {} def _save_file(self, path: Path, data: Dict[str, Any]) -> None: path.parent.mkdir(parents=True, exist_ok=True) with open(path, "wb") as f: tomli_w.dump(data, f)