install-plugins.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #!/usr/bin/env bash
  2. # ============================================================
  3. # Claude Code — Plugin installer
  4. # Run this after a fresh clone to reinstall all plugins
  5. # and their prerequisites on a new machine.
  6. #
  7. # Supports: Linux (apt/dnf/pacman), macOS (brew)
  8. # ============================================================
  9. set -euo pipefail
  10. RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
  11. ok() { echo -e "${GREEN}✓${NC} $1"; }
  12. warn() { echo -e "${YELLOW}⚠${NC} $1"; }
  13. info() { echo -e "${BLUE}→${NC} $1"; }
  14. err() { echo -e "${RED}✗${NC} $1"; }
  15. REPO="$(cd "$(dirname "$0")" && pwd)"
  16. # ============================================================
  17. # DETECT OS
  18. # ============================================================
  19. OS="unknown"
  20. PKG=""
  21. if [[ "$OSTYPE" == "darwin"* ]]; then
  22. OS="macos"
  23. elif command -v apt-get &>/dev/null; then
  24. OS="linux-apt"; PKG="apt-get"
  25. elif command -v dnf &>/dev/null; then
  26. OS="linux-dnf"; PKG="dnf"
  27. elif command -v pacman &>/dev/null; then
  28. OS="linux-pacman"; PKG="pacman"
  29. fi
  30. echo ""
  31. echo "╔══════════════════════════════════════════════════════════╗"
  32. echo "║ Claude Code — Plugin & Tool Installer ║"
  33. echo "╚══════════════════════════════════════════════════════════╝"
  34. echo ""
  35. info "OS: $OS | Repo: $REPO"
  36. echo ""
  37. # ============================================================
  38. # STEP 1 — PREREQUISITES
  39. # ============================================================
  40. echo "── Step 1: Prerequisites ───────────────────────────────────"
  41. echo ""
  42. # --- git ---
  43. if command -v git &>/dev/null; then
  44. ok "git $(git --version | awk '{print $3}')"
  45. else
  46. info "Installing git..."
  47. case $OS in
  48. macos) brew install git ;;
  49. linux-apt) sudo apt-get install -y git ;;
  50. linux-dnf) sudo dnf install -y git ;;
  51. linux-pacman) sudo pacman -S --noconfirm git ;;
  52. *) err "Cannot auto-install git on $OS — install manually"; exit 1 ;;
  53. esac
  54. ok "git installed"
  55. fi
  56. # --- Node.js (>=18) ---
  57. NODE_OK=false
  58. if command -v node &>/dev/null; then
  59. NODE_VER=$(node --version | sed 's/v//' | cut -d. -f1)
  60. if [ "$NODE_VER" -ge 18 ]; then
  61. ok "Node.js $(node --version)"; NODE_OK=true
  62. else
  63. warn "Node.js $(node --version) is too old (need >=18)"
  64. fi
  65. fi
  66. if [ "$NODE_OK" = false ]; then
  67. info "Installing Node.js 22 LTS..."
  68. case $OS in
  69. macos)
  70. brew install node@22
  71. export PATH="/opt/homebrew/opt/node@22/bin:$PATH"
  72. ;;
  73. linux-apt)
  74. curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
  75. sudo apt-get install -y nodejs
  76. ;;
  77. linux-dnf)
  78. curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash -
  79. sudo dnf install -y nodejs
  80. ;;
  81. linux-pacman)
  82. sudo pacman -S --noconfirm nodejs npm
  83. ;;
  84. *) warn "Cannot auto-install Node.js on $OS — install from https://nodejs.org" ;;
  85. esac
  86. command -v node &>/dev/null && ok "Node.js $(node --version)" || err "Node.js install failed"
  87. fi
  88. # --- Rust + Cargo (for RTK) ---
  89. if command -v cargo &>/dev/null; then
  90. ok "Rust/Cargo $(cargo --version | awk '{print $2}')"
  91. else
  92. info "Installing Rust (rustup)..."
  93. curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
  94. source "$HOME/.cargo/env"
  95. ok "Rust installed: $(cargo --version)"
  96. fi
  97. # --- Python 3 ---
  98. if command -v python3 &>/dev/null; then
  99. ok "Python $(python3 --version)"
  100. else
  101. info "Installing Python 3..."
  102. case $OS in
  103. macos) brew install python3 ;;
  104. linux-apt) sudo apt-get install -y python3 ;;
  105. linux-dnf) sudo dnf install -y python3 ;;
  106. linux-pacman) sudo pacman -S --noconfirm python ;;
  107. *) warn "Cannot auto-install Python on $OS" ;;
  108. esac
  109. fi
  110. # --- Claude Code CLI ---
  111. if command -v claude &>/dev/null; then
  112. ok "Claude Code $(claude --version 2>/dev/null | head -1)"
  113. else
  114. err "Claude Code not installed. Install from https://code.claude.com then re-run."
  115. exit 1
  116. fi
  117. echo ""
  118. # ============================================================
  119. # STEP 2 — GIT CLI TOOLS (gh + glab for /git-pr)
  120. # ============================================================
  121. echo "── Step 2: Git CLI tools ────────────────────────────────────"
  122. echo ""
  123. # --- gh (GitHub CLI) ---
  124. if command -v gh &>/dev/null; then
  125. ok "gh $(gh --version | head -1 | awk '{print $3}')"
  126. else
  127. info "Installing gh (GitHub CLI)..."
  128. case $OS in
  129. macos) brew install gh ;;
  130. linux-apt) type -p curl > /dev/null || sudo apt-get install -y curl
  131. curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
  132. echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list
  133. sudo apt-get update && sudo apt-get install -y gh ;;
  134. linux-dnf) sudo dnf install -y gh ;;
  135. linux-pacman) sudo pacman -S --noconfirm github-cli ;;
  136. *) warn "Cannot auto-install gh on $OS — install from https://cli.github.com" ;;
  137. esac
  138. command -v gh &>/dev/null && ok "gh installed" || warn "gh not installed — GitHub PRs will use API fallback"
  139. fi
  140. # --- glab (GitLab CLI) ---
  141. if command -v glab &>/dev/null; then
  142. ok "glab $(glab --version | head -1)"
  143. else
  144. info "Installing glab (GitLab CLI)..."
  145. case $OS in
  146. macos) brew install glab ;;
  147. linux-apt) curl -s https://raw.githubusercontent.com/profclems/glab/trunk/scripts/install.sh | sudo bash ;;
  148. linux-dnf) sudo dnf install -y glab ;;
  149. linux-pacman) sudo pacman -S --noconfirm glab ;;
  150. *) warn "Cannot auto-install glab on $OS — install from https://gitlab.com/gitlab-org/cli" ;;
  151. esac
  152. command -v glab &>/dev/null && ok "glab installed" || warn "glab not installed — GitLab MRs will use API fallback"
  153. fi
  154. warn "Gogs/Gitea: set GOGS_TOKEN or GITEA_TOKEN in your shell profile"
  155. echo " export GOGS_TOKEN="your-token" # add to ~/.zshrc or ~/.bashrc"
  156. echo ""
  157. # ============================================================
  158. # STEP 3 — GSTACK SUBMODULE
  159. # ============================================================
  160. echo "── Step 3: GStack submodule ─────────────────────────────────"
  161. echo ""
  162. # Note: GStack is managed as a git submodule in this repo.
  163. # It lives at skills-external/gstack/ and is symlinked to ~/.claude/skills/gstack/
  164. # by link.sh. Never clone it separately — use the submodule.
  165. #
  166. # First-time setup:
  167. # git submodule update --init --recursive
  168. # Update to latest:
  169. # git submodule update --remote skills-external/gstack
  170. # cd skills-external/gstack && ./setup
  171. # git add skills-external/gstack && git commit -m "chore: update gstack"
  172. GSTACK_DIR="$REPO/skills-external/gstack"
  173. if [ ! -d "$GSTACK_DIR/.git" ] && [ ! -f "$GSTACK_DIR/.git" ]; then
  174. info "Initializing GStack submodule..."
  175. cd "$REPO"
  176. git submodule update --init --recursive
  177. cd - > /dev/null
  178. fi
  179. if [ -d "$GSTACK_DIR" ]; then
  180. info "Running GStack setup..."
  181. cd "$GSTACK_DIR" && ./setup && cd - > /dev/null
  182. # Ensure symlink from link.sh is in place
  183. mkdir -p "$HOME/.claude/skills"
  184. ln -sf "$GSTACK_DIR" "$HOME/.claude/skills/gstack" 2>/dev/null || true
  185. ok "GStack ready at ~/.claude/skills/gstack (→ submodule)"
  186. else
  187. warn "GStack submodule directory not found after init — check .gitmodules"
  188. fi
  189. echo ""
  190. # ============================================================
  191. # STEP 3 — RTK
  192. # ============================================================
  193. echo "── Step 4: RTK — Rust Token Killer ─────────────────────────"
  194. echo ""
  195. if command -v rtk &>/dev/null; then
  196. ok "rtk already installed ($(rtk --version 2>/dev/null | head -1))"
  197. else
  198. info "Installing RTK..."
  199. cargo install --git https://github.com/rtk-ai/rtk
  200. fi
  201. info "Configuring RTK PreToolUse hook (global)..."
  202. rtk init -g --auto-patch
  203. ok "RTK configured"
  204. echo ""
  205. # ============================================================
  206. # STEP 4 — GSD
  207. # ============================================================
  208. echo "── Step 5: GSD — get-shit-done ─────────────────────────────"
  209. echo ""
  210. info "Installing GSD globally..."
  211. npx get-shit-done-cc --claude --global --auto
  212. ok "GSD installed"
  213. echo ""
  214. # ============================================================
  215. # STEP 5 — MARKETPLACE PLUGINS (user scope, explicit)
  216. # ============================================================
  217. # All claude plugin install commands use --scope user to ensure
  218. # they install to ~/.claude/plugins/ regardless of working directory.
  219. echo "── Step 6: Marketplace plugins (scope: user) ────────────────"
  220. echo ""
  221. install_plugin() {
  222. local name="$1"
  223. local source="$2"
  224. info "Installing $name..."
  225. claude plugin install --scope user "$name@$source" 2>/dev/null \
  226. && ok "$name" \
  227. || warn "$name — skipped (already installed or failed)"
  228. }
  229. # Official Anthropic (always on)
  230. install_plugin "security-guidance" "claude-plugins-official"
  231. install_plugin "frontend-design" "claude-plugins-official"
  232. install_plugin "skill-creator" "claude-plugins-official"
  233. install_plugin "pr-review-toolkit" "claude-plugins-official"
  234. echo ""
  235. # Superpowers (always on)
  236. info "Adding Superpowers marketplace..."
  237. claude plugin marketplace add obra/superpowers-marketplace 2>/dev/null || true
  238. install_plugin "superpowers" "superpowers-marketplace"
  239. echo ""
  240. # UI/UX Pro Max (toggle)
  241. info "Adding UI/UX Pro Max marketplace..."
  242. claude plugin marketplace add nextlevelbuilder/ui-ux-pro-max-skill 2>/dev/null || true
  243. install_plugin "ui-ux-pro-max" "ui-ux-pro-max-skill"
  244. echo ""
  245. # ============================================================
  246. # STEP 6 — CONTEXT7 MCP (manual — requires API key)
  247. # ============================================================
  248. echo "── Step 7: Context7 MCP ─────────────────────────────────────"
  249. echo ""
  250. if claude mcp list 2>/dev/null | grep -q "context7"; then
  251. ok "Context7 MCP already configured"
  252. else
  253. warn "Context7 requires a free API key — cannot auto-install"
  254. echo ""
  255. echo " Steps:"
  256. echo " 1. Get a free key at https://context7.com"
  257. echo " 2. Run:"
  258. echo " claude mcp add --scope user context7 -- \\"
  259. echo " npx -y @upstash/context7-mcp --api-key YOUR_KEY"
  260. echo ""
  261. fi
  262. # ============================================================
  263. # SUMMARY
  264. # ============================================================
  265. echo ""
  266. echo "╔══════════════════════════════════════════════════════════╗"
  267. echo "║ Install Summary ║"
  268. echo "╚══════════════════════════════════════════════════════════╝"
  269. echo ""
  270. echo " ALWAYS ON (installed at user scope, ~10 tokens/session each):"
  271. echo " ✅ security-guidance — PreToolUse security hook (0 tokens)"
  272. echo " ✅ rtk — token compression hook (0 tokens)"
  273. echo " ✅ superpowers — brainstorm/plan/implement/debug workflow"
  274. echo " ✅ skill-creator — create skills from conversation"
  275. echo " ✅ pr-review-toolkit — /pr-review-toolkit:review-pr"
  276. echo ""
  277. echo " TOGGLE (installed but start OFF — /plugin-check recommends when needed):"
  278. echo " 🔄 gstack — ~/.claude/skills/gstack/ (→ submodule)"
  279. echo " 🔄 gsd — ~/.claude/skills/ (npx)"
  280. echo " 🔄 frontend-design — user scope"
  281. echo " 🔄 ui-ux-pro-max — user scope"
  282. echo " 🔄 context7 MCP — see Step 6 above"
  283. echo ""
  284. echo " All plugins installed at: user scope (~/.claude/plugins/)"
  285. echo " GStack at: ~/.claude/skills/gstack/ (symlink → submodule)"
  286. echo ""
  287. echo " → Authenticate: gh auth login (GitHub) / glab auth login (GitLab)"
  288. echo " → Restart Claude Code"
  289. echo " → Run /reload-plugins"
  290. echo ""