import { throughputSeries, areaPath, dayStart } from './viewmodel.js'; /** * Sidebar skeleton: budget card + live feed card. The budget card has no tab * bar of its own — the Token/Kosten/Verlauf tabs live inside the donut card * (rendered client-side by the ported v1 budget JS in v1Budget.ts). The * subhead keeps the v1 mount points: [data-budget-mode] (Session/Gesamt), * #budgetTotal, #budgetReset; #budgetRows is where the donut card mounts. */ export function sidebarHtml(): string { return ` `; } /** * Inline script: throughput area chart renderer (used by the Verlauf tab in * the donut card) + live feed, followed by the ported v1 budget JS. */ export function sidebarJs(v1BudgetJs: string): string { return ` var DAY_MS = 24 * 3600 * 1000; ${dayStart.toString()} ${throughputSeries.toString()} ${areaPath.toString()} window.__b2RenderThroughput = function (tasks) { var box = document.getElementById('b2Throughput'); var tip = document.getElementById('b2ThroughputTip'); if (!box) return; // Verlauf tab not mounted right now — nothing to update var s = throughputSeries(tasks, 14); var p = areaPath(s, 220, 80); box.innerHTML = '' + '' + ''; if (tip) { var avg = s.reduce(function (a, b) { return a + b; }, 0) / s.length; tip.textContent = 'Erledigte Tasks · 14 Tage · Ø ' + avg.toFixed(1) + '/Tag'; } }; window.__b2FeedPush = function (html) { var feed = document.getElementById('b2Feed'); if (!feed) return; var div = document.createElement('div'); div.innerHTML = html; feed.insertBefore(div, feed.firstChild); while (feed.children.length > 5) feed.removeChild(feed.lastChild); }; // ── Agent health traffic lights (GET /health) ───────────────────────────── // active (green) <2min since last action · busy (blue, on TSK-X) · // idle (gray) · stale/offline (red, >10min with an open assignment). window.__b2RenderAgents = function (report) { var box = document.getElementById('b2Agents'); if (!box) return; var agents = report && report.agents ? report.agents : []; if (!agents.length) { box.innerHTML = '
no agents yet
'; return; } box.innerHTML = agents.map(function (a) { var loop = a.dispatch === 'architect' ? (a.taskId ? 'architect started' : a.waitingTaskId ? 'wartet auf Architekten-Start' : 'architect dispatch') : a.inLoop ? 'loop ' + compact(a.loopSinceAgoSec || 0) : a.loopExitReason ? 'out ' + compact(a.loopExitAgoSec || 0) + ' · ' + a.loopExitReason : 'loop ?'; var work = a.taskId ? a.taskId : a.waitingTaskId ? a.waitingTaskId + ' waiting' : ''; var detail = loop + (work ? ' · ' + work : ''); return '
' + '' + '' + esc(a.name) + '' + '' + esc(detail) + '
'; }).join(''); }; async function refreshAgentHealth() { try { window.__b2RenderAgents(await getJSON('/health')); } catch (_) {} } window.refreshAgentHealth = refreshAgentHealth; refreshAgentHealth(); setInterval(refreshAgentHealth, 5000); ${v1BudgetJs}`; }