#!/usr/bin/env python3 """ dump-invite-page.py -- DOM dump of a Cloudron invite/setup page (pre-acceptance). Usage: docker compose run --rm --entrypoint python3 \ -e AGENT=vp-secops provision dump-invite-page.py """ import os, sys, time from pathlib import Path from playwright.sync_api import sync_playwright STATE_DIR = Path("/app/state") AGENT = os.environ.get("AGENT", "vp-secops") import yaml with open("/app/agents.yaml") as f: manifest = yaml.safe_load(f) agent = next(a for a in manifest["agents"] if a["name"] == AGENT) invite_url = agent["cloudron_invite"] with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_context(viewport={"width": 1280, "height": 1024}).new_page() page.goto(invite_url, wait_until="networkidle", timeout=20000) page.wait_for_timeout(3000) ts = time.strftime("%H%M%S") page.screenshot(path=str(STATE_DIR / f"invite-{AGENT}-{ts}.png"), full_page=True) elements = page.evaluate("""() => { const out = []; document.querySelectorAll('input, button, [role="button"], label, a, h1, h2, h3, form').forEach(el => { const tag = el.tagName.toLowerCase(); const text = (el.textContent || '').trim().substring(0, 60); const id = el.id || ''; const type = el.getAttribute('type') || ''; const cls = (el.getAttribute('class') || '').substring(0, 50); const role = el.getAttribute('role') || ''; const vis = el.offsetParent !== null; out.push(`<${tag}> id=${id} type=${type} role=${role} class=${cls} vis=${vis} text="${text}"`); }); return out; }""") body = page.evaluate("() => document.body.innerText.substring(0, 400)") out = f"URL: {page.url}\n\nBODY:\n{body}\n\nELEMENTS:\n" + "\n".join(elements) (STATE_DIR / f"invite-{AGENT}-{ts}.txt").write_text(out) print(out) browser.close()