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: """ [C: src/tool_presets.py:ToolPresetManager.delete_bias_profile, src/tool_presets.py:ToolPresetManager.delete_preset, src/tool_presets.py:ToolPresetManager.save_bias_profile, src/tool_presets.py:ToolPresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.delete_profile, src/workspace_manager.py:WorkspaceManager.save_profile] """ 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. [C: tests/test_persona_manager.py:test_delete_persona, tests/test_persona_manager.py:test_load_all_merged, tests/test_persona_manager.py:test_save_persona, tests/test_preset_manager.py:test_delete_preset, tests/test_preset_manager.py:test_load_all_merged, tests/test_preset_manager.py:test_save_preset_global, tests/test_preset_manager.py:test_save_preset_project, tests/test_presets.py:TestPresetManager.test_delete_preset, tests/test_presets.py:TestPresetManager.test_project_overwrites_global, tests/test_presets.py:TestPresetManager.test_save_and_load_global, tests/test_presets.py:TestPresetManager.test_save_and_load_project] """ 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: """ [C: tests/test_persona_manager.py:test_save_persona] """ 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: """ [C: tests/test_persona_manager.py:test_delete_persona] """ 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]: """ [C: src/presets.py:PresetManager.delete_preset, src/presets.py:PresetManager.get_preset_scope, src/presets.py:PresetManager.load_all, src/presets.py:PresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.delete_profile, src/workspace_manager.py:WorkspaceManager.load_all_profiles, src/workspace_manager.py:WorkspaceManager.save_profile] """ 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: """ [C: src/presets.py:PresetManager.delete_preset, src/presets.py:PresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.delete_profile, src/workspace_manager.py:WorkspaceManager.save_profile] """ path.parent.mkdir(parents=True, exist_ok=True) with open(path, "wb") as f: tomli_w.dump(data, f)