mirror of
https://github.com/alirezarezvani/ClaudeForge.git
synced 2026-07-03 10:23:15 -04:00
e45065e8ba
User-facing documentation drifted behind several waves of feature work
(plugin manifest, hooks, sync command, --weekly, audit skills, Karpathy
skill, CLAUDE.local.md tier, layered hook config). Refresh + fix one
real install bug. Surgical edits only — no rewrites.
README.md:
- "What's New" block now reflects the plugin manifest, --weekly,
InstructionsLoaded hook, AGENTS.md interop, CLAUDE.local.md tier,
layered hook config, and the fail-closed guardian.
- "What's Included" expanded from 5 numbered bullets to a structured
list grouping the 5 skills (incl. three forked audit skills),
2 slash commands, 1 agent, and 3 hook scripts.
- Components Deep Dive: /sync-claude-md and the guardian's fail-closed
contract now documented.
- Project Status: 1.0.0 -> 2.1.0; Quick Stats updated to reflect
actual component counts.
- Acknowledgments: attribution to MIT-licensed forrestchang and
shanraisshan source repos for adapted patterns.
docs/ARCHITECTURE.md, docs/QUICK_START.md, docs/TROUBLESHOOTING.md,
docs/INSTALLATION.md, examples/modular-setup.md, examples/integration-
examples.md:
- Every "20-300 lines" / ">300 lines" / "exceeds 300 lines" reference
rewritten to the actual 150-line hard cap.
- Every ls/Remove-Item path that pointed at the legacy
~/.claude/commands/enhance-claude-md/ bundle now points at the
top-level enhance-claude-md.md + sync-claude-md.md files.
- integration-examples.md line-bounds shell guard now uses 20..150.
docs/CLAUDE.md:
- Install-verify ls list extended with the three new audit-skill
directories so docs match what install.sh actually creates.
install.sh + install.ps1 (REAL FIX, not just docs):
- The three forked audit skills (claude-md-drift-audit, link-check,
dependency-rescan) were registered in plugin.json but never copied
by the direct-install path. Both installers now iterate over them
after the karpathy-guidelines block, mirroring the same backup +
nested-duplicate-cleanup pattern. Banner section and uninstall
instructions list all 5 skills.
Verified:
- All 5 CLAUDE.md files in this repo still <= 150 lines after edits.
- install.sh passes bash -n syntax check.
- Plugin manifest still resolves all 8 referenced paths on disk.
- README invariants present: 2.1.0, --weekly, hooks/hooks.json,
both source-repo attributions, three audit skill names.
- Stale-claim sweep: zero "20-300" / ">300" / "exceeds 300" refs
remain in docs/ or examples/.
384 lines
13 KiB
Bash
Executable File
384 lines
13 KiB
Bash
Executable File
#!/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 " • 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/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/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
|