#!/bin/sh # update-pi-devdeps.sh — refresh every package-local @earendil-works/* dev # dependency (pinned to "latest" in each manifest) and re-resolve the lockfiles # to the newest published Pi release. # # Runs `npm update` in the bundle root and in every top-level directory that has # its own package-lock.json and declares @earendil-works/* devDependencies. # Package dirs without Pi devDependencies (locks without @earendil-works # entries) are skipped, so the Pi host runtime never lands where it does not # belong. set -eu cd "$(dirname "$0")/.." ROOT=$(pwd) # prints the @earendil-works/* devDependency names declared in $1/package.json pi_devdeps_of() { node -e ' const pkg = require(process.argv[1]); const devDeps = pkg.devDependencies || {}; const names = Object.keys(devDeps).filter((n) => n.startsWith("@earendil-works/")); process.stdout.write(names.join(" ")); ' "$1/package.json" } update_dir() { dir=$1 names=$(pi_devdeps_of "$dir") if [ -z "$names" ]; then echo "skip $dir (no @earendil-works/* devDependencies)" return 0 fi echo "==> npm update in $dir: $names" # Word splitting is intended: $names is a space-separated package list. # shellcheck disable=SC2086 (cd "$dir" && npm update $names) } # The root declares no devDependencies, but its lock records the linked # packages' @earendil-works/* devDependencies, so it is always refreshed. echo "==> npm update in $ROOT" (cd "$ROOT" && npm update @earendil-works/pi-ai @earendil-works/pi-coding-agent @earendil-works/pi-tui) for dir in "$ROOT"/*/; do [ -f "$dir/package-lock.json" ] || continue [ -f "$dir/package.json" ] || continue update_dir "$dir" done