Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 139 additions & 47 deletions automation/scripts/setup-claude-code.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
#!/usr/bin/env bash
#
# Claude Code + Ralph Plugin - Complete Setup Script
# Works on macOS and Linux
# Works on macOS and Linux, CI-friendly and non-interactive mode supported
#
# Usage: ./setup-claude-code.sh
# Usage: ./setup-claude-code.sh [-y|--yes]
#

set -euo pipefail

# ============================================================
# Non-interactive mode detection
# ============================================================
NONINTERACTIVE="${NONINTERACTIVE:-0}"
if [[ "${CI:-false}" == "true" ]]; then
NONINTERACTIVE=1
fi

# Parse command line arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-y|--yes)
NONINTERACTIVE=1
shift
;;
*)
echo "Unknown option: $1"
echo "Usage: $0 [-y|--yes]"
exit 1
;;
esac
done

# Colors for output
GREEN='\033[0;32m'
BLUE='\033[0;34m'
Expand All @@ -20,6 +43,37 @@ ok() { echo -e "${GREEN}✓${NC} $1"; }
fail() { echo -e "${RED}✗${NC} $1"; }
warn() { echo -e "${YELLOW}⚠${NC} $1"; }

# ============================================================
# Cross-platform package installer helper
# ============================================================
# Best-effort package installer that attempts to install packages
# using available package managers (brew or apt-get).
# Returns 0 always to allow script to continue even if packages fail.
# Logs warnings for failures instead of aborting the script.
install_pkg() {
local pkg="$1"
local apt_pkg="${2:-$pkg}" # Allow custom apt package name

if command -v brew &>/dev/null; then
log "Installing $pkg via Homebrew..."
brew install "$pkg" &>/dev/null || { warn "Failed to install $pkg via brew (continuing)"; return 0; }
elif command -v apt-get &>/dev/null; then
log "Installing $apt_pkg via apt-get..."
if command -v sudo &>/dev/null; then
sudo apt-get update -qq &>/dev/null || true
sudo apt-get install -y "$apt_pkg" &>/dev/null || { warn "Failed to install $apt_pkg via apt-get (continuing)"; return 0; }
else
# Try without sudo (might work in some container environments)
apt-get update -qq &>/dev/null || true
apt-get install -y "$apt_pkg" &>/dev/null || { warn "Failed to install $apt_pkg via apt-get (continuing)"; return 0; }
fi
else
warn "No supported package manager found. Please install $pkg manually."
return 0
fi
ok "$pkg installed"
}

# ============================================================
# Detect OS
# ============================================================
Expand Down Expand Up @@ -54,24 +108,38 @@ fi

# Homebrew
if ! command -v brew &>/dev/null; then
log "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Add to PATH
if [[ -f "$HOME/.zprofile" ]]; then
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$HOME/.zprofile"
eval "$(/opt/homebrew/bin/brew shellenv)" 2>/dev/null || true
if [[ "$PLATFORM" == "macos" ]]; then
log "Installing Homebrew..."
# Note: This downloads from Homebrew's official installer
# Users should verify trust in https://brew.sh before running
if [[ "$NONINTERACTIVE" == "1" ]]; then
NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || warn "Homebrew install failed (continuing)"
else
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi

# Add to PATH
if [[ -f "$HOME/.zprofile" ]]; then
if ! grep -q "/opt/homebrew/bin/brew" "$HOME/.zprofile" 2>/dev/null; then
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$HOME/.zprofile"
fi
eval "$(/opt/homebrew/bin/brew shellenv)" 2>/dev/null || true
fi
ok "Homebrew installed"
else
warn "Homebrew not available on Linux (will use apt-get where available)"
fi
ok "Homebrew installed"
else
ok "Homebrew already installed"
brew update &>/dev/null || true
fi

# Essential tools
log "Installing essential tools (jq, git)..."
brew install jq git curl &>/dev/null || true
ok "Essential tools installed"
install_pkg jq jq
install_pkg git git
install_pkg curl curl
ok "Essential tools installation attempted"

# ============================================================
# Phase 2: Claude Code Installation
Expand All @@ -84,7 +152,24 @@ if command -v claude &>/dev/null; then
ok "Claude Code already installed: $(claude --version 2>/dev/null || echo 'unknown version')"
else
log "Downloading and installing Claude Code..."
curl -fsSL https://claude.ai/install.sh | bash

# Download installer to temp file for safer execution in CI
# Note: This downloads from claude.ai - users should verify trust in this source
# Consider pinning to a specific version if security is critical
INSTALLER_URL="https://claude.ai/install.sh"
INSTALLER_SCRIPT="/tmp/claude-install-$$.sh"

if curl -fsSL "$INSTALLER_URL" -o "$INSTALLER_SCRIPT" 2>/dev/null; then
chmod +x "$INSTALLER_SCRIPT"
if [[ "$NONINTERACTIVE" == "1" ]]; then
NONINTERACTIVE=1 bash "$INSTALLER_SCRIPT" || warn "Claude Code installer failed (continuing to verification)"
else
bash "$INSTALLER_SCRIPT"
fi
rm -f "$INSTALLER_SCRIPT"
else
warn "Could not download Claude Code installer from $INSTALLER_URL (continuing to verification)"
fi

# Add to PATH
if [[ -n "${ZDOTDIR:-}" ]] && [[ -f "$ZDOTDIR/.zshrc" ]]; then
Expand All @@ -106,7 +191,12 @@ else
fi

export PATH="$HOME/.claude/bin:$PATH"
ok "Claude Code installed"

if command -v claude &>/dev/null; then
ok "Claude Code installed"
else
warn "Claude Code command not found after install attempt"
fi
fi

# ============================================================
Expand Down Expand Up @@ -188,35 +278,30 @@ echo ""

# Node.js
if ! command -v node &>/dev/null; then
log "Installing Node.js..."
brew install node &>/dev/null || true
ok "Node.js installed"
install_pkg node nodejs
else
ok "Node.js already installed: $(node --version)"
fi

# Python
if ! command -v python3 &>/dev/null; then
log "Installing Python..."
brew install python@3.11 &>/dev/null || true
ok "Python installed"
install_pkg python@3.11 python3
else
ok "Python already installed: $(python3 --version)"
fi

# GitHub CLI
if ! command -v gh &>/dev/null; then
log "Installing GitHub CLI..."
brew install gh &>/dev/null || true
ok "GitHub CLI installed"
install_pkg gh gh
else
ok "GitHub CLI already installed"
fi

# Other useful tools
log "Installing additional utilities..."
brew install tree ripgrep fd &>/dev/null || true
ok "Additional utilities installed"
install_pkg tree tree
install_pkg ripgrep ripgrep
install_pkg fd fd-find # Debian uses fd-find package name

# ============================================================
# Phase 6: Helper Scripts & Documentation
Expand Down Expand Up @@ -361,30 +446,37 @@ else
fi

echo ""
echo "Next Steps:"
echo ""
echo "1. Authenticate Claude Code:"
echo " ${BLUE}claude auth login${NC}"
echo ""
echo "2. Test it:"
echo " ${BLUE}cd ~/test-claude-project${NC}"
echo " ${BLUE}claude${NC}"
echo ""
echo "3. Try Ralph loop:"
echo " ${BLUE}/ralph-loop \"Add a hello function\" --max-iterations 5${NC}"
echo ""
echo "4. Read the quick reference:"
echo " ${BLUE}cat ~/claude-quick-ref.md${NC}"
echo ""
echo "5. Start using in your projects:"
echo " ${BLUE}cd /path/to/your/project${NC}"
echo " ${BLUE}~/start-claude.sh${NC}"
echo ""

if [[ "$NONINTERACTIVE" != "1" ]]; then
echo "Next Steps:"
echo ""
echo "1. Authenticate Claude Code:"
echo " ${BLUE}claude auth login${NC}"
echo ""
echo "2. Test it:"
echo " ${BLUE}cd ~/test-claude-project${NC}"
echo " ${BLUE}claude${NC}"
echo ""
echo "3. Try Ralph loop:"
echo " ${BLUE}/ralph-loop \"Add a hello function\" --max-iterations 5${NC}"
echo ""
echo "4. Read the quick reference:"
echo " ${BLUE}cat ~/claude-quick-ref.md${NC}"
echo ""
echo "5. Start using in your projects:"
echo " ${BLUE}cd /path/to/your/project${NC}"
echo " ${BLUE}~/start-claude.sh${NC}"
echo ""
fi

if [[ $ERRORS -gt 0 ]]; then
echo -e "${YELLOW}⚠ Please resolve the errors above before using Claude Code${NC}"
if [[ "$NONINTERACTIVE" != "1" ]]; then
echo -e "${YELLOW}⚠ Please resolve the errors above before using Claude Code${NC}"
fi
exit 1
fi

echo -e "${GREEN}Ready to build with Claude Code + Ralph! 🚀${NC}"
echo ""
if [[ "$NONINTERACTIVE" != "1" ]]; then
echo -e "${GREEN}Ready to build with Claude Code + Ralph! 🚀${NC}"
echo ""
fi
62 changes: 52 additions & 10 deletions automation/scripts/setup-ralph-project.sh
Original file line number Diff line number Diff line change
@@ -1,27 +1,63 @@
#!/bin/bash
# Setup a new project with AGENTS.md and Ralph infrastructure
# Usage: ./setup-ralph-project.sh <project-name> <language> [project-type]
# Usage: ./setup-ralph-project.sh <project-name> <language> [project-type] [-y|--yes]

set -e

# ============================================================
# Non-interactive mode detection
# ============================================================
NONINTERACTIVE="${NONINTERACTIVE:-0}"
if [[ "${CI:-false}" == "true" ]]; then
NONINTERACTIVE=1
fi

echo "🤖 Ralph Project Setup Wizard"
echo ""

# Get project details
PROJECT_NAME="$1"
LANGUAGE="$2"
PROJECT_TYPE="${3:-cli-tool}"
# Parse arguments
PROJECT_NAME=""
LANGUAGE=""
PROJECT_TYPE=""

while [[ $# -gt 0 ]]; do
case "$1" in
-y|--yes)
NONINTERACTIVE=1
shift
;;
*)
if [[ -z "$PROJECT_NAME" ]]; then
PROJECT_NAME="$1"
elif [[ -z "$LANGUAGE" ]]; then
LANGUAGE="$1"
elif [[ -z "$PROJECT_TYPE" ]]; then
PROJECT_TYPE="$1"
else
echo "Unknown argument: $1"
exit 1
fi
shift
;;
esac
done

# Set default project type
PROJECT_TYPE="${PROJECT_TYPE:-cli-tool}"

if [ -z "$PROJECT_NAME" ] || [ -z "$LANGUAGE" ]; then
echo "Usage: $0 <project-name> <language> [project-type]"
echo "Usage: $0 <project-name> <language> [project-type] [-y|--yes]"
echo ""
echo "Examples:"
echo " $0 task-manager python cli-tool"
echo " $0 my-api typescript api"
echo " $0 blog-app javascript web-app"
echo " $0 my-api typescript api -y"
echo " $0 blog-app javascript web-app --yes"
echo ""
echo "Supported languages: python, javascript, typescript, rust, go"
echo "Supported types: cli-tool, web-app, api, library, automation"
echo ""
echo "Options:"
echo " -y, --yes Non-interactive mode (auto-accept prompts)"
exit 1
fi

Expand All @@ -32,8 +68,14 @@ echo "Language: $LANGUAGE"
echo "Type: $PROJECT_TYPE"
echo "Location: $PROJECT_DIR"
echo ""
read -p "Create this project? (y/n) " -n 1 -r
echo ""

if [[ "$NONINTERACTIVE" == "1" ]]; then
echo "Non-interactive mode: proceeding automatically"
REPLY="y"
else
read -p "Create this project? (y/n) " -n 1 -r
echo ""
fi

if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Cancelled."
Expand Down
Loading