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:
@@ -40,6 +40,7 @@ from handlers.files import FilesHandlers # noqa: E402
|
||||
from handlers.git import GitHandlers # noqa: E402
|
||||
from handlers.habits import HabitsHandlers # noqa: E402
|
||||
from handlers.pdf import PDFHandlers # noqa: E402
|
||||
from handlers.ralph import RalphHandlers # noqa: E402
|
||||
from handlers.workspace import WorkspaceHandlers # noqa: E402
|
||||
from handlers.youtube import YoutubeHandlers # noqa: E402
|
||||
|
||||
@@ -95,6 +96,7 @@ class TaskBoardHandler(
|
||||
PDFHandlers,
|
||||
YoutubeHandlers,
|
||||
WorkspaceHandlers,
|
||||
RalphHandlers,
|
||||
CronHandlers,
|
||||
SimpleHTTPRequestHandler,
|
||||
):
|
||||
@@ -155,6 +157,23 @@ class TaskBoardHandler(
|
||||
self.handle_eco_logs()
|
||||
elif self.path == '/api/eco/doctor':
|
||||
self.handle_eco_doctor()
|
||||
elif self.path == '/api/ralph/status' or self.path.startswith('/api/ralph/status?'):
|
||||
self.handle_ralph_status()
|
||||
elif self.path.startswith('/api/ralph/'):
|
||||
# /api/ralph/<slug>/log or /api/ralph/<slug>/prd
|
||||
parts = self.path.split('?', 1)[0].split('/')
|
||||
# parts: ['', 'api', 'ralph', '<slug>', '<action>']
|
||||
if len(parts) >= 5:
|
||||
slug = parts[3]
|
||||
action = parts[4]
|
||||
if action == 'log':
|
||||
self.handle_ralph_log(slug)
|
||||
elif action == 'prd':
|
||||
self.handle_ralph_prd(slug)
|
||||
else:
|
||||
self.send_error(404)
|
||||
else:
|
||||
self.send_error(404)
|
||||
elif self.path.startswith('/api/'):
|
||||
self.send_error(404)
|
||||
else:
|
||||
@@ -214,6 +233,13 @@ class TaskBoardHandler(
|
||||
self.handle_eco_git_commit()
|
||||
elif self.path == '/api/eco/restart-taskboard':
|
||||
self.handle_eco_restart_taskboard()
|
||||
elif self.path.startswith('/api/ralph/') and self.path.endswith('/stop'):
|
||||
parts = self.path.split('?', 1)[0].split('/')
|
||||
if len(parts) >= 5:
|
||||
slug = parts[3]
|
||||
self.handle_ralph_stop(slug)
|
||||
else:
|
||||
self.send_error(404)
|
||||
else:
|
||||
self.send_error(404)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user