fix(cli): honor PRODUCER_HEADLESS_SHELL_PATH in findFromEnv

`hyperframes render` picks up `PRODUCER_HEADLESS_SHELL_PATH` (engine
per-worker launches read it directly, and `render.ts` even propagates
the CLI-resolved executable path into it as a courtesy). But
`hyperframes check` / `snapshot` / `compare` / `grade-compare` all
route through `openSettledCompositionPage` → `ensureBrowser` →
`findFromEnv`, and `findFromEnv` only knew the CLI-native name
`HYPERFRAMES_BROWSER_PATH`.

Field report — #hyperframes-cli-feedback ts=1784095034 (win32/x64,
CLI 0.7.58): the cached `chrome-headless-shell 152.0.7928.2` crashed
with `Failed to launch the browser process: Code: 3221225595`
(`STATUS_STACK_BUFFER_OVERRUN`). Setting `PRODUCER_HEADLESS_SHELL_PATH`
to system Chrome unblocked `render`, but `check` still crashed on the
broken cached shell because it never read that env var.

Docs and deployment manifests (`skills/hyperframes-animation/adapters/
typegpu.md`, `packages/gcp-cloud-run/Dockerfile`, `examples/k8s-jobs/
Dockerfile.example`) all instruct users to set
`PRODUCER_HEADLESS_SHELL_PATH`, so the escape hatch is
documentation-blessed but was silently half-implemented on the CLI
side.

Alias it in `findFromEnv`. Tiebreak matches `render.ts:1479` —
`HYPERFRAMES_BROWSER_PATH` wins when both are set.

This is the CLI side of the symmetry #2459 is closing on the engine
(engine gaining `HYPERFRAMES_BROWSER_PATH` honoring); the two make the
alias coherent both directions.

- Sibling to #2443 (surfaces `HYPERFRAMES_BROWSER_PATH` on download
  failures).
- Not the same class as #2040 (arm64 pin), #2078 (SIGTRAP), or #2082
  (launch crash rewrap) — those are download / launch fixes; this is
  the env-var alias gap.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-07-15 07:27:56 +00:00
co-authored by Claude Opus 4.7
parent c54bf13fb4
commit 72d30cda8d
2 changed files with 69 additions and 1 deletions
+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" };
}