Files

387 lines
14 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ClaudeForge Installer
# Automated installation script for macOS and Linux
# Version: 2.0.0
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Print colored output
print_info() {
echo -e "${BLUE}${NC} $1"
}
print_success() {
echo -e "${GREEN}${NC} $1"
}
print_warning() {
echo -e "${YELLOW}${NC} $1"
}
print_error() {
echo -e "${RED}${NC} $1"
}
# Banner
echo ""
echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}${GREEN}ClaudeForge Installer${BLUE}${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}║ Automated CLAUDE.md Management Tool ║${NC}"
echo -e "${BLUE}║ Version 2.0.0 ║${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
echo ""
# Check if running from correct directory or need to download
REMOTE_INSTALL=false
ORIGINAL_DIR=$(pwd)
if [ ! -d "skill" ] || [ ! -d "command" ] || [ ! -d "agent" ]; then
print_info "Installing from GitHub..."
REMOTE_INSTALL=true
# Create temporary directory
TEMP_DIR=$(mktemp -d)
cd "$TEMP_DIR"
print_info "Downloading ClaudeForge v2.0.0..."
# Download using curl or wget
if command -v curl &> /dev/null; then
curl -fsSL https://github.com/alirezarezvani/ClaudeForge/archive/refs/heads/main.tar.gz -o claudeforge.tar.gz
elif command -v wget &> /dev/null; then
wget -q https://github.com/alirezarezvani/ClaudeForge/archive/refs/heads/main.tar.gz -O claudeforge.tar.gz
else
print_error "Neither curl nor wget found. Please install one of them."
exit 1
fi
print_info "Extracting files..."
tar -xzf claudeforge.tar.gz
cd ClaudeForge-main
print_success "Downloaded ClaudeForge successfully"
fi
# Check for Claude Code installation
print_info "Checking for Claude Code installation..."
if [ ! -d "$HOME/.claude" ]; then
print_warning "Claude Code user directory (~/.claude) not found."
print_info "Creating ~/.claude directory structure..."
mkdir -p "$HOME/.claude"/{skills,commands,agents}
print_success "Directory structure created"
fi
# Check Claude Code version
check_claude_code_version() {
local version=""
if command -v claude &> /dev/null; then
version=$(claude --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
if [ -z "$version" ]; then
print_warning "Could not detect Claude Code version"
print_info "ClaudeForge v2.0 requires Claude Code 2.1.0 or later"
print_info "Continuing with installation (compatibility not guaranteed)"
return 0
fi
local major=$(echo "$version" | cut -d. -f1)
local minor=$(echo "$version" | cut -d. -f2)
if [ "$major" -lt 2 ]; then
print_error "Claude Code version $version is not supported"
print_error "Please upgrade to Claude Code 2.1.0 or later"
return 1
elif [ "$major" -eq 2 ] && [ "$minor" -lt 1 ]; then
print_warning "Claude Code version $version may have limited features"
print_info "Recommended: Claude Code 2.1.4 or later for full hook support"
fi
print_success "Claude Code version $version detected"
return 0
}
print_info "Checking Claude Code version..."
check_claude_code_version || exit 1
# Ask for installation scope
echo ""
print_info "Where would you like to install ClaudeForge?"
echo ""
echo -e " ${GREEN}1)${NC} User-level (~/.claude/) - Available in all Claude Code projects"
echo -e " ${GREEN}2)${NC} Project-level (./.claude/) - Available only in current project"
echo ""
while true; do
read -p "$(echo -e ${BLUE}Enter choice [1/2]:${NC} )" choice < /dev/tty
case $choice in
1)
SKILLS_DIR="$HOME/.claude/skills"
COMMANDS_DIR="$HOME/.claude/commands"
AGENTS_DIR="$HOME/.claude/agents"
SCOPE="user-level"
print_success "Installing at user-level (all projects)"
break
;;
2)
if [ "$REMOTE_INSTALL" = true ]; then
SKILLS_DIR="$ORIGINAL_DIR/.claude/skills"
COMMANDS_DIR="$ORIGINAL_DIR/.claude/commands"
AGENTS_DIR="$ORIGINAL_DIR/.claude/agents"
else
SKILLS_DIR="./.claude/skills"
COMMANDS_DIR="./.claude/commands"
AGENTS_DIR="./.claude/agents"
fi
SCOPE="project-level"
print_success "Installing at project-level (current project only)"
break
;;
*)
print_error "Invalid choice. Please enter 1 or 2."
;;
esac
done
echo ""
print_info "Installation will create:"
echo " • Skill: $SKILLS_DIR/claudeforge-skill/"
echo " • Skill: $SKILLS_DIR/karpathy-guidelines/"
echo " • Skill: $SKILLS_DIR/claude-md-drift-audit/"
echo " • Skill: $SKILLS_DIR/claude-md-link-check/"
echo " • Skill: $SKILLS_DIR/claude-md-dependency-rescan/"
echo " • Command: $COMMANDS_DIR/enhance-claude-md.md"
echo " • Command: $COMMANDS_DIR/sync-claude-md.md"
echo " • Command: $COMMANDS_DIR/claude-to-agents.md"
echo " • Agent: $AGENTS_DIR/claude-md-guardian.md"
echo ""
# Confirm installation
read -p "$(echo -e "${BLUE}Proceed with installation? [Y/n]:${NC}")" confirm < /dev/tty
confirm=${confirm:-Y}
if [[ ! $confirm =~ ^[Yy]$ ]]; then
print_warning "Installation cancelled."
exit 0
fi
echo ""
print_info "Starting installation..."
echo ""
# Create directories if they don't exist
mkdir -p "$SKILLS_DIR" "$COMMANDS_DIR" "$AGENTS_DIR"
# Install skill
print_info "Installing ClaudeForge skill..."
if [ -d "$SKILLS_DIR/claudeforge-skill" ]; then
print_warning "Existing skill found. Creating backup..."
mv "$SKILLS_DIR/claudeforge-skill" "$SKILLS_DIR/claudeforge-skill.backup.$(date +%Y%m%d_%H%M%S)"
print_success "Backup created"
fi
cp -r skill "$SKILLS_DIR/claudeforge-skill"
print_success "Skill installed → $SKILLS_DIR/claudeforge-skill/"
# Install karpathy-guidelines as a separate top-level skill so it is
# discoverable as its own skill (and applies to every project, not only
# during /enhance-claude-md runs).
print_info "Installing karpathy-guidelines skill..."
if [ -d "$SKILLS_DIR/karpathy-guidelines" ]; then
print_warning "Existing karpathy-guidelines skill found. Creating backup..."
mv "$SKILLS_DIR/karpathy-guidelines" "$SKILLS_DIR/karpathy-guidelines.backup.$(date +%Y%m%d_%H%M%S)"
print_success "Backup created"
fi
cp -r skill/karpathy-guidelines "$SKILLS_DIR/karpathy-guidelines"
# Remove the nested duplicate so the karpathy skill exists once.
rm -rf "$SKILLS_DIR/claudeforge-skill/karpathy-guidelines"
print_success "Karpathy guidelines installed → $SKILLS_DIR/karpathy-guidelines/"
# Install the forked task-style audit skills as separate top-level skills
# so each is invocable standalone (/claude-md-drift-audit etc.) and
# discoverable by /sync-claude-md --weekly.
for audit_skill in claude-md-drift-audit claude-md-link-check claude-md-dependency-rescan; do
print_info "Installing $audit_skill skill..."
audit_target="$SKILLS_DIR/$audit_skill"
if [ -d "$audit_target" ]; then
print_warning "Existing $audit_skill skill found. Creating backup..."
mv "$audit_target" "$audit_target.backup.$(date +%Y%m%d_%H%M%S)"
fi
cp -r "skill/$audit_skill" "$audit_target"
rm -rf "$SKILLS_DIR/claudeforge-skill/$audit_skill"
print_success "$audit_skill installed → $audit_target/"
done
# Install slash commands. Each .md file in command/ is installed as its own
# top-level command file so it registers as /<name> rather than as a nested
# /<dir>:<name>. README.md and other non-command files are skipped.
print_info "Installing slash commands..."
# Migrate legacy bundle directory if present.
if [ -d "$COMMANDS_DIR/enhance-claude-md" ]; then
print_warning "Legacy command bundle found. Creating backup..."
mv "$COMMANDS_DIR/enhance-claude-md" "$COMMANDS_DIR/enhance-claude-md.backup.$(date +%Y%m%d_%H%M%S)"
print_success "Backup created"
fi
for cmd_file in command/*.md; do
cmd_basename=$(basename "$cmd_file")
# Skip the directory's own README.
if [ "$cmd_basename" = "README.md" ]; then
continue
fi
cmd_target="$COMMANDS_DIR/$cmd_basename"
if [ -f "$cmd_target" ]; then
print_warning "Existing $cmd_basename found. Creating backup..."
mv "$cmd_target" "$cmd_target.backup.$(date +%Y%m%d_%H%M%S)"
fi
cp "$cmd_file" "$cmd_target"
print_success "Command installed → $cmd_target"
done
# Install guardian agent
print_info "Installing claude-md-guardian agent..."
if [ -f "$AGENTS_DIR/claude-md-guardian.md" ]; then
print_warning "Existing agent found. Creating backup..."
mv "$AGENTS_DIR/claude-md-guardian.md" "$AGENTS_DIR/claude-md-guardian.md.backup.$(date +%Y%m%d_%H%M%S)"
print_success "Backup created"
fi
cp agent/claude-md-guardian.md "$AGENTS_DIR/"
print_success "Agent installed → $AGENTS_DIR/claude-md-guardian.md"
# Optional: Install quality hooks
echo ""
read -p "$(echo -e "${BLUE}Would you like to install quality hooks (pre-commit validation)? [y/N]:${NC}")" install_hooks < /dev/tty
install_hooks=${install_hooks:-N}
if [[ $install_hooks =~ ^[Yy]$ ]]; then
if [ "$SCOPE" == "project-level" ]; then
print_info "Installing quality hooks..."
if [ "$REMOTE_INSTALL" = true ]; then
HOOKS_DIR="$ORIGINAL_DIR/.claude/hooks"
else
HOOKS_DIR=".claude/hooks"
fi
mkdir -p "$HOOKS_DIR"
cp hooks/pre-commit.sh "$HOOKS_DIR/"
chmod +x "$HOOKS_DIR/pre-commit.sh"
print_success "Quality hooks installed → $HOOKS_DIR/"
else
print_warning "Quality hooks can only be installed at project-level"
print_info "Run installer with option 2 in your project directory"
fi
fi
# Validate v2.1.4 compatibility
validate_v214_compatibility() {
print_info "Validating v2.1.4 compatibility..."
local skill_file="$SKILLS_DIR/claudeforge-skill/SKILL.md"
local agent_file="$AGENTS_DIR/claude-md-guardian.md"
# Verify new syntax is present
if ! grep -q "permissions:" "$skill_file"; then
print_error "Skill missing v2.1.4 permissions syntax"
return 1
fi
if ! grep -q "permissions:" "$agent_file"; then
print_error "Agent missing v2.1.4 permissions syntax"
return 1
fi
# Check for hooks
if grep -q "hooks:" "$agent_file"; then
print_success "Guardian agent hooks configured"
else
print_warning "Guardian agent has no hooks (optional)"
fi
print_success "v2.1.4 compatibility validated"
return 0
}
echo ""
validate_v214_compatibility || {
print_error "Installation validation failed"
exit 1
}
# Installation complete
echo ""
echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ ║${NC}"
echo -e "${GREEN}║ Installation completed successfully!${NC}"
echo -e "${GREEN}║ ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
echo ""
# Next steps
print_info "Next steps:"
echo ""
echo -e " ${GREEN}1.${NC} Restart Claude Code (important!)"
echo -e " ${GREEN}2.${NC} Navigate to your project directory"
echo -e " ${GREEN}3.${NC} Run the command:"
echo ""
echo -e " ${BLUE}/enhance-claude-md${NC}"
echo ""
echo -e " ${GREEN}4.${NC} Follow the interactive prompts"
echo ""
# Additional information
print_info "Documentation:"
echo ""
echo " • Quick Start: docs/QUICK_START.md"
echo " • Installation: docs/INSTALLATION.md"
echo " • Architecture: docs/ARCHITECTURE.md"
echo " • Troubleshooting: docs/TROUBLESHOOTING.md"
echo ""
echo -e " • GitHub: ${BLUE}https://github.com/alirezarezvani/ClaudeForge${NC}"
echo ""
# Uninstall instructions
print_info "To uninstall, run:"
echo ""
if [ "$SCOPE" == "user-level" ]; then
echo " rm -rf ~/.claude/skills/claudeforge-skill"
echo " rm -rf ~/.claude/skills/karpathy-guidelines"
echo " rm -rf ~/.claude/skills/claude-md-drift-audit"
echo " rm -rf ~/.claude/skills/claude-md-link-check"
echo " rm -rf ~/.claude/skills/claude-md-dependency-rescan"
echo " rm -f ~/.claude/commands/enhance-claude-md.md"
echo " rm -f ~/.claude/commands/sync-claude-md.md"
echo " rm -f ~/.claude/commands/claude-to-agents.md"
echo " rm -f ~/.claude/agents/claude-md-guardian.md"
else
echo " rm -rf ./.claude/skills/claudeforge-skill"
echo " rm -rf ./.claude/skills/karpathy-guidelines"
echo " rm -rf ./.claude/skills/claude-md-drift-audit"
echo " rm -rf ./.claude/skills/claude-md-link-check"
echo " rm -rf ./.claude/skills/claude-md-dependency-rescan"
echo " rm -f ./.claude/commands/enhance-claude-md.md"
echo " rm -f ./.claude/commands/sync-claude-md.md"
echo " rm -f ./.claude/commands/claude-to-agents.md"
echo " rm -f ./.claude/agents/claude-md-guardian.md"
fi
echo ""
print_success "Thank you for installing ClaudeForge!"
echo ""
# Cleanup temporary directory if remote install
if [ "$REMOTE_INSTALL" = true ]; then
cd "$HOME"
rm -rf "$TEMP_DIR"
fi