diff --git a/crates/miyabi-cli/src/main.rs b/crates/miyabi-cli/src/main.rs
index 521e01d..e44d0f8 100644
--- a/crates/miyabi-cli/src/main.rs
+++ b/crates/miyabi-cli/src/main.rs
@@ -2136,6 +2136,10 @@ const POLARIS_DASHBOARD_HTML: &str = r##"
Loading...
+
+ Completion Stats
+ Loading stats...
+
Tasks
@@ -2262,6 +2266,27 @@ const POLARIS_DASHBOARD_HTML: &str = r##"
}
}
+ function renderStats(snapshot) {
+ const tasks = Array.isArray(snapshot.tasks) ? snapshot.tasks : [];
+ if (tasks.length === 0) {
+ document.getElementById("stats").innerHTML = 'No tasks';
+ return;
+ }
+ const done = tasks.filter(t => t.current_state === "done" || t.current_state === "merged").length;
+ const active = tasks.filter(t => t.current_state === "implementing" || t.current_state === "reviewing").length;
+ const pending = tasks.filter(t => t.current_state === "pending" || t.current_state === "draft" || t.current_state === "blocked").length;
+ const total = tasks.length;
+ const pct = total > 0 ? Math.round(done / total * 100) : 0;
+
+ const bar = '';
+
+ document.getElementById("stats").innerHTML =
+ '' + pct + '%
' +
+ 'completed
' + bar +
+ '' + done + ' done / ' + active + ' active / ' + pending + ' pending / ' + total + ' total
';
+ }
+
async function refresh() {
try {
const [statusRes, locksRes, dagRes] = await Promise.all([
@@ -2280,6 +2305,7 @@ const POLARIS_DASHBOARD_HTML: &str = r##"
dagRes.json()
]);
+ renderStats(status);
renderTasks(status);
renderLocks(locks);
renderDag(dag);
@@ -2289,6 +2315,7 @@ const POLARIS_DASHBOARD_HTML: &str = r##"
" | auto-refresh every 3s";
} catch (error) {
document.getElementById("meta").textContent = "Refresh failed: " + error.message;
+ document.getElementById("stats").innerHTML = 'Failed to load';
setEmpty("tasks", "Failed to load tasks");
setEmpty("dag", "Failed to load DAG");
setEmpty("locks", "Failed to load locks");