mcp / scripts /clone_login.py
jackraynerTS's picture
Claude Opus 4.8
feat(portal): login-clone pipeline — branded TSE login pages (prototype)
aa1927e
Raw History Blame Contribute Delete
2.33 kB
#!/usr/bin/env python3
"""Thin CLI over demoprep_app.portal.login_clone — for local testing only.
The real path is the background job build_demo_from_brief starts for
demo_type="tse" (mcp_server.py), which calls the same clone_login(). This wrapper
runs capture + generation for one site and leaves everything on disk for review:
python scripts/clone_login.py https://www.example.com --company "Example" \
--use-case "Retail Sales" --out /tmp/clones/example
<out>/capture/screen-*.png the real site, as the model saw it
<out>/clone/shots/*-render-*.png the clone, rendered
<out>/clone/app/ a pristine template with the clone in place
(cd there and `npx vite` to click through it)
<out>/clone/result.json rounds, tokens, timings, why it failed if it did
Needs ANTHROPIC_API_KEY (read from .env) and Playwright's Chromium
(`playwright install chromium`).
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO))
from dotenv import load_dotenv # noqa: E402
from demoprep_app.portal.login_clone import clone_login # noqa: E402
def main() -> None:
ap = argparse.ArgumentParser(description="Clone a prospect homepage as a portal login page.")
ap.add_argument("url")
ap.add_argument("--company", required=True)
ap.add_argument("--use-case", default="Analytics")
ap.add_argument("--out", required=True, help="directory for the capture, renders and result")
ap.add_argument("--model", default=None, help="defaults to CLONE_LOGIN_MODEL or DEFAULT_LLM_MODEL")
args = ap.parse_args()
load_dotenv(REPO / ".env")
res = clone_login(args.url, args.company, args.use_case, args.out, model=args.model,
on_progress=lambda m: print(f" {m}", flush=True))
print(f"{'OK' if res.ok else 'NO CLONE'} {res.reason}")
print(f" {res.seconds}s, {res.rounds} round(s), model {res.model}, tokens in {res.input_tokens} "
f"(+{res.cache_read_tokens} cached read, {res.cache_write_tokens} cache write) / out {res.output_tokens}")
for p in res.preview:
print(f" preview: {p}")
sys.exit(0 if res.ok else 1)
if __name__ == "__main__":
main()