Initial commit - Ralph adaptat pentru Claude Code
Adaptare a sistemului Ralph (snarktank/ralph) pentru Claude Code CLI. Features: - Script ralph.sh pentru loop autonom - Skill /prd pentru generare PRD structurat - Skill /ralph pentru conversie PRD în prd.json - Script install.sh pentru instalare globală skills - Documentație completă Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
183
scripts/ralph/ralph.sh
Executable file
183
scripts/ralph/ralph.sh
Executable file
@@ -0,0 +1,183 @@
|
||||
#!/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"
|
||||
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 <<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
|
||||
# Folosim --dangerously-skip-permissions pentru a permite operațiuni fără confirmare
|
||||
# OUTPUT=$(echo "$FULL_PROMPT" | claude -p --dangerously-skip-permissions 2>&1 | tee /dev/stderr) || true
|
||||
|
||||
# Alternativ, cu output în fișier pentru debugging
|
||||
LOG_FILE="$SCRIPT_DIR/logs/iteration-$i-$(date +%Y%m%d-%H%M%S).log"
|
||||
mkdir -p "$SCRIPT_DIR/logs"
|
||||
|
||||
echo "$FULL_PROMPT" | claude -p --dangerously-skip-permissions 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
|
||||
Reference in New Issue
Block a user