| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- #!/usr/bin/env bash
- # ============================================================
- # Claude Code — Plugin installer
- # Run this after a fresh clone to reinstall all plugins
- # and their prerequisites on a new machine.
- #
- # Supports: Linux (apt/dnf/pacman), macOS (brew)
- # ============================================================
- set -euo pipefail
- RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
- ok() { echo -e "${GREEN}✓${NC} $1"; }
- warn() { echo -e "${YELLOW}⚠${NC} $1"; }
- info() { echo -e "${BLUE}→${NC} $1"; }
- err() { echo -e "${RED}✗${NC} $1"; }
- REPO="$(cd "$(dirname "$0")" && pwd)"
- # Log to file for post-mortem debugging (terminal output unchanged)
- LOG_FILE="$REPO/install-$(date +%Y%m%d-%H%M%S).log"
- if touch "$LOG_FILE" 2>/dev/null; then
- exec > >(tee -a "$LOG_FILE") 2>&1
- info "Logging to $LOG_FILE"
- else
- warn "Cannot write log to $REPO — continuing without log file"
- fi
- # Load shared detection library
- # shellcheck source=lib/detect-plugins.sh
- source "$REPO/lib/detect-plugins.sh"
- # Read pinned version from plugins.lock.json
- # Usage: pinned_version "rtk" → prints version string or "latest"
- pinned_version() {
- local key="$1"
- if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
- python3 -c "
- import json, sys
- with open('$REPO/plugins.lock.json') as f:
- d = json.load(f)
- v = d.get('$key', {}).get('version', 'latest')
- print(v)
- " 2>/dev/null || echo "latest"
- else
- echo "latest"
- fi
- }
- # ============================================================
- # DETECT OS
- # ============================================================
- OS="unknown"
- PKG=""
- if [[ "$OSTYPE" == "darwin"* ]]; then
- OS="macos"
- elif command -v apt-get &>/dev/null; then
- OS="linux-apt"; PKG="apt-get"
- elif command -v dnf &>/dev/null; then
- OS="linux-dnf"; PKG="dnf"
- elif command -v pacman &>/dev/null; then
- OS="linux-pacman"; PKG="pacman"
- fi
- echo ""
- echo "╔══════════════════════════════════════════════════════════╗"
- echo "║ Claude Code — Plugin & Tool Installer ║"
- echo "╚══════════════════════════════════════════════════════════╝"
- echo ""
- info "OS: $OS | Repo: $REPO"
- echo ""
- # ============================================================
- # STEP 1 — PREREQUISITES
- # ============================================================
- echo "── Step 1: Prerequisites ───────────────────────────────────"
- echo ""
- # --- git ---
- if command -v git &>/dev/null; then
- ok "git $(git --version | awk '{print $3}')"
- else
- info "Installing git..."
- case $OS in
- macos) brew install git ;;
- linux-apt) sudo apt-get install -y git ;;
- linux-dnf) sudo dnf install -y git ;;
- linux-pacman) sudo pacman -S --noconfirm git ;;
- *) err "Cannot auto-install git on $OS — install manually"; exit 1 ;;
- esac
- ok "git installed"
- fi
- # --- Node.js (>=18) ---
- NODE_OK=false
- if command -v node &>/dev/null; then
- NODE_VER=$(node --version | sed 's/v//' | cut -d. -f1)
- if [ "$NODE_VER" -ge 22 ]; then
- ok "Node.js $(node --version)"; NODE_OK=true
- else
- warn "Node.js $(node --version) is too old (need >=22 — GSD v2 requires it)"
- fi
- fi
- if [ "$NODE_OK" = false ]; then
- info "Installing Node.js 22 LTS..."
- case $OS in
- macos)
- brew install node@22
- export PATH="/opt/homebrew/opt/node@22/bin:$PATH"
- ;;
- linux-apt)
- curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
- sudo apt-get install -y nodejs
- ;;
- linux-dnf)
- curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash -
- sudo dnf install -y nodejs
- ;;
- linux-pacman)
- sudo pacman -S --noconfirm nodejs npm
- ;;
- *) warn "Cannot auto-install Node.js on $OS — install from https://nodejs.org" ;;
- esac
- command -v node &>/dev/null && ok "Node.js $(node --version)" || err "Node.js install failed"
- fi
- # --- Rust + Cargo (for RTK) ---
- if command -v cargo &>/dev/null; then
- ok "Rust/Cargo $(cargo --version | awk '{print $2}')"
- else
- info "Installing Rust (rustup)..."
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
- source "$HOME/.cargo/env"
- ok "Rust installed: $(cargo --version)"
- fi
- # --- Python 3 ---
- if command -v python3 &>/dev/null; then
- ok "Python $(python3 --version)"
- else
- info "Installing Python 3..."
- case $OS in
- macos) brew install python3 ;;
- linux-apt) sudo apt-get install -y python3 ;;
- linux-dnf) sudo dnf install -y python3 ;;
- linux-pacman) sudo pacman -S --noconfirm python ;;
- *) warn "Cannot auto-install Python on $OS" ;;
- esac
- fi
- # --- Claude Code CLI ---
- if command -v claude &>/dev/null; then
- ok "Claude Code $(claude --version 2>/dev/null | head -1)"
- else
- err "Claude Code not installed. Install from https://code.claude.com then re-run."
- exit 1
- fi
- echo ""
- # ============================================================
- # STEP 2 — GSTACK SUBMODULE
- # ============================================================
- echo "── Step 2: GStack submodule ─────────────────────────────────"
- echo ""
- # Note: GStack is managed as a git submodule in this repo.
- # It lives at skills-external/gstack/ and is symlinked to ~/.claude/skills/gstack/
- # by link.sh. Never clone it separately — use the submodule.
- #
- # First-time setup:
- # git submodule update --init --recursive
- # Update to latest:
- # git submodule update --remote skills-external/gstack
- # cd skills-external/gstack && ./setup
- # git add skills-external/gstack && git commit -m "chore: update gstack"
- GSTACK_DIR="$REPO/skills-external/gstack"
- if [ ! -d "$GSTACK_DIR/.git" ] && [ ! -f "$GSTACK_DIR/.git" ]; then
- info "Initializing GStack submodule..."
- cd "$REPO"
- git submodule update --init --recursive
- cd - > /dev/null
- fi
- if [ -d "$GSTACK_DIR" ]; then
- info "Running GStack setup..."
- if [ -x "$GSTACK_DIR/setup" ]; then
- if (cd "$GSTACK_DIR" && ./setup) 2>/dev/null; then
- : # setup succeeded
- else
- warn "GStack ./setup failed — submodule present but setup incomplete"
- fi
- else
- warn "GStack ./setup not found or not executable — skipping"
- fi
- # Symlinks are handled by link.sh — verify it was run
- if [ -L "$HOME/.claude/skills/gstack" ]; then
- ok "GStack ready (submodule initialized, symlink OK)"
- else
- warn "GStack submodule ready but not symlinked — run: bash link.sh"
- fi
- else
- warn "GStack submodule directory not found after init — check .gitmodules"
- fi
- echo ""
- # ============================================================
- # STEP 3 — RTK
- # ============================================================
- echo "── Step 3: RTK — Rust Token Killer ─────────────────────────"
- echo ""
- if command -v rtk &>/dev/null; then
- ok "rtk already installed ($(rtk --version 2>/dev/null | head -1))"
- else
- RTK_VER=$(pinned_version "rtk")
- if [ "$RTK_VER" != "latest" ]; then
- info "Installing RTK $RTK_VER (pinned in plugins.lock.json)..."
- cargo install --git https://github.com/rtk-ai/rtk --tag "$RTK_VER"
- else
- info "Installing RTK (latest — consider pinning in plugins.lock.json)..."
- cargo install --git https://github.com/rtk-ai/rtk
- fi
- fi
- # Only init if not already configured (avoids overwriting custom RTK config)
- if ! grep -q "rtk" "$HOME/.claude/settings.json" 2>/dev/null; then
- info "Configuring RTK PreToolUse hook (global)..."
- rtk init -g --auto-patch
- ok "RTK configured"
- else
- ok "RTK hook already present in settings.json — skipping init"
- fi
- echo ""
- # ============================================================
- # STEP 4 — GSD v2
- # ============================================================
- # GSD v2 (gsd-pi) is a standalone CLI built on the Pi SDK.
- # It is NOT a Claude Code plugin — it runs as an external process ('gsd' command).
- # Usage: run 'gsd' in your terminal from a project directory.
- # Slash commands (/gsd auto, /gsd status, etc.) are internal to a GSD session.
- echo "── Step 4: GSD v2 — gsd-pi ─────────────────────────────────"
- echo ""
- if command -v gsd &>/dev/null; then
- ok "gsd already installed ($(gsd --version 2>/dev/null | head -1 || echo 'installed'))"
- else
- GSD_VER=$(pinned_version "gsd")
- if [ "$GSD_VER" != "latest" ]; then
- info "Installing gsd-pi@${GSD_VER} (pinned in plugins.lock.json)..."
- npm install -g "gsd-pi@${GSD_VER}"
- else
- info "Installing gsd-pi@latest (consider pinning in plugins.lock.json)..."
- npm install -g gsd-pi
- fi
- command -v gsd &>/dev/null && ok "GSD v2 installed ($(gsd --version 2>/dev/null | head -1))" \
- || err "GSD v2 install failed — check npm output above"
- fi
- echo ""
- # ============================================================
- # STEP 5 — RUFLO MCP (manual — requires npm install + MCP config)
- # ============================================================
- # Ruflo is an enterprise multi-agent orchestration MCP server (formerly claude-flow).
- # 310+ MCP tools, 100+ agent types, WASM kernel, self-learning architecture.
- # Use only for projects requiring complex multi-agent coordination.
- # Default install ~340MB. Minimal: npm install -g ruflo@latest --omit=optional (~15s)
- echo "── Step 5: Ruflo MCP ────────────────────────────────────────"
- echo ""
- if detect_ruflo; then
- ok "Ruflo MCP already configured"
- else
- warn "Ruflo requires manual setup — cannot auto-install (enterprise tool)"
- echo ""
- echo " Steps:"
- echo " 1. Install the package:"
- echo " npm install -g ruflo@latest # full (~340MB)"
- echo " npm install -g ruflo@latest --omit=optional # minimal"
- echo ""
- echo " 2. Register as MCP server in Claude Code:"
- echo " claude mcp add --scope user ruflo -- npx ruflo mcp start"
- echo ""
- echo " 3. Verify:"
- echo " claude mcp list | grep ruflo"
- echo ""
- echo " Or use the automated installer:"
- echo " curl -fsSL https://cdn.jsdelivr.net/gh/ruvnet/ruflo@main/scripts/install.sh | bash -s -- --full"
- echo ""
- fi
- # ============================================================
- # STEP 6 — MARKETPLACE PLUGINS (user scope, explicit)
- # ============================================================
- # All claude plugin install commands use --scope user to ensure
- # they install to ~/.claude/plugins/ regardless of working directory.
- echo "── Step 6: Marketplace plugins (scope: user) ────────────────"
- echo ""
- install_plugin() {
- local name="$1"
- local source="$2"
- if claude plugin list 2>/dev/null | grep -qi "^\s*$name"; then
- ok "$name (already installed)"
- return
- fi
- info "Installing $name..."
- if claude plugin install --scope user "$name@$source" 2>/dev/null; then
- ok "$name"
- else
- err "$name — FAILED (run manually: claude plugin install --scope user $name@$source)"
- fi
- }
- # Official Anthropic (always on)
- install_plugin "security-guidance" "claude-plugins-official"
- install_plugin "frontend-design" "claude-plugins-official"
- install_plugin "skill-creator" "claude-plugins-official"
- install_plugin "pr-review-toolkit" "claude-plugins-official"
- echo ""
- # Superpowers (always on)
- info "Adding Superpowers marketplace..."
- claude plugin marketplace add obra/superpowers-marketplace 2>/dev/null || true
- install_plugin "superpowers" "superpowers-marketplace"
- echo ""
- # UI/UX Pro Max (toggle)
- info "Adding UI/UX Pro Max marketplace..."
- claude plugin marketplace add nextlevelbuilder/ui-ux-pro-max-skill 2>/dev/null || true
- install_plugin "ui-ux-pro-max" "ui-ux-pro-max-skill"
- echo ""
- # ============================================================
- # STEP 6 — CONTEXT7 MCP (manual — requires API key)
- # ============================================================
- echo "── Step 7: Context7 MCP ─────────────────────────────────────"
- echo ""
- if claude mcp list 2>/dev/null | grep -q "context7"; then
- ok "Context7 MCP already configured"
- else
- warn "Context7 requires a free API key — cannot auto-install"
- echo ""
- echo " Steps:"
- echo " 1. Get a free key at https://upstash.com"
- echo " 2. Run:"
- echo " claude mcp add --scope user context7 -- \\"
- echo " npx -y @upstash/context7-mcp --api-key YOUR_KEY"
- echo ""
- fi
- # ============================================================
- # SUMMARY
- # ============================================================
- echo ""
- echo "╔══════════════════════════════════════════════════════════╗"
- echo "║ Install Summary ║"
- echo "╚══════════════════════════════════════════════════════════╝"
- echo ""
- echo " ALWAYS ON (installed at user scope):"
- echo " ✅ security-guidance — PreToolUse security hook (0 tokens)"
- echo " ✅ rtk — token compression hook (0 tokens)"
- echo " ✅ superpowers — brainstorm/plan/implement/debug workflow"
- echo ""
- echo " TOGGLE (installed but start OFF — /plugin-check recommends when needed):"
- echo " 🔄 gstack — ~/.claude/skills/gstack/ (→ submodule)"
- echo " 🔄 gsd v2 — standalone CLI 'gsd' (gsd-pi, not a Claude Code plugin)"
- echo " 🔄 skill-creator — create skills from conversation (~100 tokens)"
- echo " 🔄 pr-review-toolkit — /pr-review-toolkit:review-pr (~300 tokens)"
- echo " 🔄 frontend-design — user scope (~200 tokens)"
- echo " 🔄 ui-ux-pro-max — user scope (~400 tokens)"
- echo " 🔄 context7 MCP — see Step 7 above (~200 tokens)"
- echo " 🔄 ruflo MCP — see Step 5 above (~500-1500 tokens, enterprise only)"
- echo ""
- echo " All plugins installed at: user scope (~/.claude/plugins/)"
- echo " GStack at: ~/.claude/skills/gstack/ (symlink → submodule)"
- echo ""
- echo " → Restart Claude Code — plugins load automatically"
- echo ""
|