Merge pull request #2471 from heygen-com/07-15-fix_cli_producer_headless_shell_path_alias

fix(cli): honor PRODUCER_HEADLESS_SHELL_PATH in findFromEnv
This commit is contained in:
Vance Ingalls
2026-07-15 00:59:03 -07:00
committed by GitHub
2 changed files with 69 additions and 1 deletions
+50
View File
@@ -171,6 +171,7 @@ describe("findBrowser — cache resolution", () => {
Object.defineProperty(process, "platform", { value: "linux", configurable: true });
Object.defineProperty(process, "arch", { value: "x64", configurable: true });
delete process.env["HYPERFRAMES_BROWSER_PATH"];
delete process.env["PRODUCER_HEADLESS_SHELL_PATH"];
installChildProcessMocks();
});
@@ -593,6 +594,54 @@ describe("findBrowser — cache resolution", () => {
expect(warnSpy).not.toHaveBeenCalled();
});
// Sibling env-var alias for the CLI resolver. The engine layer already
// honors `PRODUCER_HEADLESS_SHELL_PATH` (see
// `packages/engine/src/services/browserManager.ts`), and docs
// (skills/hyperframes-animation/adapters/typegpu.md,
// packages/gcp-cloud-run/Dockerfile, examples/k8s-jobs/Dockerfile.example)
// all instruct users to set that name. Before this alias, `hyperframes
// check`/`snapshot`/`compare` — which all route through `openSettledCompositionPage`
// → `ensureBrowser` → `findFromEnv` — silently ignored a documented escape
// hatch that `render` had honored, so a user with a broken pinned build
// (win32/x64 STATUS_STACK_BUFFER_OVERRUN 3221225595, #hyperframes-cli-feedback
// ts=1784095034) could render successfully but check would still crash on
// the cached headless-shell. The alias closes that direction of the
// symmetry (the engine side is being closed by #2459).
it("resolves via PRODUCER_HEADLESS_SHELL_PATH when HYPERFRAMES_BROWSER_PATH is unset", async () => {
const directShell = "/opt/chrome-headless-shell/chrome-headless-shell";
installFsMocks({ existing: new Set([directShell]) });
installPuppeteerBrowsersMock();
process.env["PRODUCER_HEADLESS_SHELL_PATH"] = directShell;
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
const { findBrowser, _resetSystemFallbackWarnForTests } = await import("./manager.js");
_resetSystemFallbackWarnForTests();
const result = await findBrowser();
expect(result?.executablePath).toBe(directShell);
expect(result?.source).toBe("env");
expect(warnSpy).not.toHaveBeenCalled();
});
it("prefers HYPERFRAMES_BROWSER_PATH over PRODUCER_HEADLESS_SHELL_PATH when both are set", async () => {
// Tiebreak matches `render.ts` — the CLI-native name canonicalizes; the
// engine name is a compatibility alias. If both are set the caller almost
// certainly meant the CLI-native one.
const hfPath = "/opt/hf/chrome-headless-shell";
const producerPath = "/opt/producer/chrome-headless-shell";
installFsMocks({ existing: new Set([hfPath, producerPath]) });
installPuppeteerBrowsersMock();
process.env["HYPERFRAMES_BROWSER_PATH"] = hfPath;
process.env["PRODUCER_HEADLESS_SHELL_PATH"] = producerPath;
const { findBrowser, _resetSystemFallbackWarnForTests } = await import("./manager.js");
_resetSystemFallbackWarnForTests();
const result = await findBrowser();
expect(result?.executablePath).toBe(hfPath);
expect(result?.source).toBe("env");
});
it("does NOT warn on macOS when falling back to system Chrome", async () => {
// macOS Chrome still works fine for the screenshot path and the perf
// claims around BeginFrame are Linux-only — keep the warning Linux-scoped
@@ -716,6 +765,7 @@ describe("downloadBrowser — install failure surfaces HYPERFRAMES_BROWSER_PATH
beforeEach(() => {
vi.resetModules();
delete process.env["HYPERFRAMES_BROWSER_PATH"];
delete process.env["PRODUCER_HEADLESS_SHELL_PATH"];
installChildProcessMocks();
});
+19 -1
View File
@@ -250,8 +250,26 @@ function whichBinary(name: string): string | undefined {
}
}
// Env-var aliases for a caller-supplied browser executable path. The CLI-native
// name `HYPERFRAMES_BROWSER_PATH` is the canonical spelling (documented via the
// download-failure hint added in #2443). `PRODUCER_HEADLESS_SHELL_PATH` is the
// engine-side name that per-worker render launches already honor (see
// `packages/engine/src/services/browserManager.ts` and `render.ts` which even
// propagates the CLI-resolved executable into it). Docs in
// `skills/hyperframes-animation/adapters/typegpu.md`,
// `packages/gcp-cloud-run/Dockerfile`, and `examples/k8s-jobs/Dockerfile.example`
// all instruct users to set `PRODUCER_HEADLESS_SHELL_PATH`, so field reports
// (e.g. `#hyperframes-cli-feedback` ts=1784095034 on win32/x64) hit the case
// where `render` completes via that env var while `check`, `snapshot`, and
// `compare` all ignore it and crash on the cached headless-shell instead.
// Alias them here so every consumer of `openSettledCompositionPage` (which
// calls `ensureBrowser` → `findFromEnv`) picks up the same escape hatch.
// Tiebreak: HYPERFRAMES_BROWSER_PATH wins when both are set, matching the
// CLI-native canonicalization in `render.ts` (which only sets
// `PRODUCER_HEADLESS_SHELL_PATH` if not already present).
function findFromEnv(): BrowserResult | undefined {
const envPath = process.env["HYPERFRAMES_BROWSER_PATH"];
const envPath =
process.env["HYPERFRAMES_BROWSER_PATH"] ?? process.env["PRODUCER_HEADLESS_SHELL_PATH"];
if (envPath && existsSync(envPath)) {
return { executablePath: envPath, source: "env" };
}