@enigmax/dashboard 0.1.69 → 0.1.70
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 +94 -1
- package/package.json +1 -1
package/assets/index.html
CHANGED
|
@@ -526,6 +526,7 @@
|
|
|
526
526
|
<a href="#/settings" data-view="settings" class="tab">Settings</a>
|
|
527
527
|
<a href="#/resources" data-view="resources" class="tab">Resources</a>
|
|
528
528
|
<a href="#/recall" data-view="recall" class="tab">Recall</a>
|
|
529
|
+
<a href="#/codegraph" data-view="codegraph" class="tab">Code graph</a>
|
|
529
530
|
<a href="#/packs" data-view="packs" class="tab">Packs</a>
|
|
530
531
|
</nav>
|
|
531
532
|
<div class="nav">
|
|
@@ -873,6 +874,19 @@
|
|
|
873
874
|
<div id="recallList"></div>
|
|
874
875
|
</section>
|
|
875
876
|
|
|
877
|
+
<section id="view-codegraph" style="display:none">
|
|
878
|
+
<div class="page-head" style="display:flex;align-items:flex-start;gap:16px">
|
|
879
|
+
<div style="flex:1">
|
|
880
|
+
<h1>Code graph</h1>
|
|
881
|
+
<p>Structural memory of your codebase - a knowledge graph of symbols, call chains, and routes. Enabling it registers the code-intelligence server in your agents so they can query the graph over MCP. Complements <a href="#/recall">Recall</a> (session memory).</p>
|
|
882
|
+
</div>
|
|
883
|
+
<button id="cgToggle" type="button" class="toggle" role="switch" aria-checked="false" aria-label="Codebase memory">off</button>
|
|
884
|
+
<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>
|
|
885
|
+
</div>
|
|
886
|
+
<div id="cgNote" class="set-note"></div>
|
|
887
|
+
<div id="cgBody"><div class="empty" style="padding:12px 0">Loading...</div></div>
|
|
888
|
+
</section>
|
|
889
|
+
|
|
876
890
|
<footer>
|
|
877
891
|
Polling pauses automatically when this tab is hidden, and the server caches each snapshot - so an open dashboard costs almost nothing.
|
|
878
892
|
Data source: <code>~/.enigma/ccr/stats.json</code> + <code>history.jsonl</code> - reset it with <code>enigma compress --clear</code>. Enigma <span id="ver"></span>
|
|
@@ -3156,6 +3170,7 @@ export {
|
|
|
3156
3170
|
const guard = (sec.guardProtects || []).map((p) => '<span class="tag">' + esc(p) + "</span>").join("");
|
|
3157
3171
|
el.innerHTML =
|
|
3158
3172
|
item("Context compression (MCP) · measured", boolPill(s.compress))
|
|
3173
|
+
+ item("Codebase memory / code graph (MCP)", boolPill(s.codeGraph))
|
|
3159
3174
|
+ item("Real tool-usage stats · measured", boolPill(s.usageStats))
|
|
3160
3175
|
+ item("Claude Code proxy · experimental", boolPill(s.proxy))
|
|
3161
3176
|
+ item("Live usage windows · real", boolPill(s.usageApi))
|
|
@@ -3713,7 +3728,7 @@ export {
|
|
|
3713
3728
|
|
|
3714
3729
|
// --- hash routing between the subpages ---
|
|
3715
3730
|
// Single source of truth for the subpage ids (savings is the default/fallback).
|
|
3716
|
-
const VIEWS = ["savings", "usage", "accounts", "skills", "settings", "resources", "recall", "packs"];
|
|
3731
|
+
const VIEWS = ["savings", "usage", "accounts", "skills", "settings", "resources", "recall", "codegraph", "packs"];
|
|
3717
3732
|
// Views that apply to a single project; the rest are global/machine-level only.
|
|
3718
3733
|
const PROJECT_VIEWS = ["settings", "skills"];
|
|
3719
3734
|
let activeView = "savings";
|
|
@@ -3734,6 +3749,7 @@ export {
|
|
|
3734
3749
|
else if (v === "usage") { loadProviderStatus(); if (!usageAccountsLoaded) { usageAccountsLoaded = true; loadUsageAccounts(); } }
|
|
3735
3750
|
else if (v === "resources") loadResources();
|
|
3736
3751
|
else if (v === "recall") loadRecall();
|
|
3752
|
+
else if (v === "codegraph") loadCodeGraph();
|
|
3737
3753
|
else if (v === "packs") loadPacks();
|
|
3738
3754
|
// The chart was sized while its view may have been hidden; nudge it on return.
|
|
3739
3755
|
else if (v === "savings") { loadSystems(true); if (chart) { try { applyRange(); } catch { /* not ready */ } } }
|
|
@@ -3857,6 +3873,82 @@ export {
|
|
|
3857
3873
|
});
|
|
3858
3874
|
}
|
|
3859
3875
|
|
|
3876
|
+
// --- code graph subpage (structural code memory) ---
|
|
3877
|
+
let cgProject = null;
|
|
3878
|
+
// A single architecture/schema field, rendered defensively (shape varies by tool version).
|
|
3879
|
+
function cgItem(x) {
|
|
3880
|
+
if (x && typeof x === "object") return String(x.name || x.label || x.path || x.id || JSON.stringify(x)).slice(0, 60);
|
|
3881
|
+
return String(x);
|
|
3882
|
+
}
|
|
3883
|
+
function cgVal(v) {
|
|
3884
|
+
if (Array.isArray(v)) {
|
|
3885
|
+
if (!v.length) return '<span class="tag">none</span>';
|
|
3886
|
+
return v.slice(0, 12).map((x) => '<span class="tag">' + esc(cgItem(x)) + "</span>").join(" ")
|
|
3887
|
+
+ (v.length > 12 ? ' <span class="set-hint">+' + (v.length - 12) + " more</span>" : "");
|
|
3888
|
+
}
|
|
3889
|
+
if (v && typeof v === "object") return '<span class="set-hint">' + esc(Object.keys(v).length + " field(s)") + "</span>";
|
|
3890
|
+
return esc(String(v));
|
|
3891
|
+
}
|
|
3892
|
+
function cgSection(title, obj) {
|
|
3893
|
+
const entries = obj && typeof obj === "object" ? Object.entries(obj) : [];
|
|
3894
|
+
if (!entries.length) return "";
|
|
3895
|
+
return '<div class="panel"><div class="set-cat-h">' + esc(title) + "</div>"
|
|
3896
|
+
+ entries.map(([k, v]) => '<div class="set-row"><div class="set-meta"><div class="set-name">' + esc(k) + '</div><div class="set-hint">' + cgVal(v) + "</div></div></div>").join("")
|
|
3897
|
+
+ "</div>";
|
|
3898
|
+
}
|
|
3899
|
+
function renderCodeGraph(view) {
|
|
3900
|
+
view = view || {};
|
|
3901
|
+
const on = !!view.enabled;
|
|
3902
|
+
const t = $("cgToggle");
|
|
3903
|
+
t.classList.toggle("on", on); t.setAttribute("aria-checked", on ? "true" : "false"); t.textContent = on ? "on" : "off";
|
|
3904
|
+
if (!view.available) {
|
|
3905
|
+
$("cgBody").innerHTML = '<div class="panel"><div class="set-cat-h">Not installed</div>'
|
|
3906
|
+
+ '<div class="set-hint" style="padding:6px 0">The code-intelligence engine is not available yet. When enabled, your agent fetches it automatically on first use (needs <code>npx</code> on PATH). Then tell your agent "Index this project".</div></div>';
|
|
3907
|
+
return;
|
|
3908
|
+
}
|
|
3909
|
+
const projects = view.projects || [];
|
|
3910
|
+
const projHtml = projects.length
|
|
3911
|
+
? projects.map((p) => {
|
|
3912
|
+
const name = p.name || p.root || "";
|
|
3913
|
+
const sel = name === view.selected;
|
|
3914
|
+
return '<div class="set-row"><div class="set-meta"><div class="set-name">' + esc(name)
|
|
3915
|
+
+ (sel ? ' <span class="tag" style="color:var(--ok)">viewing</span>' : "")
|
|
3916
|
+
+ '</div><div class="set-hint">' + esc(p.root || "") + '</div></div>'
|
|
3917
|
+
+ '<div class="set-ctl"><button type="button" class="toggle' + (sel ? " on" : "") + '" data-cg-project="' + esc(name) + '">View</button></div></div>';
|
|
3918
|
+
}).join("")
|
|
3919
|
+
: '<div class="empty" style="padding:12px 0">No projects indexed yet. In your agent, say "Index this project".</div>';
|
|
3920
|
+
let html = '<div class="panel"><div class="set-cat-h">Indexed projects <small>' + projects.length + "</small></div>" + projHtml + "</div>";
|
|
3921
|
+
if (view.architecture) html += cgSection("Architecture" + (view.selected ? " - " + view.selected : ""), view.architecture);
|
|
3922
|
+
if (view.schema) html += cgSection("Graph schema", view.schema);
|
|
3923
|
+
$("cgBody").innerHTML = html;
|
|
3924
|
+
}
|
|
3925
|
+
async function loadCodeGraph() {
|
|
3926
|
+
$("cgNote").textContent = "";
|
|
3927
|
+
try {
|
|
3928
|
+
const q = cgProject ? "?project=" + encodeURIComponent(cgProject) : "";
|
|
3929
|
+
renderCodeGraph(await (await fetch("/api/codegraph" + q, { cache: "no-store" })).json());
|
|
3930
|
+
} catch { $("cgBody").innerHTML = '<div class="empty" style="padding:12px 0">Code graph unavailable.</div>'; }
|
|
3931
|
+
}
|
|
3932
|
+
async function cgToggleAction() {
|
|
3933
|
+
const turnOn = $("cgToggle").getAttribute("aria-checked") !== "true";
|
|
3934
|
+
setNote("cgNote", "Saving...");
|
|
3935
|
+
try {
|
|
3936
|
+
const out = await (await fetch("/api/codegraph", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ op: "toggle", on: turnOn, project: cgProject || undefined }) })).json();
|
|
3937
|
+
if (out.view) renderCodeGraph(out.view);
|
|
3938
|
+
setNote("cgNote", out.ok ? (turnOn ? "Codebase memory enabled - registered in your agents (restart them to load it)." : "Codebase memory disabled.") : (out.error || "Action failed."), out.ok ? "ok" : "err");
|
|
3939
|
+
} catch { setNote("cgNote", "Could not reach the server.", "err"); }
|
|
3940
|
+
}
|
|
3941
|
+
function wireCodeGraph() {
|
|
3942
|
+
$("cgRefresh").addEventListener("click", loadCodeGraph);
|
|
3943
|
+
$("cgToggle").addEventListener("click", cgToggleAction);
|
|
3944
|
+
$("view-codegraph").addEventListener("click", (e) => {
|
|
3945
|
+
const b = e.target.closest("button[data-cg-project]");
|
|
3946
|
+
if (!b) return;
|
|
3947
|
+
cgProject = b.dataset.cgProject;
|
|
3948
|
+
loadCodeGraph();
|
|
3949
|
+
});
|
|
3950
|
+
}
|
|
3951
|
+
|
|
3860
3952
|
// --- recall subpage (local session memory; reads your own transcripts) ---
|
|
3861
3953
|
const RECALL_TYPES = ["bugfix", "feature", "refactor", "change", "discovery", "decision", "security"];
|
|
3862
3954
|
let recallProjSig = "";
|
|
@@ -4425,6 +4517,7 @@ export {
|
|
|
4425
4517
|
wireUsage();
|
|
4426
4518
|
wireResources();
|
|
4427
4519
|
wireRecall();
|
|
4520
|
+
wireCodeGraph();
|
|
4428
4521
|
wirePacks();
|
|
4429
4522
|
wireScope();
|
|
4430
4523
|
enhanceAll(); // upgrade every static <select> into the shared pretty dropdown
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/dashboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.70",
|
|
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": [
|