From 25d52df8f1fd68ab69cd7ce4d9c6efa5276a5999 Mon Sep 17 00:00:00 2001 From: Typas Liao Date: Fri, 3 Jul 2026 00:35:59 +0800 Subject: [PATCH 1/2] feat(node): install fnm with Node LTS and enable pnpm install-node.sh installs fnm (--skip-shell to avoid the installer's shell-detection abort in CI), then Node LTS and enables pnpm via corepack. Early-exits when fnm + pnpm are already present. No arg: the install is OS-uniform like uv. Persistent shell integration added statically to settings-bash/.bashrc and settings-zsh/.zshrc after the julia blocks. Co-Authored-By: Claude Opus 4.8 --- README.md | 1 + scripts/install-node.sh | 36 ++++++++++++++++++++++++++++++++++++ settings-bash/.bashrc | 4 ++++ settings-zsh/.zshrc | 4 ++++ 4 files changed, 45 insertions(+) create mode 100644 scripts/install-node.sh diff --git a/README.md b/README.md index c09746e..dbd3919 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ bash init.sh | `just julia` | Install Julia via juliaup | | `just haskell` | Install Haskell via ghcup | | `just python` | Install uv (Python package manager) | +| `just node` | Install fnm (Node version manager) with Node LTS and enable pnpm via corepack | | `just go` / `just go update` | Install or update Go | | `just neovim` / `just neovim update` | Install or update Neovim (pass `home` to install under `~/.local`) | | `just emacs` / `just emacs update` | Install or update Emacs (system build is pgtk, home build is nox) | diff --git a/scripts/install-node.sh b/scripts/install-node.sh new file mode 100644 index 0000000..72a76af --- /dev/null +++ b/scripts/install-node.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +# fnm's install is OS-uniform (curl | bash), so no arg is needed. + +# fnm (Fast Node Manager) +# --skip-shell: the installer aborts with "Could not infer shell" when $SHELL is +# unset (CI / non-interactive). Persistent shell integration lives statically in the +# repo-tracked rc files (settings-bash/.bashrc, settings-zsh/.zshrc). +if ! command -v fnm &>/dev/null; then + curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell +fi + +export PATH="$HOME/.local/share/fnm:$PATH" +eval "$(fnm env)" + +# Already fully set up (fnm present with Node + pnpm) — nothing to do. +if command -v pnpm &>/dev/null; then + echo "fnm and pnpm are already installed" + fnm --version + node --version + pnpm --version + exit 0 +fi + +# Node LTS provides corepack, which provides pnpm +fnm install --lts +fnm use lts-latest +fnm default lts-latest + +# Enable pnpm shim via corepack +corepack enable pnpm + +fnm --version +node --version +pnpm --version diff --git a/settings-bash/.bashrc b/settings-bash/.bashrc index 75cab1e..e836afb 100644 --- a/settings-bash/.bashrc +++ b/settings-bash/.bashrc @@ -172,6 +172,10 @@ case ":$PATH:" in ;; esac +# fnm (Node version manager) +export PATH="$HOME/.local/share/fnm:$PATH" +command -v fnm >/dev/null && eval "$(fnm env --use-on-cd)" + # ble.sh attach and keybindings if [[ ${BLE_VERSION-} ]]; then ble-bind -m auto_complete -f 'S-TAB' auto_complete/insert diff --git a/settings-zsh/.zshrc b/settings-zsh/.zshrc index 6c82a6c..769ba59 100644 --- a/settings-zsh/.zshrc +++ b/settings-zsh/.zshrc @@ -79,6 +79,10 @@ export PATH # <<< juliaup initialize <<< +# fnm (Node version manager) +export PATH="$HOME/.local/share/fnm:$PATH" +command -v fnm >/dev/null && eval "$(fnm env --use-on-cd)" + [ -f "$HOME/.ghcup/env" ] && source "$HOME/.ghcup/env" # ghcup-envexport PYENV_ROOT="$HOME/.pyenv" [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" From fd809feb8e102b773bf69ff646bf3e5c696e4bde Mon Sep 17 00:00:00 2001 From: Typas Liao Date: Fri, 3 Jul 2026 01:39:29 +0800 Subject: [PATCH 2/2] fix(node): force bash for fnm env to fix CI shell inference fnm's process-tree shell detection is unreliable under CI's su -l ci -c "... just ...", so `fnm env` emitted nothing and the subsequent `fnm use` aborted with "We can't find the necessary environment variables". The script always runs under bash, so pass `--shell bash` explicitly. Note mac installs fnm via Homebrew (already on PATH), so the ~/.local/share/fnm prepend is a harmless no-op there. Co-Authored-By: Claude Opus 4.8 --- scripts/install-node.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/install-node.sh b/scripts/install-node.sh index 72a76af..457e5d6 100644 --- a/scripts/install-node.sh +++ b/scripts/install-node.sh @@ -11,8 +11,15 @@ if ! command -v fnm &>/dev/null; then curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell fi +# On Linux the installer drops fnm in ~/.local/share/fnm; on mac it uses Homebrew, +# which is already on PATH (this prepend is then a harmless no-op). export PATH="$HOME/.local/share/fnm:$PATH" -eval "$(fnm env)" +# --shell bash: this script always runs under bash (shebang + `bash ...` in the +# recipe), and fnm's process-tree shell detection is unreliable in CI +# (su -l ci -c ... just), emitting nothing so a later `fnm use` aborts with +# "We can't find the necessary environment variables". Forcing the shell is safe +# regardless of the user's interactive shell. +eval "$(fnm env --shell bash)" # Already fully set up (fnm present with Node + pnpm) — nothing to do. if command -v pnpm &>/dev/null; then