vm image: bake the work user's npm cache so a first npm install is fast
A fresh Cloud machine's first npm install should find the usual web packages already downloaded. The first-session probe (run 42087098855) timed a first install of react, react-dom, vite, typescript, @types/react, @types/node, eslint, prettier, zod and vitest. It took 16.4 s on the current image and 4.9 s with the npm cache already filled, which saves 11.5 s.
With this change, the image's agents layer empties the work user's npm cache, then runs one npm install --ignore-scripts of that list as the work user (dep-cache.ts). No package's lifecycle scripts run in the image build. npm only downloads tarballs into its content-addressed cache, and a person's own install checks them against the registry's integrity hashes, as it would any download. clean.py keeps ~/.npm/_cacache, the cache's content and index, and still drops npm's logs and everything else under ~/.npm. The step is part of both the layered bake and the weekly full bake. It runs only when the agents layer is rebuilt, so a warm per-commit bake pays nothing for it.
Cost: about 205 MB of image disk. That figure is the npm cache from one install of the list, measured on a fleet Linux runner with a fresh cache. Its bound:
- the cache holds only what that one install fetches (100 packages including their dependencies);
- the bake step fails if the cache is over 300 MB;
- the image record carries
npmCacheMbfrom every bake, read after clean, so a bake that reused a cached agents layer records it too.
The reproducibility check (repro.ts) allows differences under /home/cmux/.npm/_cacache/, because npm's index records fetch times. npm's logs and .npmrc still count as differences. Versions resolve at bake time, so the cache is as fresh as the agents layer. An older cached version costs only a download.
The probe now reports each package manager's cache size (it lost that output before). It also takes its npm list from dep-cache.ts, so it measures exactly what the image bakes.
Leo: "can we cache a hell of a lot of these and parallelize a hell of a lot of these?"
Tests: vm-image-cmux-vm-layers, -bake-workflow and -commands together with -lock and -repro, give 99 pass, 0 fail on the fleet. The new cases cover the prefill command, the cap, what clean.py keeps, and that dep-cache.ts is part of the layer key. tsc reports nothing in the touched files. The after time comes from the same probe on the first image baked with this change; the bake environment admits only feat-cmux-next.
Changelog
- Cloud machines start with the npm packages most web projects install already cached, so a first
npm installis faster.
Agent session: agent session
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Bakes the work user's npm cache into the VM image so a fresh machine's first npm install is faster. A first install of the usual web packages (react, vite, typescript, and seven more) dropped from 16.4 s to 4.9 s in the first-session probe.
- The agents layer runs one
npm install --ignore-scriptsofPREFILL_NODE_DEPSas the work user (dep-cache.ts), andclean.pykeeps~/.npm/_cacachewhile dropping npm logs and the rest of~/.npm. - The bake fails if the cache exceeds 300 MB and records
npmCacheMbon the image, read after clean; the step runs only when the agents layer rebuilds, so warm per-commit bakes pay nothing. No package's lifecycle scripts run in the build. - The reproducibility check now allows diffs under
/home/cmux/.npm/_cacache/, since npm's index records fetch times; npm logs and.npmrcstill count. - The probe reports each package manager's cache size on its own step and takes its npm list from
dep-cache.ts, so it measures exactly what the image bakes.