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:
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Wave E stage 3 (owner 2026-10-10): demos run in the app's own Chromium
|
||||
* via a --browser-service helper (main.cjs boots a hidden window with a CDP
|
||||
* port), system Chrome as fallback. These pin the pure halves of that
|
||||
* chain: the handshake line parser and the spawn-env sanitizer. The live
|
||||
* chain (spawn → connect → pages() → run) is exercised on dev machines,
|
||||
* not in the suite.
|
||||
*/
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
import { browserServiceSpawnEnv, parseBrowserServiceLine } from "../src/agent/subagents/headless.ts";
|
||||
|
||||
describe("browser-service helper (pure halves)", () => {
|
||||
it("parses the handshake line into a port", () => {
|
||||
assert.equal(parseBrowserServiceLine("BROWSER_SERVICE_CDP 54321"), 54321);
|
||||
});
|
||||
|
||||
it("rejects non-handshake lines", () => {
|
||||
assert.equal(parseBrowserServiceLine("DevTools listening on ws://127.0.0.1:57983/devtools/browser/x"), null);
|
||||
assert.equal(parseBrowserServiceLine(""), null);
|
||||
assert.equal(parseBrowserServiceLine("BROWSER_SERVICE_CDP 0"), null);
|
||||
assert.equal(parseBrowserServiceLine("BROWSER_SERVICE_CDP 99999"), null);
|
||||
});
|
||||
|
||||
it("spawn env strips ELECTRON_RUN_AS_NODE — the helper must be a full app", () => {
|
||||
const env = browserServiceSpawnEnv({
|
||||
ELECTRON_RUN_AS_NODE: "1",
|
||||
LH_DEV_URL: "http://localhost:3000",
|
||||
PATH: "/usr/bin",
|
||||
});
|
||||
assert.equal("ELECTRON_RUN_AS_NODE" in env, false);
|
||||
assert.equal("LH_DEV_URL" in env, false);
|
||||
assert.equal(env.PATH, "/usr/bin");
|
||||
});
|
||||
|
||||
it("spawn env never mutates the caller's env object", () => {
|
||||
const original = { ELECTRON_RUN_AS_NODE: "1", KEEP: "yes" };
|
||||
browserServiceSpawnEnv(original);
|
||||
assert.equal(original.ELECTRON_RUN_AS_NODE, "1");
|
||||
assert.equal(original.KEEP, "yes");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user