Major improvements inspired by coleam00/ai-agents-masterclass: - prd.md: Auto-detect project context (package.json, pyproject.toml, etc.) - NEW_PROJECT_MODE: ~10 questions for new projects - FEATURE_MODE: ~5-7 questions for existing projects - Uses AskUserQuestion for interactive UX - Optional WebSearch for best practices - convert.md: Extended functionality - Generates .claude/settings.json with allow-list per tech stack - Extracts real commands from package.json scripts - Adds techStack info to prd.json - Creates screenshots/ directory - prompt.md: Browser verification with agent-browser CLI - Compact refs (@e1, @e2) for minimal token usage - requiresBrowserCheck flag per story - Screenshot saving for UI verification - ralph.sh: Screenshots directory + agent-browser check - README.md: Complete rewrite with new features Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
194 lines
6.6 KiB
Bash
Executable File
194 lines
6.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# Ralph pentru Claude Code - Loop autonom de agent AI
|
|
# Adaptat din Ralph original (snarktank/ralph) pentru Claude Code CLI
|
|
# Usage: ./ralph.sh [max_iterations] [project_dir]
|
|
|
|
set -e
|
|
|
|
MAX_ITERATIONS=${1:-10}
|
|
PROJECT_DIR=${2:-$(pwd)}
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PRD_FILE="$SCRIPT_DIR/prd.json"
|
|
PROGRESS_FILE="$SCRIPT_DIR/progress.txt"
|
|
ARCHIVE_DIR="$SCRIPT_DIR/archive"
|
|
SCREENSHOTS_DIR="$SCRIPT_DIR/screenshots"
|
|
LAST_BRANCH_FILE="$SCRIPT_DIR/.last-branch"
|
|
PROMPT_FILE="$SCRIPT_DIR/prompt.md"
|
|
|
|
# Verifică că jq este instalat
|
|
if ! command -v jq &> /dev/null; then
|
|
echo "Eroare: jq nu este instalat. Rulează: apt install jq"
|
|
exit 1
|
|
fi
|
|
|
|
# Verifică că claude este instalat
|
|
if ! command -v claude &> /dev/null; then
|
|
echo "Eroare: Claude Code CLI nu este instalat."
|
|
echo "Instalează cu: npm install -g @anthropic-ai/claude-code"
|
|
exit 1
|
|
fi
|
|
|
|
# Verifică agent-browser (opțional, pentru verificări UI)
|
|
if ! command -v agent-browser &> /dev/null; then
|
|
echo "Notă: agent-browser nu este instalat."
|
|
echo "Pentru verificări vizuale UI, instalează cu: npm install -g agent-browser && agent-browser install"
|
|
echo "Continuăm fără verificări browser..."
|
|
echo ""
|
|
fi
|
|
|
|
# Verifică existența fișierelor necesare
|
|
if [ ! -f "$PRD_FILE" ]; then
|
|
echo "Eroare: prd.json nu există în $SCRIPT_DIR"
|
|
echo "Generează mai întâi un PRD folosind skill-ul /prd și apoi /ralph"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$PROMPT_FILE" ]; then
|
|
echo "Eroare: prompt.md nu există în $SCRIPT_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
# Arhivare rulare anterioară dacă branch-ul s-a schimbat
|
|
if [ -f "$PRD_FILE" ] && [ -f "$LAST_BRANCH_FILE" ]; then
|
|
CURRENT_BRANCH=$(jq -r '.branchName // empty' "$PRD_FILE" 2>/dev/null || echo "")
|
|
LAST_BRANCH=$(cat "$LAST_BRANCH_FILE" 2>/dev/null || echo "")
|
|
|
|
if [ -n "$CURRENT_BRANCH" ] && [ -n "$LAST_BRANCH" ] && [ "$CURRENT_BRANCH" != "$LAST_BRANCH" ]; then
|
|
DATE=$(date +%Y-%m-%d)
|
|
FOLDER_NAME=$(echo "$LAST_BRANCH" | sed 's|^ralph/||')
|
|
ARCHIVE_FOLDER="$ARCHIVE_DIR/$DATE-$FOLDER_NAME"
|
|
|
|
echo "Arhivare rulare anterioară: $LAST_BRANCH"
|
|
mkdir -p "$ARCHIVE_FOLDER"
|
|
[ -f "$PRD_FILE" ] && cp "$PRD_FILE" "$ARCHIVE_FOLDER/"
|
|
[ -f "$PROGRESS_FILE" ] && cp "$PROGRESS_FILE" "$ARCHIVE_FOLDER/"
|
|
echo " Arhivat în: $ARCHIVE_FOLDER"
|
|
|
|
# Reset progress file
|
|
echo "# Ralph Progress Log" > "$PROGRESS_FILE"
|
|
echo "Started: $(date)" >> "$PROGRESS_FILE"
|
|
echo "Branch: $CURRENT_BRANCH" >> "$PROGRESS_FILE"
|
|
echo "---" >> "$PROGRESS_FILE"
|
|
fi
|
|
fi
|
|
|
|
# Salvează branch-ul curent
|
|
if [ -f "$PRD_FILE" ]; then
|
|
CURRENT_BRANCH=$(jq -r '.branchName // empty' "$PRD_FILE" 2>/dev/null || echo "")
|
|
if [ -n "$CURRENT_BRANCH" ]; then
|
|
echo "$CURRENT_BRANCH" > "$LAST_BRANCH_FILE"
|
|
fi
|
|
fi
|
|
|
|
# Creează directoare necesare
|
|
mkdir -p "$SCRIPT_DIR/logs" "$SCRIPT_DIR/archive" "$SCRIPT_DIR/screenshots"
|
|
|
|
# Inițializare progress file dacă nu există
|
|
if [ ! -f "$PROGRESS_FILE" ]; then
|
|
echo "# Ralph Progress Log" > "$PROGRESS_FILE"
|
|
echo "Started: $(date)" >> "$PROGRESS_FILE"
|
|
echo "---" >> "$PROGRESS_FILE"
|
|
fi
|
|
|
|
# Funcție pentru a verifica dacă toate story-urile sunt complete
|
|
check_all_complete() {
|
|
local incomplete=$(jq '[.userStories[] | select(.passes != true)] | length' "$PRD_FILE" 2>/dev/null || echo "999")
|
|
[ "$incomplete" -eq 0 ]
|
|
}
|
|
|
|
# Afișare status inițial
|
|
echo ""
|
|
echo "======================================================================="
|
|
echo " RALPH pentru Claude Code - Agent Autonom "
|
|
echo "======================================================================="
|
|
PROJECT_NAME=$(jq -r '.projectName // "Unknown"' "$PRD_FILE")
|
|
BRANCH_NAME=$(jq -r '.branchName // "N/A"' "$PRD_FILE")
|
|
TOTAL_STORIES=$(jq '.userStories | length' "$PRD_FILE")
|
|
COMPLETE_STORIES=$(jq '[.userStories[] | select(.passes == true)] | length' "$PRD_FILE")
|
|
echo " Proiect: $PROJECT_NAME"
|
|
echo " Branch: $BRANCH_NAME"
|
|
echo " Stories: $COMPLETE_STORIES / $TOTAL_STORIES complete"
|
|
echo " Max iterații: $MAX_ITERATIONS"
|
|
echo " Screenshots: $SCREENSHOTS_DIR"
|
|
echo "======================================================================="
|
|
echo ""
|
|
|
|
# Verificare rapidă - poate toate sunt deja complete?
|
|
if check_all_complete; then
|
|
echo "Toate story-urile sunt deja complete!"
|
|
exit 0
|
|
fi
|
|
|
|
# Loop principal
|
|
for i in $(seq 1 $MAX_ITERATIONS); do
|
|
echo ""
|
|
echo "==================================================================="
|
|
echo " Ralph Iterația $i din $MAX_ITERATIONS"
|
|
echo "==================================================================="
|
|
|
|
# Status curent
|
|
COMPLETE_NOW=$(jq '[.userStories[] | select(.passes == true)] | length' "$PRD_FILE")
|
|
NEXT_STORY=$(jq -r '[.userStories[] | select(.passes != true)] | sort_by(.priority) | .[0] | "\(.id): \(.title)"' "$PRD_FILE")
|
|
echo " Progress: $COMPLETE_NOW / $TOTAL_STORIES stories complete"
|
|
echo " Next: $NEXT_STORY"
|
|
echo ""
|
|
|
|
# Pregătește prompt-ul cu context
|
|
FULL_PROMPT=$(cat <<EOF
|
|
# Context pentru această iterație Ralph
|
|
|
|
## PRD (prd.json):
|
|
$(cat "$PRD_FILE")
|
|
|
|
## Progress până acum (progress.txt):
|
|
$(cat "$PROGRESS_FILE")
|
|
|
|
## Instrucțiuni pentru această iterație:
|
|
$(cat "$PROMPT_FILE")
|
|
EOF
|
|
)
|
|
|
|
# Execută Claude Code în modul non-interactiv
|
|
LOG_FILE="$SCRIPT_DIR/logs/iteration-$i-$(date +%Y%m%d-%H%M%S).log"
|
|
mkdir -p "$SCRIPT_DIR/logs"
|
|
|
|
# --output-format json avoids streaming mode issues
|
|
echo "$FULL_PROMPT" | claude -p --dangerously-skip-permissions --output-format json 2>&1 | tee "$LOG_FILE" || true
|
|
OUTPUT=$(cat "$LOG_FILE")
|
|
|
|
# Verifică dacă toate task-urile sunt complete
|
|
if echo "$OUTPUT" | grep -q "<promise>COMPLETE</promise>"; then
|
|
echo ""
|
|
echo "==================================================================="
|
|
echo " RALPH A TERMINAT TOATE TASK-URILE!"
|
|
echo " Completat la iterația $i din $MAX_ITERATIONS"
|
|
echo "==================================================================="
|
|
exit 0
|
|
fi
|
|
|
|
# Verifică și prin prd.json
|
|
if check_all_complete; then
|
|
echo ""
|
|
echo "==================================================================="
|
|
echo " TOATE STORY-URILE DIN PRD SUNT COMPLETE!"
|
|
echo "==================================================================="
|
|
exit 0
|
|
fi
|
|
|
|
echo " Iterația $i completă. Continuăm..."
|
|
sleep 2
|
|
done
|
|
|
|
echo ""
|
|
echo "==================================================================="
|
|
echo " Ralph a atins limita de iterații ($MAX_ITERATIONS)"
|
|
echo " Verifică progress.txt pentru status."
|
|
echo "==================================================================="
|
|
echo ""
|
|
|
|
# Afișează stories incomplete
|
|
echo "Stories incomplete:"
|
|
jq -r '.userStories[] | select(.passes != true) | " - \(.id): \(.title)"' "$PRD_FILE"
|
|
|
|
exit 1
|