#!/usr/bin/env bash # Install Cursor subagents from this repository. # Works on macOS, Linux, WSL, and Git Bash on Windows. set -e RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" CATEGORIES_DIR="$SCRIPT_DIR/categories" GLOBAL_AGENTS_DIR="${HOME}/.cursor/agents" LOCAL_AGENTS_DIR=".cursor/agents" MODE="global" ACTION="install" CATEGORY="" ALL=0 INTERACTIVE=1 usage() { cat <<'EOF' Usage: ./install-agents.sh [options] Options: --all Install all agents --category Install one category (e.g. 04-quality-security) --local Install into current project (.cursor/agents) --global Install globally (~/.cursor/agents) [default] --uninstall-all Remove agents previously installed from this repo -h, --help Show help Examples: ./install-agents.sh --all ./install-agents.sh --category 04-quality-security ./install-agents.sh --all --local ./install-agents.sh --uninstall-all EOF } while [ $# -gt 0 ]; do case "$1" in --all) ALL=1; INTERACTIVE=0; shift ;; --category) CATEGORY="${2:-}" INTERACTIVE=0 if [ -z "$CATEGORY" ]; then echo "${RED}--category requires a name${NC}" exit 1 fi shift 2 ;; --local) MODE="local"; shift ;; --global) MODE="global"; shift ;; --uninstall-all) ACTION="uninstall-all"; INTERACTIVE=0; shift ;; -h|--help) usage; exit 0 ;; *) echo "${RED}Unknown option: $1${NC}" usage exit 1 ;; esac done if [ ! -d "$CATEGORIES_DIR" ]; then echo "${RED}Error: categories/ not found next to this script.${NC}" exit 1 fi target_dir() { if [ "$MODE" = "local" ]; then printf '%s\n' "$LOCAL_AGENTS_DIR" else printf '%s\n' "$GLOBAL_AGENTS_DIR" fi } list_categories() { for d in "$CATEGORIES_DIR"/*/; do [ -d "$d" ] || continue basename "$d" done | sort } install_files_from_list() { dest="$(target_dir)" mkdir -p "$dest" count=0 while IFS= read -r src; do [ -n "$src" ] || continue [ -f "$src" ] || continue cp "$src" "$dest/$(basename "$src")" count=$((count + 1)) done printf "${GREEN}Installed %s agent(s) → %s${NC}\n" "$count" "$dest" } all_agent_files() { for cat in "$CATEGORIES_DIR"/*/; do [ -d "$cat" ] || continue for f in "$cat"*.md; do [ -f "$f" ] || continue base="$(basename "$f")" [ "$base" = "README.md" ] && continue printf '%s\n' "$f" done done | sort } agents_in_category() { cat_name="$1" for f in "$CATEGORIES_DIR/$cat_name"/*.md; do [ -f "$f" ] || continue base="$(basename "$f")" [ "$base" = "README.md" ] && continue printf '%s\n' "$f" done | sort } uninstall_all() { dest="$(target_dir)" if [ ! -d "$dest" ]; then printf "${YELLOW}Nothing to uninstall: %s does not exist.${NC}\n" "$dest" return 0 fi tmp="$(mktemp)" all_agent_files > "$tmp" removed=0 while IFS= read -r src; do base="$(basename "$src")" if [ -f "$dest/$base" ]; then rm -f "$dest/$base" removed=$((removed + 1)) fi done < "$tmp" rm -f "$tmp" printf "${GREEN}Removed %s agent file(s) from %s${NC}\n" "$removed" "$dest" } interactive_menu() { printf "${BOLD}${CYAN}Cursor Subagents Installer${NC}\n\n" echo "Install mode:" echo " 1) Global — all Cursor projects (~/.cursor/agents)" echo " 2) Local — current project only (.cursor/agents)" printf "Choice [1]: " read -r mode_choice case "${mode_choice:-1}" in 2) MODE="local" ;; *) MODE="global" ;; esac echo echo "What to install:" echo " 1) All agents" echo " 2) One category" echo " 3) Uninstall all agents from this repo" printf "Choice [1]: " read -r action_choice case "${action_choice:-1}" in 3) ACTION="uninstall-all" ;; 2) echo echo "Categories:" i=1 # shellcheck disable=SC2034 cat_list="" while IFS= read -r c; do printf " %2d) %s\n" "$i" "$c" eval "CAT_$i=\"\$c\"" i=$((i + 1)) done <