// deck-it - llm panel // Copyright (C) 2026 Danilo M. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import { offline } from "../offline.js"; const num = (v) => (v == null ? null : Number(v)); const money = (v) => (num(v) == null ? "—" : `$${num(v).toFixed(2)}`); const tokens = (n) => { if (n == null) return "—"; if (n >= 1e9) return `${(n / 1e9).toFixed(1)}B`; if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`; if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`; return String(n); }; const CLAUDE_ICON = ''; const OPENCODE_ICON = ''; function section(icon, title, model) { const sec = document.createElement("section"); sec.className = "llm-sec"; const head = document.createElement("header"); head.className = "llm-head"; head.innerHTML = `${icon}

`; head.querySelector("h3").textContent = title; head.querySelector(".model").textContent = model || "—"; sec.append(head); return sec; } function gauge(label, value) { const d = document.createElement("div"); d.className = "gauge"; const l = document.createElement("span"); l.className = "glabel"; l.textContent = label; const v = document.createElement("span"); v.className = "gvalue num"; v.textContent = value == null ? "—" : `${Math.round(value)}%`; const bar = document.createElement("div"); bar.className = "gbar"; const fill = document.createElement("i"); fill.style.width = `${Math.max(0, Math.min(100, value || 0))}%`; bar.append(fill); d.append(l, v, bar); return d; } function stat(label, value, sub) { const d = document.createElement("div"); d.className = "lbig"; const l = document.createElement("span"); l.className = "mlabel"; l.textContent = label; const v = document.createElement("span"); v.className = "mvalue num"; v.textContent = value; const s = document.createElement("span"); s.className = "msub"; s.textContent = sub || ""; d.append(l, v, s); return d; } export default { title: "LLM usage", interval: 5, mount(el) { el.innerHTML = `
`; }, update(state, el) { const box = el.querySelector(".llm"); if (state.offline) { offline(box, { icon: "/logos/claude.svg", title: "Usage dashboard is off", detail: "Start llm-cost-dashboard and Claude and opencode usage appear here.", }); return; } box.textContent = ""; const c = state.claude ?? {}; const o = state.opencode ?? {}; const claude = section(CLAUDE_ICON, "Claude Code", c.model); const gauges = document.createElement("div"); gauges.className = "gauges"; gauges.append( gauge("Context", c.context_pct), gauge("5h", c.five_hour_pct), gauge("7d", c.seven_day_pct), ); claude.append(gauges); box.append(claude); const opencode = section(OPENCODE_ICON, "opencode", o.model); const pair = document.createElement("div"); pair.className = "lpair"; pair.append( stat("session", money(o.session_cost), `${tokens(o.session_tokens)} · ${o.session_calls ?? 0} calls`), stat("total", money(o.cost), `${tokens(o.tokens)} · ${o.calls ?? 0} calls`), ); opencode.append(pair); box.append(opencode); }, };