1"""Authentic screenshot capture with a manifest (no synthetic imagery).2Modes: native_live (a real Terminal/Safari window via /usr/sbin/screencapture -l <windowid>), dashboard_live (Safari showing the3evidence viewer while runs execute), viewer_postrun (same viewer after runs), transcript_replay (not used unless labelled).4Each capture records tool+version, surface, UTC time, SHA-256, linked run/event ids, selection rule and caption."""5from __future__ import annotations6import hashlib, json, os, subprocess, datetime, re7from .contracts import utcnow89def _sha(p):10 return hashlib.sha256(open(p, "rb").read()).hexdigest()1112def window_id(app_name: str, title_substring: str = "") -> int | None:13 """Find a CGWindow id of a visible window of `app_name` (optionally with a title substring) via a tiny Swift-free route: osascript + python Quartz."""14 try:15 import Quartz # type: ignore16 wins = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionOnScreenOnly | Quartz.kCGWindowListExcludeDesktopElements, Quartz.kCGNullWindowID)17 for w in wins:18 if w.get("kCGWindowOwnerName") == app_name and (title_substring in (w.get("kCGWindowName") or "")) and w.get("kCGWindowLayer", 0) == 0:19 return int(w["kCGWindowNumber"])20 except Exception: # noqa: BLE00121 pass22 # fallback: osascript (System Events) cannot give CGWindow ids reliably; return None23 return None2425def capture_window(wid: int, out_path: str) -> bool:26 os.makedirs(os.path.dirname(out_path), exist_ok=True)27 r = subprocess.run(["/usr/sbin/screencapture", "-x", "-o", "-l", str(wid), out_path], capture_output=True)28 return r.returncode == 0 and os.path.exists(out_path) and os.path.getsize(out_path) > 02930def capture_screen(out_path: str) -> bool:31 os.makedirs(os.path.dirname(out_path), exist_ok=True)32 r = subprocess.run(["/usr/sbin/screencapture", "-x", out_path], capture_output=True)33 return r.returncode == 0 and os.path.exists(out_path)3435def tool_version() -> str:36 try:37 v = subprocess.run(["sw_vers", "-productVersion"], capture_output=True, text=True).stdout.strip()38 return f"/usr/sbin/screencapture (macOS {v})"39 except Exception: # noqa: BLE00140 return "/usr/sbin/screencapture"4142def record(store, screenshot_id, path, mode, surface, run_id=None, task_id=None, treatment=None, phase=None, event_id=None, selection_rule="", caption="", claim_ids="", redaction="none"):43 rec = {"screenshot_id": screenshot_id, "run_id": run_id, "task_id": task_id, "treatment": treatment, "phase": phase, "event_id": event_id,44 "capture_timestamp_utc": utcnow(), "capture_mode": mode, "capture_tool": tool_version(), "source_surface": surface,45 "original_path": path, "original_sha256": _sha(path), "redacted_public_path": None, "redacted_sha256": None,46 "redaction_description": redaction, "selection_rule": selection_rule, "caption": caption, "claim_ids": claim_ids}47 store.add_screenshot(rec)48 return rec4950def publish(store, screenshot_id, public_path, crop=None, description="copied without modification"):51 """Create the public copy (optionally cropped with sips) and record its hash."""52 row = store.query("SELECT original_path FROM screenshots WHERE screenshot_id=?", (screenshot_id,))[0]53 os.makedirs(os.path.dirname(public_path), exist_ok=True)54 if crop:55 x, y, w, h = crop56 subprocess.run(["sips", "-c", str(h), str(w), "--cropOffset", str(y), str(x), row["original_path"], "--out", public_path], capture_output=True, check=True)57 else:58 subprocess.run(["cp", row["original_path"], public_path], check=True)59 with store.tx() as c:60 c.execute("UPDATE screenshots SET redacted_public_path=?, redacted_sha256=?, redaction_description=? WHERE screenshot_id=?", (public_path, _sha(public_path), description, screenshot_id))61 return public_path6263def window_bounds(wid: int):64 import Quartz # type: ignore65 for w in Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID):66 if int(w["kCGWindowNumber"]) == wid:67 b = w["kCGWindowBounds"]; return int(b["X"]), int(b["Y"]), int(b["Width"]), int(b["Height"])68 return None6970def capture_region(bounds, out_path: str) -> bool:71 """Composited screen capture of a rectangle (used for Safari, whose web content is not captured by -l window capture)."""72 x, y, w, h = bounds; os.makedirs(os.path.dirname(out_path), exist_ok=True)73 r = subprocess.run(["/usr/sbin/screencapture", "-x", "-R", f"{x},{y},{w},{h}", out_path], capture_output=True)74 return r.returncode == 0 and os.path.exists(out_path) and os.path.getsize(out_path) > 07576def capture_safari_dashboard(store, screenshot_id, url, out_path, mode, **meta) -> dict | None:77 """Open/reload the URL in the front Safari window in the current Space, bring it to front, capture the composited region."""78 import time79 subprocess.run(["osascript", "-e", 'tell application "Safari" to activate', "-e", f'tell application "Safari" to set URL of front document to "{url}"'], capture_output=True)80 time.sleep(4)81 import Quartz # type: ignore82 wins = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionOnScreenOnly | Quartz.kCGWindowListExcludeDesktopElements, Quartz.kCGNullWindowID)83 c = [w for w in wins if w.get("kCGWindowOwnerName") == "Safari" and w.get("kCGWindowLayer", 0) == 0 and w.get("kCGWindowName")]84 if not c: return None85 b = c[0]["kCGWindowBounds"]; bounds = (int(b["X"]), int(b["Y"]), int(b["Width"]), int(b["Height"]))86 if not capture_region(bounds, out_path): return None87 return record(store, screenshot_id, out_path, mode, f"Safari window '{c[0].get('kCGWindowName')}' → {url} (composited region capture of the evidence viewer over runs/state.sqlite)", **meta)88