#!/usr/bin/env tsx
/** Reports whether the pinned Linux Chromium gets a hardware WebGPU adapter; software-only is not a failure. */
// Dynamic `puppeteer-core` import from a real file, same as probe-beginframe.ts —
// an inline `bun -e` eval's synthetic `/app/[eval]` path can't see the hoisted dep.
// Usage: bun probe-webgpu-adapter.ts --executable-path /opt/chrome/chrome-headless-shell
import { createServer } from "node:http";
import type { AddressInfo } from "node:net";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
import {
buildChromeArgs,
assertWebGpuAdapterAvailable,
WebGpuUnavailableError,
} from "../../engine/src/services/browserManager.ts";
const PROBE_HTML = '
';
function parseExecutablePath(args: string[]): string {
for (let i = 0; i < args.length; i += 1) {
if (args[i] === "--executable-path") return resolve(args[i + 1]);
if (args[i].startsWith("--executable-path=")) {
return resolve(args[i].slice("--executable-path=".length));
}
}
throw new Error("--executable-path is required");
}
async function main(): Promise {
const executablePath = parseExecutablePath(process.argv.slice(2));
const puppeteer = await import("puppeteer-core");
// navigator.gpu only exists on a secure-context origin; file:// is not one, http://127.0.0.1 is.
const server = createServer((_req, res) => res.end(PROBE_HTML));
await new Promise((done) => server.listen(0, "127.0.0.1", done));
try {
const args = buildChromeArgs(
{
width: 800,
height: 600,
captureMode: "screenshot",
platform: "linux",
requiresWebGpu: true,
},
{ browserGpuMode: "software" },
);
const browser = await puppeteer.launch({ executablePath, headless: true, args });
try {
const page = await browser.newPage();
await page.goto(`http://127.0.0.1:${(server.address() as AddressInfo).port}/`);
await assertWebGpuAdapterAvailable(page, true);
console.log("WebGPU adapter probe: hardware adapter available");
} catch (err) {
if (!(err instanceof WebGpuUnavailableError)) throw err;
console.log(
"WebGPU adapter probe: no usable adapter; data-requires-webgpu compositions will not render on this host",
);
} finally {
await browser.close();
}
} finally {
server.close();
}
}
const invokedPath = process.argv[1] ? resolve(process.argv[1]) : "";
if (invokedPath === fileURLToPath(import.meta.url)) {
void main().catch((err) => {
console.error("[probe-webgpu-adapter] FAIL —", err instanceof Error ? err.message : err);
process.exit(1);
});
}