from __future__ import annotations from datetime import datetime, timezone import json from pathlib import Path from typing import Any def utc_now_iso() -> str: """Return current UTC time in ISO-8601 format.""" return datetime.now(timezone.utc).isoformat() def log(message: str) -> None: """Print a timestamped log line.""" print(f"[{utc_now_iso()}] {message}") def get_workspace_root(current_file: str | Path) -> Path: """Infer workspace root from a script path inside code/.""" current = Path(current_file).resolve() return current.parents[1] def get_prompt_dir(workspace_root: Path, prompt_folder: str) -> Path: """Resolve prompts/ directory safely.""" folder = prompt_folder.strip().strip("/") if not folder: raise ValueError("Prompt folder argument is empty") target = (workspace_root / "prompts" / folder).resolve() prompts_root = (workspace_root / "prompts").resolve() if prompts_root not in target.parents and target != prompts_root: raise ValueError("Prompt folder escapes prompts root") if not target.exists() or not target.is_dir(): raise FileNotFoundError(f"Prompt folder not found: {target}") return target def read_prompt_texts(prompt_dir: Path) -> dict[str, str]: """Read all .txt files from prompt directory.""" result: dict[str, str] = {} for txt_file in sorted(prompt_dir.glob("*.txt")): result[txt_file.name] = txt_file.read_text(encoding="utf-8") return result def read_json(path: Path, default: Any = None) -> Any: """Read JSON file; return default when missing.""" if not path.exists(): return default return json.loads(path.read_text(encoding="utf-8")) def write_json(path: Path, data: Any) -> None: """Write JSON with stable formatting.""" path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(data, indent=2, sort_keys=True), encoding="utf-8")