feat(ralph): smart gates + DAG + dashboard live (W3)
Restructurare Ralph QC loop pe smart gate dispatcher tag-driven (în loc de 5 faze fixe), DAG dependsOn cu propagare blocked, retry guard 3-strike, rate limit detection, plus dashboard live cu polling 5s. Changes: - tools/ralph_prd_generator.py: parametru optional final_plan_path; când e furnizat, invocă Claude Opus pe final-plan.md pentru extragere user stories cu schema extinsă (tags, dependsOn, acceptanceCriteria 3-5). Backward compat păstrat — fără final_plan_path, fallback la heuristic-ul vechi. - tools/ralph/prd-template.json: schema W3 (tags[], dependsOn[], retries, failed, blocked, failureReason, requiresDesignReview). - tools/ralph/prompt.md: 4 faze (impl, base quality, smart gates, commit) + dispatcher pe story.tags. Tags vide → run-all-gates fallback (safe default). - tools/ralph_dag.py (nou): tag validation heuristic anti-silent-regression (force ui dacă diff atinge .vue/.tsx/.html/.css/.scss; force db pentru migrations sau .sql; force vercel dacă există vercel.json) + topological sort cu blocked propagation + atomic prd.json updates. - tools/ralph/ralph.sh: --max-turns 30, DAG-aware story selection, retry counter cu auto-fail la 3, rate limit detection (sleep 30min + 1 retry), CLI subcommands prin tools/ralph_dag.py helper. - dashboard/handlers/ralph.py (nou): /api/ralph/status + /<slug>/log + /prd + /stop. Defensive vs corrupt prd.json. Sandbox-ed PID kill. - dashboard/ralph.html (nou): live cards 3/2/1 col responsive, polling 5s, drawer pentru log/PRD viewer, status colors (--status-running/blocked/ failed/complete declarate inline), Lucide icons cu aria-labels. - dashboard/api.py: mount /api/ralph/* (GET status/log/prd, POST stop). - tests/: 72 teste noi (smart gates, DAG, retry, dashboard endpoint). Note arhitecturale: - Polling 5s ales peste SSE/WebSocket (suficient pentru iter Ralph 8-15min) - Tag validation rulează POST-iter pe diff git pentru anti-silent-regression - Rate limit retry: 1 dată per rulare, apoi mark failed=rate_limited Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,17 @@
|
||||
"projectName": "feature-name",
|
||||
"branchName": "ralph/feature-name",
|
||||
"description": "Descriere scurtă a feature-ului",
|
||||
"techStack": {
|
||||
"type": "python",
|
||||
"commands": {
|
||||
"start": "python main.py",
|
||||
"build": "",
|
||||
"lint": "ruff check .",
|
||||
"typecheck": "mypy .",
|
||||
"test": "pytest"
|
||||
},
|
||||
"port": 8000
|
||||
},
|
||||
"userStories": [
|
||||
{
|
||||
"id": "US-001",
|
||||
@@ -12,7 +23,15 @@
|
||||
"Criteriu specific și verificabil",
|
||||
"npm run typecheck passes"
|
||||
],
|
||||
"tags": [],
|
||||
"dependsOn": [],
|
||||
"requiresBrowserCheck": false,
|
||||
"requiresDesignReview": false,
|
||||
"passes": false,
|
||||
"failed": false,
|
||||
"blocked": false,
|
||||
"retries": 0,
|
||||
"failureReason": "",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,203 +1,120 @@
|
||||
# Ralph - Instrucțiuni pentru Iterație
|
||||
# Ralph - Instrucțiuni pentru Iterație (smart gates)
|
||||
|
||||
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.
|
||||
Ești un agent autonom care implementează user stories dintr-un PRD. Aceasta este O SINGURĂ iterație — implementezi UN singur story, validezi prin gate-urile relevante, apoi te oprești.
|
||||
|
||||
## Workflow pentru această iterație
|
||||
## Workflow per iterație (4 faze, gates condiționale pe `story.tags`)
|
||||
|
||||
### 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)
|
||||
- Notează `techStack.commands` din PRD pentru comenzile corecte
|
||||
### Faza 0: Citește contextul
|
||||
|
||||
### 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>
|
||||
```
|
||||
- PRD-ul (`prd.json`) și `progress.txt` sunt furnizate în context.
|
||||
- Identifică următorul story candidate:
|
||||
- `passes != true` ȘI `failed != true` ȘI `blocked != true`
|
||||
- DAG: toate ID-urile din `dependsOn[]` au `passes == true` (altfel sare la următorul independent)
|
||||
- Cea mai mică `priority` printre cele eligibile.
|
||||
- Notează `techStack.commands` (lint, typecheck, test, start) și `techStack.port`.
|
||||
- Notează `story.tags[]` — alegerea Faza 3 depinde de ele.
|
||||
|
||||
### 3. Selectează story-ul
|
||||
- Alege story-ul cu cea mai mică prioritate care are `passes: false`
|
||||
- Citește atent acceptance criteria
|
||||
- Verifică câmpul `requiresBrowserCheck` - dacă e `true`, trebuie verificare vizuală
|
||||
### Faza 1: IMPLEMENTARE (mereu)
|
||||
|
||||
### 4. Implementare
|
||||
- Implementează DOAR acest story
|
||||
- Urmează patterns existente în codebase
|
||||
- Fii minimal și focusat - nu adăuga funcționalități extra
|
||||
1.1. **Branch management** — verifică să fii pe `branchName` din PRD; checkout/create dacă lipsește.
|
||||
1.2. **Citește acceptance criteria** — fiecare criteriu e un test mental concret de trecut.
|
||||
1.3. **Implementează cod minimal** — DOAR ce cere story-ul. Urmează patterns existente. Fără over-engineering, fără side features.
|
||||
1.4. **Update `notes`** în `prd.json` cu fișierele atinse (pentru audit ulterior).
|
||||
|
||||
### 5. Quality Checks
|
||||
Rulează TOATE verificările înainte de commit. Folosește comenzile din `techStack.commands`:
|
||||
### Faza 2: QUALITY BASE (mereu, înainte de gates)
|
||||
|
||||
Folosește `techStack.commands`:
|
||||
|
||||
```bash
|
||||
# Folosește comenzile din prd.json techStack.commands:
|
||||
{techStack.commands.typecheck} # Type checking
|
||||
{techStack.commands.lint} # Linting
|
||||
{techStack.commands.test} # Tests (dacă există)
|
||||
{techStack.commands.typecheck} # ex: npm run typecheck / mypy .
|
||||
{techStack.commands.lint} # ex: npm run lint / ruff check .
|
||||
{techStack.commands.test} # ex: npm test / pytest
|
||||
```
|
||||
|
||||
**Comenzi standard per stack:**
|
||||
**Loop intern**: dacă vreuna eșuează → repară și repetă, max 3 retries în această fază. Dacă încă fail după 3, ieși cu sumar de erori în `progress.txt` (ralph.sh va decide retry-ul iterației).
|
||||
|
||||
| Stack | Typecheck | Lint | Test |
|
||||
|-------|-----------|------|------|
|
||||
| Next.js/TS | npm run typecheck | npm run lint | npm test |
|
||||
| Node.js | npm run typecheck | npm run lint | npm test |
|
||||
| Python | mypy . | ruff check . | python -m pytest |
|
||||
| Go | - | golangci-lint run | go test ./... |
|
||||
### Faza 3: SMART GATES (dispatcher pe `story.tags`)
|
||||
|
||||
**IMPORTANT**: Nu face commit dacă verificările eșuează. Repară mai întâi.
|
||||
Tags posibile: `ui`, `db`, `vercel`, `refactor`, `docs`, `backend`, `infra`.
|
||||
|
||||
### 6. Verificare Browser (pentru UI stories)
|
||||
Aplică DOAR gate-urile potrivite — **nu rulează toate**:
|
||||
|
||||
**DACĂ story-ul are `requiresBrowserCheck: true` sau implică UI:**
|
||||
| Tag | Gate |
|
||||
|-------------|---------------------------------------------------------------------------------------|
|
||||
| `refactor` | `/workflow:simplify` pe diff (reduce complexity fără behavior change) |
|
||||
| `ui` | `/qa` Playwright/agent-browser snapshot pe `localhost:{techStack.port}` + screenshot |
|
||||
| `ui` + `requiresDesignReview` | `/plan-design-review` pe screenshot capturat |
|
||||
| `vercel` | push branch + `gh pr checks --watch` (timeout 5 min); fail dacă PR checks eșuează |
|
||||
| `db` | verify schema diff (alembic / prisma migrate diff / `psql \\d+ tablename`) |
|
||||
| `docs` | doar typecheck base (Faza 2 e suficient); skip gate dedicat |
|
||||
| `backend` | `/review` pe diff (intern — second pass review pe API contracts, error handling) |
|
||||
| `infra` | `/review` pe diff + manual smoke test al modificărilor (CI config, Dockerfile, etc.) |
|
||||
| _(tags vide)_ | **run-all-gates fallback** — `/review` + `/qa` + `/workflow:simplify` (safe default) |
|
||||
|
||||
Folosește **agent-browser CLI** pentru verificare vizuală. Agent-browser e optimizat pentru agenți AI cu referințe compacte (@e1, @e2) care consumă minim tokeni.
|
||||
**Mecanism**: skill-urile gstack se invocă prin text mention în prompt — Claude (subprocess `claude -p`) le vede ca tool-uri disponibile via `~/.claude/skills/gstack/`.
|
||||
|
||||
#### 6.1 Pornește dev server-ul
|
||||
```bash
|
||||
# Folosește comanda din techStack.commands.start
|
||||
{techStack.commands.start}
|
||||
# Exemplu: npm run dev
|
||||
```
|
||||
**Multi-tag**: rulează gate-uri pentru fiecare tag (ex: `["ui", "backend"]` → atât `/qa` cât și `/review`).
|
||||
|
||||
Așteaptă să pornească (verifică output-ul pentru "ready" sau similar).
|
||||
**Important**: dacă vreun gate eșuează, NU marca `passes=true`. Repară (max 3 fix-uri în iterație) sau lasă pentru iterația următoare (ralph.sh se ocupă de retry counter).
|
||||
|
||||
#### 6.2 Navighează la pagină
|
||||
```bash
|
||||
agent-browser navigate "http://localhost:{techStack.port}"
|
||||
# Exemplu: agent-browser navigate "http://localhost:3000"
|
||||
```
|
||||
### Faza 4: COMMIT + MARK
|
||||
|
||||
#### 6.3 Ia snapshot pentru verificare
|
||||
```bash
|
||||
agent-browser snapshot
|
||||
```
|
||||
|
||||
Snapshot-ul returnează o listă de elemente cu referințe compacte:
|
||||
```
|
||||
@e1: heading "Welcome"
|
||||
@e2: button "Login"
|
||||
@e3: textbox "Email"
|
||||
@e4: textbox "Password"
|
||||
@e5: button "Submit"
|
||||
```
|
||||
|
||||
**Verifică în snapshot:**
|
||||
- Elementele cheie din acceptance criteria există
|
||||
- Textul e corect
|
||||
- Structura paginii e corectă
|
||||
|
||||
#### 6.4 Testează interacțiunile (dacă e cazul)
|
||||
```bash
|
||||
# Click pe un element
|
||||
agent-browser click @e2
|
||||
|
||||
# Fill un input
|
||||
agent-browser fill @e3 "test@example.com"
|
||||
|
||||
# Așteaptă o schimbare
|
||||
agent-browser snapshot # verifică noua stare
|
||||
```
|
||||
|
||||
#### 6.5 Salvează screenshot ca dovadă
|
||||
```bash
|
||||
agent-browser screenshot ./scripts/ralph/screenshots/US-{id}-$(date +%Y%m%d-%H%M%S).png
|
||||
# Exemplu: agent-browser screenshot ./scripts/ralph/screenshots/US-001-20240115-143022.png
|
||||
```
|
||||
|
||||
#### 6.6 Verifică erori
|
||||
```bash
|
||||
# Verifică console pentru erori
|
||||
agent-browser console
|
||||
```
|
||||
|
||||
**IMPORTANT**:
|
||||
- NU marca story-ul complete dacă verificarea vizuală eșuează!
|
||||
- Dacă găsești erori în browser, repară-le înainte de commit
|
||||
- Screenshots sunt salvate în `scripts/ralph/screenshots/` pentru referință
|
||||
|
||||
### 7. 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
|
||||
|
||||
### 8. Commit
|
||||
Format commit message:
|
||||
4.1. **Commit** cu mesaj descriptiv:
|
||||
```
|
||||
feat: [Story ID] - [Story Title]
|
||||
|
||||
- ce ai schimbat (1-3 bullets)
|
||||
- gates rulate: typecheck PASS, lint PASS, /qa PASS
|
||||
```
|
||||
|
||||
### 9. 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`
|
||||
|
||||
### 10. Actualizează progress.txt
|
||||
Adaugă la sfârșitul fișierului `scripts/ralph/progress.txt`:
|
||||
4.2. **Update `prd.json`**:
|
||||
- `passes: true` DOAR DACĂ toate gate-urile relevante au pasat
|
||||
- `notes` populat cu rezultate gate (ex: "qa: ok, design-review: 8/10")
|
||||
|
||||
4.3. **Append `progress.txt`**:
|
||||
```markdown
|
||||
## Iterație: [timestamp]
|
||||
### Story implementat: [ID] - [Title]
|
||||
### Status: Complete
|
||||
### Story implementat: [ID] - [Title] (tags: [ui, backend])
|
||||
### Status: Complete / Partial / Failed
|
||||
|
||||
### Verificări:
|
||||
### Gates rulate:
|
||||
- Typecheck: PASS
|
||||
- Lint: PASS
|
||||
- Tests: PASS/SKIP
|
||||
- Browser check: PASS/N/A
|
||||
- /qa (ui): PASS — screenshot la scripts/ralph/screenshots/...
|
||||
- /review (backend): PASS
|
||||
|
||||
### Learnings:
|
||||
- [Ce ai învățat]
|
||||
- [Patterns descoperite]
|
||||
- [Patterns descoperite, gotchas]
|
||||
|
||||
### Next steps:
|
||||
- [Ce rămâne de făcut]
|
||||
### Next:
|
||||
- [Stories eligibile pentru iterația următoare]
|
||||
---
|
||||
```
|
||||
|
||||
## 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. **VERIFICARE BROWSER PENTRU UI** - Obligatorie dacă `requiresBrowserCheck: true`
|
||||
4. **ACTUALIZEAZĂ prd.json** - Altfel iterația următoare va repeta munca
|
||||
5. **FII CONCIS** - Nu over-engineer
|
||||
1. **UN SINGUR STORY PE ITERAȚIE** — nu implementa mai mult de un story.
|
||||
2. **DAG STRICT** — nu sări peste `dependsOn` neîmplinite.
|
||||
3. **GATES PE TAGS** — rulează doar ce e relevant; tags vide = run-all-gates fallback.
|
||||
4. **NU MARCA `passes=true` cu gate failed** — altfel ralph.sh nu va relua story-ul.
|
||||
5. **FII CONCIS** — fără over-engineering, fără docs auto-generate dacă story-ul nu cere.
|
||||
|
||||
## Comenzi agent-browser (referință rapidă)
|
||||
## Comenzi agent-browser (referință rapidă pentru gate `ui`)
|
||||
|
||||
```bash
|
||||
# Navigare
|
||||
agent-browser navigate "http://localhost:3000/page"
|
||||
|
||||
# Snapshot (vedere compactă a paginii)
|
||||
agent-browser snapshot
|
||||
|
||||
# Click pe element (folosind ref din snapshot)
|
||||
agent-browser navigate "http://localhost:{techStack.port}"
|
||||
agent-browser snapshot # listă elemente compactă (@e1, @e2...)
|
||||
agent-browser click @e5
|
||||
|
||||
# Fill input
|
||||
agent-browser fill @e3 "value"
|
||||
|
||||
# Screenshot
|
||||
agent-browser screenshot ./path/to/file.png
|
||||
|
||||
# Console logs
|
||||
agent-browser console
|
||||
|
||||
# Așteaptă text
|
||||
agent-browser screenshot ./scripts/ralph/screenshots/US-{id}-$(date +%Y%m%d-%H%M%S).png
|
||||
agent-browser console # erori JS
|
||||
agent-browser wait-for "Loading complete"
|
||||
```
|
||||
|
||||
## Condiție de terminare
|
||||
|
||||
Dacă TOATE stories au `passes: true`, răspunde cu:
|
||||
Dacă TOATE story-urile au `passes: true` (sau combinat cu `failed: true` / `blocked: true` astfel că nimic nu mai e eligibil):
|
||||
|
||||
```
|
||||
<promise>COMPLETE</promise>
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
#!/bin/bash
|
||||
# Ralph pentru Claude Code - Loop autonom de agent AI
|
||||
# Ralph pentru Claude Code - Loop autonom de agent AI (W3: smart gates + DAG + rate limit)
|
||||
# Adaptat din Ralph original (snarktank/ralph) pentru Claude Code CLI
|
||||
# Usage: ./ralph.sh [max_iterations] [project_dir]
|
||||
#
|
||||
# Env vars (opționale):
|
||||
# RALPH_MAX_TURNS — --max-turns per iter (default 30)
|
||||
# RALPH_RATE_LIMIT_SLEEP — sleep după rate limit detection (default 1800 = 30min)
|
||||
# RALPH_DAG_HELPER — path la tools/ralph_dag.py (auto-detect default)
|
||||
# RALPH_PYTHON — interpreter Python pentru DAG helper (default python3)
|
||||
|
||||
set -e
|
||||
|
||||
@@ -15,6 +21,24 @@ SCREENSHOTS_DIR="$SCRIPT_DIR/screenshots"
|
||||
LAST_BRANCH_FILE="$SCRIPT_DIR/.last-branch"
|
||||
PROMPT_FILE="$SCRIPT_DIR/prompt.md"
|
||||
|
||||
# W3 config
|
||||
MAX_TURNS=${RALPH_MAX_TURNS:-30}
|
||||
RATE_LIMIT_SLEEP=${RALPH_RATE_LIMIT_SLEEP:-1800}
|
||||
RALPH_PYTHON=${RALPH_PYTHON:-python3}
|
||||
|
||||
# DAG helper auto-detect: prefer co-located cu echo-core; fallback la $SCRIPT_DIR
|
||||
if [ -n "$RALPH_DAG_HELPER" ] && [ -f "$RALPH_DAG_HELPER" ]; then
|
||||
DAG_HELPER="$RALPH_DAG_HELPER"
|
||||
elif [ -f "/home/moltbot/echo-core/tools/ralph_dag.py" ]; then
|
||||
DAG_HELPER="/home/moltbot/echo-core/tools/ralph_dag.py"
|
||||
elif [ -f "/home/moltbot/echo-core-qc/tools/ralph_dag.py" ]; then
|
||||
DAG_HELPER="/home/moltbot/echo-core-qc/tools/ralph_dag.py"
|
||||
elif [ -f "$SCRIPT_DIR/ralph_dag.py" ]; then
|
||||
DAG_HELPER="$SCRIPT_DIR/ralph_dag.py"
|
||||
else
|
||||
DAG_HELPER=""
|
||||
fi
|
||||
|
||||
# Verifică că jq este instalat
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "Eroare: jq nu este instalat. Rulează: apt install jq"
|
||||
@@ -132,6 +156,51 @@ check_all_complete() {
|
||||
[ "$incomplete" -eq 0 ]
|
||||
}
|
||||
|
||||
# W3: nimic eligibil = toate sunt fie passes, fie failed, fie blocked
|
||||
check_no_eligible() {
|
||||
local n=$(jq '[.userStories[] | select(.passes != true and .failed != true and .blocked != true)] | length' "$PRD_FILE" 2>/dev/null || echo "999")
|
||||
[ "$n" -eq 0 ]
|
||||
}
|
||||
|
||||
# W3: alege next eligible story via DAG helper. Print story ID sau "" dacă nimic.
|
||||
dag_next_story() {
|
||||
if [ -n "$DAG_HELPER" ]; then
|
||||
"$RALPH_PYTHON" "$DAG_HELPER" next-story "$PRD_FILE" 2>/dev/null || echo ""
|
||||
else
|
||||
# Fallback simplu (fără DAG): primul story cu passes!=true && failed!=true && blocked!=true, priority asc
|
||||
jq -r '[.userStories[] | select(.passes != true and .failed != true and .blocked != true)] | sort_by(.priority) | .[0].id // ""' "$PRD_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
dag_incr_retry() {
|
||||
local sid="$1"
|
||||
if [ -n "$DAG_HELPER" ]; then
|
||||
"$RALPH_PYTHON" "$DAG_HELPER" incr-retry "$PRD_FILE" "$sid" 2>/dev/null || echo "0"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
dag_mark_failed() {
|
||||
local sid="$1" reason="$2"
|
||||
if [ -n "$DAG_HELPER" ]; then
|
||||
"$RALPH_PYTHON" "$DAG_HELPER" mark-failed "$PRD_FILE" "$sid" "$reason" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
dag_force_tags() {
|
||||
local sid="$1"
|
||||
if [ -n "$DAG_HELPER" ]; then
|
||||
"$RALPH_PYTHON" "$DAG_HELPER" force-tags "$PRD_FILE" "$sid" "$PROJECT_DIR" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# W3: detectează rate limit în output Claude (heuristic — Anthropic nu are exit code dedicat)
|
||||
is_rate_limited() {
|
||||
local output="$1"
|
||||
echo "$output" | grep -qiE "rate limit|rate_limit_exceeded|429|too many requests"
|
||||
}
|
||||
|
||||
# Afișare status inițial
|
||||
echo ""
|
||||
echo "======================================================================="
|
||||
@@ -155,6 +224,9 @@ if check_all_complete; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Tracker pentru rate limit retry (max 1 retry de iterație-rate-limit per rulare)
|
||||
RATE_LIMIT_RETRY_USED=0
|
||||
|
||||
# Loop principal
|
||||
for i in $(seq 1 $MAX_ITERATIONS); do
|
||||
echo ""
|
||||
@@ -162,17 +234,38 @@ for i in $(seq 1 $MAX_ITERATIONS); do
|
||||
echo " Ralph Iterația $i din $MAX_ITERATIONS"
|
||||
echo "==================================================================="
|
||||
|
||||
# W3: alege next story via DAG (propagă blocked dacă vreun dep a eșuat)
|
||||
CURRENT_STORY=$(dag_next_story)
|
||||
if [ -z "$CURRENT_STORY" ]; then
|
||||
echo ""
|
||||
echo "==================================================================="
|
||||
if check_all_complete; then
|
||||
echo " TOATE STORY-URILE DIN PRD SUNT COMPLETE!"
|
||||
exit 0
|
||||
else
|
||||
echo " NICIUN STORY ELIGIBIL (toate fie complete, fie failed, fie blocked)"
|
||||
echo " Stories incomplete:"
|
||||
jq -r '.userStories[] | select(.passes != true) | " - \(.id): \(.title) [failed=\(.failed // false) blocked=\(.blocked // false) retries=\(.retries // 0)]"' "$PRD_FILE"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 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")
|
||||
NEXT_TITLE=$(jq -r --arg id "$CURRENT_STORY" '.userStories[] | select(.id == $id) | "\(.id): \(.title)"' "$PRD_FILE")
|
||||
STORY_TAGS=$(jq -r --arg id "$CURRENT_STORY" '.userStories[] | select(.id == $id) | (.tags // []) | join(",")' "$PRD_FILE")
|
||||
STORY_RETRIES=$(jq -r --arg id "$CURRENT_STORY" '.userStories[] | select(.id == $id) | (.retries // 0)' "$PRD_FILE")
|
||||
echo " Progress: $COMPLETE_NOW / $TOTAL_STORIES stories complete"
|
||||
echo " Next: $NEXT_STORY"
|
||||
echo " Next: $NEXT_TITLE [tags: ${STORY_TAGS:-<none>}, retries: $STORY_RETRIES]"
|
||||
echo ""
|
||||
|
||||
# Pregătește prompt-ul cu context
|
||||
FULL_PROMPT=$(cat <<EOF
|
||||
# Context pentru această iterație Ralph
|
||||
|
||||
## Story țintă (DAG-eligible):
|
||||
$CURRENT_STORY (tags: ${STORY_TAGS:-<none>})
|
||||
|
||||
## PRD (prd.json):
|
||||
$(cat "$PRD_FILE")
|
||||
|
||||
@@ -188,10 +281,34 @@ EOF
|
||||
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-format json + --max-turns pentru control runtime
|
||||
set +e
|
||||
echo "$FULL_PROMPT" | claude -p \
|
||||
--dangerously-skip-permissions \
|
||||
--output-format json \
|
||||
--max-turns "$MAX_TURNS" \
|
||||
2>&1 | tee "$LOG_FILE"
|
||||
CLAUDE_EXIT=${PIPESTATUS[1]}
|
||||
set -e
|
||||
OUTPUT=$(cat "$LOG_FILE")
|
||||
|
||||
# W3: rate limit detection (max 1 retry per rulare)
|
||||
if is_rate_limited "$OUTPUT" || [ "$CLAUDE_EXIT" = "29" ]; then
|
||||
if [ "$RATE_LIMIT_RETRY_USED" = "0" ]; then
|
||||
echo ""
|
||||
echo " ⏸️ Rate limit detectat. Sleep ${RATE_LIMIT_SLEEP}s, apoi retry o dată."
|
||||
RATE_LIMIT_RETRY_USED=1
|
||||
echo "## Rate limit la iter $i — sleep $RATE_LIMIT_SLEEP" >> "$PROGRESS_FILE"
|
||||
sleep "$RATE_LIMIT_SLEEP"
|
||||
continue # retry aceeași iterație
|
||||
else
|
||||
echo " ❌ Rate limit din nou — abort run, mark $CURRENT_STORY rate_limited"
|
||||
dag_mark_failed "$CURRENT_STORY" "rate_limited"
|
||||
echo "## Rate limit final la iter $i — abort" >> "$PROGRESS_FILE"
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
# Verifică dacă toate task-urile sunt complete
|
||||
if echo "$OUTPUT" | grep -q "<promise>COMPLETE</promise>"; then
|
||||
echo ""
|
||||
@@ -211,6 +328,23 @@ EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# W3: tag validation post-iter — chiar dacă Opus a marcat docs, dacă diff atinge .vue/.tsx, force ui
|
||||
dag_force_tags "$CURRENT_STORY" >/dev/null 2>&1 || true
|
||||
|
||||
# W3: dacă story-ul curent ÎNCĂ nu trece (passes==false), incrementăm retries
|
||||
STILL_INCOMPLETE=$(jq -r --arg id "$CURRENT_STORY" '.userStories[] | select(.id == $id) | (.passes == true)' "$PRD_FILE")
|
||||
if [ "$STILL_INCOMPLETE" != "true" ]; then
|
||||
NEW_RETRY=$(dag_incr_retry "$CURRENT_STORY")
|
||||
echo " Story $CURRENT_STORY încă incomplet. Retries: $NEW_RETRY/3"
|
||||
if [ "$NEW_RETRY" -ge 3 ] 2>/dev/null; then
|
||||
echo " ❌ $CURRENT_STORY failed: max_retries — sare la următorul"
|
||||
# mark-failed e deja făcut de incr-retry când >=3, dar idempotent o re-aplicăm
|
||||
dag_mark_failed "$CURRENT_STORY" "max_retries"
|
||||
fi
|
||||
else
|
||||
echo " ✅ Story $CURRENT_STORY marcat passes=true în iterația asta."
|
||||
fi
|
||||
|
||||
echo " Iterația $i completă. Continuăm..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user