Files
notplanned/ventures/preview-sidecar/demo.py
T
claudeandClaude Sonnet 5 029323fe97 Build standalone preview-sidecar tool and receipt-styled landing page
Localhost port watcher: detects a newly bound dev-server port via
bounded TCP probing, opens an iframe preview pane, and captures a
one-click timestamped screenshot receipt via headless Chrome. No
Claude Code changes, stdlib-only, 16 passing tests plus a real
end-to-end dogfood (demo.py) with a genuine recorded screenshot.

Landing page at ventures/preview-sidecar/site/index.html uses a
receipt/ticket visual identity (narrow thermal-paper column, dotted
rules, wax stamp, monospace totals) distinct from the finishline
venture, with one above-the-fold signup CTA and an honest free/paid
pricing section.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-10 10:36:31 -07:00

94 lines
4.3 KiB
Python

#!/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(
"<html><body style='font-family:sans-serif;margin:0;background:#1d4ed8;color:#fff'>"
"<div style='padding:48px 40px'>"
"<h1 style='margin:0 0 12px;font-size:40px'>Hello from dev server</h1>"
"<p style='margin:0;font-size:18px;opacity:.9'>Started by preview-sidecar demo.py</p>"
"</div></body></html>")
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()