Files
stack/package.json
T
Jason WoltjeandClaude Opus 5 cb2bf4e4a4
ci/woodpecker/pr/ci Pipeline is pending approval
installer: provision Node instead of refusing to run without it
The installer's promise is that one command turns a bare host into a working
one, but Node was carved out of that: it was checked as a prerequisite and the
run died on a greenfield host. That made the documented one-command install a
two-command install whose first command always failed.

It now installs a user-local Node under ~/.mosaic/node when the system Node is
missing or too old, from the official nodejs.org tarballs, verified against
SHASUMS256.txt. User-local rather than apt/dnf/brew: no root, one code path on
every distro, and it works on an immutable host. A system Node that is already
new enough is preferred and left untouched. --no-node-install (or
MOSAIC_NO_NODE_INSTALL=1) keeps the old refuse-and-explain behaviour, and
neither --check nor --uninstall provisions anything.

PATH now lands in the login profile as well as the interactive rc. Writing only
~/.bashrc looked right interactively and was invisible to every way an agent
seat actually starts -- bash -lc, ssh host cmd, a systemd unit -- because
Debian's .bashrc returns early when non-interactive.

Verified end to end on mosaic-sbx-dev rolled back to its greenfield snapshot:
red on origin/next (rc=1, "Required command not found: node"), green with this
change (Node v22.23.2 fetched and verified, CLI 0.0.50-next.2413 installed), and
a fresh `bash -lc` finds both. tools/install-node-provisioning.test.sh pins the
behaviour offline against a file:// dist fixture, including the refusals and the
checksum gate.

The next-lane test's Node 20 case moves to --no-node-install: the >= 22 gate must
still fire before anything is installed, but refusing is no longer the outcome
when provisioning is allowed.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WYgWocp36goy8hj2ui6ps1
2026-08-15 12:44:39 -05:00

33 lines
1.1 KiB
JSON

{
"name": "mosaic-stack",
"private": true,
"packageManager": "[email protected]",
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"preflight": "node scripts/preflight.mjs",
"clean:generated": "node scripts/clean-generated.mjs",
"typecheck": "pnpm preflight && turbo run typecheck",
"test:checkout": "node --test scripts/*.test.mjs",
"test": "pnpm test:checkout && turbo run test && pnpm run test:installer",
"test:installer": "bash tools/install-next-lane.test.sh && bash tools/install-node-provisioning.test.sh",
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"",
"prepare": "node scripts/install-hooks.mjs"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"eslint": "^9.0.0",
"typescript-eslint": "^8.0.0",
"husky": "^9.0.0",
"lint-staged": "^15.0.0",
"prettier": "^3.0.0",
"turbo": "^2.0.0",
"typescript": "^5.8.0",
"vitest": "^2.0.0"
},
"license": "MIT"
}