From 11d962abb45cace8ffc9e69aed0279ec7ebc0da5 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Wed, 18 Mar 2026 15:55:09 -0400 Subject: [PATCH] feat: add model health indicator to auto-mode progress widget (#1232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a traffic-light health indicator to the progress widget: 🟢 progressing, 🟡 struggling, 🔴 stuck Uses existing health tracker signals. No separate summary model needed. Fixes #1221 --- .../extensions/gsd/auto-dashboard.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/resources/extensions/gsd/auto-dashboard.ts b/src/resources/extensions/gsd/auto-dashboard.ts index c4addc4cf..b738dfa71 100644 --- a/src/resources/extensions/gsd/auto-dashboard.ts +++ b/src/resources/extensions/gsd/auto-dashboard.ts @@ -11,6 +11,7 @@ import type { GSDState } from "./types.js"; import { getCurrentBranch } from "./worktree.js"; import { getActiveHook } from "./post-unit-hooks.js"; import { getLedger, getProjectTotals, formatCost, formatTokenCount, formatTierSavings } from "./metrics.js"; +import { getHealthTrend, getConsecutiveErrorUnits } from "./doctor-proactive.js"; import { resolveMilestoneFile, resolveSliceFile, @@ -649,6 +650,31 @@ export function updateProgressWidget( * Build a compact string-array representation of the progress widget. * Used as a fallback when the factory-based widget cannot render (RPC mode). */ +// ─── Model Health Indicator ─────────────────────────────────────────────────── + +/** + * Compute a traffic-light health indicator from observable signals. + * 🟢 progressing well — no errors, trend stable/improving + * 🟡 struggling — some errors or degrading trend + * 🔴 stuck — consecutive errors, likely needs attention + */ +export function getModelHealthIndicator(): { emoji: string; label: string } { + const trend = getHealthTrend(); + const consecutiveErrors = getConsecutiveErrorUnits(); + + if (consecutiveErrors >= 3) { + return { emoji: "🔴", label: "stuck" }; + } + if (consecutiveErrors >= 1 || trend === "degrading") { + return { emoji: "🟡", label: "struggling" }; + } + if (trend === "improving") { + return { emoji: "🟢", label: "progressing well" }; + } + // stable or unknown + return { emoji: "🟢", label: "progressing" }; +} + function buildProgressTextLines( verb: string, phaseLabel: string, @@ -697,6 +723,11 @@ function buildProgressTextLines( } if (next) lines.push(` Next: ${next}`); + + // Model health indicator + const health = getModelHealthIndicator(); + lines.push(` Health: ${health.emoji} ${health.label}`); + lines.push(` ${widgetPwd}`); return lines;