Repository navigation
node consumers: node-lts interpreter only at runtime, node-lts to build (fixes #751) - #752
Conversation
pkgs#670 fixed pnpm by depending on `subsetOf node ["node"]`. The other 17 packages that run under node still pulled in the whole `node` package at runtime: npm, npx and /usr/lib/node_modules/npm included. In any session that also contains node-lts, two npm trees get hardlinked first-writer-wins per file. Since node-lts 24.19.0 moved its bundled npm ahead of node's, the blend no longer loads: every npm/npx dies with "Class extends value undefined". webapp's activation hook (`npx astro dev`) hits this, so webapp is pinned to an older pkgs. None of these packages invoke npm at runtime. Build deps keep the full package, since builds need npm. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: gominimal/pkgs/.coderabbit.yaml Review profile: CHILL Plan: Essentials Run ID: 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (5)
Included review availability: 0 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour. 📝 WalkthroughWalkthroughPackage build specifications switch applicable Node build dependencies to Node LTS and select only its Node output for runtime dependencies. The Next.js build script also changes how it replaces and validates ChangesNode runtime dependencies
Next.js sharp build
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: Merge Risk: ⚪ Minimal · up to No actionable merge-blocking issue is established. Projects that need npm or npx should declare Node explicitly. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Mirror image of the previous commit: capy and vlt pulled in the whole node-lts package at runtime, so a session with `node` plus either of them got the same two-npm blend. Interpreter only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
mitodrummer
left a comment
There was a problem hiding this comment.
Thanks for turning this around quickly. The subsetOf … ["node"] approach is right: the node output is only usr/bin/node, so these packages stop contributing an npm tree, which is the cause of #751.
On the convention call you left for Tom and me: these runtime deps should use node-lts, not node.
nodeis pinned to 25.8.2. Odd-numbered Node lines never become LTS, and 25.x is past end-of-life, so every tool here currently runs on a Node that no longer gets security fixes.node-lts(24.19.0) is a supported LTS line, and that's what these projects target upstream.- No package here needs 25. The strictest
enginesrange I found is agent-browser's>=24; wrangler needs>=22and next>=20.9. node-ltshas the samenodeoutput, sosubsetOf node-lts ["node"]works as a drop-in replacement. It also mostly settles your open two-/usr/bin/nodeitem. A session that includesnode-lts(e.g. webapp) would then get the sameusr/bin/nodefile from every package, so there's no first-writer-wins race. The collision would only remain in sessions that choosenodeexplicitly.
Suggested scope:
- Change
runtime_depstosubsetOf node-lts ["node"]for all 17 packages here, pluspnpm(#670 pointed it atnodetoo). - Moving
build_depstonode-ltsis optional and not needed for this bug, but it would keep each package's build and runtime on the same Node. - Keep
nodeas the explicit opt-in for anyone who wants the newest Node.
One behaviour change to call out in the PR description, broader than the lerna note: a project that listed only one of these packages (e.g. next, typescript, eslint) with no node/node-lts used to get npm/npx transitively. After this PR it has neither, and npm install fails with "command not found". I think that trade is right, since a project that needs npm should declare a Node, but it should be stated plainly.
Once CI has built the branch, I'll run the #751 repro against the head commit.
Per Karl's review: `node` is 25.8.2, an odd line that never becomes LTS and is past end-of-life, so every tool here ran on a Node without security fixes. No package needs 25 (strictest `engines` is agent-browser's >=24). One runtime flavor across the catalog also removes the remaining two-/usr/bin/node race: every package now ships the same interpreter file, so the only sessions with two are ones that explicitly add `node`. Build deps move too. That is required, not just tidier: pnpm's runtime interpreter enters the build closure of everything built with pnpm (next, agent-browser), so leaving builds on `node` would put two /usr/bin/node binaries in those sandboxes. `node` stays in the catalog as an explicit user opt-in. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ame (review) Addresses Karl's review on #753: - shared-tree now also rejects a broad recursive glob (`usr/**`, `usr/lib/**`, `**`) whose literal prefix is an ancestor of usr/lib/node_modules, in any package that BUILDS with a node runtime. Such a glob would capture an npm install and ship it. Non-node packages are exempt, so the 11 C libraries using `usr/**` are untouched. - Synthetic cases: usr/**, usr/lib/** and ** are flagged; usr/bin/*, usr/lib/*.so, usr/share/** and a C lib's usr/** are not. - Full catalog: main still fails the same 20 packages; with #752 it passes all 531. - AGENTS.md now claims only what the guard checks: build and runtime deps. node-lts for test_deps is stated as convention, since `minimal dump` has no tests to check. - capy: rename the output node_modules -> libexec to match the other four, and drop the stale "same shape as cf's node_modules" comment. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Five import lines had `subsetOf` prepended ahead of `standaloneTest`. Lowercase identifiers sort alphabetically, so the import-line checker failed them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thanks, Karl. Everything from your review is in.
Also since your review:
Checked: |
mitodrummer
left a comment
There was a problem hiding this comment.
Approving. minimal-check was still running at approval time, so please merge only once it's green. After it merges I'll re-pin gominimal/webapp to the new pkgs commit and confirm the #751 repro is fixed.
|
Correction to my approval note: |
…uilts on every arch sharp is one of next's optionalDependencies, so `npm install -g next.tgz` already creates node_modules/sharp, and `cp -r` of the source-built sharp nested it at sharp/sharp/ where nothing loads it. The npm copy won: - amd64: its prebuilt @img/sharp-linux-x64 had been deleted, so sharp failed to load at all. This is the sharp_uses_system_libvips failure on #752. - arm64: @img/sharp-linux-arm64 was never deleted, so sharp quietly loaded the prebuilt addon with bundled libvips, and the test passed without testing its name. Pre-existing, not caused by the node-lts move. Main's CI Skips next's standalone tests unless next is rebuilt, and #752 forces the rebuild. The fix: - rm the npm sharp before copying the source build in; - remove @img/sharp-* for every arch; - guard the @img/colour copy the same way; - check at build time that sharp loads its OWN src/build/Release addon with a libvips version. Verified in the Linux sandbox (arm64): - fixed: `sharp 0.35.4 vips 8.18.6 addon sharp-linux-arm64-0.35.4.node` - negative control, without the rm: the build FAILS with `Could not load the "sharp" module using the linux-arm64 runtime` Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Fix for the Root cause (pre-existing, not the node-lts move):
Main never caught it because CI Skips next's standalone tests unless next is rebuilt, and this PR forces that rebuild. Fix:
Verified in the Linux sandbox (arm64):
amd64 is covered by CI on this push. Once it's green, the head is ready for your #751 repro. |
…ominimal#751) (gominimal#753) * node packages: private libexec prefixes + a guard against a second npm (gominimal#751) Two follow-ups to gominimal#752: 1. cf, wrangler, next, mermaid-cli and capy installed into the shared usr/lib/node_modules, the tree the node runtime's own npm lives in (Tom's gominimal#370 warning). They now install into usr/libexec/<pkg> with relative usr/bin symlinks, like vlt and pnpm. A `test -e` on each link fails the build if an upstream bin is renamed, rather than shipping a dangling link. mermaid-cli's wrapper and next's sharp/test paths follow the move. 2. node-runtime-guard (BLOCKING, as Karl suggested in gominimal#751). It evaluates the whole catalog on amd64 and arm64 and rejects: - outputs under usr/lib/node_modules; - runtime deps that carry a node runtime's npm; - packages on `node` rather than `node-lts`. A dump failure exits 2 and fails the check, so an unverified run cannot go green. Full-catalog dry run: - main: FAILS 20 packages (34 flavor, 19 runtime-npm, 5 shared-tree). - main + gominimal#752 + this: PASSES all 531 packages. This check is red until gominimal#752 lands. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * AGENTS.md: document the Node pattern the guard enforces The rules that node-runtime-guard enforces are now written down where package authors and agents look first: - node-lts, not node; - interpreter-only at runtime; - a private libexec prefix, with a worked build.sh and build.ncl. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * node-runtime-guard: catch broad globs; align AGENTS.md; capy output name (review) Addresses Karl's review on gominimal#753: - shared-tree now also rejects a broad recursive glob (`usr/**`, `usr/lib/**`, `**`) whose literal prefix is an ancestor of usr/lib/node_modules, in any package that BUILDS with a node runtime. Such a glob would capture an npm install and ship it. Non-node packages are exempt, so the 11 C libraries using `usr/**` are untouched. - Synthetic cases: usr/**, usr/lib/** and ** are flagged; usr/bin/*, usr/lib/*.so, usr/share/** and a C lib's usr/** are not. - Full catalog: main still fails the same 20 packages; with gominimal#752 it passes all 531. - AGENTS.md now claims only what the guard checks: build and runtime deps. node-lts for test_deps is stated as convention, since `minimal dump` has no tests to check. - capy: rename the output node_modules -> libexec to match the other four, and drop the stale "same shape as cf's node_modules" comment. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Fixes #751. Follow-up to #665/#670. Scope updated per @mitodrummer's review.
What
Karl's #751 has the repro. With
node-ltsplusagent-browserorcfin one session,/usr/lib/node_modules/npmbecomes a blend of two npm versions. Everynpm/npxthen dies withClass extends value undefined. That breaks webapp'smin session activate, which runsnpx astro dev.Every package that runs under Node now:
subsetOf node-lts ["node"]. No package can contribute an npm tree to a session or build closure anymore. This is the fix(node-lts): repair the bundled npm's shadowed minipass — everynpm installis broken #670 fix generalized from pnpm to all of them.node-ltsfor build, runtime and tests, notnode.nodeis 25.8.2, an odd release line that never becomes LTS and is past end-of-life. No package here needs 25: the strictestenginesis agent-browser's>=24. With one flavor across the catalog, every package ships the same/usr/bin/nodefile, so there is no first-writer race on the interpreter either. The only sessions left with two Node binaries are ones that explicitly addnode.nodestays in the catalog as an explicit user opt-in for the newest Node.Packages (19): agent-browser, bash-language-server, capy*, cf, emscripten, eslint, json-server, lerna, mermaid-cli, next, pi, pnpm, prettier, pyright, serve, typescript-language-server, typescript, vlt*, wrangler, yarn
* already on
node-lts; only the runtime subset changes.Why build deps move too, not just runtime: pnpm's runtime interpreter enters the build closure of everything built with pnpm (next, agent-browser). If pnpm moved to
node-ltswhile those builds stayed onnode, those sandboxes would get two/usr/bin/nodebinaries, and which one wins would be arbitrary.Behaviour change
A project that listed only one of these packages (e.g.
next,typescript,eslint) with nonode/node-ltsused to getnpm/npxtransitively. After this PR it gets neither, sonpm installfails with "command not found". A project that needs npm should declare a Node (node-lts, ornodefor Current). lerna is the sharpest case, becauselerna run/publishspawn the npm client.Verification
mip dump -p --arch amd64|arm64evaluates all 531 packages on this branch. No package outside the two runtimes referencesnodein build or runtime deps, and every runtime reference issubset_of node-lts ["node"].Companion PR
The structural guard Karl suggested, plus moving cf, wrangler, next, mermaid-cli and capy out of the shared
usr/lib/node_modulesinto privateusr/libexec/<pkg>directories, comes in a separate PR. It will go red until this one lands. Dry-run on the full catalog: main fails 19 packages, and this branch plus that PR passes all 531.🤖 Generated with Claude Code
Summary by CodeRabbit