import json from pathlib import Path from typing import Any def load_runtime_config(path: str) -> tuple[dict[str, Any], str | None]: p = Path(path).expanduser() if not p.exists(): return {}, None try: data = json.loads(p.read_text(encoding="utf-8")) except Exception as e: return {}, f"Failed to parse config '{p}': {e}" if not isinstance(data, dict): return {}, f"Config '{p}' must be a JSON object" return data, None def save_runtime_config(path: str, config: dict[str, Any]) -> str | None: p = Path(path).expanduser() try: p.parent.mkdir(parents=True, exist_ok=True) p.write_text(json.dumps(config, indent=2, sort_keys=True), encoding="utf-8") return None except Exception as e: return f"Failed to save config '{p}': {e}" def collect_cli_overrides(argv: list[str]) -> set[str]: """ Collect option names explicitly passed on CLI, normalized to argparse dest form. Example: --focus-epics-enabled -> focus_epics_enabled """ out: set[str] = set() for token in argv[1:]: if not token.startswith("--"): continue key = token[2:] if "=" in key: key = key.split("=", 1)[0] out.add(key.replace("-", "_")) return out