@enigmax/dashboard 0.1.58 → 0.1.60

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 +70 -5
  2. package/package.json +1 -1
package/assets/index.html CHANGED
@@ -708,6 +708,20 @@
708
708
  </div>
709
709
  <div id="recallNote" class="set-note"></div>
710
710
  <div id="recallBody"><div class="empty" style="padding:12px 0">Loading...</div></div>
711
+ <div id="recallProviderPanel" class="panel" style="display:none">
712
+ <div class="set-cat-h">Memory provider</div>
713
+ <div class="set-hint" style="padding:4px 0">Which LLM curates your memory (keeps only what's worth remembering). <code>claude-local</code> uses your Claude Code login - no key. For another provider, pick it and set the model/base/key; the key can also come from <code>ENIGMA_RECALL_API_KEY</code>.</div>
714
+ <div class="set-row"><div class="set-meta"><div class="set-name">LLM curation</div><div class="set-hint">off = deterministic heuristic, no network</div></div><div class="set-ctl"><button id="recallLlmBtn" type="button" class="toggle">...</button></div></div>
715
+ <div class="ladd" style="gap:8px;flex-wrap:wrap;margin-top:8px">
716
+ <select id="recallProv" class="linput" style="max-width:160px"></select>
717
+ <input id="recallModel" class="linput" placeholder="model (provider default)" style="flex:1;min-width:160px">
718
+ </div>
719
+ <div id="recallKeyRow" class="ladd" style="gap:8px;flex-wrap:wrap;margin-top:8px">
720
+ <input id="recallBase" class="linput" placeholder="API base URL (provider default)" style="flex:1;min-width:200px">
721
+ <input id="recallKey" class="linput" type="password" placeholder="API key" style="flex:1;min-width:160px">
722
+ </div>
723
+ <div style="margin-top:8px"><button id="recallProvSave" type="button" class="toggle on">Save provider</button></div>
724
+ </div>
711
725
  <div id="recallSearch" class="panel" style="display:none">
712
726
  <div class="set-cat-h">Search</div>
713
727
  <div class="ladd" style="gap:8px;flex-wrap:wrap">
@@ -3347,18 +3361,20 @@ export {
3347
3361
  v = v || {};
3348
3362
  if (!v.available) {
3349
3363
  $("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>';
3350
- $("recallSearch").style.display = "none"; $("recallList").innerHTML = ""; return;
3364
+ $("recallSearch").style.display = "none"; $("recallProviderPanel").style.display = "none"; $("recallList").innerHTML = ""; return;
3351
3365
  }
3352
3366
  if (!v.enabled) {
3353
3367
  $("recallBody").innerHTML = '<div class="panel"><div class="set-cat-h">Session memory is off</div>'
3354
- + '<div class="set-hint" style="padding:8px 0">Build a searchable memory of your coding sessions from your own transcripts. Turn it on with:</div>'
3355
- + '<code>enigma config recall on</code></div>';
3356
- $("recallSearch").style.display = "none"; $("recallList").innerHTML = ""; return;
3368
+ + '<div class="set-hint" style="padding:8px 0">Build a searchable memory of your coding sessions from your own transcripts.</div>'
3369
+ + '<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
+ + '<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;
3357
3372
  }
3358
3373
  const s = v.stats || {};
3359
3374
  const types = Object.entries(s.byType || {}).map(([t, n]) => '<span class="tag">' + esc(t) + " " + n + "</span>").join(" ");
3360
3375
  const last = v.lastSync ? "last sync " + new Date(v.lastSync).toLocaleString() : "not synced yet";
3361
- $("recallBody").innerHTML = '<div class="panel"><div class="set-cat-h">Stored memory</div>'
3376
+ $("recallBody").innerHTML = '<div class="panel"><div style="display:flex;justify-content:space-between;align-items:center;gap:10px"><div class="set-cat-h" style="margin:0">Stored memory</div>'
3377
+ + '<button type="button" class="toggle on" data-recall-on="0" title="Turn session memory off">Disable</button></div>'
3362
3378
  + '<div class="set-hint" style="padding:6px 0">' + (s.observations || 0) + " observations · " + (s.sessions || 0) + " sessions · "
3363
3379
  + (s.projects || 0) + " projects · " + Math.round((s.dbBytes || 0) / 1024) + " KB · " + esc(last) + "</div>"
3364
3380
  + (types ? '<div style="padding-top:6px">' + types + "</div>" : "") + "</div>";
@@ -3371,8 +3387,27 @@ export {
3371
3387
  $("recallProject").value = keep;
3372
3388
  recallProjSig = sig;
3373
3389
  }
3390
+ renderRecallProvider(v.provider);
3374
3391
  renderRecallList(v.items);
3375
3392
  }
3393
+ let recallProvSig = "";
3394
+ function renderRecallProvider(p) {
3395
+ if (!p) { $("recallProviderPanel").style.display = "none"; return; }
3396
+ $("recallProviderPanel").style.display = "";
3397
+ const sig = (p.providers || []).join("|");
3398
+ if (sig !== recallProvSig) { $("recallProv").innerHTML = (p.providers || []).map((x) => '<option value="' + x + '">' + x + "</option>").join(""); recallProvSig = sig; }
3399
+ $("recallProv").value = p.provider;
3400
+ $("recallModel").value = p.model || "";
3401
+ $("recallBase").value = p.base || "";
3402
+ $("recallKey").placeholder = p.keyFromEnv ? "set via ENIGMA_RECALL_API_KEY" : (p.hasKey ? "set - leave blank to keep" : "API key");
3403
+ $("recallKey").disabled = !!p.keyFromEnv;
3404
+ // claude-local needs no base/key; hide that row for it.
3405
+ $("recallKeyRow").style.display = p.provider === "claude-local" ? "none" : "";
3406
+ const llmBtn = $("recallLlmBtn");
3407
+ llmBtn.textContent = p.llm ? "on" : "off";
3408
+ llmBtn.classList.toggle("on", !!p.llm);
3409
+ llmBtn.dataset.on = p.llm ? "1" : "0";
3410
+ }
3376
3411
  let recallItemsById = {};
3377
3412
  function recallRowHtml(it, anchorId) {
3378
3413
  const ic = '<span class="aicon" title="' + esc(it.source) + '" aria-label="' + esc(it.source) + '">' + (agentSvg(it.source) || esc(it.source)) + "</span>";
@@ -3430,9 +3465,39 @@ export {
3430
3465
  setNote("recallNote", out.ok ? (op === "sync" ? "Synced." : "Cleared.") : (out.error || "Action failed."), out.ok ? "ok" : "err");
3431
3466
  } catch { setNote("recallNote", "Could not reach the server.", "err"); }
3432
3467
  }
3468
+ async function setRecallEnabled(on) {
3469
+ setNote("recallNote", on ? "Enabling recall..." : "Disabling recall...");
3470
+ try {
3471
+ const out = await (await fetch("/api/settings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key: "recall", value: on }) })).json();
3472
+ if (!out.ok) { setNote("recallNote", "Could not change recall: " + (out.error || "error"), "err"); return; }
3473
+ setNote("recallNote", out.restartNote || (on ? "Recall enabled." : "Recall disabled."), "ok");
3474
+ loadRecall();
3475
+ } catch { setNote("recallNote", "Could not reach the server.", "err"); }
3476
+ }
3477
+ async function recallProviderPost(extra, msg) {
3478
+ setNote("recallNote", msg || "Saving provider...");
3479
+ try {
3480
+ const out = await (await fetch("/api/recall", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(Object.assign({ op: "set-provider" }, extra)) })).json();
3481
+ if (out.view) renderRecall(out.view);
3482
+ setNote("recallNote", out.ok ? "Saved." : (out.error || "Failed."), out.ok ? "ok" : "err");
3483
+ } catch { setNote("recallNote", "Could not reach the server.", "err"); }
3484
+ }
3433
3485
  function wireRecall() {
3434
3486
  $("recallSync").addEventListener("click", () => recallAction("sync"));
3435
3487
  $("recallClear").addEventListener("click", () => recallAction("clear", "Delete all stored session memory? This cannot be undone."));
3488
+ $("recallBody").addEventListener("click", (e) => {
3489
+ const t = e.target.closest("[data-recall-on]");
3490
+ if (t) setRecallEnabled(t.dataset.recallOn === "1");
3491
+ });
3492
+ // Provider panel: toggle which select fields apply; save provider; flip LLM curation.
3493
+ $("recallProv").addEventListener("change", () => { $("recallKeyRow").style.display = $("recallProv").value === "claude-local" ? "none" : ""; });
3494
+ $("recallProvSave").addEventListener("click", () => {
3495
+ const e = { provider: $("recallProv").value, model: $("recallModel").value.trim(), base: $("recallBase").value.trim() };
3496
+ if (!$("recallKey").disabled && $("recallKey").value) e.key = $("recallKey").value; // only send a key the user typed
3497
+ recallProviderPost(e, "Saving provider...");
3498
+ $("recallKey").value = "";
3499
+ });
3500
+ $("recallLlmBtn").addEventListener("click", () => recallProviderPost({ llm: $("recallLlmBtn").dataset.on !== "1" }, "Updating curation..."));
3436
3501
  let t; const deb = () => { clearTimeout(t); t = setTimeout(loadRecall, 250); };
3437
3502
  $("recallQ").addEventListener("input", deb);
3438
3503
  $("recallType").addEventListener("change", loadRecall);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enigmax/dashboard",
3
- "version": "0.1.58",
3
+ "version": "0.1.60",
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": [