install-plugins.sh 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. # Log to file for post-mortem debugging (terminal output unchanged)
  17. LOG_FILE="$REPO/install-$(date +%Y%m%d-%H%M%S).log"
  18. if touch "$LOG_FILE" 2>/dev/null; then
  19. exec > >(tee -a "$LOG_FILE") 2>&1
  20. info "Logging to $LOG_FILE"
  21. else
  22. warn "Cannot write log to $REPO — continuing without log file"
  23. fi
  24. # Load shared detection library
  25. # shellcheck source=lib/detect-plugins.sh
  26. source "$REPO/lib/detect-plugins.sh"
  27. # Read pinned version from plugins.lock.json
  28. # Usage: pinned_version "rtk" → prints version string or "latest"
  29. pinned_version() {
  30. local key="$1"
  31. if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
  32. python3 -c "
  33. import json, sys
  34. with open('$REPO/plugins.lock.json') as f:
  35. d = json.load(f)
  36. v = d.get('$key', {}).get('version', 'latest')
  37. print(v)
  38. " 2>/dev/null || echo "latest"
  39. else
  40. echo "latest"
  41. fi
  42. }
  43. # ============================================================
  44. # DETECT OS
  45. # ============================================================
  46. OS="unknown"
  47. PKG=""
  48. if [[ "$OSTYPE" == "darwin"* ]]; then
  49. OS="macos"
  50. elif command -v apt-get &>/dev/null; then
  51. OS="linux-apt"; PKG="apt-get"
  52. elif command -v dnf &>/dev/null; then
  53. OS="linux-dnf"; PKG="dnf"
  54. elif command -v pacman &>/dev/null; then
  55. OS="linux-pacman"; PKG="pacman"
  56. fi
  57. echo ""
  58. echo "╔══════════════════════════════════════════════════════════╗"
  59. echo "║ Claude Code — Plugin & Tool Installer ║"
  60. echo "╚══════════════════════════════════════════════════════════╝"
  61. echo ""
  62. info "OS: $OS | Repo: $REPO"
  63. echo ""
  64. # ============================================================
  65. # STEP 1 — PREREQUISITES
  66. # ============================================================
  67. echo "── Step 1: Prerequisites ───────────────────────────────────"
  68. echo ""
  69. # --- git ---
  70. if command -v git &>/dev/null; then
  71. ok "git $(git --version | awk '{print $3}')"
  72. else
  73. info "Installing git..."
  74. case $OS in
  75. macos) brew install git ;;
  76. linux-apt) sudo apt-get install -y git ;;
  77. linux-dnf) sudo dnf install -y git ;;
  78. linux-pacman) sudo pacman -S --noconfirm git ;;
  79. *) err "Cannot auto-install git on $OS — install manually"; exit 1 ;;
  80. esac
  81. ok "git installed"
  82. fi
  83. # --- Node.js (>=18) ---
  84. NODE_OK=false
  85. if command -v node &>/dev/null; then
  86. NODE_VER=$(node --version | sed 's/v//' | cut -d. -f1)
  87. if [ "$NODE_VER" -ge 22 ]; then
  88. ok "Node.js $(node --version)"; NODE_OK=true
  89. else
  90. warn "Node.js $(node --version) is too old (need >=22 — GSD v2 requires it)"
  91. fi
  92. fi
  93. if [ "$NODE_OK" = false ]; then
  94. info "Installing Node.js 22 LTS..."
  95. case $OS in
  96. macos)
  97. brew install node@22
  98. export PATH="/opt/homebrew/opt/node@22/bin:$PATH"
  99. ;;
  100. linux-apt)
  101. curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
  102. sudo apt-get install -y nodejs
  103. ;;
  104. linux-dnf)
  105. curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash -
  106. sudo dnf install -y nodejs
  107. ;;
  108. linux-pacman)
  109. sudo pacman -S --noconfirm nodejs npm
  110. ;;
  111. *) warn "Cannot auto-install Node.js on $OS — install from https://nodejs.org" ;;
  112. esac
  113. command -v node &>/dev/null && ok "Node.js $(node --version)" || err "Node.js install failed"
  114. fi
  115. # --- Rust + Cargo (for RTK) ---
  116. if command -v cargo &>/dev/null; then
  117. ok "Rust/Cargo $(cargo --version | awk '{print $2}')"
  118. else
  119. info "Installing Rust (rustup)..."
  120. curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
  121. source "$HOME/.cargo/env"
  122. ok "Rust installed: $(cargo --version)"
  123. fi
  124. # --- Python 3 ---
  125. if command -v python3 &>/dev/null; then
  126. ok "Python $(python3 --version)"
  127. else
  128. info "Installing Python 3..."
  129. case $OS in
  130. macos) brew install python3 ;;
  131. linux-apt) sudo apt-get install -y python3 ;;
  132. linux-dnf) sudo dnf install -y python3 ;;
  133. linux-pacman) sudo pacman -S --noconfirm python ;;
  134. *) warn "Cannot auto-install Python on $OS" ;;
  135. esac
  136. fi
  137. # --- pipx (for Graphifyy) ---
  138. if command -v pipx &>/dev/null; then
  139. ok "pipx $(pipx --version 2>/dev/null)"
  140. else
  141. info "Installing pipx..."
  142. case $OS in
  143. macos) brew install pipx ;;
  144. linux-apt) sudo apt-get install -y pipx ;;
  145. linux-dnf) sudo dnf install -y pipx ;;
  146. linux-pacman) sudo pacman -S --noconfirm python-pipx ;;
  147. *) warn "Cannot auto-install pipx on $OS" ;;
  148. esac
  149. pipx ensurepath 2>/dev/null || true
  150. fi
  151. # --- Claude Code CLI ---
  152. if command -v claude &>/dev/null; then
  153. ok "Claude Code $(claude --version 2>/dev/null | head -1)"
  154. else
  155. err "Claude Code not installed. Install from https://code.claude.com then re-run."
  156. exit 1
  157. fi
  158. echo ""
  159. # ============================================================
  160. # STEP 2 — GSTACK SUBMODULE
  161. # ============================================================
  162. echo "── Step 2: GStack submodule ─────────────────────────────────"
  163. echo ""
  164. # Note: GStack is managed as a git submodule in this repo.
  165. # It lives at skills-external/gstack/ and is symlinked to ~/.claude/skills/gstack/
  166. # by link.sh. Never clone it separately — use the submodule.
  167. #
  168. # First-time setup:
  169. # git submodule update --init --recursive
  170. # Update to latest:
  171. # git submodule update --remote skills-external/gstack
  172. # cd skills-external/gstack && ./setup
  173. # git add skills-external/gstack && git commit -m "chore: update gstack"
  174. GSTACK_DIR="$REPO/skills-external/gstack"
  175. if [ ! -d "$GSTACK_DIR/.git" ] && [ ! -f "$GSTACK_DIR/.git" ]; then
  176. info "Initializing GStack submodule..."
  177. cd "$REPO"
  178. git submodule update --init --recursive
  179. cd - > /dev/null
  180. fi
  181. if [ -d "$GSTACK_DIR" ]; then
  182. # --- bun (required by GStack ./setup) ---
  183. if ! command -v bun &>/dev/null; then
  184. info "Installing bun (required by GStack)..."
  185. BUN_VERSION="1.3.10"
  186. tmpfile=$(mktemp)
  187. curl -fsSL "https://bun.sh/install" -o "$tmpfile"
  188. BUN_VERSION="$BUN_VERSION" bash "$tmpfile" && rm -f "$tmpfile"
  189. export PATH="$HOME/.bun/bin:$PATH"
  190. command -v bun &>/dev/null && ok "bun $(bun --version)" || err "bun install failed"
  191. else
  192. ok "bun $(bun --version)"
  193. fi
  194. info "Running GStack setup..."
  195. if [ -x "$GSTACK_DIR/setup" ]; then
  196. if (cd "$GSTACK_DIR" && ./setup); then
  197. : # setup succeeded
  198. else
  199. warn "GStack ./setup failed — check output above"
  200. fi
  201. else
  202. warn "GStack ./setup not found or not executable — skipping"
  203. fi
  204. # Symlinks are handled by link.sh — verify it was run
  205. if [ -L "$HOME/.claude/skills/gstack" ]; then
  206. ok "GStack ready (submodule initialized, symlink OK)"
  207. else
  208. warn "GStack submodule ready but not symlinked — run: bash link.sh"
  209. fi
  210. else
  211. warn "GStack submodule directory not found after init — check .gitmodules"
  212. fi
  213. echo ""
  214. # ============================================================
  215. # STEP 3 — RTK
  216. # ============================================================
  217. echo "── Step 3: RTK — Rust Token Killer ─────────────────────────"
  218. echo ""
  219. if command -v rtk &>/dev/null; then
  220. ok "rtk already installed ($(rtk --version 2>/dev/null | head -1))"
  221. else
  222. RTK_VER=$(pinned_version "rtk")
  223. if [ "$RTK_VER" != "latest" ]; then
  224. info "Installing RTK $RTK_VER (pinned in plugins.lock.json)..."
  225. cargo install --git https://github.com/rtk-ai/rtk --tag "$RTK_VER"
  226. else
  227. info "Installing RTK (latest — consider pinning in plugins.lock.json)..."
  228. cargo install --git https://github.com/rtk-ai/rtk
  229. fi
  230. fi
  231. # Only init if not already configured (avoids overwriting custom RTK config)
  232. if ! grep -q "rtk" "$HOME/.claude/settings.json" 2>/dev/null; then
  233. info "Configuring RTK PreToolUse hook (global)..."
  234. rtk init -g --auto-patch
  235. ok "RTK configured"
  236. else
  237. ok "RTK hook already present in settings.json — skipping init"
  238. fi
  239. echo ""
  240. # ============================================================
  241. # STEP 4 — GSD v2
  242. # ============================================================
  243. # GSD v2 (gsd-pi) is a standalone CLI built on the Pi SDK.
  244. # It is NOT a Claude Code plugin — it runs as an external process ('gsd' command).
  245. # Usage: run 'gsd' in your terminal from a project directory.
  246. # Slash commands (/gsd auto, /gsd status, etc.) are internal to a GSD session.
  247. echo "── Step 4: GSD v2 — gsd-pi ─────────────────────────────────"
  248. echo ""
  249. if command -v gsd &>/dev/null; then
  250. ok "gsd already installed ($(gsd --version 2>/dev/null | head -1 || echo 'installed'))"
  251. else
  252. GSD_VER=$(pinned_version "gsd")
  253. if [ "$GSD_VER" != "latest" ]; then
  254. info "Installing gsd-pi@${GSD_VER} (pinned in plugins.lock.json)..."
  255. npm install -g "gsd-pi@${GSD_VER}"
  256. else
  257. info "Installing gsd-pi@latest (consider pinning in plugins.lock.json)..."
  258. npm install -g gsd-pi
  259. fi
  260. command -v gsd &>/dev/null && ok "GSD v2 installed ($(gsd --version 2>/dev/null | head -1))" \
  261. || err "GSD v2 install failed — check npm output above"
  262. fi
  263. echo ""
  264. # ============================================================
  265. # STEP 5 — RUFLO CLI (enterprise multi-agent orchestration)
  266. # ============================================================
  267. # Ruflo (formerly claude-flow) is an enterprise multi-agent orchestration CLI.
  268. # 310+ tools, 100+ agent types, WASM kernel, self-learning architecture.
  269. # Use only for projects requiring complex multi-agent coordination.
  270. # Default install ~340MB. Minimal: npm install -g ruflo@latest --omit=optional (~15s)
  271. echo "── Step 5: Ruflo CLI ──────────────────────────────────────"
  272. echo ""
  273. if detect_ruflo; then
  274. ok "Ruflo CLI already installed ($(ruflo --version 2>/dev/null | head -1 || echo 'installed'))"
  275. else
  276. RUFLO_VER=$(pinned_version "ruflo")
  277. if [ "$RUFLO_VER" != "latest" ]; then
  278. info "Installing ruflo@${RUFLO_VER} (pinned, minimal --omit=optional)..."
  279. npm install -g "ruflo@${RUFLO_VER}" --omit=optional
  280. else
  281. info "Installing ruflo@latest (minimal --omit=optional)..."
  282. npm install -g ruflo@latest --omit=optional
  283. fi
  284. command -v ruflo &>/dev/null && ok "Ruflo CLI installed ($(ruflo --version 2>/dev/null | head -1))" \
  285. || err "Ruflo install failed — run manually: npm install -g ruflo@latest --omit=optional"
  286. fi
  287. if command -v ruflo &>/dev/null; then
  288. info "Init in a project: ruflo init --wizard"
  289. info "Spawn agent: ruflo agent spawn -t coder"
  290. info "Start swarm: ruflo swarm init"
  291. info "Diagnostics: ruflo doctor"
  292. fi
  293. # ============================================================
  294. # STEP 6 — MARKETPLACE PLUGINS (user scope, explicit)
  295. # ============================================================
  296. # All claude plugin install commands use --scope user to ensure
  297. # they install to ~/.claude/plugins/ regardless of working directory.
  298. echo "── Step 6: Marketplace plugins (scope: user) ────────────────"
  299. echo ""
  300. install_plugin() {
  301. local name="$1"
  302. local source="$2"
  303. if claude plugin list 2>/dev/null | grep -qi "$name"; then
  304. ok "$name (already installed)"
  305. return
  306. fi
  307. info "Installing $name..."
  308. if claude plugin install --scope user "$name@$source" 2>/dev/null; then
  309. ok "$name"
  310. else
  311. err "$name — FAILED (run manually: claude plugin install --scope user $name@$source)"
  312. fi
  313. }
  314. # Anthropic bundled plugins (from anthropics/claude-code repo)
  315. # These are NOT in claude-plugins-official — they require the claude-code marketplace
  316. info "Adding Anthropic bundled plugins marketplace..."
  317. claude plugin marketplace add anthropics/claude-code 2>/dev/null || true
  318. install_plugin "security-guidance" "claude-code-plugins"
  319. install_plugin "frontend-design" "claude-code-plugins"
  320. install_plugin "pr-review-toolkit" "claude-code-plugins"
  321. install_plugin "plugin-dev" "claude-code-plugins"
  322. echo ""
  323. # Superpowers (always on)
  324. info "Adding Superpowers marketplace..."
  325. claude plugin marketplace add obra/superpowers-marketplace 2>/dev/null || true
  326. install_plugin "superpowers" "superpowers-marketplace"
  327. echo ""
  328. # UI/UX Pro Max (toggle)
  329. info "Adding UI/UX Pro Max marketplace..."
  330. claude plugin marketplace add nextlevelbuilder/ui-ux-pro-max-skill 2>/dev/null || true
  331. install_plugin "ui-ux-pro-max" "ui-ux-pro-max-skill"
  332. echo ""
  333. # ============================================================
  334. # STEP 7 — CONTEXT7 CLI (ctx7)
  335. # ============================================================
  336. echo "── Step 7: Context7 CLI ─────────────────────────────────────"
  337. echo ""
  338. if command -v ctx7 &>/dev/null; then
  339. ok "ctx7 already installed ($(ctx7 --version 2>/dev/null | head -1 || echo 'installed'))"
  340. else
  341. CTX7_VER=$(pinned_version "ctx7")
  342. if [ "$CTX7_VER" != "latest" ]; then
  343. info "Installing ctx7@${CTX7_VER} (pinned in plugins.lock.json)..."
  344. npm install -g "ctx7@${CTX7_VER}"
  345. else
  346. info "Installing ctx7@latest (consider pinning in plugins.lock.json)..."
  347. npm install -g ctx7
  348. fi
  349. command -v ctx7 &>/dev/null && ok "ctx7 installed ($(ctx7 --version 2>/dev/null | head -1))" \
  350. || err "ctx7 install failed — run manually: npm install -g ctx7"
  351. fi
  352. # Suggest setup for Claude Code integration (optional — ctx7 also works standalone)
  353. if command -v ctx7 &>/dev/null; then
  354. info "Run 'ctx7 setup --claude' to configure Context7 for Claude Code"
  355. info "Or use ctx7 standalone: ctx7 docs /vercel/next.js \"middleware\""
  356. info "Free higher rate limits: ctx7 login (OAuth) or --api-key from context7.com/dashboard"
  357. fi
  358. # ============================================================
  359. # STEP 8 — GRAPHIFYY (codebase knowledge graph)
  360. # ============================================================
  361. echo "── Step 8: Graphifyy — Knowledge Graph ──────────────────────"
  362. echo ""
  363. if command -v graphify &>/dev/null; then
  364. ok "graphify already installed"
  365. else
  366. info "Installing graphifyy via pipx..."
  367. pipx install graphifyy 2>/dev/null \
  368. && ok "graphifyy installed" \
  369. || err "graphifyy install failed — run manually: pipx install graphifyy"
  370. fi
  371. if command -v graphify &>/dev/null; then
  372. info "Running graphify install (dependencies)..."
  373. graphify install 2>/dev/null || warn "graphify install failed — run manually"
  374. info "Configuring Claude Code integration..."
  375. graphify claude install 2>/dev/null || warn "graphify claude install failed — run manually"
  376. ok "Graphifyy configured for Claude Code"
  377. fi
  378. echo ""
  379. # ============================================================
  380. # SUMMARY
  381. # ============================================================
  382. echo ""
  383. echo "╔══════════════════════════════════════════════════════════╗"
  384. echo "║ Install Summary ║"
  385. echo "╚══════════════════════════════════════════════════════════╝"
  386. echo ""
  387. echo " ALWAYS ON (installed at user scope):"
  388. echo " ✅ security-guidance — PreToolUse security hook (0 tokens) [claude-code-plugins]"
  389. echo " ✅ rtk — token compression hook (0 tokens)"
  390. echo " ✅ superpowers — brainstorm/plan/implement/debug workflow"
  391. echo ""
  392. echo " TOGGLE (installed but start OFF — /plugin-check recommends when needed):"
  393. echo " 🔄 gstack — ~/.claude/skills/gstack/ (→ submodule)"
  394. echo " 🔄 gsd v2 — standalone CLI 'gsd' (gsd-pi, not a Claude Code plugin)"
  395. echo " 🔄 plugin-dev — create plugins/skills (~100 tokens) [claude-code-plugins]"
  396. echo " 🔄 pr-review-toolkit — /pr-review-toolkit:review-pr (~300 tokens) [claude-code-plugins]"
  397. echo " 🔄 frontend-design — UI design skill (~200 tokens) [claude-code-plugins]"
  398. echo " 🔄 ui-ux-pro-max — user scope (~400 tokens)"
  399. echo " 🔄 context7 CLI — ctx7 (npm global, standalone or MCP setup)"
  400. echo " 🔄 ruflo CLI — enterprise multi-agent orchestration (~500-1500 tokens)"
  401. echo " 🔄 graphifyy — codebase knowledge graph (pipx, PreToolUse hook)"
  402. echo ""
  403. echo " All plugins installed at: user scope (~/.claude/plugins/)"
  404. echo " GStack at: ~/.claude/skills/gstack/ (symlink → submodule)"
  405. echo ""
  406. echo " → Restart Claude Code — plugins load automatically"
  407. echo ""