@enigmax/dashboard 0.1.60 → 0.1.61
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 +89 -14
- package/package.json +1 -1
package/assets/index.html
CHANGED
|
@@ -710,10 +710,13 @@
|
|
|
710
710
|
<div id="recallBody"><div class="empty" style="padding:12px 0">Loading...</div></div>
|
|
711
711
|
<div id="recallProviderPanel" class="panel" style="display:none">
|
|
712
712
|
<div class="set-cat-h">Memory provider</div>
|
|
713
|
-
<div class="set-hint" style="padding:4px 0">Which
|
|
714
|
-
<div class="set-row"><div class="set-meta"><div class="set-name">LLM curation</div><div class="set-hint">
|
|
713
|
+
<div class="set-hint" style="padding:4px 0">Which model curates your memory - it keeps only what's worth remembering. The default reuses your local Claude Code login (no key). Or pick Anthropic or an OpenAI-compatible API and add its key. The key is stored encrypted, and <code>ENIGMA_RECALL_API_KEY</code> overrides it.</div>
|
|
714
|
+
<div class="set-row"><div class="set-meta"><div class="set-name">LLM curation</div><div class="set-hint">Off falls back to a local heuristic - no network calls</div></div><div class="set-ctl"><button id="recallLlmBtn" type="button" class="toggle" data-kind="bool" role="switch" aria-checked="false" aria-label="LLM curation">off</button></div></div>
|
|
715
715
|
<div class="ladd" style="gap:8px;flex-wrap:wrap;margin-top:8px">
|
|
716
|
-
<
|
|
716
|
+
<div class="dd" id="recallProvDD">
|
|
717
|
+
<button type="button" class="dd-btn" aria-haspopup="listbox" aria-expanded="false"><span class="dd-ic"></span><span class="dd-label"></span><svg class="dd-caret" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"></polyline></svg></button>
|
|
718
|
+
<ul class="dd-menu" role="listbox" aria-label="Memory provider" hidden></ul>
|
|
719
|
+
</div>
|
|
717
720
|
<input id="recallModel" class="linput" placeholder="model (provider default)" style="flex:1;min-width:160px">
|
|
718
721
|
</div>
|
|
719
722
|
<div id="recallKeyRow" class="ladd" style="gap:8px;flex-wrap:wrap;margin-top:8px">
|
|
@@ -730,6 +733,24 @@
|
|
|
730
733
|
<select id="recallProject" class="linput" style="max-width:200px"></select>
|
|
731
734
|
</div>
|
|
732
735
|
</div>
|
|
736
|
+
<div id="recallAddPanel" class="panel" style="display:none">
|
|
737
|
+
<div class="set-cat-h">Add a memory</div>
|
|
738
|
+
<div class="set-hint" style="padding:4px 0">Write one yourself, or generate it from a short note with the configured model.</div>
|
|
739
|
+
<div class="ladd" style="gap:8px;flex-wrap:wrap">
|
|
740
|
+
<select id="recallNewType" class="linput" style="max-width:150px"></select>
|
|
741
|
+
<input id="recallNewTitle" class="linput" placeholder="Title" style="flex:1;min-width:200px">
|
|
742
|
+
<input id="recallNewProject" class="linput" placeholder="Project (optional)" style="flex:1;min-width:140px">
|
|
743
|
+
</div>
|
|
744
|
+
<div class="ladd" style="gap:8px;flex-wrap:wrap;margin-top:8px">
|
|
745
|
+
<input id="recallNewNarrative" class="linput" placeholder="What's worth remembering (optional)" style="flex:1;min-width:240px">
|
|
746
|
+
<input id="recallNewFacts" class="linput" placeholder="Facts, comma-separated (optional)" style="flex:1;min-width:200px">
|
|
747
|
+
</div>
|
|
748
|
+
<div style="margin-top:8px"><button id="recallCreate" type="button" class="toggle on">Save memory</button></div>
|
|
749
|
+
<div class="ladd" style="gap:8px;flex-wrap:wrap;margin-top:12px;border-top:1px solid rgba(128,128,128,.2);padding-top:12px">
|
|
750
|
+
<input id="recallGenNote" class="linput" placeholder="Note to generate a memory from..." style="flex:1;min-width:260px">
|
|
751
|
+
<button id="recallGenerate" type="button" class="toggle" title="Generate a structured memory from your note">Generate with LLM</button>
|
|
752
|
+
</div>
|
|
753
|
+
</div>
|
|
733
754
|
<div id="recallList"></div>
|
|
734
755
|
</section>
|
|
735
756
|
|
|
@@ -3361,14 +3382,14 @@ export {
|
|
|
3361
3382
|
v = v || {};
|
|
3362
3383
|
if (!v.available) {
|
|
3363
3384
|
$("recallBody").innerHTML = '<div class="panel"><div class="empty" style="padding:16px 0">Recall needs the enigma binary - open the dashboard via the enigma app.</div></div>';
|
|
3364
|
-
$("recallSearch").style.display = "none"; $("recallProviderPanel").style.display = "none"; $("recallList").innerHTML = ""; return;
|
|
3385
|
+
$("recallSearch").style.display = "none"; $("recallProviderPanel").style.display = "none"; $("recallAddPanel").style.display = "none"; $("recallList").innerHTML = ""; return;
|
|
3365
3386
|
}
|
|
3366
3387
|
if (!v.enabled) {
|
|
3367
3388
|
$("recallBody").innerHTML = '<div class="panel"><div class="set-cat-h">Session memory is off</div>'
|
|
3368
3389
|
+ '<div class="set-hint" style="padding:8px 0">Build a searchable memory of your coding sessions from your own transcripts.</div>'
|
|
3369
3390
|
+ '<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap"><button type="button" class="toggle" data-recall-on="1">Enable recall</button>'
|
|
3370
3391
|
+ '<span class="set-hint">or run <code>enigma config recall on</code></span></div></div>';
|
|
3371
|
-
$("recallSearch").style.display = "none"; $("recallProviderPanel").style.display = "none"; $("recallList").innerHTML = ""; return;
|
|
3392
|
+
$("recallSearch").style.display = "none"; $("recallProviderPanel").style.display = "none"; $("recallAddPanel").style.display = "none"; $("recallList").innerHTML = ""; return;
|
|
3372
3393
|
}
|
|
3373
3394
|
const s = v.stats || {};
|
|
3374
3395
|
const types = Object.entries(s.byType || {}).map(([t, n]) => '<span class="tag">' + esc(t) + " " + n + "</span>").join(" ");
|
|
@@ -3379,7 +3400,9 @@ export {
|
|
|
3379
3400
|
+ (s.projects || 0) + " projects · " + Math.round((s.dbBytes || 0) / 1024) + " KB · " + esc(last) + "</div>"
|
|
3380
3401
|
+ (types ? '<div style="padding-top:6px">' + types + "</div>" : "") + "</div>";
|
|
3381
3402
|
$("recallSearch").style.display = "";
|
|
3403
|
+
$("recallAddPanel").style.display = "";
|
|
3382
3404
|
if (!$("recallType").options.length) $("recallType").innerHTML = '<option value="">All types</option>' + RECALL_TYPES.map((t) => '<option value="' + t + '">' + t + "</option>").join("");
|
|
3405
|
+
if (!$("recallNewType").options.length) $("recallNewType").innerHTML = RECALL_TYPES.map((t) => '<option value="' + t + '">' + t + "</option>").join("");
|
|
3383
3406
|
const sig = (v.projects || []).join("|");
|
|
3384
3407
|
if (sig !== recallProjSig) {
|
|
3385
3408
|
const keep = $("recallProject").value;
|
|
@@ -3390,13 +3413,30 @@ export {
|
|
|
3390
3413
|
renderRecallProvider(v.provider);
|
|
3391
3414
|
renderRecallList(v.items);
|
|
3392
3415
|
}
|
|
3393
|
-
|
|
3416
|
+
// Provider picker shows the right logo + a human label (the stored value stays the
|
|
3417
|
+
// internal id). claude-local and anthropic are Anthropic models (Claude logo); openai
|
|
3418
|
+
// is any OpenAI-compatible endpoint (OpenAI/Codex logo).
|
|
3419
|
+
const RECALL_PROV_META = {
|
|
3420
|
+
"claude-local": { label: "Claude Code (local login)", icon: "claude" },
|
|
3421
|
+
"anthropic": { label: "Anthropic API", icon: "claude" },
|
|
3422
|
+
"openai": { label: "OpenAI-compatible", icon: "codex" },
|
|
3423
|
+
};
|
|
3424
|
+
let recallProvDD = null, recallProvVal = "claude-local";
|
|
3394
3425
|
function renderRecallProvider(p) {
|
|
3395
3426
|
if (!p) { $("recallProviderPanel").style.display = "none"; return; }
|
|
3396
3427
|
$("recallProviderPanel").style.display = "";
|
|
3397
|
-
|
|
3398
|
-
if (
|
|
3399
|
-
|
|
3428
|
+
recallProvVal = p.provider;
|
|
3429
|
+
if (!recallProvDD) {
|
|
3430
|
+
const entries = (p.providers || []).map((v) => {
|
|
3431
|
+
const m = RECALL_PROV_META[v] || { label: v, icon: "" };
|
|
3432
|
+
return { value: v, label: m.label, icon: agentSvg(m.icon) };
|
|
3433
|
+
});
|
|
3434
|
+
recallProvDD = iconDropdown("recallProvDD", entries, () => recallProvVal, (val) => {
|
|
3435
|
+
recallProvVal = val;
|
|
3436
|
+
$("recallKeyRow").style.display = val === "claude-local" ? "none" : "";
|
|
3437
|
+
});
|
|
3438
|
+
}
|
|
3439
|
+
recallProvDD.render();
|
|
3400
3440
|
$("recallModel").value = p.model || "";
|
|
3401
3441
|
$("recallBase").value = p.base || "";
|
|
3402
3442
|
$("recallKey").placeholder = p.keyFromEnv ? "set via ENIGMA_RECALL_API_KEY" : (p.hasKey ? "set - leave blank to keep" : "API key");
|
|
@@ -3407,6 +3447,7 @@ export {
|
|
|
3407
3447
|
llmBtn.textContent = p.llm ? "on" : "off";
|
|
3408
3448
|
llmBtn.classList.toggle("on", !!p.llm);
|
|
3409
3449
|
llmBtn.dataset.on = p.llm ? "1" : "0";
|
|
3450
|
+
llmBtn.setAttribute("aria-checked", p.llm ? "true" : "false");
|
|
3410
3451
|
}
|
|
3411
3452
|
let recallItemsById = {};
|
|
3412
3453
|
function recallRowHtml(it, anchorId) {
|
|
@@ -3425,7 +3466,8 @@ export {
|
|
|
3425
3466
|
+ facts
|
|
3426
3467
|
+ (it.concepts && it.concepts.length ? '<div style="margin-top:6px">' + tags(it.concepts) + "</div>" : "")
|
|
3427
3468
|
+ list("Modified", it.files) + list("Read", it.filesRead)
|
|
3428
|
-
+ '<div style="margin-top:8px"><button type="button" class="toggle" data-tl="' + it.id + '">Show timeline</button
|
|
3469
|
+
+ '<div style="margin-top:8px;display:flex;gap:8px;flex-wrap:wrap"><button type="button" class="toggle" data-tl="' + it.id + '">Show timeline</button>'
|
|
3470
|
+
+ (it.id ? '<button type="button" class="btn-danger" data-del="' + it.id + '" title="Delete this memory">Delete</button>' : "") + "</div>"
|
|
3429
3471
|
+ '<div class="rtl" id="rtl-' + it.id + '"></div></div>';
|
|
3430
3472
|
}
|
|
3431
3473
|
function renderRecallList(items) {
|
|
@@ -3482,6 +3524,16 @@ export {
|
|
|
3482
3524
|
setNote("recallNote", out.ok ? "Saved." : (out.error || "Failed."), out.ok ? "ok" : "err");
|
|
3483
3525
|
} catch { setNote("recallNote", "Could not reach the server.", "err"); }
|
|
3484
3526
|
}
|
|
3527
|
+
// Generic recall action post (delete/create/generate); refreshes the view and returns ok.
|
|
3528
|
+
async function recallOpPost(body, msg, okMsg) {
|
|
3529
|
+
setNote("recallNote", msg || "Working...");
|
|
3530
|
+
try {
|
|
3531
|
+
const out = await (await fetch("/api/recall", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) })).json();
|
|
3532
|
+
if (out.view) renderRecall(out.view);
|
|
3533
|
+
setNote("recallNote", out.ok ? (okMsg || "Done.") : (out.error || "Failed."), out.ok ? "ok" : "err");
|
|
3534
|
+
return out.ok;
|
|
3535
|
+
} catch { setNote("recallNote", "Could not reach the server.", "err"); return false; }
|
|
3536
|
+
}
|
|
3485
3537
|
function wireRecall() {
|
|
3486
3538
|
$("recallSync").addEventListener("click", () => recallAction("sync"));
|
|
3487
3539
|
$("recallClear").addEventListener("click", () => recallAction("clear", "Delete all stored session memory? This cannot be undone."));
|
|
@@ -3489,20 +3541,43 @@ export {
|
|
|
3489
3541
|
const t = e.target.closest("[data-recall-on]");
|
|
3490
3542
|
if (t) setRecallEnabled(t.dataset.recallOn === "1");
|
|
3491
3543
|
});
|
|
3492
|
-
// Provider panel:
|
|
3493
|
-
|
|
3544
|
+
// Provider panel: save provider; flip LLM curation. The provider picker is the
|
|
3545
|
+
// custom icon dropdown (recallProvVal), wired in renderRecallProvider.
|
|
3494
3546
|
$("recallProvSave").addEventListener("click", () => {
|
|
3495
|
-
const e = { provider:
|
|
3547
|
+
const e = { provider: recallProvVal, model: $("recallModel").value.trim(), base: $("recallBase").value.trim() };
|
|
3496
3548
|
if (!$("recallKey").disabled && $("recallKey").value) e.key = $("recallKey").value; // only send a key the user typed
|
|
3497
3549
|
recallProviderPost(e, "Saving provider...");
|
|
3498
3550
|
$("recallKey").value = "";
|
|
3499
3551
|
});
|
|
3500
3552
|
$("recallLlmBtn").addEventListener("click", () => recallProviderPost({ llm: $("recallLlmBtn").dataset.on !== "1" }, "Updating curation..."));
|
|
3553
|
+
// Add a memory: manual form, or generate one from a note via the configured model.
|
|
3554
|
+
$("recallCreate").addEventListener("click", async () => {
|
|
3555
|
+
const title = $("recallNewTitle").value.trim();
|
|
3556
|
+
if (!title) { setNote("recallNote", "A title is required.", "err"); return; }
|
|
3557
|
+
const facts = $("recallNewFacts").value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
3558
|
+
const ok = await recallOpPost({
|
|
3559
|
+
op: "create", type: $("recallNewType").value, title, project: $("recallNewProject").value.trim(),
|
|
3560
|
+
narrative: $("recallNewNarrative").value.trim(), facts,
|
|
3561
|
+
}, "Saving memory...", "Memory saved.");
|
|
3562
|
+
if (ok) { $("recallNewTitle").value = ""; $("recallNewNarrative").value = ""; $("recallNewFacts").value = ""; }
|
|
3563
|
+
});
|
|
3564
|
+
$("recallGenerate").addEventListener("click", async () => {
|
|
3565
|
+
const prompt = $("recallGenNote").value.trim();
|
|
3566
|
+
if (!prompt) { setNote("recallNote", "Write a note to generate from.", "err"); return; }
|
|
3567
|
+
const ok = await recallOpPost({ op: "generate", prompt, project: $("recallNewProject").value.trim() }, "Generating memory...", "Memory generated.");
|
|
3568
|
+
if (ok) $("recallGenNote").value = "";
|
|
3569
|
+
});
|
|
3501
3570
|
let t; const deb = () => { clearTimeout(t); t = setTimeout(loadRecall, 250); };
|
|
3502
3571
|
$("recallQ").addEventListener("input", deb);
|
|
3503
3572
|
$("recallType").addEventListener("change", loadRecall);
|
|
3504
3573
|
$("recallProject").addEventListener("change", loadRecall);
|
|
3505
|
-
$("recallList").addEventListener("click", (e) => {
|
|
3574
|
+
$("recallList").addEventListener("click", async (e) => {
|
|
3575
|
+
const del = e.target.closest("[data-del]");
|
|
3576
|
+
if (del) {
|
|
3577
|
+
if (!(await askConfirm("Delete memory", "Delete this memory? This cannot be undone.", true))) return;
|
|
3578
|
+
recallOpPost({ op: "delete", id: Number(del.dataset.del) }, "Deleting...", "Memory deleted.");
|
|
3579
|
+
return;
|
|
3580
|
+
}
|
|
3506
3581
|
const tl = e.target.closest("[data-tl]");
|
|
3507
3582
|
if (tl) { loadRecallTimeline(tl.dataset.tl); return; }
|
|
3508
3583
|
const row = e.target.closest("[data-rid]");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/dashboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.61",
|
|
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": [
|