Skip to content

fix(cli): macOS 12 users get Chrome 150 automatically and can render - #4185

Open
miguel-heygen wants to merge 1 commit into
mainfrom
fix/cli-macos12-managed-chrome-refusal
Open

miguel-heygen wants to merge 1 commit into
mainfrom
fix/cli-macos12-managed-chrome-refusal

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • On macOS 12 and older (Darwin below 22), HyperFrames now installs and uses Chrome 150 headless shell instead of the current pinned build. Chrome 151 dropped macOS 12, so users there could not render at all before; now they render normally.
  • One decision owns it: chromeMajorCeiling() (a tiny engine module, also exported as a subpath so the CLI does not load the whole engine). The CLI's managed-build choice (cache match, download, puppeteer-cache lookup) and the engine's own cache lookup both go through it, so render, validate, layout, capture, Studio and direct engine use agree.
  • HYPERFRAMES_BROWSER_PATH and PRODUCER_HEADLESS_SHELL_PATH still win. A newer cached build is ignored on macOS 12; hosts on macOS 13+ are unchanged.
  • Fast (drawElement) capture is off by default on those hosts, because the engine's own measurements show video with caption fades and stacked fades are damaged on Chrome 150 and below (the gates for them were removed for the 151 floor). Screenshot capture is correct, only slower. --experimental-fast-capture=true still opts in.
  • Projects using HTML-in-canvas keep working: the same flag exposes the API on 150 (checked on a Linux 150.0.7871.124 headless shell: drawElementImage is a function with --enable-features=CanvasDrawElement, undefined without it).
  • Stale text fixed: the "system Chrome crashes" comment, the "Dev/Canary ~151+" fallback line, and the macOS crash hint (it no longer tells users to install 150 when HyperFrames already does).

Not covered, said plainly

  • No macOS 12 machine was available. The behaviour on a real Darwin 21 launch is inferred from the binary's declared minimum OS (150 declares macOS 12; 152 declares macOS 13, per the independent review) and the field report.
  • The API check ran on Linux: it proves the API exists in the 150 headless shell, not that macOS 12 renders it.
  • Two callers still pick a browser on their own: the Studio dev server (vite.browser.ts) and the HDR headed capture (hdrCapture.ts) scan the puppeteer cache for the newest build with no ceiling. Small follow-up, same helper.
  • Darwin below 22 also covers macOS 11 and 10.15; Chrome 150 may not launch there. Not a change from today.
  • os.release() that does not parse falls back to the current pin (old behaviour).

Test plan

  • Darwin 21 downloads 150.0.7871.124; Darwin 22 keeps 152.0.7977.30; env override wins on Darwin 21; a cached 152 (managed and puppeteer cache) is not used on Darwin 21 while a cached 150 is.
  • Engine picker skips a newer managed-cache build on a faked Darwin 21 (subprocess test).
  • Default fast capture off on a ceiling host, opt-in still on, telemetry reason old_chrome.
  • Mutation: forcing the pin turns 4 of the new manager tests red; removing the ceiling clause turns the fast-capture test red.
  • tsc --noEmit clean for engine, producer, cli; package-subpath contract check passes; cli src/browser + src/commands (1143 tests) and engine config/browserManager/ceiling (183 tests) pass on a Linux box.

Review

Independent read-only review found one blocking gap (fast capture on 150, fixed here), the barrel import cost (fixed with the subpath), the stale crash hint (fixed), and the two unresolved callers above (noted). The review ran on the head before those fixes; the fixes carry their own tests and mutation checks.

@miguel-heygen
miguel-heygen force-pushed the fix/cli-macos12-managed-chrome-refusal branch from 6cd5728 to ee17024 Compare September 19, 2026 18:55
@miguel-heygen miguel-heygen changed the title fix(cli): refuse the pinned Chrome before launch on macOS 12 fix(cli): macOS 12 users get Chrome 150 automatically and can render Sep 19, 2026
[
"--eval",
`Object.defineProperty(process, "platform", { value: ${JSON.stringify(hostPlatform)} }); Object.defineProperty(process, "arch", { value: ${JSON.stringify(hostArch)} }); import(${JSON.stringify(moduleUrl)}).then(({ resolveHeadlessShellPath }) => process.stdout.write(resolveHeadlessShellPath({}) ?? ""))`,
`Object.defineProperty(process, "platform", { value: ${JSON.stringify(hostPlatform)} }); Object.defineProperty(process, "arch", { value: ${JSON.stringify(hostArch)} }); const os = require("node:os"); os.release = () => "24.0.0"; require("node:module").syncBuiltinESMExports(); import(${JSON.stringify(moduleUrl)}).then(({ resolveHeadlessShellPath }) => process.stdout.write(resolveHeadlessShellPath({}) ?? ""))`,
[
"--eval",
`Object.defineProperty(process, "platform", { value: ${JSON.stringify(hostPlatform)} }); Object.defineProperty(process, "arch", { value: ${JSON.stringify(hostArch)} }); import(${JSON.stringify(moduleUrl)}).then(({ resolveHeadlessShellPath }) => process.stdout.write(resolveHeadlessShellPath({}) ?? ""))`,
`Object.defineProperty(process, "platform", { value: ${JSON.stringify(hostPlatform)} }); Object.defineProperty(process, "arch", { value: ${JSON.stringify(hostArch)} }); const os = require("node:os"); os.release = () => "24.0.0"; require("node:module").syncBuiltinESMExports(); import(${JSON.stringify(moduleUrl)}).then(({ resolveHeadlessShellPath }) => process.stdout.write(resolveHeadlessShellPath({}) ?? ""))`,
"bun",
[
"--eval",
`Object.defineProperty(process, "platform", { value: "darwin" }); Object.defineProperty(process, "arch", { value: "x64" }); const os = require("node:os"); os.release = () => "21.6.0"; require("node:module").syncBuiltinESMExports(); import(${JSON.stringify(moduleUrl)}).then(({ resolveHeadlessShellPath }) => process.stdout.write(resolveHeadlessShellPath({}) ?? ""))`,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants