From 0894030754c4e927fd94f026ec745b0636c8540d Mon Sep 17 00:00:00 2001 From: iris Date: Thu, 4 Jun 2026 18:36:08 +0200 Subject: [PATCH 1/2] fix(#1285): handle restart queue kind in dashboard container row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pending-label derivation had no case for op.kind === 'restart', so it fell through to the rebuild/rebuild-queued else branch โ€” showing a misleading 'rebuild pending' badge when the operator issued a restart. Add explicit 'restarting' / 'restart queued' cases alongside the existing meta_update and destroy cases. Also add restart / startup_sweep / perm_change to QUEUE_KIND_GLYPH so they render with a meaningful glyph (โ†บ / โšก / ๐Ÿ”‘) instead of '?' in the rebuild-queue panel. --- frontend/packages/dashboard/src/tabs.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/packages/dashboard/src/tabs.js b/frontend/packages/dashboard/src/tabs.js index 9895687a..9b6fc238 100644 --- a/frontend/packages/dashboard/src/tabs.js +++ b/frontend/packages/dashboard/src/tabs.js @@ -651,9 +651,11 @@ window.marked = marked; || (op && (op.state === 'running' ? (op.kind === 'meta_update' ? 'meta-updating' : op.kind === 'destroy' ? 'destroying' + : op.kind === 'restart' ? 'restarting' : 'rebuilding') : (op.kind === 'meta_update' ? 'meta-update queued' : op.kind === 'destroy' ? 'destroy queued' + : op.kind === 'restart' ? 'restart queued' : 'rebuild queued'))); const opRunning = transientKind != null || (op != null && op.state === 'running'); @@ -2177,6 +2179,9 @@ window.marked = marked; meta_update: 'โ—†', spawn: 'โœจ', destroy: '๐Ÿ—‘', + restart: 'โ†บ', + startup_sweep: 'โšก', + perm_change: '๐Ÿ”‘', }; const QUEUE_STATE_GLYPH = { queued: 'โธ', From bddeb5478e38b8ae6284be3a93a6ba542e4823dd Mon Sep 17 00:00:00 2001 From: iris Date: Thu, 4 Jun 2026 18:40:47 +0200 Subject: [PATCH 2/2] fix(#1286): pretty-print system events in the agent terminal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The catch-all renderer was dumping raw JSON (in loud orange) for claude's system events like api_retry โ€” producing noise like: ! {"attempt":1,"error":"unknown","subtype":"api_retry",...} Replace the single 'init' filter with a full system-event block: - api_retry โ†’ muted note: 'โš  api retry 1/10 ยท unknown ยท 502ms' - api_error โ†’ amber note: 'โœ— api error ยท ' - other subtypes (context_window_exceeded, etc.) โ†’ 'โš™ ' The loud orange sys catch-all is now reserved for truly unrecognised top-level event types, not routine operational noise. --- frontend/packages/agent/src/app.js | 33 +++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/frontend/packages/agent/src/app.js b/frontend/packages/agent/src/app.js index 70db5adc..feedcce7 100644 --- a/frontend/packages/agent/src/app.js +++ b/frontend/packages/agent/src/app.js @@ -1431,11 +1431,38 @@ window.marked = marked; return false; } function renderStream(v, api) { - // Drop session init, claude's result line, rate-limit โ€” noise. - // TurnEnd communicates pass/fail; session init isn't actionable. - if (v.type === 'system' && v.subtype === 'init') return; + // Drop claude's result line and rate-limit โ€” noise. TurnEnd + // communicates pass/fail; rate-limit events are noisy status chatter. if (v.type === 'rate_limit_event') return; if (v.type === 'result') return; + // `system` events: `init` is silent startup noise; `api_retry` + // and `api_error` get human-readable notes; unknown subtypes get a + // muted line rather than a raw-JSON dump in the loud `sys` colour. + if (v.type === 'system') { + if (v.subtype === 'init') return; + if (v.subtype === 'api_retry') { + const parts = ['โš  api retry']; + if (v.attempt != null && v.max_retries != null) + parts.push(v.attempt + '/' + v.max_retries); + if (v.error) parts.push(String(v.error)); + else if (v.error_status) parts.push('HTTP ' + v.error_status); + if (v.retry_delay_ms != null) + parts.push(Math.round(v.retry_delay_ms) + 'ms'); + api.row('note', parts.join(' ยท ')); + return; + } + if (v.subtype === 'api_error') { + const msg = v.error || v.message + || (v.error_status ? 'HTTP ' + v.error_status : 'unknown'); + api.row('note stderr', 'โœ— api error ยท ' + msg); + return; + } + // Other system subtypes (context_window_exceeded, etc.) โ€” render a + // muted note with the subtype label; reserve the loud orange `sys` + // catch-all for truly unrecognised top-level types. + api.row('note', 'โš™ ' + (v.subtype || 'system')); + return; + } // Background-task subagent events (claude's `Task` tool spawns // a separate session whose progress lands here as `task_*` // subtypes). Match by subtype so we don't have to track which