Files
webstudio/packages/cli/bin.js
Oleg Isonen b1d23f69c0 fix: Report unsupported Node versions at CLI startup (#6201)
## Summary

- Reject unsupported Node.js versions before loading the CLI bundle.
- Report the declared engine range and detected version with an
install-and-retry instruction.
- Keep the runtime check aligned with `package.json#engines.node`.

## Root cause

The CLI declares Node.js 22.12+ but did not enforce that requirement at
startup. Package managers can warn and continue, allowing unsupported
runtimes to reach preview code. Execa 10 then initializes
`Set.prototype.union()`, which is unavailable in Node 20 and causes the
delayed `screenshot.responsive` failure.

## Technical choices

- Validate the runtime directly at the published executable boundary.
- Parse the declared engine range with `semver`.
- Dynamically import the CLI only after the runtime passes validation.
- Report the exact engine range rather than assuming every valid range
means “or newer.”
- Test the published `bin.js` in a subprocess with an injected
unsupported runtime version.
- Write the actionable startup failure to stderr and exit nonzero.
- No migrations or public API changes.

## Checklist

- [x] Add the startup runtime guard.
- [x] Add executable-level regression coverage for unsupported Node.js.
- [x] Verify the supported runtime still loads the CLI.
- [x] Review fixture impact; no fixture inputs or outputs are affected.
- [x] Review authoritative documentation; `docs/university/cli.md`
already requires Node.js 22.12+, so no update is needed.
- [ ] Run agent evaluations — not run because the requester declined
them.

## Verification

- Published and local launcher tests: 4 passed.
- CLI typecheck: passed.
- Targeted lint and formatting: passed.
- CLI production build: passed.
- Node.js 18.16.1 and 20.12.2 executable checks: exited 1 before loading
the CLI, reported the `>=22.12.0` requirement, and wrote no stdout.
- Node.js 22 executable check: CLI loaded successfully.
- Package dry run: includes the guarded `bin.js` and no separate runtime
helper.
- `git diff --check`: passed.
- The executable-level regression test was confirmed to fail against the
previous message/implementation and pass after the direct guard was
applied.

## Known limitation

An MCP client may wrap a subprocess startup failure in its own UI, but
the CLI now provides the actionable requirement and installation
instruction on stderr before any tool runs.

Closes #6190
2026-08-20 00:17:52 +02:00

25 lines
706 B
JavaScript
Executable File

#!/usr/bin/env node
import { createRequire } from "node:module";
import semver from "semver";
const require = createRequire(import.meta.url);
const packageJson = require("./package.json");
const start = async () => {
const currentVersion = process.versions.node;
const supportedVersionRange = packageJson.engines.node;
if (semver.satisfies(currentVersion, supportedVersionRange) === false) {
console.error(
`Webstudio CLI requires Node.js ${supportedVersionRange}. Detected Node.js ${currentVersion}. Install a supported Node.js version and try again.`
);
process.exitCode = 1;
return;
}
const { main } = await import("./lib/cli.js");
await main();
};
await start();