#!/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" 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ă 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 # 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 "=======================================================================" 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 <&1 | tee "$LOG_FILE" || true OUTPUT=$(cat "$LOG_FILE") # Verifică dacă toate task-urile sunt complete if echo "$OUTPUT" | grep -q "COMPLETE"; 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