#!/usr/bin/env python3 """Real end-to-end dogfood: start a throwaway dev server, detect it with sidecar.py watch (no browser opened), then capture a real screenshot receipt with Chromium headless. No mocks. Cleans up only its own temp resources. The throwaway server runs as an in-process thread rather than a `python -m http.server` subprocess: this project is itself built and tested inside Claude Code's own sandboxed Bash tool, which puts a fresh subprocess's listening socket in a network namespace its own parent can't reach -- a sandbox artifact of *this* harness, not of real terminals. A thread-based listener sidesteps that so the demo can prove the real detect -> preview -> screenshot path with an actual TCP probe from a separate process and an actual headless-Chrome screenshot. On a normal dev machine, `npm run dev` / `vite` / etc. are plain reachable subprocesses and this workaround is moot. """ import http.server import json import shutil import subprocess import sys import tempfile import threading from pathlib import Path ROOT = Path(__file__).parent.resolve() SIDECAR = ROOT / "sidecar.py" class _QuietHandler(http.server.SimpleHTTPRequestHandler): def log_message(self, *args): pass def start_demo_server(site_dir): handler = lambda *a, **kw: _QuietHandler(*a, directory=site_dir, **kw) httpd = http.server.HTTPServer(("127.0.0.1", 0), handler) thread = threading.Thread(target=httpd.serve_forever, daemon=True) thread.start() return httpd def main(): with tempfile.TemporaryDirectory(prefix="preview-sidecar-demo-") as site_dir, \ tempfile.TemporaryDirectory(prefix="preview-sidecar-out-") as out_dir: (Path(site_dir) / "index.html").write_text( "" "
" "

Hello from dev server

" "

Started by preview-sidecar demo.py

" "
") httpd = start_demo_server(site_dir) port = httpd.server_port print(f"$ (throwaway dev server listening on 127.0.0.1:{port}, serving a one-page site)") try: print(f"$ python3 sidecar.py watch --ports {port} --interval 0.3 --max-cycles 3 --no-open --out {out_dir}") watch = subprocess.run( [sys.executable, str(SIDECAR), "watch", "--ports", str(port), "--interval", "0.3", "--max-cycles", "3", "--no-open", "--out", out_dir], capture_output=True, text=True, timeout=30) print(watch.stdout.strip()) assert f"detected 127.0.0.1:{port}" in watch.stdout, watch.stdout events = (Path(out_dir) / "events.jsonl").read_text().strip().splitlines() assert len(events) == 1, events event = json.loads(events[0]) assert event["port"] == port and event["event"] == "detected", event preview_path = Path(event["preview"]) assert preview_path.exists() assert f"http://127.0.0.1:{port}" in preview_path.read_text() print(f" preview pane written: {preview_path.name} (iframe -> http://127.0.0.1:{port})") chrome = shutil.which("google-chrome") or shutil.which("chromium") or \ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" print(f"$ python3 sidecar.py screenshot --port {port} --out {out_dir} --chrome '{chrome}'") shot = subprocess.run( [sys.executable, str(SIDECAR), "screenshot", "--port", str(port), "--out", out_dir, "--chrome", chrome], capture_output=True, text=True, timeout=30) print(shot.stdout.strip() or shot.stderr.strip()) if shot.returncode == 0: receipt = json.loads(shot.stdout) assert Path(receipt["png"]).stat().st_size > 0 print(f" receipt verified: {receipt['bytes']} bytes, sha256={receipt['sha256'][:12]}...") else: print(" (no Chromium-family browser on this host; screenshot step skipped honestly)") finally: httpd.shutdown() httpd.server_close() print(f"$ (dev server on {port} stopped)") if __name__ == "__main__": main()