npm could never run `npm ci` here. The Dockerfile said so in a comment: @hanzo/gui
pulls a react-native tree whose platform and optional packages resolve differently
between npm versions, so a lockfile written by one npm failed under another, and
the build ran `npm install` — resolving the tree fresh every time and using the
committed lockfile as a suggestion. A lockfile nobody installs from is decoration,
which is how it drifted far enough that `npm ci` was already dead on main before
this change (react-native-worklets missing from the tree it claimed to describe).
pnpm records every platform in the lockfile, so the build installs exactly what is
committed and fails loudly rather than quietly resolving something else. Both
Dockerfiles now `corepack enable && pnpm install --frozen-lockfile`, corepack takes
the version from `packageManager`, and package-lock.json is gone. .gitignore is
reversed accordingly: pnpm-lock.yaml is the tracked one and every other manager's
lockfile is ignored, so a stray `npm install` cannot leave a second source of truth.
pnpm-workspace.yaml carries the two settings this needs, both documented in place.
Install scripts are denied unless named, and esbuild and sharp are named because the
app does not build without them. The release-age gate is excluded by SCOPE for
@hanzo/* rather than by version, because pnpm rewrites a per-version entry on every
bump, and a file that rewrites itself during install makes --frozen-lockfile fail in
CI — the exact determinism this change exists to get.
Verified on pnpm 11.17.0: frozen-lockfile install clean, tsc 0 errors, 3056 tests
passing, `pnpm build` compiles, and `pnpm build:embed` emits the real bundle cloud
fail-hards on (367KB index.html, 5.5M _next). node_modules stays self-contained —
every symlink is relative into node_modules/.pnpm — so the runner stage's
COPY --from=build of node_modules still resolves.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Decomplect hanzoai/cloud's build: the console SPA static export (npm run
build:embed -> out/) is now a versioned immutable image (console-embed, /dist)
built by console's OWN CI, not re-run inside every cloud release. cloud will
FROM registry.hanzo.ai/hanzoai/console-embed:<ver> AS console + COPY --from,
turning the ~15-min cache-busted npm+Next long pole into a registry pull.
- Dockerfile.embed: node build -> FROM scratch with /dist (fail-hard on a
missing/placeholder bundle, same invariant cloud's console stage enforced;
bakes the same public console.hanzo.ai analytics id).
- hanzo.yml: images: console-embed (hanzoai/ci builds + auto-mirrors to
registry.hanzo.ai). Next.js server image stays in build-image.yml.
- cicd.yml: canonical hanzoai/ci caller.
Co-authored-by: hanzo-dev <dev@hanzo.ai>