Files

312 lines
12 KiB
Bash
Executable File

#!/usr/bin/env bash
# shellcheck disable=SC2086
# Installs Pi Coding Agent and recommended packages.
# Pi: https://pi.dev
#
# Supported platforms:
# macOS : Apple Silicon (arm64), Intel (x86_64)
# Linux : x86_64, aarch64
#
# Prerequisites:
# - Node.js 18+ (and npm)
# - curl
set -euo pipefail
# ────────────────────────────────────────────
# Constants
# ────────────────────────────────────────────
PI_INSTALL_URL="https://pi.dev/install.sh"
PI_NPM_PACKAGE="@earendil-works/pi-coding-agent"
# Packages to install after pi is available
# Format: "package_name|description"
PACKAGES=(
"pi-subagents|Delegate work to focused child agents — code review, scouting, implementation, parallel audits, orchestration, background jobs"
"context-mode|Context window protection — sandbox tools, session continuity, BM25 knowledge base, think-in-code paradigm"
"pi-mcp-adapter|Use MCP servers with Pi without burning your context window — one proxy tool instead of hundreds"
"pi-web-access|Web search, content extraction, and video understanding — zero-config Exa search, Perplexity, Gemini, YouTube"
"@plannotator/pi-extension|File-based plan mode with visual browser UI for reviewing, annotating, and approving agent plans"
"@juicesharp/rpiv-ask-user-question|Structured questionnaire tool with typed options — the model asks you instead of guessing"
"pi-lens|Real-time code feedback — LSP diagnostics, linters, formatters, type-checking, structural analysis, read-before-edit guard"
"@juicesharp/rpiv-todo|Persistent todo list across sessions — tasks survive /reload and compaction with dependency tracking"
"pi-simplify|Review recently changed code for clarity, consistency, and maintainability improvements"
"@juicesharp/rpiv-advisor|Second opinion from a stronger reviewer model before the agent acts"
"@juicesharp/rpiv-pi|Skill-based development workflow — discover, research, design, plan, implement, validate pipeline with named subagents"
"@samfp/pi-memory|Persistent memory for Pi — learns corrections, preferences, and project patterns across sessions"
"pi-btw|Parallel side conversations (/btw) without interrupting the main agent run"
"pi-docparser|Document parsing tool — PDFs, Office docs, spreadsheets, images, and OCR via LiteParse"
"pi-ollama-cloud|Ollama Cloud provider plugin — dynamic model discovery, web search and fetch tools, no local server required"
)
# ────────────────────────────────────────────
# Utility functions (all stderr output)
# ────────────────────────────────────────────
info() { echo "[INFO] $*" >&2; }
warn() { echo "[WARN] $*" >&2; }
error() {
echo "[ERROR] $*" >&2
exit 1
}
success() { echo "[OK] $*" >&2; }
# ────────────────────────────────────────────
# Ensure Homebrew is available on macOS
# ────────────────────────────────────────────
ensure_brew() {
if command -v brew &>/dev/null; then
return 0
fi
info "Homebrew is not installed. Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
if [ -d /opt/homebrew/bin ]; then
export PATH="/opt/homebrew/bin:$PATH"
fi
if [ -d /usr/local/bin ]; then
export PATH="/usr/local/bin:$PATH"
fi
command -v brew &>/dev/null || error "Homebrew installation failed. Install it manually: https://brew.sh/"
success "Homebrew installed"
}
# ────────────────────────────────────────────
# Detect OS / Architecture
# ────────────────────────────────────────────
OS="$(uname -s)"
ARCH="$(uname -m)"
# ────────────────────────────────────────────
# Check required commands
# ────────────────────────────────────────────
for cmd in curl; do
command -v "$cmd" &>/dev/null || error "'$cmd' is required."
done
# Check for Node.js (npm) — install if missing
if ! command -v npm &>/dev/null; then
info "npm is not installed. Installing Node.js..."
case "$OS" in
Darwin)
ensure_brew
brew install node
success "Node.js installed via Homebrew"
;;
Linux)
if command -v apt-get &>/dev/null; then
sudo apt-get update -y && sudo apt-get install -y nodejs npm
success "Node.js installed via apt-get"
elif command -v dnf &>/dev/null; then
sudo dnf install -y nodejs
success "Node.js installed via dnf"
elif command -v yum &>/dev/null; then
sudo yum install -y nodejs
success "Node.js installed via yum"
elif command -v zypper &>/dev/null; then
sudo zypper -n install nodejs npm
success "Node.js installed via zypper"
elif command -v pacman &>/dev/null; then
sudo pacman -S --noconfirm nodejs npm
success "Node.js installed via pacman"
else
error "No supported package manager found. Install Node.js 18+ manually: https://nodejs.org/"
fi
;;
*)
error "Cannot auto-install Node.js on this OS. Install Node.js 18+ manually: https://nodejs.org/"
;;
esac
# Verify npm is now available
if ! command -v npm &>/dev/null; then
error "Node.js installation completed but npm not found. Install Node.js 18+ manually: https://nodejs.org/"
fi
fi
info "npm is available: $(command -v npm)"
# ────────────────────────────────────────────
# Detect OS / Architecture (already set above)
# ────────────────────────────────────────────
case "$OS" in
Darwin | Linux) ;;
*)
error "Unsupported OS: $OS. This script only supports macOS and Linux."
;;
esac
info "Platform: $OS ($ARCH)"
# ────────────────────────────────────────────
# Step 1: Install Pi Coding Agent
# ────────────────────────────────────────────
info "Installing Pi Coding Agent..."
if command -v pi &>/dev/null; then
CURRENT_VER="$(pi --version 2>/dev/null || echo 'unknown')"
info "Pi is already installed (version: $CURRENT_VER). Skipping installation."
else
# Try curl-based installer first
if curl -fsSL "$PI_INSTALL_URL" 2>/dev/null | sh; then
success "Pi installed via curl installer"
else
# Fallback to npm
info "curl install failed. Falling back to npm..."
command -v npm &>/dev/null || error "npm is required. Install Node.js 18+: https://nodejs.org/"
npm install -g "$PI_NPM_PACKAGE"
success "Pi installed via npm"
fi
fi
# ────────────────────────────────────────────
# Resolve pi binary path (may not be in PATH yet after fresh install)
# ────────────────────────────────────────────
PI_BIN=""
# 1) Try current PATH
if command -v pi &>/dev/null; then
PI_BIN="$(command -v pi)"
fi
# 2) Try expanding common locations where npm/pip/curl-installer place the binary
# pi-node uses versioned dirs like node-v22.22.2-linux-x64, so we glob for any subdir
if [ -z "$PI_BIN" ]; then
for candidate in \
"$HOME/.local/share/pi-node/current/bin/pi" \
"$HOME/.local/bin/pi" \
"$HOME/.npm/bin/pi" \
"/usr/local/bin/pi" \
"$HOME/.nvm/versions/node/$(ls "$HOME/.nvm/versions/node/" 2>/dev/null | tail -1)/bin/pi" \
"${NVM_DIR:-$HOME/.nvm}/versions/node/$(ls "${NVM_DIR:-$HOME/.nvm}/versions/node/" 2>/dev/null | tail -1)/bin/pi"; do
if [ -x "$candidate" ]; then
PI_BIN="$candidate"
break
fi
done
# Glob for pi-node versioned installs (e.g. ~/.local/share/pi-node/node-v22.22.2-linux-x64/bin/pi)
if [ -z "$PI_BIN" ]; then
_latest_pi_node="$HOME/.local/share/pi-node"
if [ -d "$_latest_pi_node" ]; then
_pi_node_bin="$(find "$_latest_pi_node" -name pi -path '*/bin/pi' -type f 2>/dev/null | head -1)"
if [ -n "$_pi_node_bin" ] && [ -x "$_pi_node_bin" ]; then
PI_BIN="$_pi_node_bin"
fi
fi
fi
fi
# 3) Try npm prefix to locate the global bin
if [ -z "$PI_BIN" ] && command -v npm &>/dev/null; then
NPM_PREFIX="$(npm config get prefix 2>/dev/null || true)"
if [ -n "$NPM_PREFIX" ] && [ -x "$NPM_PREFIX/bin/pi" ]; then
PI_BIN="$NPM_PREFIX/bin/pi"
fi
fi
# Add pi's directory to PATH for this session so pi install subprocess works,
# and permanently add it to the shell profile if not already there.
if [ -n "$PI_BIN" ]; then
PI_DIR="$(dirname "$PI_BIN")"
case ":$PATH:" in
*":$PI_DIR:"*) ;; # already in PATH
*)
export PATH="$PI_DIR:$PATH"
info "Added $PI_DIR to PATH for this session"
# Permanently add to shell profile
SHELL_RC=""
if [ -n "${ZSH_VERSION:-}" ] && [ -f "$HOME/.zshrc" ]; then
SHELL_RC="$HOME/.zshrc"
elif [ -f "$HOME/.bashrc" ]; then
SHELL_RC="$HOME/.bashrc"
fi
if [ -n "$SHELL_RC" ]; then
PATH_LINE="export PATH=\"$PI_DIR:\$PATH\""
if ! grep -qF "$PI_DIR" "$SHELL_RC" 2>/dev/null; then
echo "" >>"$SHELL_RC"
echo "# Added by install-pi.sh" >>"$SHELL_RC"
echo "$PATH_LINE" >>"$SHELL_RC"
success "Added $PI_DIR to $SHELL_RC (takes effect on next login)"
else
info "$PI_DIR already in $SHELL_RC"
fi
else
warn "Could not detect shell config. Add this line to your profile manually:"
warn " export PATH=\"$PI_DIR:\$PATH\""
fi
;;
esac
success "Pi is available: $PI_BIN"
else
error "'pi' command not found. Check your PATH or reinstall Node.js."
fi
# ────────────────────────────────────────────
# Step 2: Install packages using the resolved pi binary
# ────────────────────────────────────────────
info ""
info "Installing Pi packages..."
info "────────────────────────────────────────"
TOTAL=${#PACKAGES[@]}
COUNT=0
FAILED=()
for entry in "${PACKAGES[@]}"; do
PKG="${entry%%|*}"
DESC="${entry#*|}"
COUNT=$((COUNT + 1))
info "[$COUNT/$TOTAL] $PKG — $DESC"
if "$PI_BIN" install "npm:$PKG" 2>&1; then
success " → $PKG installed"
else
warn " → $PKG failed (install manually later: pi install npm:$PKG)"
FAILED+=("$PKG")
fi
done
info ""
info "────────────────────────────────────────"
if [ ${#FAILED[@]} -eq 0 ]; then
success "All packages installed! ($TOTAL/$TOTAL)"
else
warn "Some packages failed to install:"
for pkg in "${FAILED[@]}"; do
warn " - $pkg"
done
info "You can install failed packages manually with:"
for pkg in "${FAILED[@]}"; do
info " pi install npm:$pkg"
done
fi
# ────────────────────────────────────────────
# Step 3: Post-install notes
# ────────────────────────────────────────────
info ""
info "══════════════════════════════════════════"
success "Pi Coding Agent installation complete!"
info "══════════════════════════════════════════"
info ""
info "Pi binary: $PI_BIN"
info ""
info "Getting started:"
info " 1. Navigate to your project: cd /path/to/project"
info " 2. Start Pi: pi"
info " 3. Log in: /login"
info ""
info "Useful commands:"
info " pi — Start interactive session"
info " pi -p '...' — Ask a single question (print mode)"
info " pi --help — Show help"
info ""
info "List installed packages:"
info " pi list — Show installed packages"
info ""
info "For Ollama Cloud:"
info " Set your API key in ~/.pi/agent/auth.json"
info " See: https://pi.dev/packages/pi-ollama-cloud"