r""" Load this PC's older Run events into `dbo.CV_RunEvent` (2026-10-30), once, so the Portal on Dokploy lists the Runs from before the bot copied its events to the database itself. A Run already in the table is skipped, so a second run of this tool adds nothing. python tools\import_run_events.py # import python tools\import_run_events.py --dry-run # only say what it would do Run it from PowerShell on the bot PC (Windows login to the database). """ import sys import json from datetime import datetime from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "src")) from ecw_bot import settings as cfg # noqa: E402 RUN_PREFIX = "events_" def rows_of(run_id: str, text: str) -> list: """(run_id, at, kind, line) per timed JSON line; a bad line skipped.""" out = [] for line in text.splitlines(): try: e = json.loads(line) at = datetime.fromisoformat(e["t"]) except (ValueError, KeyError, TypeError): continue out.append((run_id, at, str(e.get("kind", ""))[:40], line)) return out def main(argv) -> int: dry = "--dry-run" in argv import pyodbc conn = pyodbc.connect(cfg.RESULTS_DB_CONN, timeout=15) cur = conn.cursor() have = {r[0] for r in cur.execute( "SELECT DISTINCT run_id FROM dbo.CV_RunEvent").fetchall()} added_runs = added_rows = 0 for path in sorted(Path(cfg.LOGS).glob(f"{RUN_PREFIX}*.jsonl")): run_id = path.stem[len(RUN_PREFIX):] if run_id in have: continue rows = rows_of(run_id, path.read_text(encoding="utf-8", errors="replace")) if not rows: continue added_runs += 1 added_rows += len(rows) if not dry: cur.executemany( "INSERT INTO dbo.CV_RunEvent (run_id, at, kind, body) " "VALUES (?, ?, ?, ?)", rows) if not dry: conn.commit() conn.close() verb = "Would add" if dry else "Added" print(f"{verb} {added_runs} run(s), {added_rows} event(s); " f"{len(have)} run(s) were already in the table.") return 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))