diff --git a/build.sh b/build.sh index 55ee93a6..883359b1 100755 --- a/build.sh +++ b/build.sh @@ -531,8 +531,8 @@ EOF echo " Fetch complete." - # Fetch npm-global CLI tarballs (claude-code, gemini-cli, pi) - echo "==> [2b/7] Fetching npm-global CLI tarballs..." + # Fetch pinned npm-global CLI tarballs (pi, gemini-cli) + echo "==> [2b/7] Fetching pinned npm-global CLI tarballs..." OUT_DIR="$NPM_GLOBALS_DIR" "${SCRIPT_DIR}/scripts/fetch-npm-globals.sh" || { echo " ERROR: fetch-npm-globals.sh failed" exit 1 diff --git a/firstboot/MODULE-MANIFEST.md b/firstboot/MODULE-MANIFEST.md index 73fe8232..d1d4a2d8 100644 --- a/firstboot/MODULE-MANIFEST.md +++ b/firstboot/MODULE-MANIFEST.md @@ -436,7 +436,7 @@ ### **1.5.1: shell-npm-globals.sh** -**Purpose:** Install bundled npm CLI tools (claude, gemini, pi) from ISO cache +**Purpose:** Install pinned bundled npm CLI tools (pi, gemini) from ISO cache **Wizard Inputs:** None (automatic) diff --git a/firstboot/firstboot.sh b/firstboot/firstboot.sh index 382d850e..98cbc1a7 100644 --- a/firstboot/firstboot.sh +++ b/firstboot/firstboot.sh @@ -317,7 +317,7 @@ run_step_if "install" "system" clawdie_shell_system_config "H run_step_if "install" "desktop" clawdie_shell_desktop_detect "Desktop enablement" 7 run_step_if "install" "pf" clawdie_shell_pf "PF firewall + jail NAT" 8 run_step_if "install" "tailscale" clawdie_shell_tailscale_setup "Tailscale remote access" 8 -run_step_if "install upgrade" "npm-globals" clawdie_shell_npm_globals_install "Install bundled npm CLIs (claude/gemini/pi)" 8 +run_step_if "install upgrade" "npm-globals" clawdie_shell_npm_globals_install "Install pinned bundled npm CLIs (pi/gemini)" 8 run_step_if "install upgrade" "deploy" clawdie_shell_deploy "Extract tarball + just install" 8 log_msg "[firstboot] Complete." diff --git a/firstboot/shell-npm-globals.sh b/firstboot/shell-npm-globals.sh index 036d61f5..d57c0da6 100755 --- a/firstboot/shell-npm-globals.sh +++ b/firstboot/shell-npm-globals.sh @@ -1,11 +1,11 @@ #!/bin/sh # Clawdie Shell — NPM Globals Module -# Purpose: Install bundled npm-global CLI tools (claude-code, gemini-cli, pi) +# Purpose: Install pinned bundled npm-global CLI tools (pi, gemini-cli) # from local tarballs shipped on the install media. Fully offline. # POSIX-compliant (no bash-isms) # # Runs after shell-pkg.sh (so node24 + npm exist) and before shell-deploy.sh -# (so the agent runtime can find `claude`, `gemini`, `pi` on PATH at first run). +# (so the agent runtime can find `pi` and `gemini` on PATH at first run). set -eu diff --git a/packages/npm-globals.txt b/packages/npm-globals.txt new file mode 100644 index 00000000..951e8f05 --- /dev/null +++ b/packages/npm-globals.txt @@ -0,0 +1,8 @@ +# Bundled npm global CLIs for offline firstboot/live operator use. +# Pin exact versions to prevent build-to-build drift. +# +# Keep Pi current through coordinated version-sync work; do not rely on +# npm's moving latest dist-tag during ISO builds. + +@earendil-works/pi-coding-agent@0.75.5 +@google/gemini-cli@0.43.0 diff --git a/scripts/fetch-npm-globals.sh b/scripts/fetch-npm-globals.sh index d10c42a8..f8b20540 100755 --- a/scripts/fetch-npm-globals.sh +++ b/scripts/fetch-npm-globals.sh @@ -1,36 +1,39 @@ #!/bin/sh # Fetch npm-global CLIs as .tgz tarballs for offline install on the ISO target. # -# These three packages are agent runtimes the firstboot installer will -# `npm install -g` from local tarballs (no network needed): -# -# @anthropic-ai/claude-code — Claude Code CLI (agent harness) -# @google/gemini-cli — Gemini CLI (alt agent) -# @earendil-works/pi-coding-agent — pi CLI (used by Clawdie-AI + paperclip adapters) +# These packages are installed by firstboot with `npm install -g` from local +# tarballs (no network needed on the target). Exact versions are pinned in +# packages/npm-globals.txt to prevent build-to-build drift. # # Notes: # - Codex is shipped via the FreeBSD `codex` pkg (see pkg-list-host.txt), # not via npm — kept out of this bundle on purpose. +# - Claude Code is intentionally not bundled in the XFCE USB image path. # - opencode + cursor have no working FreeBSD distribution (upstream gap). # - Output is dual-purpose: bundled into the ISO and used by firstboot. # # Usage: # ./scripts/fetch-npm-globals.sh # fetch into tmp/npm-globals/ # OUT_DIR=/some/path ./scripts/fetch-npm-globals.sh +# NPM_GLOBALS_LIST=/path/to/list ./scripts/fetch-npm-globals.sh set -eu SCRIPT_DIR="$(dirname "$(realpath "$0")")" ROOT_DIR="$(dirname "$SCRIPT_DIR")" OUT_DIR="${OUT_DIR:-${ROOT_DIR}/tmp/npm-globals}" - -PACKAGES="@anthropic-ai/claude-code @google/gemini-cli @earendil-works/pi-coding-agent" +NPM_GLOBALS_LIST="${NPM_GLOBALS_LIST:-${ROOT_DIR}/packages/npm-globals.txt}" if ! command -v npm >/dev/null 2>&1; then echo "ERROR: npm not found in PATH (install www/npm-node24)" >&2 exit 1 fi +if [ ! -f "$NPM_GLOBALS_LIST" ]; then + echo "ERROR: npm globals list not found: $NPM_GLOBALS_LIST" >&2 + exit 1 +fi + mkdir -p "$OUT_DIR" cd "$OUT_DIR" @@ -40,13 +43,17 @@ cd "$OUT_DIR" rm -f ./*.tgz echo "==> Fetching npm-global tarballs into ${OUT_DIR}" -for pkg in $PACKAGES; do +echo "==> Package list: ${NPM_GLOBALS_LIST}" +while IFS= read -r pkg || [ -n "$pkg" ]; do + case "$pkg" in + ''|'#'*) continue ;; + esac echo " npm pack ${pkg}" - # `npm pack ` downloads the latest published tarball without + # `npm pack @` downloads the pinned published tarball without # installing it. Output is `-.tgz` (scoped names get # their slash flattened to a dash). npm pack "$pkg" >/dev/null -done +done < "$NPM_GLOBALS_LIST" echo "" echo "==> Bundle contents:"