@enigmax/dashboard 0.1.3 → 0.1.5
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 +62 -15
- package/package.json +1 -1
package/assets/index.html
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
body {
|
|
14
14
|
margin: 0; background: var(--bg); color: var(--text);
|
|
15
15
|
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
16
|
-
-webkit-font-smoothing: antialiased; padding: 24px; max-width:
|
|
16
|
+
-webkit-font-smoothing: antialiased; padding: 24px; max-width: 2200px; margin: 0 auto;
|
|
17
17
|
}
|
|
18
18
|
a { color: var(--accent2); }
|
|
19
19
|
header { display: flex; align-items: center; gap: 20px; margin-bottom: 24px; flex-wrap: wrap; }
|
|
@@ -108,6 +108,10 @@
|
|
|
108
108
|
border-radius: 7px; padding: 5px 10px; font-size: 12px; font-family: inherit; cursor: pointer;
|
|
109
109
|
}
|
|
110
110
|
.set-note { color: var(--accent); font-size: 12px; min-height: 16px; margin-top: 10px; }
|
|
111
|
+
/* Settings: two-column grid of rows on wide screens, so a long config list stays compact. */
|
|
112
|
+
.set-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: 0 32px; }
|
|
113
|
+
.set-grid .set-row { padding: 10px 0; }
|
|
114
|
+
.panel > .set-cat-h { margin-top: 0; }
|
|
111
115
|
.tag {
|
|
112
116
|
display: inline-block; font-size: 11px; color: var(--muted); background: var(--surface2);
|
|
113
117
|
border: 1px solid var(--border); border-radius: 6px; padding: 1px 7px; margin-left: 6px; vertical-align: middle;
|
|
@@ -173,9 +177,16 @@
|
|
|
173
177
|
</div>
|
|
174
178
|
|
|
175
179
|
<div class="panel">
|
|
176
|
-
<
|
|
180
|
+
<div class="panel-head">
|
|
181
|
+
<h2>Enigma Systems <small>what's active - configuration, not savings</small></h2>
|
|
182
|
+
<div class="ctrls">
|
|
183
|
+
<button id="refreshBtn" type="button" class="toggle">Refresh</button>
|
|
184
|
+
<button id="updateBtn" type="button" class="toggle on">Check & update</button>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
177
187
|
<div class="sub" style="margin-bottom:14px">Only Context Compression and (opt-in) real tool-usage are measured for savings below. The rest is shown as state: enigma can't measure their effect because they run inside the agent, not through enigma - so it reports their configuration honestly instead of inventing a number.</div>
|
|
178
188
|
<div id="systems" class="sys-grid"><div class="empty" style="padding:16px 0">Loading...</div></div>
|
|
189
|
+
<div id="updateNote" class="set-note"></div>
|
|
179
190
|
</div>
|
|
180
191
|
|
|
181
192
|
<div class="panel">
|
|
@@ -289,11 +300,9 @@
|
|
|
289
300
|
<div class="page-head">
|
|
290
301
|
<h1>Settings</h1>
|
|
291
302
|
<p>Everything you can configure with <code>enigma config</code> or the terminal UI, editable here. Changes apply at global scope and take effect immediately; toggles that change agent memory need an agent restart.</p>
|
|
292
|
-
</div>
|
|
293
|
-
<div class="panel">
|
|
294
|
-
<div id="settingsBody"><div class="empty" style="padding:24px 0">Loading settings...</div></div>
|
|
295
303
|
<div id="settingsNote" class="set-note"></div>
|
|
296
304
|
</div>
|
|
305
|
+
<div id="settingsBody"><div class="empty" style="padding:24px 0">Loading settings...</div></div>
|
|
297
306
|
</section>
|
|
298
307
|
|
|
299
308
|
<footer>
|
|
@@ -640,9 +649,14 @@
|
|
|
640
649
|
$("updated").textContent = "Updated " + new Date(data.generatedAt || Date.now()).toLocaleTimeString();
|
|
641
650
|
}
|
|
642
651
|
|
|
643
|
-
|
|
644
|
-
|
|
652
|
+
// Auto-refresh is on by default while the tab is focused; `live` mirrors the
|
|
653
|
+
// dashboard-live config (read from /api/status). A forced refresh (button / view
|
|
654
|
+
// change) always runs so the user can refresh even with auto-refresh off.
|
|
655
|
+
let live = true;
|
|
656
|
+
async function poll(force) {
|
|
657
|
+
// Never hit the server while the tab is hidden, or when auto-refresh is off (unless forced).
|
|
645
658
|
if (document.hidden) return;
|
|
659
|
+
if (!live && !force) return;
|
|
646
660
|
try {
|
|
647
661
|
const res = await fetch("/api/stats", { cache: "no-store" });
|
|
648
662
|
render(await res.json());
|
|
@@ -670,9 +684,11 @@
|
|
|
670
684
|
function renderSettings(cats) {
|
|
671
685
|
const el = $("settingsBody");
|
|
672
686
|
if (!cats.length) { el.innerHTML = '<div class="empty" style="padding:24px 0">No settings available.</div>'; return; }
|
|
673
|
-
|
|
687
|
+
// One panel per category; settings laid out in a responsive 2-column grid so a
|
|
688
|
+
// long config list stays scannable on a wide screen.
|
|
689
|
+
el.innerHTML = cats.map((c) => '<div class="panel"><div class="set-cat-h">' + esc(c.title) + "</div>"
|
|
674
690
|
+ (c.blurb ? '<div class="set-cat-b">' + esc(c.blurb) + "</div>" : "")
|
|
675
|
-
+ c.settings.map(settingRow).join("") + "</div>").join("");
|
|
691
|
+
+ '<div class="set-grid">' + c.settings.map(settingRow).join("") + "</div></div>").join("");
|
|
676
692
|
}
|
|
677
693
|
|
|
678
694
|
async function postSetting(key, value, ctl) {
|
|
@@ -721,25 +737,54 @@
|
|
|
721
737
|
const skillTags = '<span class="tag">' + (sk.enigma || 0) + " enigma</span>"
|
|
722
738
|
+ '<span class="tag ext">' + (sk.external || 0) + " external</span>"
|
|
723
739
|
+ ((sk.disabled || 0) ? '<span class="tag">' + sk.disabled + " disabled</span>" : "");
|
|
740
|
+
const sec = s.security || {};
|
|
741
|
+
const ps = s.proxyStats || {};
|
|
742
|
+
const proxyMeasured = (ps.calls || 0) > 0
|
|
743
|
+
? item("Proxy measured · real", '<span class="tag">' + fmt(ps.calls) + " calls</span><span class=\"tag\">"
|
|
744
|
+
+ fmt(ps.input) + " in</span><span class=\"tag\">" + fmt(ps.output) + " out</span><span class=\"tag\">" + fmt(ps.cacheRead) + " cache</span>")
|
|
745
|
+
: "";
|
|
746
|
+
const guard = (sec.guardProtects || []).map((p) => '<span class="tag">' + esc(p) + "</span>").join("");
|
|
724
747
|
el.innerHTML =
|
|
725
748
|
item("Context compression (MCP) · measured", boolPill(s.compress))
|
|
726
749
|
+ item("Real tool-usage stats · measured", boolPill(s.usageStats))
|
|
750
|
+
+ item("Claude Code measuring proxy · experimental", boolPill(s.proxy))
|
|
751
|
+
+ proxyMeasured
|
|
727
752
|
+ item("Token-efficient output", levelPill(s.outputStyle))
|
|
728
753
|
+ item("Minimal code", levelPill(s.minimalCode))
|
|
729
754
|
+ item("Parallel sub-agents", boolPill(s.parallelSubagents))
|
|
730
755
|
+ item("Auto-lint on edit", boolPill(s.autoLint))
|
|
731
756
|
+ item("Commit emoji", boolPill(s.commitEmoji))
|
|
732
757
|
+ item("Local dashboard", pill(s.dashboard === "off" ? "off" : "lvl", s.dashboard || "off"))
|
|
758
|
+
+ item("Permission bypass (security)", boolPill(sec.permissionBypass))
|
|
759
|
+
+ item("Commit guard blocks", guard || '<span class="tag">set up with enigma security</span>')
|
|
733
760
|
+ item("Skills", skillTags);
|
|
734
761
|
}
|
|
735
762
|
|
|
736
|
-
async function
|
|
763
|
+
async function runUpdate() {
|
|
764
|
+
$("updateNote").textContent = "Checking for updates...";
|
|
765
|
+
try {
|
|
766
|
+
const res = await fetch("/api/update", { method: "POST", headers: { "Content-Type": "application/json" }, body: "{}" });
|
|
767
|
+
const out = await res.json();
|
|
768
|
+
$("updateNote").textContent = out.ok ? (out.note || "Updated.") : ("Update failed: " + (out.error || "error"));
|
|
769
|
+
loadSystems();
|
|
770
|
+
if (skillsLoaded) loadSkills();
|
|
771
|
+
} catch { $("updateNote").textContent = "Could not reach the server to update."; }
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
async function loadSystems(force) {
|
|
775
|
+
if (!live && !force) return;
|
|
737
776
|
try {
|
|
738
777
|
const r = await fetch("/api/status", { cache: "no-store" });
|
|
739
|
-
|
|
778
|
+
const sys = (await r.json()).systems;
|
|
779
|
+
if (sys) live = sys.live !== false; // pick up the dashboard-live config
|
|
780
|
+
renderSystems(sys);
|
|
740
781
|
} catch { $("systems").innerHTML = '<div class="empty" style="padding:16px 0">Status unavailable.</div>'; }
|
|
741
782
|
}
|
|
742
783
|
|
|
784
|
+
function onSavings() { const h = (location.hash || "").replace(/^#\/?/, ""); return h !== "settings" && h !== "skills"; }
|
|
785
|
+
// One refresh of everything visible on the Savings view; `force` ignores auto-refresh-off.
|
|
786
|
+
function refreshAll(force) { poll(force); if (onSavings()) loadSystems(force); }
|
|
787
|
+
|
|
743
788
|
// --- skills subpage (lists enigma + external skills over /api/skills) ---
|
|
744
789
|
function skillRow(s) {
|
|
745
790
|
const ver = s.version ? '<span class="tag">v' + esc(s.version) + "</span>" : "";
|
|
@@ -845,15 +890,17 @@
|
|
|
845
890
|
if (v === "settings" && !settingsLoaded) { settingsLoaded = true; loadSettings(); }
|
|
846
891
|
if (v === "skills" && !skillsLoaded) { skillsLoaded = true; loadSkills(); }
|
|
847
892
|
// The chart was sized while its view may have been hidden; nudge it on return.
|
|
848
|
-
if (v === "savings") { loadSystems(); if (chart) { try { applyRange(); } catch { /* not ready */ } } }
|
|
893
|
+
if (v === "savings") { loadSystems(true); if (chart) { try { applyRange(); } catch { /* not ready */ } } }
|
|
849
894
|
}
|
|
850
895
|
|
|
851
896
|
initChart();
|
|
852
|
-
poll();
|
|
853
|
-
setInterval(
|
|
854
|
-
document.addEventListener("visibilitychange", () => { if (!document.hidden)
|
|
897
|
+
poll(true);
|
|
898
|
+
setInterval(() => refreshAll(false), POLL_MS);
|
|
899
|
+
document.addEventListener("visibilitychange", () => { if (!document.hidden) refreshAll(true); });
|
|
855
900
|
wireSettings();
|
|
856
901
|
wireSkills();
|
|
902
|
+
$("updateBtn").addEventListener("click", runUpdate);
|
|
903
|
+
$("refreshBtn").addEventListener("click", () => refreshAll(true));
|
|
857
904
|
window.addEventListener("hashchange", route);
|
|
858
905
|
route();
|
|
859
906
|
</script>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/dashboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
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": [
|