from __future__ import annotations import json from pathlib import Path from typing import Any from app.core.config import SERVER_DIR from app.services.agent_asset_spreadsheet import RULE_LIBRARY_NAMES JSON_RULE_MIME_TYPE = "application/json" class AgentAssetRuleLibraryManager: def __init__(self, rule_root: Path | None = None) -> None: self.rule_root = Path(rule_root or (SERVER_DIR / "rules")).resolve() def ensure_rule_library_dirs(self) -> None: for library in sorted(RULE_LIBRARY_NAMES): (self.rule_root / library).mkdir(parents=True, exist_ok=True) def resolve_rule_library_path(self, *, library: str, file_name: str) -> Path: normalized_library = str(library or "").strip() if normalized_library not in RULE_LIBRARY_NAMES: raise ValueError("Invalid rule library.") normalized_name = Path(str(file_name or "").strip()).name.strip() if not normalized_name or not normalized_name.endswith(".json"): raise ValueError("Rule JSON file name must end with .json.") library_dir = (self.rule_root / normalized_library).resolve() target_path = (library_dir / normalized_name).resolve() try: target_path.relative_to(library_dir) except ValueError: raise ValueError("Invalid rule JSON path.") from None return target_path def read_rule_library_json(self, *, library: str, file_name: str) -> dict[str, Any]: target_path = self.resolve_rule_library_path(library=library, file_name=file_name) if not target_path.exists(): raise FileNotFoundError("Rule JSON file not found.") try: payload = json.loads(target_path.read_text(encoding="utf-8")) except json.JSONDecodeError as exc: raise ValueError("Rule JSON file is invalid.") from exc if not isinstance(payload, dict): raise ValueError("Rule JSON payload must be an object.") return payload def write_rule_library_json( self, *, library: str, file_name: str, payload: dict[str, Any], ) -> dict[str, Any]: if not isinstance(payload, dict): raise ValueError("Rule JSON payload must be an object.") rule_code = str(payload.get("rule_code") or "").strip() if not rule_code: raise ValueError("Rule JSON must include rule_code.") evaluator = str(payload.get("evaluator") or "").strip() if not evaluator: raise ValueError("Rule JSON must include evaluator.") target_path = self.resolve_rule_library_path(library=library, file_name=file_name) target_path.parent.mkdir(parents=True, exist_ok=True) target_path.write_text( f"{json.dumps(payload, ensure_ascii=False, indent=2)}\n", encoding="utf-8", ) return payload def list_rule_library_json_files(self, *, library: str) -> list[str]: library_dir = self.resolve_rule_library_path( library=library, file_name="placeholder.json", ).parent library_dir.mkdir(parents=True, exist_ok=True) return sorted(path.name for path in library_dir.glob("*.json") if path.is_file())