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:
137
scripts/ralph/generate-prd.md
Normal file
137
scripts/ralph/generate-prd.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Skill: Generare PRD pentru Ralph
|
||||
|
||||
Când utilizatorul cere să generezi un PRD pentru Ralph, urmează acest workflow:
|
||||
|
||||
## Pas 1: Întrebări de clarificare
|
||||
|
||||
Pune 3-5 întrebări pentru a înțelege feature-ul:
|
||||
|
||||
**Exemplu:**
|
||||
```
|
||||
Pentru a genera un PRD bun, am nevoie de câteva clarificări:
|
||||
|
||||
A) Care este scopul principal al feature-ului?
|
||||
1. Funcționalitate nouă pentru utilizatori
|
||||
2. Îmbunătățire performanță
|
||||
3. Refactoring/cleanup cod
|
||||
4. Altceva: [descrie]
|
||||
|
||||
B) Cine sunt utilizatorii țintă?
|
||||
1. End users
|
||||
2. Developers/Admin
|
||||
3. Sistem automatizat
|
||||
4. Altceva: [descrie]
|
||||
|
||||
C) Care sunt constrângerile tehnice?
|
||||
1. Trebuie să folosească framework/librărie existentă
|
||||
2. Fără dependențe noi
|
||||
3. Flexibil
|
||||
4. Altceva: [descrie]
|
||||
```
|
||||
|
||||
## Pas 2: Generează PRD Markdown
|
||||
|
||||
După clarificări, generează documentul în `/tasks/prd-[feature-name].md`:
|
||||
|
||||
```markdown
|
||||
# PRD: [Feature Name]
|
||||
|
||||
## 1. Introducere
|
||||
[Descriere scurtă a feature-ului și contextul]
|
||||
|
||||
## 2. Obiective
|
||||
- Obiectiv principal
|
||||
- Obiective secundare
|
||||
- Metrici de succes
|
||||
|
||||
## 3. User Stories
|
||||
### US-001: [Titlu]
|
||||
**Ca** [tip utilizator]
|
||||
**Vreau** [funcționalitate]
|
||||
**Pentru că** [beneficiu]
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] Criteriu 1 specific și testabil
|
||||
- [ ] Criteriu 2 specific și testabil
|
||||
- [ ] npm run typecheck passes
|
||||
|
||||
### US-002: [Titlu]
|
||||
...
|
||||
|
||||
## 4. Cerințe Funcționale
|
||||
1. [Cerință 1]
|
||||
2. [Cerință 2]
|
||||
...
|
||||
|
||||
## 5. Non-Goals (Ce NU facem)
|
||||
- [Explicit ce nu este în scope]
|
||||
|
||||
## 6. Considerații Tehnice
|
||||
- Stack tehnologic
|
||||
- Patterns de urmat
|
||||
- Dependențe
|
||||
|
||||
## 7. Considerații UI/UX
|
||||
- [Dacă e relevant]
|
||||
|
||||
## 8. Success Metrics
|
||||
- [Cum măsurăm succesul]
|
||||
|
||||
## 9. Open Questions
|
||||
- [Întrebări nerezolvate]
|
||||
```
|
||||
|
||||
## Pas 3: Convertește în prd.json
|
||||
|
||||
După aprobare, convertește PRD-ul markdown în format JSON pentru Ralph:
|
||||
|
||||
```json
|
||||
{
|
||||
"projectName": "feature-name",
|
||||
"branchName": "ralph/feature-name",
|
||||
"description": "Descriere din PRD",
|
||||
"userStories": [
|
||||
{
|
||||
"id": "US-001",
|
||||
"title": "Titlu din PRD",
|
||||
"description": "Ca [user], vreau [feature] pentru că [benefit]",
|
||||
"priority": 1,
|
||||
"acceptanceCriteria": [
|
||||
"Criteriu 1",
|
||||
"Criteriu 2",
|
||||
"npm run typecheck passes"
|
||||
],
|
||||
"passes": false,
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Salvează în `scripts/ralph/prd.json`.
|
||||
|
||||
## Reguli importante pentru stories
|
||||
|
||||
### ✅ Story de mărime corectă (UN context window):
|
||||
- Adaugă un câmp în baza de date
|
||||
- Creează un component UI simplu
|
||||
- Adaugă un endpoint API
|
||||
- Scrie tests pentru o funcție
|
||||
|
||||
### ❌ Story prea mare (trebuie spart):
|
||||
- "Implementează autentificarea completă"
|
||||
- "Creează dashboard-ul admin"
|
||||
- "Adaugă sistem de notificări"
|
||||
|
||||
### Ordinea priorităților:
|
||||
1. Schema/Database changes
|
||||
2. Backend logic
|
||||
3. API endpoints
|
||||
4. UI components
|
||||
5. Integration/polish
|
||||
|
||||
### Acceptance criteria trebuie să fie:
|
||||
- Specifice și verificabile
|
||||
- Nu vagi ("funcționează bine", "UX bun")
|
||||
- Include întotdeauna `npm run typecheck passes`
|
||||
- Pentru UI: "Verifică în browser că [specific behavior]"
|
||||
33
scripts/ralph/prd-template.json
Normal file
33
scripts/ralph/prd-template.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"projectName": "Numele Proiectului",
|
||||
"branchName": "ralph/feature-name",
|
||||
"description": "Descriere scurtă a feature-ului care se implementează",
|
||||
"userStories": [
|
||||
{
|
||||
"id": "US-001",
|
||||
"title": "Titlu story 1",
|
||||
"description": "As a [user type], I want [feature] so that [benefit]",
|
||||
"priority": 1,
|
||||
"acceptanceCriteria": [
|
||||
"Criteriu 1 specific și verificabil",
|
||||
"Criteriu 2 specific și verificabil",
|
||||
"npm run typecheck passes"
|
||||
],
|
||||
"passes": false,
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"id": "US-002",
|
||||
"title": "Titlu story 2",
|
||||
"description": "As a [user type], I want [feature] so that [benefit]",
|
||||
"priority": 2,
|
||||
"acceptanceCriteria": [
|
||||
"Criteriu 1",
|
||||
"Criteriu 2",
|
||||
"npm run typecheck passes"
|
||||
],
|
||||
"passes": false,
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
118
scripts/ralph/prompt.md
Normal file
118
scripts/ralph/prompt.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Ralph - Instrucțiuni pentru Iterație
|
||||
|
||||
Ești un agent autonom care implementează user stories dintr-un PRD. Aceasta este O SINGURĂ iterație - implementezi UN singur story și apoi te oprești.
|
||||
|
||||
## Workflow pentru această iterație
|
||||
|
||||
### 1. Citește contextul
|
||||
- PRD-ul și progress.txt sunt furnizate în context
|
||||
- Înțelege ce stories sunt deja complete (`passes: true`)
|
||||
- Identifică următorul story de implementat (prioritate cea mai mică dintre cele incomplete)
|
||||
|
||||
### 2. Management branch
|
||||
- Verifică dacă ești pe branch-ul corect (specificat în `branchName` din PRD)
|
||||
- Dacă nu, creează și checkout branch-ul:
|
||||
```bash
|
||||
git checkout -b <branchName>
|
||||
```
|
||||
- Dacă branch-ul există deja, doar checkout:
|
||||
```bash
|
||||
git checkout <branchName>
|
||||
```
|
||||
|
||||
### 3. Selectează story-ul
|
||||
- Alege story-ul cu cea mai mică prioritate care are `passes: false`
|
||||
- Citește atent acceptance criteria
|
||||
|
||||
### 4. Implementare
|
||||
- Implementează DOAR acest story
|
||||
- Urmează patterns existente în codebase
|
||||
- Fii minimal și focusat - nu adăuga funcționalități extra
|
||||
|
||||
### 5. Quality Checks
|
||||
Rulează TOATE verificările înainte de commit:
|
||||
```bash
|
||||
npm run typecheck # sau echivalentul proiectului
|
||||
npm run lint # dacă există
|
||||
npm run test # dacă există
|
||||
```
|
||||
|
||||
**IMPORTANT**: Nu face commit dacă verificările eșuează. Repară mai întâi.
|
||||
|
||||
### 6. Documentare (dacă ai descoperit ceva util)
|
||||
Dacă ai descoperit patterns sau gotchas, actualizează `AGENTS.md` în directorul relevant:
|
||||
- API patterns
|
||||
- Dependențe non-evidente
|
||||
- Convenții de cod
|
||||
- Cum să testezi anumite funcționalități
|
||||
|
||||
### 7. Commit
|
||||
Format commit message:
|
||||
```
|
||||
feat: [Story ID] - [Story Title]
|
||||
```
|
||||
|
||||
Exemplu:
|
||||
```
|
||||
feat: US-003 - Add user authentication endpoint
|
||||
```
|
||||
|
||||
### 8. Marchează story-ul ca complet
|
||||
**CRITIC**: Actualizează `scripts/ralph/prd.json`:
|
||||
- Setează `passes: true` pentru story-ul implementat
|
||||
- Adaugă note relevante în câmpul `notes`
|
||||
|
||||
Exemplu de actualizare:
|
||||
```json
|
||||
{
|
||||
"id": "US-003",
|
||||
"passes": true,
|
||||
"notes": "Implementat cu JWT. Vezi src/auth/jwt.ts pentru middleware."
|
||||
}
|
||||
```
|
||||
|
||||
### 9. Actualizează progress.txt
|
||||
Adaugă la sfârșitul fișierului `scripts/ralph/progress.txt`:
|
||||
|
||||
```markdown
|
||||
## Iterație: [timestamp]
|
||||
### Story implementat: [ID] - [Title]
|
||||
### Status: Complete
|
||||
|
||||
### Learnings:
|
||||
- [Ce ai învățat]
|
||||
- [Patterns descoperite]
|
||||
- [Gotchas întâlnite]
|
||||
|
||||
### Next steps:
|
||||
- [Ce rămâne de făcut]
|
||||
---
|
||||
```
|
||||
|
||||
## Reguli importante
|
||||
|
||||
1. **UN SINGUR STORY PE ITERAȚIE** - Nu implementa mai mult de un story
|
||||
2. **TOATE CHECKS TREBUIE SĂ TREACĂ** - Nu face commit cu erori
|
||||
3. **ACTUALIZEAZĂ prd.json** - Altfel iterația următoare va repeta munca
|
||||
4. **FII CONCIS** - Nu over-engineer, implementează minim necesar
|
||||
5. **DOCUMENTEAZĂ** - Learnings în progress.txt, patterns în AGENTS.md
|
||||
|
||||
## Condiție de terminare
|
||||
|
||||
Dacă TOATE stories au `passes: true`, răspunde cu:
|
||||
|
||||
```
|
||||
<promise>COMPLETE</promise>
|
||||
```
|
||||
|
||||
Aceasta semnalează că Ralph a terminat toate task-urile.
|
||||
|
||||
## Dacă întâmpini probleme
|
||||
|
||||
- **Story prea mare**: Notează în progress.txt și sugerează descompunerea
|
||||
- **Dependență lipsă**: Verifică dacă un story anterior nu a fost implementat corect
|
||||
- **Test eșuează**: Repară și încearcă din nou, documentează fix-ul
|
||||
- **Blocat complet**: Notează în progress.txt motivul și continuă cu următorul story dacă e posibil
|
||||
|
||||
---
|
||||
ÎNCEPE IMPLEMENTAREA ACUM. Selectează story-ul cu prioritatea cea mai mică care nu este complet și implementează-l.
|
||||
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