@enigmax/dashboard 0.1.106 → 0.1.108

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.
Files changed (2) hide show
  1. package/assets/index.html +62 -13
  2. package/package.json +1 -1
package/assets/index.html CHANGED
@@ -88,6 +88,11 @@
88
88
  }
89
89
  @keyframes caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }
90
90
  .sub { font-family: var(--mono); color: var(--muted); font-size: 10.5px; text-transform: uppercase; letter-spacing: 1.6px; }
91
+ /* Explanatory prose. `.sub` is a label style - uppercase, mono, wide tracking - and
92
+ a paragraph set in it is unreadable and looks generated. Sentences get a sentence
93
+ face, a real line-height, and a measure that stops before the eye loses the line. */
94
+ .lede { color: var(--muted); font-size: 13px; line-height: 1.55; max-width: 78ch; }
95
+ .lede b { color: var(--text); font-weight: 600; }
91
96
  /* Sections as a vertical rail: the sidebar is already the surface, so the active
92
97
  entry is a filled pill and the rest are plain rows. */
93
98
  .tabs { display: flex; flex-direction: column; gap: 2px; }
@@ -115,7 +120,12 @@
115
120
  .live { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 12px; font-family: var(--mono); padding: 5px 12px; background: rgba(0,0,0,0.25); border: 1px solid var(--border-soft); border-radius: 999px; }
116
121
  .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--good); box-shadow: 0 0 8px var(--good); }
117
122
  .dot.stale { background: var(--muted); box-shadow: none; }
118
- .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(166px, 1fr)); gap: 14px; margin-bottom: 22px; }
123
+ /* Four columns, not auto-fill. auto-fill packed as many 166px cards per row as fit,
124
+ which left whatever did not divide evenly as dead space on the right - and letting
125
+ them grow into it instead produced 580px cards containing the digit 0. A fixed
126
+ four with the hero spanning two divides exactly, and the cards get a readable size
127
+ rather than the smallest one that fits. */
128
+ .grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin-bottom: 22px; }
119
129
  .card {
120
130
  position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
121
131
  padding: 18px; box-shadow: var(--shadow-1); overflow: hidden;
@@ -183,7 +193,10 @@
183
193
  .bar-fill { height: 100%; border-radius: 999px; transition: width .4s cubic-bezier(.4,0,.2,1); }
184
194
  .bar-row .num { width: 90px; text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
185
195
  .bar-row .money { width: 78px; text-align: right; color: var(--good); font-family: var(--mono); font-variant-numeric: tabular-nums; }
186
- .empty { color: var(--muted); font-size: 14px; text-align: center; padding: 40px 0; }
196
+ /* Spans every column: an empty state dropped into a grid container was sitting in
197
+ the first cell, so "Status unavailable." read as left-aligned in a full-width
198
+ panel. Ignored outside a grid, so one rule covers both. */
199
+ .empty { grid-column: 1 / -1; color: var(--muted); font-size: 14px; text-align: center; padding: 32px 0; }
187
200
  .tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
188
201
  .tbl th { position: sticky; top: 0; z-index: 1; text-align: left; background: var(--surface); color: var(--muted); font-family: var(--mono); font-weight: 600; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.6px; padding: 8px 10px; border-bottom: 1px solid var(--border); }
189
202
  .tbl td { padding: 8px 10px; border-bottom: 1px solid var(--border-soft); font-variant-numeric: tabular-nums; }
@@ -570,7 +583,7 @@
570
583
  }
571
584
  @media (max-width: 720px) {
572
585
  .content { padding: 16px; }
573
- .grid { grid-template-columns: repeat(2, 1fr); }
586
+ .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
574
587
  header { gap: 12px; }
575
588
  .nav { margin-left: auto; flex-wrap: wrap; gap: 10px; }
576
589
  /* A settings row is label + controls side by side, and the control cluster is
@@ -895,7 +908,7 @@
895
908
  <button id="updateBtn" type="button" class="toggle on">Check &amp; update</button>
896
909
  </div>
897
910
  </div>
898
- <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>
911
+ <div class="lede" 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>
899
912
  <div id="systems" class="sys-grid"><div class="empty" style="padding:16px 0">Loading...</div></div>
900
913
  <div id="updateNote" class="set-note"></div>
901
914
  <div id="fixPathResult" class="fixres"></div>
@@ -989,7 +1002,7 @@
989
1002
  </div>
990
1003
  <div class="panel" id="usagePanel" style="display:none">
991
1004
  <h2 style="margin:0 0 4px">Usage limits <small>same windows Claude Code shows</small></h2>
992
- <div class="sub" style="margin-bottom:12px">Cards marked <span class="tag meas">live</span> show the <b>real % and reset</b> Anthropic reports (the same as Claude's own UI). Turn on <code>enigma config usage-api on</code> to fetch them with your local Claude Code login - no proxy or plan limit needed. (The proxy also captures them from <code>enigma claude</code> traffic.) Until live data lands, the card falls back to tokens used, or a % against a plan limit you set (on the card, or <code>enigma config plan-weekly-limit &lt;tokens&gt;</code>). Per-model live data appears only when Anthropic sends it.</div>
1005
+ <div class="lede" style="margin-bottom:12px">Cards marked <span class="tag meas">live</span> show the <b>real % and reset</b> Anthropic reports (the same as Claude's own UI). Turn on <code>enigma config usage-api on</code> to fetch them with your local Claude Code login - no proxy or plan limit needed. (The proxy also captures them from <code>enigma claude</code> traffic.) Until live data lands, the card falls back to tokens used, or a % against a plan limit you set (on the card, or <code>enigma config plan-weekly-limit &lt;tokens&gt;</code>). Per-model live data appears only when Anthropic sends it.</div>
993
1006
  <div id="uWindows"></div>
994
1007
  <div class="grid" style="margin-bottom:16px">
995
1008
  <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>
@@ -1009,7 +1022,7 @@
1009
1022
  <div>Projected <b id="uBlockProj">-</b></div>
1010
1023
  </div>
1011
1024
  </div>
1012
- <div id="uProviders" class="sub" style="margin:4px 0 0"></div>
1025
+ <div id="uProviders" class="lede" style="margin:4px 0 0"></div>
1013
1026
  <div id="uByAccountWrap">
1014
1027
  <h2 style="margin:18px 0 10px">By Account <small>per Claude login</small></h2>
1015
1028
  <div id="uByAccount"></div>
@@ -1023,11 +1036,11 @@
1023
1036
  </div>
1024
1037
  <div class="panel" id="usageHint" style="display:none">
1025
1038
  <h2 style="margin-bottom:8px">Real tool usage <small>opt-in</small></h2>
1026
- <div class="sub">Turn on <b>Real tool-usage stats</b> in <a href="#/settings">Settings</a> to read your Claude Code sessions for token consumption and cost. enigma reads only your local session transcripts; nothing is sent anywhere.</div>
1039
+ <div class="lede">Turn on <b>Real tool-usage stats</b> in <a href="#/settings">Settings</a> to read your Claude Code sessions for token consumption and cost. enigma reads only your local session transcripts; nothing is sent anywhere.</div>
1027
1040
  </div>
1028
1041
  <div class="panel" id="usageUnavail" style="display:none">
1029
1042
  <h2 id="unavailTitle" style="margin-bottom:8px">No local usage data</h2>
1030
- <div class="sub" id="unavailBody"></div>
1043
+ <div class="lede" id="unavailBody"></div>
1031
1044
  </div>
1032
1045
  </section>
1033
1046
 
@@ -1140,7 +1153,7 @@
1140
1153
 
1141
1154
  <div class="panel" id="gateSetPanel">
1142
1155
  <div class="set-cat-h">Pipeline settings</div>
1143
- <div class="sub" style="margin-bottom:10px">What the daemon runs and how hard it tries. Model and auto-fix limits are what a run's duration and token cost actually hang on.</div>
1156
+ <div class="lede" style="margin-bottom:10px">What the daemon runs and how hard it tries. Model and auto-fix limits are what a run's duration and token cost actually hang on.</div>
1144
1157
  <div class="set-grid">
1145
1158
  <div class="set-row">
1146
1159
  <div class="set-meta"><div class="set-name">Agent</div><div class="set-hint" id="gateAgentHint">which coding agent the pipeline drives</div></div>
@@ -1164,7 +1177,7 @@
1164
1177
  </div>
1165
1178
  </div>
1166
1179
  <div class="set-cat-h" style="margin-top:18px">Findings</div>
1167
- <div class="sub" style="margin-bottom:10px">Who decides what happens to something the review turns up.</div>
1180
+ <div class="lede" style="margin-bottom:10px">Who decides what happens to something the review turns up.</div>
1168
1181
  <div class="set-grid">
1169
1182
  <div class="set-row span">
1170
1183
  <div class="set-meta"><div class="set-name">When the gate finds something</div><div class="set-hint" id="gateFixHint"></div></div>
@@ -1172,13 +1185,13 @@
1172
1185
  </div>
1173
1186
  </div>
1174
1187
  <div class="set-cat-h" style="margin-top:18px">Auto-fix attempts</div>
1175
- <div class="sub" style="margin-bottom:10px">Follow-up rounds a step gets before it pauses for you. Every round is another full agent pass over the diff, so this is the setting that multiplies a run's cost. 0 pauses immediately.</div>
1188
+ <div class="lede" style="margin-bottom:10px">Follow-up rounds a step gets before it pauses for you. Every round is another full agent pass over the diff, so this is the setting that multiplies a run's cost. 0 pauses immediately.</div>
1176
1189
  <div class="set-grid" id="gateAutoFix"></div>
1177
1190
  </div>
1178
1191
 
1179
1192
  <div class="panel" id="gateRepoPanel" style="display:none">
1180
1193
  <div class="set-cat-h">Repository configuration</div>
1181
- <div class="sub" style="margin-bottom:10px">Committed with the repository and merged over the global config. Only the fields the gate trusts from a branch take effect.</div>
1194
+ <div class="lede" style="margin-bottom:10px">Committed with the repository and merged over the global config. Only the fields the gate trusts from a branch take effect.</div>
1182
1195
  <textarea id="gateRepoCfg" class="linput gate-yaml" spellcheck="false" autocapitalize="none" autocorrect="off" aria-label="Repository gate configuration"></textarea>
1183
1196
  <div class="ladd" style="gap:8px;align-items:center">
1184
1197
  <button id="gateRepoCfgSave" type="button" class="toggle on" disabled title="No changes to save">Save</button>
@@ -1326,7 +1339,7 @@
1326
1339
  <div class="page-head" style="display:flex;align-items:flex-start;gap:16px">
1327
1340
  <div style="flex:1">
1328
1341
  <h1>Code graph</h1>
1329
- <p>Structural memory of your codebase - a native knowledge graph of the symbols each file defines, the modules it imports and cross-file references. Enabling it exposes enigma's code-graph tools to your agents over MCP. Complements <a href="#/recall">Recall</a> (session memory).</p>
1342
+ <p>Structural memory of your codebase - a native knowledge graph of the symbols each file defines, what imports what, and which symbol calls which. Your agents query it over MCP to find code, trace a change's blast radius and read a file's API surface without opening it. Complements <a href="#/recall">Recall</a> (session memory).</p>
1330
1343
  </div>
1331
1344
  <button id="cgToggle" type="button" class="toggle" data-kind="bool" role="switch" aria-checked="false" aria-label="Code graph">Off</button>
1332
1345
  <button id="cgRefresh" type="button" class="iconbtn" title="Refresh" aria-label="Refresh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M23 4v6h-6"/><path d="M1 20v-6h6"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg></button>
@@ -1337,6 +1350,12 @@
1337
1350
  <div class="set-hint" style="padding:4px 0">Build the graph for a codebase. Leave the path empty to index enigma's own working directory.</div>
1338
1351
  <div class="ladd" style="gap:8px;flex-wrap:wrap"><input id="cgRoot" class="linput" placeholder="absolute project path (optional)" style="flex:1;min-width:240px"><button id="cgIndex" type="button" class="toggle on">Index</button></div>
1339
1352
  </div>
1353
+ <div class="panel">
1354
+ <div class="set-cat-h">Ask the graph</div>
1355
+ <div class="set-hint" style="padding:4px 0">Describe a task and get the symbols and files it concerns, ranked, with exact line numbers. The same answer your agents get from the MCP tools.</div>
1356
+ <div class="ladd" style="gap:8px;flex-wrap:wrap"><input id="cgQuery" class="linput" placeholder="where is the session token refreshed?" style="flex:1;min-width:240px"><button id="cgAsk" type="button" class="toggle on">Ask</button></div>
1357
+ <div id="cgAskOut"></div>
1358
+ </div>
1340
1359
  <div id="cgBody"><div class="empty" style="padding:12px 0">Loading...</div></div>
1341
1360
  </section>
1342
1361
 
@@ -5567,9 +5586,25 @@ export {
5567
5586
  }).join("")
5568
5587
  : '<div class="empty" style="padding:12px 0">No projects indexed yet. Use "Index a project" above.</div>';
5569
5588
  let html = '<div class="panel"><div class="set-cat-h">Indexed projects <small>' + projects.length + "</small></div>" + projHtml + "</div>";
5589
+ // Drift is stated, not hidden: a graph that has fallen behind the code answers
5590
+ // confidently and wrongly, and the only cue would otherwise be a stale line number.
5591
+ const fresh = view.freshness;
5592
+ if (fresh) {
5593
+ const stale = fresh.stale || 0;
5594
+ html += '<div class="panel"><div class="set-cat-h">Freshness</div><div class="set-row"><div class="set-meta"><div class="set-name">'
5595
+ + (stale === 0 ? "Up to date" : stale + " file" + (stale === 1 ? "" : "s") + " changed since indexing")
5596
+ + '</div><div class="set-hint">' + esc("indexed " + new Date(fresh.indexedAt).toLocaleString()
5597
+ + (fresh.truncated ? " · incomplete: the scan hit a limit, so some files were never indexed" : "")) + "</div></div>"
5598
+ + (stale === 0 ? "" : '<div class="set-ctl"><button type="button" class="toggle on" data-cg-reindex="' + esc(fresh.root) + '">Re-index</button></div>')
5599
+ + "</div></div>";
5600
+ }
5570
5601
  if (view.architecture) html += cgSection("Architecture" + (view.selected ? " - " + view.selected : ""), view.architecture);
5571
5602
  if (view.schema) html += cgSection("Graph schema", view.schema);
5572
5603
  $("cgBody").innerHTML = html;
5604
+ const ask = view.ask;
5605
+ $("cgAskOut").innerHTML = ask
5606
+ ? '<pre style="white-space:pre-wrap;overflow-x:auto;margin:10px 0 0;font-size:12px">' + esc(ask.report) + "</pre>"
5607
+ : "";
5573
5608
  }
5574
5609
  async function loadCodeGraph() {
5575
5610
  $("cgNote").textContent = "";
@@ -5596,11 +5631,25 @@ export {
5596
5631
  const out = await cgPost({ op: "index", root: root || undefined }, "Indexing...");
5597
5632
  if (out) { if (out.view && out.view.selected) cgProject = out.view.selected; setNote("cgNote", out.ok ? "Indexed." : (out.error || "Indexing failed."), out.ok ? "ok" : "err"); }
5598
5633
  }
5634
+ async function cgAskAction() {
5635
+ const query = $("cgQuery").value.trim();
5636
+ if (!query) { setNote("cgNote", "Type a question first.", "err"); return; }
5637
+ const out = await cgPost({ op: "ask", query, project: cgProject || undefined }, "Searching...");
5638
+ if (out) setNote("cgNote", out.ok ? "" : (out.error || "Query failed."), out.ok ? "ok" : "err");
5639
+ }
5599
5640
  function wireCodeGraph() {
5600
5641
  $("cgRefresh").addEventListener("click", loadCodeGraph);
5601
5642
  $("cgToggle").addEventListener("click", cgToggleAction);
5602
5643
  $("cgIndex").addEventListener("click", cgIndexAction);
5644
+ $("cgAsk").addEventListener("click", cgAskAction);
5645
+ $("cgQuery").addEventListener("keydown", (e) => { if (e.key === "Enter") cgAskAction(); });
5603
5646
  $("view-codegraph").addEventListener("click", (e) => {
5647
+ const reindex = e.target.closest("button[data-cg-reindex]");
5648
+ if (reindex) {
5649
+ cgPost({ op: "index", root: reindex.dataset.cgReindex }, "Re-indexing...")
5650
+ .then((out) => { if (out) setNote("cgNote", out.ok ? "Re-indexed." : (out.error || "Indexing failed."), out.ok ? "ok" : "err"); });
5651
+ return;
5652
+ }
5604
5653
  const b = e.target.closest("button[data-cg-project]");
5605
5654
  if (!b) return;
5606
5655
  cgProject = b.dataset.cgProject;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enigmax/dashboard",
3
- "version": "0.1.106",
3
+ "version": "0.1.108",
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": [