Spaces:
Paused
Paused
| """Headless verification of model-built web apps (the web `run_python`). | |
| smolbuilder's agent writes HTML/CSS/JS but, unlike the Python path, had no way | |
| to *run* it — so it shipped broken apps and couldn't tell. This bridges to a | |
| small Node + jsdom checker (engine/webcheck.js) that loads the page, runs its | |
| scripts, clicks every button, and reports JavaScript errors. | |
| Graceful degradation is deliberate: if Node or jsdom isn't available (e.g. a | |
| minimal Space image), we return `None` ("unverifiable") rather than failing the | |
| build — the agent/router fall back to the structural check. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import shutil | |
| import subprocess | |
| import tempfile | |
| from pathlib import Path | |
| _CHECKER = Path(__file__).with_name("webcheck.js") | |
| def available() -> bool: | |
| """True if we can actually run the headless check (Node present).""" | |
| return shutil.which("node") is not None and _CHECKER.exists() | |
| def check_html(html: str, timeout: int = 20) -> tuple[bool | None, list[str]]: | |
| """Run the headless check on an HTML document. | |
| Returns (ok, errors): | |
| - (True, []) the app loaded and all buttons clicked without error | |
| - (False, [...]) real JavaScript errors were found | |
| - (None, [...]) unverifiable (Node/jsdom missing, or the checker broke) | |
| """ | |
| node = shutil.which("node") | |
| if not node or not _CHECKER.exists(): | |
| return None, ["node/jsdom unavailable (skipped runtime check)"] | |
| with tempfile.NamedTemporaryFile("w", suffix=".html", delete=False) as f: | |
| f.write(html) | |
| path = f.name | |
| try: | |
| proc = subprocess.run( | |
| [node, str(_CHECKER), path], | |
| capture_output=True, text=True, timeout=timeout, | |
| ) | |
| except subprocess.TimeoutExpired: | |
| return None, [f"runtime check timed out after {timeout}s"] | |
| finally: | |
| Path(path).unlink(missing_ok=True) | |
| if proc.returncode == 3: # jsdom not installed | |
| return None, ["jsdom not installed (skipped runtime check)"] | |
| line = (proc.stdout or "").strip().splitlines() | |
| if not line: | |
| return None, [f"runtime check produced no output: {proc.stderr.strip()[:200]}"] | |
| try: | |
| data = json.loads(line[-1]) | |
| except json.JSONDecodeError: | |
| return None, [f"runtime check output unparseable: {line[-1][:200]}"] | |
| if data.get("ok") is None: | |
| return None, [data.get("infra", "unverifiable")] | |
| return bool(data.get("ok")), list(data.get("errors", [])) | |