from __future__ import annotations import argparse import asyncio import logging import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parent if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from sync_state_machine.config import load_overrides_from_file from sync_state_machine.pipeline import run_profile_from_file def _resolve_config_path(raw_path: str) -> Path: path = Path(raw_path) if not path.is_absolute(): path = PROJECT_ROOT / path return path.resolve() async def _main() -> int: parser = argparse.ArgumentParser(description="Run sync pipeline from config override file") parser.add_argument( "--config_path", required=True, help="Path to run profile file (JSON/YAML, supports relative path, e.g. run_profiles/jsonl_to_jsonl.local.json)", ) args = parser.parse_args() cfg_path = _resolve_config_path(args.config_path) if not cfg_path.exists() or not cfg_path.is_file(): raise FileNotFoundError(f"Config file not found: {cfg_path}") print(f"🧩 Loaded config file: {cfg_path}") await run_profile_from_file( project_root=PROJECT_ROOT, config_path=cfg_path, print_summary=True, ) return 0 def main() -> int: try: return asyncio.run(_main()) except KeyboardInterrupt: print("\n⚠️ Interrupted by user") return 130 except Exception as exc: print(f"\n❌ Pipeline failed: {type(exc).__name__}: {exc}") return 1 finally: logging.shutdown() if __name__ == "__main__": raise SystemExit(main())