Sync: Complete project state with all MEGA SPRINT V1-V3 features and Codex stubs

This commit is contained in:
renato97
2026-04-08 17:58:47 -03:00
parent c9d3528900
commit 6d080d43b3
372 changed files with 189715 additions and 8590 deletions

491
ralph/gui/app.py Normal file
View File

@@ -0,0 +1,491 @@
#!/usr/bin/env python3
"""Minimal Ralph dashboard for localhost monitoring."""
from __future__ import annotations
import argparse
import json
import os
from datetime import datetime
from http import HTTPStatus
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from typing import Any, Dict, List
from urllib.parse import urlparse
RALPH_ROOT = Path(__file__).resolve().parents[1]
STATE_DIR = RALPH_ROOT / "state"
RUNS_DIR = RALPH_ROOT / "runs"
def _read_json(path: Path, default: Any) -> Any:
try:
return json.loads(path.read_text(encoding="utf-8"))
except Exception:
return default
def _read_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8")
except Exception:
return ""
def _tail_jsonl(path: Path, limit: int = 80) -> List[Dict[str, Any]]:
if not path.exists():
return []
try:
lines = path.read_text(encoding="utf-8").splitlines()
except Exception:
return []
events: List[Dict[str, Any]] = []
for line in lines[-limit:]:
line = line.strip()
if not line:
continue
try:
events.append(json.loads(line))
except Exception:
continue
events.reverse()
return events
def _is_pid_running(pid: Any) -> bool:
try:
pid_value = int(pid)
except Exception:
return False
if pid_value <= 0:
return False
try:
os.kill(pid_value, 0)
except PermissionError:
return True
except OSError:
return False
return True
def _iso_to_local(value: Any) -> str:
if not value:
return ""
try:
return datetime.fromisoformat(str(value).replace("Z", "+00:00")).strftime("%Y-%m-%d %H:%M:%S")
except Exception:
return str(value)
def _collect_recent_runs(limit: int = 8) -> List[Dict[str, Any]]:
runs: List[Dict[str, Any]] = []
if not RUNS_DIR.exists():
return runs
for run_dir in sorted([p for p in RUNS_DIR.iterdir() if p.is_dir()], key=lambda item: item.name, reverse=True)[:limit]:
summary_path = run_dir / "SUMMARY.md"
final_status_path = run_dir / "final_status.txt"
summary_text = _read_text(summary_path).strip()
final_status_text = _read_text(final_status_path).strip()
changes_exists = (run_dir / "CHANGES.md").exists()
implementer_patch = (run_dir / "implementer.patch").exists()
final_patch = (run_dir / "final.patch").exists()
runs.append(
{
"run_id": run_dir.name,
"path": str(run_dir),
"updated_at": datetime.fromtimestamp(run_dir.stat().st_mtime).strftime("%Y-%m-%d %H:%M:%S"),
"summary_excerpt": "\n".join(summary_text.splitlines()[:10]),
"final_status_excerpt": "\n".join(final_status_text.splitlines()[:8]),
"changes_exists": changes_exists,
"implementer_patch": implementer_patch,
"final_patch": final_patch,
}
)
return runs
def build_dashboard() -> Dict[str, Any]:
current_run = _read_json(STATE_DIR / "current_run.json", {})
background = _read_json(STATE_DIR / "last_background_run.json", {})
background["alive"] = _is_pid_running(background.get("pid"))
return {
"generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"current_run": current_run,
"background": background,
"events": _tail_jsonl(STATE_DIR / "events.jsonl", limit=120),
"recent_runs": _collect_recent_runs(),
"provider_smoke": _read_json(STATE_DIR / "provider_smoke.json", {}),
}
HTML_TEMPLATE = """<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ralph Dashboard</title>
<style>
:root {
--bg: #f3efe5;
--ink: #1a1a1a;
--muted: #5f5a52;
--card: #fffaf2;
--line: #d8cfbf;
--ok: #2a7f62;
--warn: #a96814;
--bad: #ad2e24;
--run: #144c7d;
--shadow: rgba(0, 0, 0, 0.08);
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
background: linear-gradient(180deg, #efe7d8 0%, var(--bg) 100%);
color: var(--ink);
}
header {
padding: 20px 24px;
background: #17324d;
color: #fff8eb;
border-bottom: 4px solid #c98b2b;
}
header h1 { margin: 0 0 6px; font-size: 28px; }
header p { margin: 0; color: #d7e4ef; }
main { padding: 20px 24px 32px; }
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 16px;
margin-bottom: 18px;
}
.card {
background: var(--card);
border: 1px solid var(--line);
border-radius: 14px;
padding: 16px;
box-shadow: 0 8px 24px var(--shadow);
}
.card h2 {
margin: 0 0 10px;
font-size: 18px;
}
.muted { color: var(--muted); }
.badge {
display: inline-block;
padding: 4px 9px;
border-radius: 999px;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
background: #ece4d6;
color: var(--ink);
}
.status-completed, .status-success, .status-running { color: var(--ok); }
.status-failed, .status-error { color: var(--bad); }
.status-pending, .status-warning { color: var(--warn); }
.agents { display: grid; gap: 10px; }
.agent {
border: 1px solid var(--line);
border-radius: 10px;
padding: 10px 12px;
background: #fffdf8;
}
.agent strong { display: block; margin-bottom: 4px; }
.timeline {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 10px;
max-height: 540px;
overflow: auto;
}
.timeline li {
border-left: 4px solid #c98b2b;
padding: 8px 10px 8px 12px;
background: #fffdf8;
border-radius: 8px;
border: 1px solid var(--line);
}
.run-list {
display: grid;
gap: 12px;
}
.run-item {
border: 1px solid var(--line);
border-radius: 12px;
padding: 12px;
background: #fffdf8;
}
pre {
white-space: pre-wrap;
word-break: break-word;
background: #f6f1e8;
border: 1px solid var(--line);
border-radius: 10px;
padding: 12px;
margin: 8px 0 0;
font-size: 12px;
}
.empty {
padding: 16px;
border: 1px dashed var(--line);
border-radius: 10px;
color: var(--muted);
background: #faf6ef;
}
</style>
</head>
<body>
<header>
<h1>Ralph Dashboard</h1>
<p>Simple local view of who is working, what stage the swarm is in, and what happened last.</p>
</header>
<main>
<div class="grid">
<section class="card">
<h2>Overview</h2>
<div id="overview" class="muted">Loading...</div>
</section>
<section class="card">
<h2>Background Runner</h2>
<div id="background" class="muted">Loading...</div>
</section>
<section class="card">
<h2>Provider Smoke</h2>
<div id="providers" class="muted">Loading...</div>
</section>
</div>
<div class="grid">
<section class="card">
<h2>Current Run</h2>
<div id="current-run" class="muted">Loading...</div>
</section>
<section class="card">
<h2>Agent Status</h2>
<div id="agents" class="agents"></div>
</section>
</div>
<div class="grid">
<section class="card">
<h2>Timeline</h2>
<ul id="timeline" class="timeline"></ul>
</section>
<section class="card">
<h2>Recent Runs</h2>
<div id="recent-runs" class="run-list"></div>
</section>
</div>
</main>
<script>
function statusBadge(value) {
const text = value || "unknown";
const cls = "badge status-" + String(text).toLowerCase();
return `<span class="${cls}">${text}</span>`;
}
function renderAgent(name, data) {
if (!data) return "";
const started = data.started_at ? new Date(data.started_at).toLocaleString() : "";
const finished = data.finished_at ? new Date(data.finished_at).toLocaleString() : "";
const output = data.output_file ? `<div class="muted">${data.output_file}</div>` : "";
return `
<div class="agent">
<strong>${name}</strong>
<div>${statusBadge(data.status)}</div>
${started ? `<div class="muted">Start: ${started}</div>` : ""}
${finished ? `<div class="muted">End: ${finished}</div>` : ""}
${output}
</div>
`;
}
function renderOverview(data) {
const run = data.current_run || {};
if (!run.run_id) {
return `<div class="empty">No current run state has been written yet.</div>`;
}
return `
<div><strong>Run ID:</strong> ${run.run_id}</div>
<div><strong>Stage:</strong> ${statusBadge(run.stage)}</div>
<div><strong>Status:</strong> ${statusBadge(run.status)}</div>
<div><strong>Message:</strong> ${run.latest_message || "-"}</div>
<div class="muted">Updated: ${data.generated_at}</div>
`;
}
function renderBackground(data) {
const bg = data.background || {};
if (!bg.pid) {
return `<div class="empty">No background launch metadata found.</div>`;
}
return `
<div><strong>PID:</strong> ${bg.pid}</div>
<div><strong>Alive:</strong> ${statusBadge(bg.alive ? "running" : "stopped")}</div>
<div><strong>Run label:</strong> ${bg.run_label || "-"}</div>
<div class="muted">${bg.stdout_log || ""}</div>
<div class="muted">${bg.stderr_log || ""}</div>
`;
}
function renderProviders(data) {
const smoke = data.provider_smoke || {};
const checks = smoke.checks || [];
if (!checks.length) {
return `<div class="empty">No provider smoke data found yet.</div>`;
}
return checks.map((item) => `
<div class="agent">
<strong>${item.provider || "provider"}</strong>
<div>${statusBadge(item.status || "unknown")}</div>
<div class="muted">${item.model || ""}</div>
</div>
`).join("");
}
function renderCurrentRun(data) {
const run = data.current_run || {};
if (!run.run_id) {
return `<div class="empty">No active or recent run state.</div>`;
}
return `
<div><strong>Run:</strong> ${run.run_id}</div>
<div><strong>Task dir:</strong> ${run.task_directory || "-"}</div>
<div><strong>Worktree:</strong> ${run.worktree || "-"}</div>
<div><strong>Started:</strong> ${run.started_at ? new Date(run.started_at).toLocaleString() : "-"}</div>
<div><strong>Finished:</strong> ${run.finished_at ? new Date(run.finished_at).toLocaleString() : "-"}</div>
${(run.errors || []).length ? `<pre>${(run.errors || []).join("\\n")}</pre>` : ""}
`;
}
function renderAgents(data) {
const run = data.current_run || {};
const html = [];
if (run.implementer) {
html.push(renderAgent("Implementer: " + (run.implementer.name || "unknown"), run.implementer));
}
(run.reviewers || []).forEach((reviewer) => {
html.push(renderAgent("Reviewer: " + (reviewer.name || "unknown"), reviewer));
});
if (run.codex_master) {
html.push(renderAgent("Codex Master", run.codex_master));
}
if (run.fix_pass) {
html.push(renderAgent("Fix Pass", run.fix_pass));
}
document.getElementById("agents").innerHTML = html.length ? html.join("") : `<div class="empty">No agent state yet.</div>`;
}
function renderTimeline(data) {
const events = data.events || [];
const target = document.getElementById("timeline");
if (!events.length) {
target.innerHTML = `<li class="empty">No events yet.</li>`;
return;
}
target.innerHTML = events.map((event) => `
<li>
<div><strong>${event.actor || "system"}</strong> ${statusBadge(event.status || "unknown")}</div>
<div>${event.message || "-"}</div>
<div class="muted">${event.stage || "-"} · ${new Date(event.timestamp).toLocaleString()}</div>
</li>
`).join("");
}
function renderRecentRuns(data) {
const runs = data.recent_runs || [];
const target = document.getElementById("recent-runs");
if (!runs.length) {
target.innerHTML = `<div class="empty">No run folders found.</div>`;
return;
}
target.innerHTML = runs.map((run) => `
<div class="run-item">
<div><strong>${run.run_id}</strong></div>
<div class="muted">${run.updated_at}</div>
<div>${run.changes_exists ? statusBadge("changes") : statusBadge("no changes")}</div>
<div>${run.final_patch ? statusBadge("final patch") : statusBadge("no final patch")}</div>
${run.final_status_excerpt ? `<pre>${run.final_status_excerpt}</pre>` : ""}
${run.summary_excerpt ? `<pre>${run.summary_excerpt}</pre>` : ""}
</div>
`).join("");
}
async function refresh() {
const response = await fetch("/api/dashboard", { cache: "no-store" });
const data = await response.json();
document.getElementById("overview").innerHTML = renderOverview(data);
document.getElementById("background").innerHTML = renderBackground(data);
document.getElementById("providers").innerHTML = renderProviders(data);
document.getElementById("current-run").innerHTML = renderCurrentRun(data);
renderAgents(data);
renderTimeline(data);
renderRecentRuns(data);
}
refresh();
setInterval(refresh, 2000);
</script>
</body>
</html>
"""
class RalphHandler(BaseHTTPRequestHandler):
def _send_json(self, payload: Dict[str, Any]) -> None:
body = json.dumps(payload, indent=2).encode("utf-8")
self.send_response(HTTPStatus.OK)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Cache-Control", "no-store")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def _send_html(self, payload: str) -> None:
body = payload.encode("utf-8")
self.send_response(HTTPStatus.OK)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.send_header("Cache-Control", "no-store")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_GET(self) -> None:
route = urlparse(self.path).path
if route == "/api/dashboard":
self._send_json(build_dashboard())
return
if route == "/" or route == "/index.html":
self._send_html(HTML_TEMPLATE)
return
self.send_error(HTTPStatus.NOT_FOUND, "Not found")
def log_message(self, fmt: str, *args: Any) -> None:
return
def main() -> None:
parser = argparse.ArgumentParser(description="Run the Ralph localhost dashboard.")
parser.add_argument("--host", default="127.0.0.1", help="Bind host (default: 127.0.0.1)")
parser.add_argument("--port", type=int, default=8765, help="Bind port (default: 8765)")
args = parser.parse_args()
server = ThreadingHTTPServer((args.host, args.port), RalphHandler)
print(f"Ralph dashboard listening on http://{args.host}:{args.port}")
server.serve_forever()
if __name__ == "__main__":
main()