ralph-claude-code/install.sh
Frank Bria 9b19d70e35
feat(structure): migrate Ralph files to .ralph/ subfolder (#109)
* feat(structure): migrate Ralph files to .ralph/ subfolder

BREAKING CHANGE: Ralph configuration files now live in .ralph/ subfolder

This refactoring moves all Ralph-specific files into a hidden .ralph/
directory while keeping src/ at the project root. This improves
compatibility with existing tooling and keeps the project root clean.

Changes:
- Move PROMPT.md, @fix_plan.md, @AGENT.md to .ralph/
- Move specs/, logs/, docs/generated/, examples/ to .ralph/
- Move state files (.response_analysis, .circuit_breaker_state, etc.) to .ralph/
- Keep src/ at project root (unchanged)
- Add RALPH_DIR=".ralph" configuration variable
- Add ralph-migrate command for existing projects
- Create migrate_to_ralph_folder.sh migration script
- Update all path references in scripts and tests
- Update documentation (README.md, CLAUDE.md)

New project structure:
  project/
  ├── .ralph/           # Ralph configuration
  │   ├── PROMPT.md
  │   ├── @fix_plan.md
  │   ├── @AGENT.md
  │   ├── specs/
  │   ├── logs/
  │   └── docs/generated/
  └── src/              # Source code (unchanged)

Migration: Run `ralph-migrate` in existing projects to upgrade.

All 310 tests pass (100% pass rate).

* chore: add .claude/settings.local.json to .gitignore

* fix: address code review feedback for .ralph/ subfolder structure

Fixes multiple path-related issues identified in code review:

Test fixes:
- Fix create_sample_prompt to use $RALPH_DIR/PROMPT.md in test_session_continuity.bats
- Fix result_file path to use $RALPH_DIR/.json_parse_result in test_json_parsing.bats
- Fix @fix_plan.md and .response_analysis paths in test_cli_modern.bats
- Update templates directory missing test to account for global fallback

Template fix:
- Fix @fix_plan.md reference in templates/PROMPT.md to use .ralph/ prefix

Script fixes:
- Fix PROMPT_FILE comparison in ralph_loop.sh to use $RALPH_DIR/PROMPT.md
- Fix examples migration logic in migrate_to_ralph_folder.sh (remove premature mkdir)
- Move templates directory check AFTER cd in setup.sh (was checking wrong location)
- Add template directory validation with fallback to global templates

All 310 tests pass.

* Update migrate_to_ralph_folder.sh

Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>

* fix: address code review feedback for .ralph/ subfolder structure

Code Review Fixes:
- Fix test_json_parsing.bats: all result_file and session file paths now use $RALPH_DIR prefix
- Fix ralph_loop.sh help text: paths now show .ralph/.ralph_session, .ralph/.call_count, etc.
- Fix migrate_to_ralph_folder.sh:
  - Proper error handling for date command (separate local declaration)
  - Use cp -a source/. dest/ pattern to preserve dotfiles and attributes
  - Remove 2>/dev/null suppression to surface copy errors
- Update create_files.sh to use .ralph/ structure for embedded scripts
- Update .gitignore with all .ralph/ state file paths
- Add old structure detection in ralph_loop.sh with helpful migration message

Version Update:
- Bump to v0.10.0 (breaking change: structural reorganization)
- Update README.md and CLAUDE.md with new version and release notes
- Add ralph-migrate documentation to Key Commands section

All 310 tests pass.

---------

Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
2026-01-20 23:22:30 -07:00

336 lines
No EOL
9.6 KiB
Bash
Executable file

#!/bin/bash
# Ralph for Claude Code - Global Installation Script
set -e
# Configuration
INSTALL_DIR="$HOME/.local/bin"
RALPH_HOME="$HOME/.ralph"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log() {
local level=$1
local message=$2
local color=""
case $level in
"INFO") color=$BLUE ;;
"WARN") color=$YELLOW ;;
"ERROR") color=$RED ;;
"SUCCESS") color=$GREEN ;;
esac
echo -e "${color}[$(date '+%H:%M:%S')] [$level] $message${NC}"
}
# Check dependencies
check_dependencies() {
log "INFO" "Checking dependencies..."
local missing_deps=()
local os_type
os_type=$(uname)
if ! command -v node &> /dev/null && ! command -v npx &> /dev/null; then
missing_deps+=("Node.js/npm")
fi
if ! command -v jq &> /dev/null; then
missing_deps+=("jq")
fi
if ! command -v git &> /dev/null; then
missing_deps+=("git")
fi
# Check for timeout command (platform-specific)
if [[ "$os_type" == "Darwin" ]]; then
# macOS: check for gtimeout from coreutils
if ! command -v gtimeout &> /dev/null && ! command -v timeout &> /dev/null; then
missing_deps+=("coreutils (for timeout command)")
fi
else
# Linux: check for standard timeout command
if ! command -v timeout &> /dev/null; then
missing_deps+=("coreutils")
fi
fi
if [ ${#missing_deps[@]} -ne 0 ]; then
log "ERROR" "Missing required dependencies: ${missing_deps[*]}"
echo "Please install the missing dependencies:"
echo " Ubuntu/Debian: sudo apt-get install nodejs npm jq git coreutils"
echo " macOS: brew install node jq git coreutils"
echo " CentOS/RHEL: sudo yum install nodejs npm jq git coreutils"
exit 1
fi
# Additional macOS-specific warning for coreutils
if [[ "$os_type" == "Darwin" ]]; then
if command -v gtimeout &> /dev/null; then
log "INFO" "GNU coreutils detected (gtimeout available)"
elif command -v timeout &> /dev/null; then
log "INFO" "timeout command available"
fi
fi
# Claude Code CLI will be downloaded automatically when first used
log "INFO" "Claude Code CLI (@anthropic-ai/claude-code) will be downloaded when first used."
# Check tmux (optional)
if ! command -v tmux &> /dev/null; then
log "WARN" "tmux not found. Install for integrated monitoring: apt-get install tmux / brew install tmux"
fi
log "SUCCESS" "Dependencies check completed"
}
# Create installation directory
create_install_dirs() {
log "INFO" "Creating installation directories..."
mkdir -p "$INSTALL_DIR"
mkdir -p "$RALPH_HOME"
mkdir -p "$RALPH_HOME/templates"
mkdir -p "$RALPH_HOME/lib"
log "SUCCESS" "Directories created: $INSTALL_DIR, $RALPH_HOME"
}
# Install Ralph scripts
install_scripts() {
log "INFO" "Installing Ralph scripts..."
# Copy templates to Ralph home
cp -r "$SCRIPT_DIR/templates/"* "$RALPH_HOME/templates/"
# Copy lib scripts (response_analyzer.sh, circuit_breaker.sh)
cp -r "$SCRIPT_DIR/lib/"* "$RALPH_HOME/lib/"
# Create the main ralph command
cat > "$INSTALL_DIR/ralph" << 'EOF'
#!/bin/bash
# Ralph for Claude Code - Main Command
RALPH_HOME="$HOME/.ralph"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Source the actual ralph loop script with global paths
exec "$RALPH_HOME/ralph_loop.sh" "$@"
EOF
# Create ralph-monitor command
cat > "$INSTALL_DIR/ralph-monitor" << 'EOF'
#!/bin/bash
# Ralph Monitor - Global Command
RALPH_HOME="$HOME/.ralph"
exec "$RALPH_HOME/ralph_monitor.sh" "$@"
EOF
# Create ralph-setup command
cat > "$INSTALL_DIR/ralph-setup" << 'EOF'
#!/bin/bash
# Ralph Project Setup - Global Command
RALPH_HOME="$HOME/.ralph"
exec "$RALPH_HOME/setup.sh" "$@"
EOF
# Create ralph-import command
cat > "$INSTALL_DIR/ralph-import" << 'EOF'
#!/bin/bash
# Ralph PRD Import - Global Command
RALPH_HOME="$HOME/.ralph"
exec "$RALPH_HOME/ralph_import.sh" "$@"
EOF
# Create ralph-migrate command
cat > "$INSTALL_DIR/ralph-migrate" << 'EOF'
#!/bin/bash
# Ralph Migration - Global Command
# Migrates existing projects from flat structure to .ralph/ subfolder
RALPH_HOME="$HOME/.ralph"
exec "$RALPH_HOME/migrate_to_ralph_folder.sh" "$@"
EOF
# Copy actual script files to Ralph home with modifications for global operation
cp "$SCRIPT_DIR/ralph_monitor.sh" "$RALPH_HOME/"
# Copy PRD import script to Ralph home
cp "$SCRIPT_DIR/ralph_import.sh" "$RALPH_HOME/"
# Copy migration script to Ralph home
cp "$SCRIPT_DIR/migrate_to_ralph_folder.sh" "$RALPH_HOME/"
# Make all commands executable
chmod +x "$INSTALL_DIR/ralph"
chmod +x "$INSTALL_DIR/ralph-monitor"
chmod +x "$INSTALL_DIR/ralph-setup"
chmod +x "$INSTALL_DIR/ralph-import"
chmod +x "$INSTALL_DIR/ralph-migrate"
chmod +x "$RALPH_HOME/ralph_monitor.sh"
chmod +x "$RALPH_HOME/ralph_import.sh"
chmod +x "$RALPH_HOME/migrate_to_ralph_folder.sh"
chmod +x "$RALPH_HOME/lib/"*.sh
log "SUCCESS" "Ralph scripts installed to $INSTALL_DIR"
}
# Install global ralph_loop.sh
install_ralph_loop() {
log "INFO" "Installing global ralph_loop.sh..."
# Create modified ralph_loop.sh for global operation
sed \
-e "s|RALPH_HOME=\"\$HOME/.ralph\"|RALPH_HOME=\"\$HOME/.ralph\"|g" \
-e "s|\$script_dir/ralph_monitor.sh|\$RALPH_HOME/ralph_monitor.sh|g" \
-e "s|\$script_dir/ralph_loop.sh|\$RALPH_HOME/ralph_loop.sh|g" \
"$SCRIPT_DIR/ralph_loop.sh" > "$RALPH_HOME/ralph_loop.sh"
chmod +x "$RALPH_HOME/ralph_loop.sh"
log "SUCCESS" "Global ralph_loop.sh installed"
}
# Install global setup.sh
install_setup() {
log "INFO" "Installing global setup script..."
# Create modified setup.sh for global operation
cat > "$RALPH_HOME/setup.sh" << 'EOF'
#!/bin/bash
# Ralph Project Setup Script - Global Version
set -e
PROJECT_NAME=${1:-"my-project"}
RALPH_HOME="$HOME/.ralph"
echo "🚀 Setting up Ralph project: $PROJECT_NAME"
# Create project directory in current location
mkdir -p "$PROJECT_NAME"
cd "$PROJECT_NAME"
# Create structure with .ralph/ subfolder
mkdir -p src
mkdir -p .ralph/{specs/stdlib,examples,logs,docs/generated}
# Copy templates from Ralph home to .ralph/ subfolder
cp "$RALPH_HOME/templates/PROMPT.md" .ralph/
cp "$RALPH_HOME/templates/fix_plan.md" .ralph/@fix_plan.md
cp "$RALPH_HOME/templates/AGENT.md" .ralph/@AGENT.md
cp -r "$RALPH_HOME/templates/specs/"* .ralph/specs/ 2>/dev/null || true
# Initialize git
git init
echo "# $PROJECT_NAME" > README.md
git add .
git commit -m "Initial Ralph project setup"
echo "✅ Project $PROJECT_NAME created!"
echo "Next steps:"
echo " 1. Edit .ralph/PROMPT.md with your project requirements"
echo " 2. Update .ralph/specs/ with your project specifications"
echo " 3. Run: ralph --monitor"
echo " 4. Monitor: ralph-monitor (if running manually)"
EOF
chmod +x "$RALPH_HOME/setup.sh"
log "SUCCESS" "Global setup script installed"
}
# Check PATH
check_path() {
log "INFO" "Checking PATH configuration..."
if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
log "WARN" "$INSTALL_DIR is not in your PATH"
echo ""
echo "Add this to your ~/.bashrc, ~/.zshrc, or ~/.profile:"
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
echo ""
echo "Then run: source ~/.bashrc (or restart your terminal)"
echo ""
else
log "SUCCESS" "$INSTALL_DIR is already in PATH"
fi
}
# Main installation
main() {
echo "🚀 Installing Ralph for Claude Code globally..."
echo ""
check_dependencies
create_install_dirs
install_scripts
install_ralph_loop
install_setup
check_path
echo ""
log "SUCCESS" "🎉 Ralph for Claude Code installed successfully!"
echo ""
echo "Global commands available:"
echo " ralph --monitor # Start Ralph with integrated monitoring"
echo " ralph --help # Show Ralph options"
echo " ralph-setup my-project # Create new Ralph project"
echo " ralph-import prd.md # Convert PRD to Ralph project"
echo " ralph-migrate # Migrate existing project to .ralph/ structure"
echo " ralph-monitor # Manual monitoring dashboard"
echo ""
echo "Quick start:"
echo " 1. ralph-setup my-awesome-project"
echo " 2. cd my-awesome-project"
echo " 3. # Edit .ralph/PROMPT.md with your requirements"
echo " 4. ralph --monitor"
echo ""
if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
echo "⚠️ Don't forget to add $INSTALL_DIR to your PATH (see above)"
fi
}
# Handle command line arguments
case "${1:-install}" in
install)
main
;;
uninstall)
log "INFO" "Uninstalling Ralph for Claude Code..."
rm -f "$INSTALL_DIR/ralph" "$INSTALL_DIR/ralph-monitor" "$INSTALL_DIR/ralph-setup" "$INSTALL_DIR/ralph-import" "$INSTALL_DIR/ralph-migrate"
rm -rf "$RALPH_HOME"
log "SUCCESS" "Ralph for Claude Code uninstalled"
;;
--help|-h)
echo "Ralph for Claude Code Installation"
echo ""
echo "Usage: $0 [install|uninstall]"
echo ""
echo "Commands:"
echo " install Install Ralph globally (default)"
echo " uninstall Remove Ralph installation"
echo " --help Show this help"
;;
*)
echo "Unknown command: $1"
echo "Use --help for usage information"
exit 1
;;
esac