fix(setup): mirror nvm init into .zshrc so zsh sees node + pnpm #255

Merged
julien merged 1 commits from fix/dev-vm-nvm-zshrc into main 2026-05-29 18:55:31 +02:00
Owner

Summary

Fix the dev-VM bootstrap so node and pnpm are on PATH in zsh sessions. On a fresh VM provisioned with docs/setup/scripts/, a freshly-cloned checkout fails to run anything (command not found: pnpm, and node too) because the nvm init never reaches the interactive shell.

Root cause

Two setup scripts interact badly:

  • 20-zsh.sh patches ~/.bashrc with an exec zsh -l hand-off on interactive shells (chsh is blocked on the corp VM, so this is how zsh becomes the effective shell), and patches ~/.zshrc with theme/plugins/fzf only.
  • 40-node.sh runs the upstream nvm installer, which appends its init block to ~/.bashrc (its default target).

Because 20-zsh.sh runs first, the exec zsh -l guard sits above the nvm block in ~/.bashrc. On every interactive shell, bash execs into zsh before reaching the nvm block — so it never runs — and ~/.zshrc has no nvm init at all. Net result: zsh sessions have neither node nor pnpm on PATH, even though nvm + Node + corepack installed correctly.

This is a procedure bug, not a one-off: every VM built from these scripts hits it.

Fix

40-node.sh now mirrors the nvm init block into ~/.zshrc after enabling corepack — idempotent via a managed marker, same pattern 20-zsh.sh already uses for its ~/.bashrc patch:

# Managed by docs/setup/scripts/40-node.sh — nvm init for zsh.
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

docs/setup/01-dev-debian-vm-setup.md — the 40-node.sh row in the bootstrap table now notes the ~/.zshrc patch and why it is needed.

What lands

File Change
docs/setup/scripts/40-node.sh Append an idempotent nvm-init block to ~/.zshrc after corepack enable.
docs/setup/01-dev-debian-vm-setup.md Document the ~/.zshrc nvm patch in the 40-node.sh table row.

Manual remediation for already-provisioned VMs

VMs built before this fix won't be retroactively patched (the scripts are idempotent and skip already-installed nvm). On those, run once:

cat >> ~/.zshrc <<'EOF'

# nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
EOF
exec zsh -l

(Or re-run 40-node.sh once this lands — the marker check makes it safe; it will add the block and skip the rest.)

Test plan

  • bash -n docs/setup/scripts/40-node.sh — syntax valid.
  • Manual remediation block verified on the affected VM: after appending + exec zsh -l, node --version (v24) and pnpm --version (10.34.1) both resolve.
  • Next fresh VM bootstrap: node + pnpm resolve in the first zsh session with no manual step.
  • Re-running 40-node.sh on an already-set-up VM is a no-op on the nvm install and adds the ~/.zshrc block exactly once (marker idempotency).

Related

  • docs/setup/01-dev-debian-vm-setup.md — dev-VM bootstrap procedure.
  • 20-zsh.sh — owns the .bashrc → zsh hand-off this fix complements.
## Summary Fix the dev-VM bootstrap so `node` and `pnpm` are on `PATH` in zsh sessions. On a fresh VM provisioned with `docs/setup/scripts/`, a freshly-cloned checkout fails to run anything (`command not found: pnpm`, and `node` too) because the nvm init never reaches the interactive shell. ## Root cause Two setup scripts interact badly: - `20-zsh.sh` patches `~/.bashrc` with an `exec zsh -l` hand-off on interactive shells (chsh is blocked on the corp VM, so this is how zsh becomes the effective shell), and patches `~/.zshrc` with theme/plugins/fzf only. - `40-node.sh` runs the upstream nvm installer, which appends its init block to **`~/.bashrc`** (its default target). Because `20-zsh.sh` runs first, the `exec zsh -l` guard sits **above** the nvm block in `~/.bashrc`. On every interactive shell, bash execs into zsh before reaching the nvm block — so it never runs — and `~/.zshrc` has no nvm init at all. Net result: zsh sessions have neither `node` nor `pnpm` on `PATH`, even though nvm + Node + corepack installed correctly. This is a procedure bug, not a one-off: every VM built from these scripts hits it. ## Fix `40-node.sh` now mirrors the nvm init block into `~/.zshrc` after enabling corepack — idempotent via a managed marker, same pattern `20-zsh.sh` already uses for its `~/.bashrc` patch: ```sh # Managed by docs/setup/scripts/40-node.sh — nvm init for zsh. export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" ``` `docs/setup/01-dev-debian-vm-setup.md` — the `40-node.sh` row in the bootstrap table now notes the `~/.zshrc` patch and why it is needed. ## What lands | File | Change | | --- | --- | | `docs/setup/scripts/40-node.sh` | Append an idempotent nvm-init block to `~/.zshrc` after corepack enable. | | `docs/setup/01-dev-debian-vm-setup.md` | Document the `~/.zshrc` nvm patch in the `40-node.sh` table row. | ## Manual remediation for already-provisioned VMs VMs built before this fix won't be retroactively patched (the scripts are idempotent and skip already-installed nvm). On those, run once: ```sh cat >> ~/.zshrc <<'EOF' # nvm export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" EOF exec zsh -l ``` (Or re-run `40-node.sh` once this lands — the marker check makes it safe; it will add the block and skip the rest.) ## Test plan - [x] `bash -n docs/setup/scripts/40-node.sh` — syntax valid. - [x] Manual remediation block verified on the affected VM: after appending + `exec zsh -l`, `node --version` (v24) and `pnpm --version` (10.34.1) both resolve. - [ ] Next fresh VM bootstrap: `node` + `pnpm` resolve in the first zsh session with no manual step. - [ ] Re-running `40-node.sh` on an already-set-up VM is a no-op on the nvm install and adds the `~/.zshrc` block exactly once (marker idempotency). ## Related - `docs/setup/01-dev-debian-vm-setup.md` — dev-VM bootstrap procedure. - `20-zsh.sh` — owns the `.bashrc` → zsh hand-off this fix complements.
julien added 1 commit 2026-05-29 17:22:37 +02:00
fix(setup): mirror nvm init into .zshrc so zsh sees node + pnpm
CI / scan (pull_request) Successful in 4m38s
CI / commits (pull_request) Successful in 4m37s
CI / check (pull_request) Successful in 4m53s
CI / a11y (pull_request) Successful in 3m14s
Docs site / build (pull_request) Successful in 3m20s
CI / perf (pull_request) Successful in 4m49s
ef7c1a72b2
On the dev VM, 20-zsh.sh hands off to zsh via an exec in .bashrc
(chsh is blocked on the corp VM), and 40-node.sh's nvm installer only
patches .bashrc. The hand-off execs zsh before the nvm block runs and
.zshrc has no nvm init, so zsh sessions get neither node nor pnpm on
PATH on a fresh clone.

40-node.sh now appends an idempotent nvm-init block to .zshrc after
corepack enable (same marker pattern 20-zsh.sh uses for .bashrc).
Document the .zshrc patch in the bootstrap table.

Already-provisioned VMs: re-run 40-node.sh (marker-safe) or append the
block manually.
julien merged commit 645f81a443 into main 2026-05-29 18:55:31 +02:00
julien deleted branch fix/dev-vm-nvm-zshrc 2026-05-29 18:55:35 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: julien/apf_portal#255