wave E stage 3: demos run in the app's own Chromium (browser-service helper)

Demos execute JS and need a browser; the app's own binary now provides
one: main.cjs boots a hidden window + CDP port under --browser-service
(before the single-instance lock - a helper is deliberately a second
instance of this binary), lifetime tied to the server's stdin (EOF =
quit, no orphans). headless.ts connects over CDP as PRIMARY (owner
ruling 2026-10-10), system Chrome stays the fallback, graceful refusal
when neither. Electron's CDP has no Target.createTarget, so the helper's
pre-created window is THE page, reused and reset per job behind a
serialized queue. PDFs and SVGs never reach a browser anymore (native
since stages 1-2); stale Chrome wording in model-facing tool copy made
engine-neutral. Live-proofed end-to-end from the dev tree (helper seen
by process watch, js-ran 42 probe, no orphan). Gates 1523/1523.
This commit is contained in:
amosblomqvist
2026-10-11 07:03:45 +03:00
parent e9cf841ce7
commit 8ebaf0da6e
6 changed files with 266 additions and 40 deletions
+4 -3
View File
@@ -16,7 +16,8 @@ import { healToolRecord } from "../tools/heal.ts";
*
* Shape: a ToolLoopAgent with two executable tools (write_demo / run_demo) —
* the engine is injectable (tests use a scripted faux engine) and the headless
* API is injectable (tests use a fake; production uses system Chrome).
* API is injectable (tests use a fake; production uses the app's own
* Chromium browser service, system Chrome as fallback).
*
* Failure semantics (decided in the W6 brief): `tested: true` means "the
* verify loop ran"; on failure the result is { title, html: "", tested: true,
@@ -64,7 +65,7 @@ Build quality:
THE HOUSE RULE — never deliver untested:
1. Call write_demo with the complete HTML document.
2. Call run_demo. It loads the file in headless Chrome, waits ~2s, and reports console errors, uncaught
2. Call run_demo. It loads the file in a headless browser, waits ~2s, and reports console errors, uncaught
errors (window.onerror), and failed requests. Optionally pass a probe: a JS expression evaluated in
the page (e.g. "typeof window.simulate === 'function'" or a state assertion) to check deeper.
3. If run_demo reports problems, FIX the document and call write_demo again, then run_demo again.
@@ -119,7 +120,7 @@ export function createDemoBuilderTools(
name: "run_demo",
label: "run_demo",
description:
"Headlessly execute the current demo in Chrome and report console errors, uncaught errors, and failed requests. " +
"Headlessly execute the current demo in a browser and report console errors, uncaught errors, and failed requests. " +
"Optionally pass a probe expression to assert on page state.",
parameters: runDemoInput,
execute: serverExecute("run_demo", runDemoInput, async ({ probe }) => {