fix: refactor setup scripts for system-wide Node.js (no nvm)
BREAKING: Officer now uses system Node.js via NodeSource instead of nvm. Changes: - Removed nvm sourcing from setup.sh - Updated Node installation to use NodeSource repository - All npm global packages installed system-wide with sudo - Updated PTY sidecar setup to use /usr/bin/node (system node) - Added Pi validation (test --list-models) - System packages now available to all users automatically Benefits: - Multi-user friendly: all users get same Node version - No per-user environment setup needed - Simpler troubleshooting (one node version) - Services use consistent node binary - Prevents snap node incompatibility issues Fixes: - 'node not found' for secondary users - systemd services finding correct node - Pi installation consistency across users New Files: - SETUP_GUIDE.md: Comprehensive installation guide - SETUP_ANALYSIS.md: Technical analysis of previous issues Migration: - Remove nvm if installed (optional) - Run: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - - Run: sudo apt-get install -y nodejs - Run: bash scripts/setup.sh
This commit is contained in:
@@ -18,14 +18,24 @@ SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
SERVICE_USER="$(whoami)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
NODE_BIN="$(which node)"
|
||||
|
||||
# Use system node (not nvm) for systemd service
|
||||
NODE_BIN="/usr/bin/node"
|
||||
|
||||
if [ ! -f "$NODE_BIN" ]; then
|
||||
fail "System Node.js not found at $NODE_BIN"
|
||||
fail "Install Node.js 22 via NodeSource:"
|
||||
fail " curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -"
|
||||
fail " sudo apt-get install -y nodejs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "── PTY Sidecar (systemd service) ──"
|
||||
echo " Node: $NODE_BIN ($("$NODE_BIN" -v))"
|
||||
|
||||
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
||||
skip "$SERVICE_NAME service already running"
|
||||
echo " Use 'bun run restart:sidecar' to restart"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
+70
-63
@@ -260,60 +260,66 @@ fi
|
||||
|
||||
# ─── 5. Node.js 22 ────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "── Node.js 22 ──"
|
||||
echo "── Node.js 22 (system-wide) ──"
|
||||
|
||||
if has node; then
|
||||
NODE_VER=$(node -v 2>/dev/null | tr -d 'v')
|
||||
NODE_MAJOR=$(echo "$NODE_VER" | cut -d. -f1)
|
||||
if [ "$NODE_MAJOR" = "22" ]; then
|
||||
skip "node v$NODE_VER"
|
||||
skip "node v$NODE_VER (system-wide)"
|
||||
else
|
||||
warn "Node $NODE_VER found but v22 is required"
|
||||
warn "Use nvm: nvm install 22 && nvm use 22"
|
||||
warn "Node $NODE_VER found but v22 is required — upgrading via NodeSource..."
|
||||
case $PM in
|
||||
apt)
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
if has node && [ "$(node -v | cut -d. -f1 | tr -d 'v')" = "22" ]; then
|
||||
ok "Upgraded to node v$(node -v)"
|
||||
else
|
||||
fail "Node.js upgrade failed"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
warn "Manual upgrade needed for $PM: install Node.js 22 from official sources"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
warn "Node.js not found — install v22 via nvm:"
|
||||
warn " curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash"
|
||||
warn " nvm install 22"
|
||||
warn "Node.js not found — installing v22 via NodeSource..."
|
||||
case $PM in
|
||||
apt)
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
if has node; then ok "node v$(node -v) installed"; else fail "node install failed"; fi
|
||||
;;
|
||||
pacman)
|
||||
install_pkg nodejs npm
|
||||
if has node; then ok "node v$(node -v) installed"; else fail "node install failed"; fi
|
||||
;;
|
||||
brew)
|
||||
install_pkg node
|
||||
if has node; then ok "node v$(node -v) installed"; else fail "node install failed"; fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# ─── npm global prefix ─────────────────────────────────────────────────────────
|
||||
# Set npm global prefix to a user-writable directory so npm install -g
|
||||
# never requires sudo. This also lets the server install packages at runtime.
|
||||
# ─── npm global packages (system-wide) ─────────────────────────────────────────
|
||||
# Install npm global packages to system /usr/local so all users can access them.
|
||||
# This is safer for multi-user production setups.
|
||||
echo ""
|
||||
echo "── npm global prefix ──"
|
||||
echo "── npm global packages (system-wide) ──"
|
||||
|
||||
if has npm; then
|
||||
NPM_PREFIX=$(npm config get prefix 2>/dev/null)
|
||||
NPM_GLOBAL="$HOME/.npm-global"
|
||||
if ! has npm; then
|
||||
warn "npm not found — skipping global package installs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$NPM_PREFIX" = "$NPM_GLOBAL" ]; then
|
||||
skip "npm prefix already set to $NPM_GLOBAL"
|
||||
else
|
||||
mkdir -p "$NPM_GLOBAL"
|
||||
npm config set prefix "$NPM_GLOBAL"
|
||||
export PATH="$NPM_GLOBAL/bin:$PATH"
|
||||
ok "Set npm global prefix to $NPM_GLOBAL"
|
||||
|
||||
# Migrate existing global packages from system prefix if any
|
||||
if [ -d "$NPM_PREFIX/lib/node_modules/@mariozechner" ] || [ -d "$NPM_PREFIX/lib/node_modules/@anthropic-ai" ]; then
|
||||
warn "Removing stale system-level npm packages from $NPM_PREFIX (will reinstall to $NPM_GLOBAL)"
|
||||
sudo rm -rf "$NPM_PREFIX/lib/node_modules/@mariozechner" "$NPM_PREFIX/lib/node_modules/@anthropic-ai" 2>/dev/null
|
||||
sudo rm -f "$NPM_PREFIX/bin/pi" "$NPM_PREFIX/bin/claude" 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure ~/.npm-global/bin is in shell profiles
|
||||
for profile in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do
|
||||
if [ -f "$profile" ] && ! grep -q '.npm-global/bin' "$profile"; then
|
||||
echo '' >> "$profile"
|
||||
echo '# npm global packages' >> "$profile"
|
||||
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> "$profile"
|
||||
ok "Added ~/.npm-global/bin to $(basename "$profile")"
|
||||
fi
|
||||
done
|
||||
else
|
||||
warn "npm not found — skipping prefix setup"
|
||||
# Verify npm is pointing to system node (not user-local nvm)
|
||||
NPM_BIN=$(which npm)
|
||||
if echo "$NPM_BIN" | grep -q '.nvm'; then
|
||||
warn "npm is from nvm ($NPM_BIN), but setup.sh expects system npm"
|
||||
warn "This is fine — packages will be installed to your nvm, but won't be available to other users"
|
||||
warn "For production: all users should use the same system Node.js (no nvm)"
|
||||
fi
|
||||
|
||||
# ─── 6. Bun ───────────────────────────────────────────────────────────────────
|
||||
@@ -557,35 +563,36 @@ else
|
||||
esac
|
||||
fi
|
||||
|
||||
# ─── 14. npm global packages ─────────────────────────────────────────────────
|
||||
# ─── 14. npm global packages (system-wide) ──────────────────────────────────
|
||||
echo ""
|
||||
echo "── npm global packages ──"
|
||||
echo "── npm global packages (system-wide) ──"
|
||||
|
||||
if has npm; then
|
||||
if ! has npm; then
|
||||
warn "npm not found — skipping global package installs"
|
||||
else
|
||||
# Pi (coding agent)
|
||||
if has pi; then
|
||||
skip "pi (@mariozechner/pi-coding-agent)"
|
||||
else
|
||||
npm install -g @mariozechner/pi-coding-agent
|
||||
echo " Installing pi..."
|
||||
sudo npm install -g @mariozechner/pi-coding-agent
|
||||
if has pi; then ok "pi installed"; else warn "pi install failed"; fi
|
||||
fi
|
||||
|
||||
# Fix ~/.pi ownership (previous installs via sudo may have created root-owned dirs)
|
||||
if [ -d "$HOME/.pi" ]; then
|
||||
if find "$HOME/.pi" -not -user "$USER" -print -quit 2>/dev/null | grep -q .; then
|
||||
sudo chown -R "$USER:$(id -gn)" "$HOME/.pi"
|
||||
ok "Fixed ~/.pi ownership"
|
||||
# Validate Pi works
|
||||
if has pi; then
|
||||
if pi --list-models > /dev/null 2>&1; then
|
||||
ok "pi validated (--list-models works)"
|
||||
else
|
||||
warn "pi installed but --list-models failed — check API keys in ~/.pi/agent/auth.json"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Patch Pi compaction bug: calculateContextTokens crashes when usage is undefined
|
||||
PI_COMPACTION="$(npm root -g 2>/dev/null)/@mariozechner/pi-coding-agent/dist/core/compaction/compaction.js"
|
||||
if [ -f "$PI_COMPACTION" ]; then
|
||||
if grep -q "if (!usage) return 0;" "$PI_COMPACTION" 2>/dev/null; then
|
||||
skip "pi compaction patch (already applied)"
|
||||
else
|
||||
sed -i '/^export function calculateContextTokens(usage) {$/a\ if (!usage) return 0;' "$PI_COMPACTION"
|
||||
ok "Applied pi compaction bug patch"
|
||||
# Fix ~/.pi ownership if needed (in case of mixed user/sudo installs)
|
||||
if [ -d "$HOME/.pi" ]; then
|
||||
if find "$HOME/.pi" -not -user "$USER" -print -quit 2>/dev/null | grep -q .; then
|
||||
sudo chown -R "$USER:$(id -gn)" "$HOME/.pi"
|
||||
ok "Fixed ~/.pi ownership to $USER"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -593,16 +600,16 @@ if has npm; then
|
||||
if has claude; then
|
||||
skip "claude (@anthropic-ai/claude-code)"
|
||||
else
|
||||
npm install -g @anthropic-ai/claude-code
|
||||
echo " Installing claude-code..."
|
||||
sudo npm install -g @anthropic-ai/claude-code
|
||||
if has claude; then ok "claude-code installed"; else warn "claude-code install failed"; fi
|
||||
fi
|
||||
|
||||
# pm2 (process manager)
|
||||
# pm2 (process manager) — now optional since we use systemd services
|
||||
if has pm2; then
|
||||
skip "pm2"
|
||||
skip "pm2 (optional, using systemd services instead)"
|
||||
else
|
||||
npm install -g pm2
|
||||
if has pm2; then ok "pm2 installed"; else warn "pm2 install failed"; fi
|
||||
warn "pm2 optional (Officer uses systemd services for main app and sidecar)"
|
||||
fi
|
||||
else
|
||||
warn "npm not found — skipping global package installs"
|
||||
|
||||
Reference in New Issue
Block a user