@enigmax/dashboard 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/index.html +71 -0
- package/package.json +1 -1
package/assets/index.html
CHANGED
|
@@ -141,6 +141,15 @@
|
|
|
141
141
|
.linput { flex: 1; min-width: 0; background: var(--surface2); color: var(--text); border: 1px solid var(--border); border-radius: 7px; padding: 5px 10px; font-size: 12px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
142
142
|
.laddb { background: var(--surface2); color: var(--accent); border: 1px solid var(--border); border-radius: 7px; padding: 5px 14px; font-size: 12px; cursor: pointer; font-family: inherit; }
|
|
143
143
|
.laddb:hover { border-color: var(--accent); }
|
|
144
|
+
/* Claude-style usage window gauges (current session / weekly all / weekly Sonnet). */
|
|
145
|
+
.wgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; margin-bottom: 18px; }
|
|
146
|
+
.wcard { background: var(--surface2); border: 1px solid var(--border); border-radius: 12px; padding: 16px; }
|
|
147
|
+
.wtitle { font-size: 13px; font-weight: 600; color: var(--text); }
|
|
148
|
+
.wreset { font-size: 12px; color: var(--muted); margin-top: 2px; }
|
|
149
|
+
.wval { font-size: 22px; font-weight: 600; color: var(--accent); margin-top: 12px; }
|
|
150
|
+
.wval.muted { font-size: 14px; font-weight: 500; color: var(--muted); }
|
|
151
|
+
.wset { display: flex; gap: 6px; margin-top: 10px; }
|
|
152
|
+
.wlimit { flex: 1; min-width: 0; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 7px; padding: 4px 8px; font-size: 12px; }
|
|
144
153
|
.sys-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 0 24px; }
|
|
145
154
|
.sys-item { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--surface2); font-size: 13px; }
|
|
146
155
|
.sys-item .k { color: var(--muted); }
|
|
@@ -276,6 +285,9 @@
|
|
|
276
285
|
<p>Measured token consumption and estimated cost, read-only from your own Claude Code session transcripts (<code>~/.claude/projects</code>). Cost is an estimate from a per-model price table; real spend is billed by Anthropic. Nothing is sent anywhere.</p>
|
|
277
286
|
</div>
|
|
278
287
|
<div class="panel" id="usagePanel" style="display:none">
|
|
288
|
+
<h2 style="margin:0 0 4px">Usage limits <small>same windows Claude Code shows</small></h2>
|
|
289
|
+
<div class="sub" style="margin-bottom:12px">Reset times and tokens are measured from your transcripts; the <b>% used</b> needs your plan limit (set it on a card, or with <code>enigma config plan-weekly-limit <tokens></code>). The weekly reset day/time is <code>enigma config plan-weekly-reset "mon 11:00"</code>.</div>
|
|
290
|
+
<div id="uWindows"></div>
|
|
279
291
|
<div class="grid" style="margin-bottom:16px">
|
|
280
292
|
<div class="card"><div class="label">Est. Cost</div><div id="uCost" class="value accent">-</div><div class="foot">All sessions, per-model pricing</div></div>
|
|
281
293
|
<div class="card"><div class="label">Cache Saved</div><div id="uCacheMoney" class="value good">-</div><div class="foot">Est. from prompt caching</div></div>
|
|
@@ -515,6 +527,63 @@
|
|
|
515
527
|
// Real tool-usage panel (Claude Code transcripts). null = the opt-in flag is off.
|
|
516
528
|
function shortProject(p) { p = String(p || ""); return p.length > 44 ? "..." + p.slice(-41) : p; }
|
|
517
529
|
|
|
530
|
+
// --- Claude-style usage windows (current session / weekly all / weekly Sonnet) ---
|
|
531
|
+
function fmtResetIn(ms) {
|
|
532
|
+
const d = ms - Date.now();
|
|
533
|
+
if (d <= 0) return "now";
|
|
534
|
+
const h = Math.floor(d / 3600000), m = Math.round((d % 3600000) / 60000);
|
|
535
|
+
return h ? ("in " + h + " hr " + m + " min") : ("in " + m + " min");
|
|
536
|
+
}
|
|
537
|
+
function fmtResetAt(ms) {
|
|
538
|
+
const dt = new Date(ms);
|
|
539
|
+
return "Resets " + dt.toLocaleDateString([], { weekday: "short" }) + " " + dt.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
|
540
|
+
}
|
|
541
|
+
function windowCard(w, sub) {
|
|
542
|
+
const reset = w.kind === "session"
|
|
543
|
+
? (w.resetsAt ? "Resets " + fmtResetIn(w.resetsAt) : "No active session")
|
|
544
|
+
: (w.resetsAt ? fmtResetAt(w.resetsAt) : "");
|
|
545
|
+
let body;
|
|
546
|
+
if (sub === "weeklySonnet" && (w.used || 0) === 0) {
|
|
547
|
+
body = '<div class="wval muted">You haven\'t used Sonnet yet</div>';
|
|
548
|
+
} else if (w.pct != null) {
|
|
549
|
+
const p = Math.round(w.pct);
|
|
550
|
+
const col = w.pct >= 90 ? "var(--accent2)" : "var(--accent)";
|
|
551
|
+
body = '<div class="wval">' + p + '% used</div>'
|
|
552
|
+
+ '<div class="bar-track" style="margin-top:8px"><div class="bar-fill" style="width:' + Math.min(100, w.pct) + '%;background:' + col + '"></div></div>';
|
|
553
|
+
} else {
|
|
554
|
+
body = '<div class="wval">' + fmt(w.used || 0) + ' tok</div>'
|
|
555
|
+
+ '<div class="wset"><input type="number" min="0" class="wlimit" data-plan="' + sub + '" placeholder="set limit (tokens)">'
|
|
556
|
+
+ '<button type="button" class="laddb" data-plan="' + sub + '">Set</button></div>';
|
|
557
|
+
}
|
|
558
|
+
return '<div class="wcard"><div class="wtitle">' + esc(w.label) + '</div><div class="wreset">' + esc(reset) + '</div>' + body + '</div>';
|
|
559
|
+
}
|
|
560
|
+
function renderWindows(u) {
|
|
561
|
+
const w = u && u.windows;
|
|
562
|
+
if (!w) { $("uWindows").innerHTML = ""; return; }
|
|
563
|
+
$("uWindows").innerHTML = '<div class="wgrid">'
|
|
564
|
+
+ windowCard(w.session, "session")
|
|
565
|
+
+ windowCard(w.weeklyAll, "weekly")
|
|
566
|
+
+ windowCard(w.weeklySonnet, "weeklySonnet")
|
|
567
|
+
+ "</div>";
|
|
568
|
+
}
|
|
569
|
+
async function planSet(key, value) {
|
|
570
|
+
try { await fetch("/api/plan", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key, value: Number(value) }) }); refreshAll(true); }
|
|
571
|
+
catch { /* leave as-is */ }
|
|
572
|
+
}
|
|
573
|
+
function wireUsage() {
|
|
574
|
+
const el = $("uWindows");
|
|
575
|
+
el.addEventListener("click", (e) => {
|
|
576
|
+
const b = e.target.closest("button[data-plan]"); if (!b) return;
|
|
577
|
+
const inp = el.querySelector('input.wlimit[data-plan="' + b.dataset.plan + '"]');
|
|
578
|
+
if (inp && inp.value) planSet(b.dataset.plan, inp.value);
|
|
579
|
+
});
|
|
580
|
+
el.addEventListener("keydown", (e) => {
|
|
581
|
+
if (e.key !== "Enter") return;
|
|
582
|
+
const inp = e.target.closest("input.wlimit");
|
|
583
|
+
if (inp && inp.value) planSet(inp.dataset.plan, inp.value);
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
518
587
|
// One token/cost breakdown table (By Model / By Project), sorted by cost then tokens.
|
|
519
588
|
function renderUsageTable(el, map, pending, label) {
|
|
520
589
|
const entries = Object.entries(map || {}).sort((a, b) => ((b[1].cost || 0) - (a[1].cost || 0)) || ((b[1].input + b[1].output) - (a[1].input + a[1].output)));
|
|
@@ -540,6 +609,7 @@
|
|
|
540
609
|
if (!u) { panel.style.display = "none"; hint.style.display = "block"; return; }
|
|
541
610
|
hint.style.display = "none";
|
|
542
611
|
panel.style.display = "block";
|
|
612
|
+
renderWindows(u);
|
|
543
613
|
$("uCost").textContent = fmtUsd(u.cost || 0);
|
|
544
614
|
$("uCacheMoney").textContent = fmtUsd(cacheMoney(u.cacheRead || 0));
|
|
545
615
|
$("uCacheRead").textContent = fmt(u.cacheRead || 0);
|
|
@@ -1180,6 +1250,7 @@
|
|
|
1180
1250
|
wireSettings();
|
|
1181
1251
|
wireSkills();
|
|
1182
1252
|
wireAccounts();
|
|
1253
|
+
wireUsage();
|
|
1183
1254
|
$("cfgExport").addEventListener("click", exportConfig);
|
|
1184
1255
|
$("cfgImport").addEventListener("click", importConfig);
|
|
1185
1256
|
$("updateBtn").addEventListener("click", runUpdate);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/dashboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Local browser dashboard UI for enigma: the static page and chart assets enigma serves on its loopback dashboard (savings, real tool usage, in-browser settings). Installed on demand by enigma-cli; not a runtime dependency.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|