#!/usr/bin/env bash ################################################################################ # Claude Code Customizations Installer # This script automates the setup of custom agents, MCP tools, skills, and plugins # for Claude Code on a new machine. ################################################################################ set -e # Exit on error # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # No Color # Configuration CLAUDE_DIR="$HOME/.claude" AGENTS_DIR="$CLAUDE_DIR/agents" SKILLS_DIR="$CLAUDE_DIR/skills" PLUGINS_DIR="$CLAUDE_DIR/plugins" BACKUP_DIR="$HOME/.claude-backup-$(date +%Y%m%d_%H%M%S)" SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" # Counters AGENTS_INSTALLED=0 SKILLS_INSTALLED=0 ################################################################################ # Helper Functions ################################################################################ log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } check_command() { if ! command -v $1 &> /dev/null; then log_error "$1 is not installed. Please install it first." exit 1 fi } backup_file() { local file="$1" if [ -f "$file" ]; then mkdir -p "$BACKUP_DIR" cp "$file" "$BACKUP_DIR/" log_info "Backed up $file to $BACKUP_DIR" fi } ################################################################################ # Prerequisites Check ################################################################################ check_prerequisites() { log_info "Checking prerequisites..." check_command "node" check_command "npm" check_command "python3" check_command "curl" # Check Node.js version (need 14+) NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1) if [ "$NODE_VERSION" -lt 14 ]; then log_error "Node.js version 14 or higher required. Current: $(node -v)" exit 1 fi log_success "Prerequisites check passed" } ################################################################################ # Directory Structure Setup ################################################################################ setup_directories() { log_info "Setting up directory structure..." # Create main directories including skills mkdir -p "$CLAUDE_DIR"/{skills,agents,plugins/cache,plugins/marketplaces,hooks,debug,file-history,paste-cache,projects,session-env,shell-snapshots,todos} # Create agent category directories mkdir -p "$AGENTS_DIR"/{engineering,marketing,product,studio-operations,project-management,testing,design,bonus} log_success "Directory structure created" } ################################################################################ # Fetch Latest Agents from GitHub (Optional) ################################################################################ fetch_latest_agents() { log_info "Checking for agent updates from GitHub..." local GITHUB_REPO="https://github.com/contains-studio/agents" local TEMP_AGENT_DIR="/tmp/claude-agents-latest-$RANDOM" local UPDATE_FOUND=false # Create temp directory mkdir -p "$TEMP_AGENT_DIR" # Try to clone using git if command -v git &> /dev/null; then if git clone --depth 1 --quiet "$GITHUB_REPO" "$TEMP_AGENT_DIR" 2>/dev/null; then UPDATE_FOUND=true log_success "Fetched latest agents from GitHub" # Copy updated agents to source directory for category in engineering marketing product studio-operations project-management testing design bonus; do if [ -d "$TEMP_AGENT_DIR/$category" ]; then mkdir -p "$SCRIPT_DIR/agents/$category" cp -f "$TEMP_AGENT_DIR/$category"/*.md "$SCRIPT_DIR/agents/$category/" 2>/dev/null || true fi done # Update README if present if [ -f "$TEMP_AGENT_DIR/README.md" ]; then cp -f "$TEMP_AGENT_DIR/README.md" "$SCRIPT_DIR/agents/README.md" 2>/dev/null || true fi log_info "Local agents updated from GitHub" else log_warning "Failed to fetch from GitHub (using local agents)" fi else log_warning "Git not found (using local agents)" fi # Cleanup rm -rf "$TEMP_AGENT_DIR" return 0 } ################################################################################ # Settings Configuration ################################################################################ setup_settings() { log_info "Configuring Claude Code settings..." local settings_file="$CLAUDE_DIR/settings.json" backup_file "$settings_file" # Prompt for API credentials read -p "Enter your ANTHROPIC_AUTH_TOKEN (or press Enter to skip): " API_TOKEN read -p "Enter your ANTHROPIC_BASE_URL (default: https://api.anthropic.com): " API_BASE API_BASE=${API_BASE:-https://api.anthropic.com} # Create settings.json cat > "$settings_file" << EOF { "env": { "ANTHROPIC_AUTH_TOKEN": "${API_TOKEN}", "ANTHROPIC_BASE_URL": "${API_BASE}", "API_TIMEOUT_MS": "3000000", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1" }, "enabledPlugins": { "glm-plan-bug@zai-coding-plugins": true, "glm-plan-usage@zai-coding-plugins": true } } EOF # Create local settings for permissions local local_settings="$CLAUDE_DIR/settings.local.json" backup_file "$local_settings" cat > "$local_settings" << EOF { "permissions": { "allow": [ "Bash(npm install:*)", "Bash(npm run content:*)", "Bash(npm run build:*)", "Bash(grep:*)", "Bash(find:*)", "Bash(for:*)", "Bash(do sed:*)", "Bash(done)", "Bash(python3:*)", "Bash(while read f)", "Bash(do echo \\"\\$f%-* \\$f\\")", "Bash(ls:*)", "Bash(node:*)", "Bash(pm2 delete:*)", "Bash(pm2 start npm:*)", "Bash(pm2 save:*)" ] } } EOF log_success "Settings configured" } ################################################################################ # MCP Services Installation ################################################################################ install_mcp_services() { log_info "Installing MCP services..." # Install @z_ai/mcp-server globally for vision tools log_info "Installing @z_ai/mcp-server (vision analysis tools)..." npm install -g @z_ai/mcp-server 2>/dev/null || { log_warning "Global install failed, trying with npx..." # It's okay if this fails, the tools will use npx } # Install @z_ai/coding-helper for MCP management log_info "Installing @z_ai/coding-helper..." npm install -g @z_ai/coding-helper 2>/dev/null || { log_warning "Global install failed, will use npx" } log_success "MCP services installation completed" } ################################################################################ # Agent Installation ################################################################################ install_agents() { log_info "Installing custom agents..." local source_agents="$SCRIPT_DIR/agents" if [ ! -d "$source_agents" ]; then log_warning "Agent source directory not found at $source_agents" log_warning "Agents will not be installed" return fi # Copy agents from each category for category in engineering marketing product studio-operations project-management testing design bonus; do if [ -d "$source_agents/$category" ]; then mkdir -p "$AGENTS_DIR/$category" agent_count=$(cp -f "$source_agents/$category"/*.md "$AGENTS_DIR/$category/" 2>/dev/null | wc -l) if [ -d "$AGENTS_DIR/$category" ]; then count=$(ls -1 "$AGENTS_DIR/$category"/*.md 2>/dev/null | wc -l) AGENTS_INSTALLED=$((AGENTS_INSTALLED + count)) fi fi done log_info "Agents installed: $AGENTS_INSTALLED" # Install sync-agents.sh script if available if [ -f "$SCRIPT_DIR/extra-tools/sync-agents.sh" ]; then log_info "Installing sync-agents.sh script..." cp "$SCRIPT_DIR/extra-tools/sync-agents.sh" "$CLAUDE_DIR/sync-agents.sh" chmod +x "$CLAUDE_DIR/sync-agents.sh" log_success "sync-agents.sh installed (run: ~/.claude/sync-agents.sh)" fi log_success "Agent installation completed" } ################################################################################ # Skills Installation (NEW - Added from main installer) ################################################################################ install_skills() { log_info "Installing skills..." local source_skills="$SCRIPT_DIR/skills" if [ ! -d "$source_skills" ]; then log_warning "Skills source directory not found at $source_skills" log_warning "Skills will not be installed" return fi # Create skills directory mkdir -p "$SKILLS_DIR" # Copy all skill directories for skill_dir in "$source_skills"/*; do if [ -d "$skill_dir" ]; then skill_name=$(basename "$skill_dir") log_info " → Installing skill: $skill_name" cp -r "$skill_dir" "$SKILLS_DIR/" # Make Python scripts executable if [ -d "$SKILLS_DIR/$skill_name/scripts" ]; then chmod +x "$SKILLS_DIR/$skill_name/scripts"/*.py 2>/dev/null || true fi SKILLS_INSTALLED=$((SKILLS_INSTALLED + 1)) fi done log_success "✓ Skills installed: $SKILLS_INSTALLED skill(s)" log_success "✓ Skills location: $SKILLS_DIR/" } ################################################################################ # Plugins Installation ################################################################################ install_plugins() { log_info "Installing Claude Code plugins..." # Initialize plugin registry local installed_plugins="$PLUGINS_DIR/installed_plugins.json" local known_marketplaces="$PLUGINS_DIR/known_marketplaces.json" backup_file "$installed_plugins" backup_file "$known_marketplaces" cat > "$known_marketplaces" << EOF { "marketplaces": { "https://github.com/anthropics/claude-plugins": { "displayName": "Official Claude Plugins", "contact": "support@anthropic.com" } } } EOF # Install GLM plugins via npx log_info "Installing GLM Coding Plan plugins..." # Create plugin cache structure mkdir -p "$PLUGINS_DIR/cache/zai-coding-plugins"/{glm-plan-bug,glm-plan-usage} # Note: Actual plugin installation happens via the @z_ai/coding-helper # which should already be installed cat > "$installed_plugins" << EOF { "version": 2, "plugins": { "glm-plan-bug@zai-coding-plugins": [ { "scope": "user", "installPath": "$PLUGINS_DIR/cache/zai-coding-plugins/glm-plan-bug/0.0.1", "version": "0.0.1", "installedAt": "$(date -u +%Y-%m-%dT%H:%M:%S.000Z)", "lastUpdated": "$(date -u +%Y-%m-%dT%H:%M:%S.000Z)" } ], "glm-plan-usage@zai-coding-plugins": [ { "scope": "user", "installPath": "$PLUGINS_DIR/cache/zai-coding-plugins/glm-plan-usage/0.0.1", "version": "0.0.1", "installedAt": "$(date -u +%Y-%m-%dT%H:%M:%S.000Z)", "lastUpdated": "$(date -u +%Y-%m-%dT%H:%M:%S.000Z)" } ] } } EOF log_success "Plugins configured" } ################################################################################ # Verification ################################################################################ verify_installation() { log_info "Verifying installation..." local errors=0 # Check directories [ -d "$CLAUDE_DIR" ] || { log_error "Claude directory missing"; errors=$((errors+1)); } [ -d "$AGENTS_DIR" ] || { log_error "Agents directory missing"; errors=$((errors+1)); } [ -d "$SKILLS_DIR" ] || { log_warning "Skills directory missing (optional)"; } [ -d "$PLUGINS_DIR" ] || { log_error "Plugins directory missing"; errors=$((errors+1)); } # Check files [ -f "$CLAUDE_DIR/settings.json" ] || { log_error "settings.json missing"; errors=$((errors+1)); } [ -f "$CLAUDE_DIR/settings.local.json" ] || { log_error "settings.local.json missing"; errors=$((errors+1)); } [ -f "$PLUGINS_DIR/installed_plugins.json" ] || { log_error "installed_plugins.json missing"; errors=$((errors+1)); } # Check MCP availability if command -v npx &> /dev/null; then log_success "npx available for MCP tools" else log_error "npx not available" errors=$((errors+1)) fi # Count agents and skills if [ -d "$AGENTS_DIR" ]; then agent_count=$(find "$AGENTS_DIR" -name "*.md" | wc -l) log_success "Agents installed: $agent_count" fi if [ -d "$SKILLS_DIR" ]; then skill_count=$(find "$SKILLS_DIR" -maxdepth 1 -type d | wc -l) skill_count=$((skill_count - 1)) # Subtract 1 for the skills directory itself if [ $skill_count -gt 0 ]; then log_success "Skills installed: $skill_count skill(s)" fi fi if [ $errors -eq 0 ]; then log_success "Installation verification passed" return 0 else log_error "Installation verification failed with $errors errors" return 1 fi } ################################################################################ # Main Installation Flow ################################################################################ main() { echo -e "${CYAN}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ Claude Code Customizations - Automated Installer ║${NC}" echo -e "${CYAN}╚════════════════════════════════════════════════════════════╝${NC}" echo "" # Parse command line arguments SKIP_GIT_FETCH=false while [[ $# -gt 0 ]]; do case $1 in --skip-git-fetch) SKIP_GIT_FETCH=true shift ;; --help) echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --skip-git-fetch Skip fetching latest agents from GitHub" echo " --help Show this help message" echo "" exit 0 ;; *) log_error "Unknown option: $1" echo "Use --help for usage information" exit 1 ;; esac done # Run installation steps check_prerequisites setup_directories setup_settings # Fetch latest agents from GitHub (optional) if [ "$SKIP_GIT_FETCH" = false ]; then fetch_latest_agents fi install_mcp_services install_agents install_skills # NEW: Skills installation install_plugins # Verify installation if verify_installation; then echo "" log_success "═══════════════════════════════════════════════════════════" log_success "Installation completed successfully!" log_success "═══════════════════════════════════════════════════════════" echo "" log_info "Summary:" log_info " → Agents installed: $AGENTS_INSTALLED" log_info " → Skills installed: $SKILLS_INSTALLED" echo "" log_info "Next steps:" echo " 1. Restart Claude Code to load all customizations" echo " 2. Verify agents are available in Claude Code" echo " 3. Verify skills are available (check: ~/.claude/skills/)" echo " 4. Test MCP tools by starting a new session" echo "" echo "Backup location: $BACKUP_DIR" echo "" echo "Sync agents later: ~/.claude/sync-agents.sh" echo "" else log_error "Installation failed. Please check the errors above." exit 1 fi } # Run main function main "$@"