fix(webui): raise declared Node floor from >=18 to 20.19.0 - #2886
Conversation
Add a repo-wide guard that fails CI if package.json's engines.node, the CI jobs that build src/gaia/apps/webui, and the installer scripts' Node gate ever disagree again. Written first, against the current >=18 / '20' / -lt 18 state, so it fails before the floor is corrected.
The build actually needs Node 20.19+ (the locked vite/rolldown toolchain declares that floor) -- Node 18 crashes at parse time, and anything below 20.19 either fails outright or gets silently skipped native bindings. engines.node still said >=18, so a contributor or packager following it got a cryptic bundler error instead of an actionable one. Bring engines.node, both installer scripts' version gate, and the docs that quote a Node floor into agreement with the measured 20.19.0 value. CI already runs Node >=20.19 everywhere it builds this package (bare '20'/'24' pins resolve to a current patch), so no workflow changes are needed. MCP-launcher docs (github.mdx, tavily.mdx) intentionally keep their separate, lower "Node 18+" guidance -- that's an npx runtime requirement, unrelated to this build toolchain. Also corrects a stale "Electron 40 / Node 20" comment left over from an earlier Electron version.
Testing gate — evidenceGAIA's PR-to- Unit — drift guard, clean env (main checkout's Real-world — the floor is measured, not asserted: the Node matrix in the PR description (Radeon dGPU box, Installer script: |
|
Verdict: Approve with suggestions. This PR raises the declared Node.js floor for the Agent UI from 18 to 20.19.0 and lines up every place that states it — the docs, both installer scripts' version gate, One thing worth tightening before or shortly after merge: the installer scripts now say "Node.js 20.19+ is required" but only actually enforce a major-version check (they block Node < 20, but wave through anything 20.x). So a user on Node 20.0–20.18 sails past the friendly error and then hits exactly the cryptic bundler crash this PR set out to prevent — the toolchain genuinely needs 20.19+. The npm Real-world evidenceThe evidence bundle ( 🔍 Technical details🟡 Installer gate enforces major-only, but the stated/real floor is 20.19.0 ( Both scripts parse only the major version and compare against So Node 20.0.0–20.18.x passes the gate, yet the docstring of the new test itself notes the build fails below 20.12 ( and the PowerShell equivalent can compare 🟢 Nit — workflow glob misses
Strengths
|
|
Closing in favour of #2887, which now carries the one-line |
Closes #2879
Why this matters
src/gaia/apps/webui/package.jsondeclaredengines.node: ">=18", but the Agent UI cannot build on Node 18 — it dies at parse time (node:util.styleText, added in Node 20.12), and the locked bundler (vite@8.2.0/rolldown@1.2.1) declares it needs Node 20.19+. The same stale "Node 18" claim was repeated across the curl-to-bash installer scripts and setup docs, and nothing checked that these places agreed. Anyone following the declared floor — a new contributor, a packager, an automated setup — got a broken Agent UI and a cryptic error that didn't point at the cause. This raises the declared floor to the honest 20.19.0 everywhere it's stated, and adds a drift guard so the declarations can't silently diverge again.The floor was measured on real Node versions, not guessed — see the evidence below. The narrower "bump CI to a newer Node just to silence a cosmetic transitive-dependency warning" work is intentionally not in this PR (asymmetric risk mid-release-candidate); it's a separate follow-up.
Test plan
tests/unit/test_webui_node_engines.py— new drift guard, written first and run red against the pre-fix tree (engines.node='>=18' is not a simple '>=X.Y.Z' floor), green after the fix. It walks every workflow YAML (no hardcoded job list), asserts a non-empty set of webui-building jobs, and checks each pinned Node — plus both installer scripts — satisfies the declared floor.python util/lint.py --allclean (Black/isort/flake8/pylint/bandit PASS).tests/unit/suite: 8135 passed, 3/3 new tests green. (7 failures are throwaway-venv provisioning artifacts — unactivated PATH,uv venvshipping withoutpip, a nested-worktree.env, and a[dev]+[ui]extras combo — none touch a changed file; all pass in CI's clean environment.)Node floor measurement (Radeon dGPU box, Ubuntu, npm ci)
styleTextparse error (cited from issue; reproduced on two checkouts)styleText@rolldown/binding-linux-x64-gnu(the optional dep's ownenginesgate excludes 20.12.2), so the bundler can't find its native binding. (Correction to the original hypothesis, which predicted "builds but warns".)Why 20.19.0 and not 22.x: the residual EBADENGINE above 20.19 comes from
node-abi@4.33.0(>=22.12.0) and the test-onlyjsdom@30.0.1/mute-stream@4.0.0(^22.22.2 || ^24.15.0 || >=26.0.0) — none of which the Agent UI build needs (the app has no native production deps to rebuild). Their warning is cosmetic; chasing it would over-declare the floor and needlessly restrict consumers. (Note:whatwg-url@17.1.0carries a different constraint,^22.14.0 || >=24.0.0, and does not belong to that group.)CI needs no edits. Six jobs pin
node-versionand buildsrc/gaia/apps/webui:test_electron.yml:test-webui-vitest,pypi.yml:build,build-installers.yml:build,publish.yml:validate,publish.yml:build-npm(all'20'), andpublish.yml:publish-npm('24', deliberately higher for npm-provenance OIDC). A real green run (gh run 30467337052) shows bare'20'resolving to 20.20.2 — above the 20.19.0 floor — so every pin already satisfies it. The drift guard's self-updating selector independently picked up the same six jobs.Consumer scope: one coherent floor is declared everywhere (package.json,
.nvmrcalreadyv20.20.0, installer scripts, docs) rather than a split build-vs-runtime pair — two numbers is exactly the drift this fixes, and issue #2880's build preflight readsengines.nodeand needs it to carry the build floor. Sub-floor consumers get only a non-fatal warning (noengine-strictanywhere in the repo). The MCP-npx "Node 18+" note in the connector docs is left as-is — that's an unrelated launcher requirement, not the webui build toolchain.