@enigmax/dashboard 0.1.12 → 0.1.14
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 +113 -19
- package/package.json +1 -1
package/assets/index.html
CHANGED
|
@@ -8,40 +8,67 @@
|
|
|
8
8
|
:root {
|
|
9
9
|
--bg: #0b0e14; --surface: #151a23; --surface2: #1b2230; --border: #232a36;
|
|
10
10
|
--text: #e6e6e6; --muted: #8a93a3; --accent: #e0a458; --accent2: #d7875f; --good: #6fcf97;
|
|
11
|
+
/* Type roles: a monospace "machine readout" face carries the brand, headings,
|
|
12
|
+
labels and numeric data (this is a CLI tool's dashboard); sans carries prose. */
|
|
13
|
+
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
|
14
|
+
--sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
15
|
+
--ring: rgba(224,164,88,0.6);
|
|
11
16
|
}
|
|
12
17
|
* { box-sizing: border-box; }
|
|
13
18
|
body {
|
|
14
19
|
margin: 0; background: var(--bg); color: var(--text);
|
|
15
|
-
font-family:
|
|
20
|
+
font-family: var(--sans);
|
|
16
21
|
-webkit-font-smoothing: antialiased; padding: 24px; max-width: 2200px; margin: 0 auto;
|
|
17
22
|
}
|
|
18
23
|
a { color: var(--accent2); }
|
|
24
|
+
/* Quality floor: one visible keyboard-focus ring for every interactive control
|
|
25
|
+
(the custom-styled buttons/tabs/links carry no native outline otherwise). */
|
|
26
|
+
a:focus-visible, button:focus-visible, select:focus-visible,
|
|
27
|
+
input:focus-visible, [tabindex]:focus-visible {
|
|
28
|
+
outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 6px;
|
|
29
|
+
}
|
|
30
|
+
@media (prefers-reduced-motion: reduce) {
|
|
31
|
+
*, *::before, *::after {
|
|
32
|
+
animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
|
|
33
|
+
transition-duration: 0.01ms !important;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
19
36
|
header { display: flex; align-items: center; gap: 20px; margin-bottom: 24px; flex-wrap: wrap; }
|
|
20
|
-
.brand { display: flex; flex-direction: column; }
|
|
21
|
-
.wordmark {
|
|
22
|
-
|
|
23
|
-
|
|
37
|
+
.brand { display: flex; flex-direction: column; gap: 3px; }
|
|
38
|
+
.wordmark {
|
|
39
|
+
font-family: var(--mono); font-size: 19px; font-weight: 600; letter-spacing: 0.5px;
|
|
40
|
+
display: inline-flex; align-items: center;
|
|
41
|
+
}
|
|
42
|
+
/* Signature: a blinking block caret turns the wordmark into a live terminal prompt. */
|
|
43
|
+
.wordmark span {
|
|
44
|
+
display: inline-block; width: 0.46em; height: 1.05em; margin-left: 4px;
|
|
45
|
+
background: var(--accent); transform: translateY(1px); text-indent: -9999px; overflow: hidden;
|
|
46
|
+
animation: caret 1.1s steps(1, end) infinite;
|
|
47
|
+
}
|
|
48
|
+
@keyframes caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }
|
|
49
|
+
.sub { font-family: var(--mono); color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 1.4px; }
|
|
24
50
|
.tabs { display: flex; gap: 4px; }
|
|
25
51
|
.tabs .tab {
|
|
26
|
-
text-decoration: none; color: var(--muted); font-size:
|
|
27
|
-
padding: 7px
|
|
52
|
+
font-family: var(--mono); text-decoration: none; color: var(--muted); font-size: 12px; font-weight: 600;
|
|
53
|
+
padding: 7px 14px; border-radius: 8px; border: 1px solid transparent; transition: background .15s, color .15s, border-color .15s;
|
|
28
54
|
}
|
|
29
55
|
.tabs .tab:hover { color: var(--text); background: var(--surface); }
|
|
30
56
|
.tabs .tab.active { color: var(--accent); background: var(--surface); border-color: var(--border); }
|
|
31
|
-
.live { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 12px; }
|
|
57
|
+
.live { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 12px; font-family: var(--mono); }
|
|
32
58
|
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--good); box-shadow: 0 0 8px var(--good); }
|
|
33
59
|
.dot.stale { background: var(--muted); box-shadow: none; }
|
|
34
60
|
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
|
|
35
|
-
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 16px; }
|
|
36
|
-
.card
|
|
37
|
-
.card .
|
|
61
|
+
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 16px; transition: border-color .15s; }
|
|
62
|
+
.card:hover { border-color: var(--surface2); }
|
|
63
|
+
.card .label { font-family: var(--mono); color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.7px; }
|
|
64
|
+
.card .value { font-family: var(--mono); font-size: 28px; font-weight: 600; margin-top: 8px; font-variant-numeric: tabular-nums; letter-spacing: -0.5px; }
|
|
38
65
|
.card .value.accent { color: var(--accent); }
|
|
39
66
|
.card .value.good { color: var(--good); }
|
|
40
67
|
.card .foot { color: var(--muted); font-size: 12px; margin-top: 4px; }
|
|
41
68
|
.panel { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 18px; margin-bottom: 20px; }
|
|
42
69
|
.panel-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
|
|
43
|
-
.panel h2 { font-size:
|
|
44
|
-
.panel h2 small { color: var(--muted); font-weight: 400; margin-left: 8px; }
|
|
70
|
+
.panel h2 { font-family: var(--mono); font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.8px; margin: 0; color: var(--text); }
|
|
71
|
+
.panel h2 small { font-family: var(--sans); color: var(--muted); font-weight: 400; font-size: 12px; text-transform: none; letter-spacing: 0; margin-left: 8px; }
|
|
45
72
|
.ctrls { margin-left: auto; display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
|
|
46
73
|
.ranges { display: flex; gap: 4px; }
|
|
47
74
|
.ranges button {
|
|
@@ -85,11 +112,11 @@
|
|
|
85
112
|
footer { color: var(--muted); font-size: 12px; line-height: 1.6; margin-top: 8px; }
|
|
86
113
|
code { background: var(--surface2); padding: 1px 6px; border-radius: 5px; color: var(--accent2); }
|
|
87
114
|
.page-head { margin-bottom: 18px; }
|
|
88
|
-
.page-head h1 { font-size: 18px; font-weight:
|
|
115
|
+
.page-head h1 { font-family: var(--mono); font-size: 18px; font-weight: 600; letter-spacing: 0.3px; margin: 0 0 4px; }
|
|
89
116
|
.page-head p { color: var(--muted); font-size: 13px; margin: 0; max-width: 720px; line-height: 1.5; }
|
|
90
117
|
.set-cat { margin-bottom: 18px; }
|
|
91
118
|
.set-cat:last-child { margin-bottom: 0; }
|
|
92
|
-
.set-cat-h { color: var(--accent); font-size: 12px; text-transform: uppercase; letter-spacing: 0.
|
|
119
|
+
.set-cat-h { font-family: var(--mono); color: var(--accent); font-size: 12px; text-transform: uppercase; letter-spacing: 0.7px; margin-bottom: 4px; }
|
|
93
120
|
.set-cat-b { color: var(--muted); font-size: 12px; margin-bottom: 8px; }
|
|
94
121
|
.set-row { display: flex; align-items: center; gap: 14px; padding: 9px 0; border-bottom: 1px solid var(--surface2); }
|
|
95
122
|
.set-row:last-child { border-bottom: none; }
|
|
@@ -150,6 +177,22 @@
|
|
|
150
177
|
.wval.muted { font-size: 14px; font-weight: 500; color: var(--muted); }
|
|
151
178
|
.wset { display: flex; gap: 6px; margin-top: 10px; }
|
|
152
179
|
.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; }
|
|
180
|
+
/* Fix-path result: per-tool rows with a status dot, badge, reason and resolved path. */
|
|
181
|
+
.fixres { margin-top: 12px; display: none; }
|
|
182
|
+
.fixres.show { display: block; }
|
|
183
|
+
.fixres-head { font-size: 13px; font-weight: 600; margin-bottom: 4px; }
|
|
184
|
+
.fixres-head.ok { color: var(--good); }
|
|
185
|
+
.fixres-head.fixed { color: var(--accent); }
|
|
186
|
+
.fixres-head.bad { color: var(--accent2); }
|
|
187
|
+
.fxrow { display: flex; align-items: flex-start; gap: 10px; padding: 9px 0; border-top: 1px solid var(--surface2); }
|
|
188
|
+
.fxdot { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; flex: 0 0 auto; }
|
|
189
|
+
.fxdot.ok { background: var(--good); }
|
|
190
|
+
.fxdot.fixed { background: var(--accent); }
|
|
191
|
+
.fxdot.bad { background: var(--accent2); }
|
|
192
|
+
.fxmain { min-width: 0; flex: 1; }
|
|
193
|
+
.fxtitle { font-size: 13px; display: flex; align-items: center; gap: 8px; }
|
|
194
|
+
.fxmsg { color: var(--muted); font-size: 12px; margin-top: 2px; }
|
|
195
|
+
.fxpath { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; color: var(--muted); margin-top: 3px; word-break: break-all; }
|
|
153
196
|
.sys-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 0 24px; }
|
|
154
197
|
.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; }
|
|
155
198
|
.sys-item .k { color: var(--muted); }
|
|
@@ -157,13 +200,20 @@
|
|
|
157
200
|
.pill.on { color: #06210f; background: var(--good); border-color: var(--good); font-weight: 600; }
|
|
158
201
|
.pill.off { color: var(--muted); background: var(--surface2); }
|
|
159
202
|
.pill.lvl { color: #1a1206; background: var(--accent); border-color: var(--accent); font-weight: 600; }
|
|
160
|
-
@media (max-width: 720px) {
|
|
203
|
+
@media (max-width: 720px) {
|
|
204
|
+
body { padding: 16px; }
|
|
205
|
+
.grid { grid-template-columns: repeat(2, 1fr); }
|
|
206
|
+
header { gap: 12px; }
|
|
207
|
+
.tabs { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
|
208
|
+
.tabs .tab { white-space: nowrap; }
|
|
209
|
+
.nav { margin-left: 0; }
|
|
210
|
+
}
|
|
161
211
|
</style>
|
|
162
212
|
</head>
|
|
163
213
|
<body>
|
|
164
214
|
<header>
|
|
165
215
|
<div class="brand">
|
|
166
|
-
<div class="wordmark">Enigma<span>.</span></div>
|
|
216
|
+
<div class="wordmark">Enigma<span aria-hidden="true">.</span></div>
|
|
167
217
|
<div class="sub">Savings dashboard</div>
|
|
168
218
|
</div>
|
|
169
219
|
<nav class="tabs">
|
|
@@ -212,6 +262,7 @@
|
|
|
212
262
|
<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>
|
|
213
263
|
<div id="systems" class="sys-grid"><div class="empty" style="padding:16px 0">Loading...</div></div>
|
|
214
264
|
<div id="updateNote" class="set-note"></div>
|
|
265
|
+
<div id="fixPathResult" class="fixres"></div>
|
|
215
266
|
</div>
|
|
216
267
|
|
|
217
268
|
<div class="panel">
|
|
@@ -1039,13 +1090,56 @@
|
|
|
1039
1090
|
// Detect & repair every tool's launch path; the server persists any off-PATH
|
|
1040
1091
|
// binary so `enigma <tool>` works, and returns the refreshed status.
|
|
1041
1092
|
async function runFixPath() {
|
|
1093
|
+
const btn = $("fixPathBtn");
|
|
1094
|
+
$("fixPathResult").className = "fixres";
|
|
1042
1095
|
$("updateNote").textContent = "Detecting tool paths...";
|
|
1096
|
+
if (btn) { btn.disabled = true; }
|
|
1043
1097
|
try {
|
|
1044
1098
|
const res = await fetch("/api/fix-path", { method: "POST", headers: { "Content-Type": "application/json" }, body: "{}" });
|
|
1045
1099
|
const out = await res.json();
|
|
1046
|
-
$("updateNote").textContent =
|
|
1100
|
+
$("updateNote").textContent = "";
|
|
1101
|
+
renderFixPath(out);
|
|
1047
1102
|
loadSystems(true);
|
|
1048
|
-
} catch {
|
|
1103
|
+
} catch {
|
|
1104
|
+
$("updateNote").textContent = "";
|
|
1105
|
+
$("fixPathResult").className = "fixres show";
|
|
1106
|
+
$("fixPathResult").innerHTML = '<div class="fixres-head bad">Could not reach the server to fix tool paths.</div>';
|
|
1107
|
+
} finally { if (btn) { btn.disabled = false; } }
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// Short, non-redundant reason per tool (the resolved path is shown separately below).
|
|
1111
|
+
function fixReason(r) {
|
|
1112
|
+
if (!r.installed) return "Not installed. Install it, then run fix-path again.";
|
|
1113
|
+
if (r.changed) return "Found off PATH and saved - 'enigma " + esc(r.command) + "' now launches it.";
|
|
1114
|
+
return "Launchable - '" + esc(r.command) + "' works.";
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Render the fix-path outcome as one row per tool: status dot + badge + reason + path.
|
|
1118
|
+
function renderFixPath(out) {
|
|
1119
|
+
const box = $("fixPathResult");
|
|
1120
|
+
const results = out.results || [];
|
|
1121
|
+
box.className = "fixres show";
|
|
1122
|
+
if (!results.length) {
|
|
1123
|
+
box.innerHTML = '<div class="fxmsg">' + esc((out.lines || []).join(" ") || (out.ok ? "Tool paths OK." : "Could not fix tools.")) + "</div>";
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
const fixedN = results.filter((r) => r.changed).length;
|
|
1127
|
+
const badN = results.filter((r) => !r.ok).length;
|
|
1128
|
+
let head, hc;
|
|
1129
|
+
if (badN) { head = badN + " of " + results.length + " tools need attention"; hc = "bad"; }
|
|
1130
|
+
else if (fixedN) { head = "Repaired " + fixedN + " of " + results.length + " tools - all launchable now"; hc = "fixed"; }
|
|
1131
|
+
else { head = "All " + results.length + " tools launchable"; hc = "ok"; }
|
|
1132
|
+
const rows = results.map((r) => {
|
|
1133
|
+
const cls = !r.ok ? "bad" : (r.changed ? "fixed" : "ok");
|
|
1134
|
+
const badge = !r.ok ? '<span class="pill off">not found</span>'
|
|
1135
|
+
: (r.changed ? '<span class="pill lvl">fixed</span>' : '<span class="pill on">ok</span>');
|
|
1136
|
+
return '<div class="fxrow"><span class="fxdot ' + cls + '"></span><div class="fxmain">'
|
|
1137
|
+
+ '<div class="fxtitle">' + esc(r.label) + " " + badge + "</div>"
|
|
1138
|
+
+ '<div class="fxmsg">' + fixReason(r) + "</div>"
|
|
1139
|
+
+ (r.path ? '<div class="fxpath">' + esc(r.path) + "</div>" : "")
|
|
1140
|
+
+ "</div></div>";
|
|
1141
|
+
}).join("");
|
|
1142
|
+
box.innerHTML = '<div class="fixres-head ' + hc + '">' + esc(head) + "</div>" + rows;
|
|
1049
1143
|
}
|
|
1050
1144
|
|
|
1051
1145
|
async function loadSystems(force) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/dashboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
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": [
|