@enigmax/dashboard 0.1.50 → 0.1.53
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 +98 -0
- package/package.json +1 -1
package/assets/index.html
CHANGED
|
@@ -156,6 +156,9 @@
|
|
|
156
156
|
.set-meta { flex: 1; min-width: 0; }
|
|
157
157
|
.set-name { font-size: 13px; color: var(--text); }
|
|
158
158
|
.set-hint { font-size: 12px; color: var(--muted); margin-top: 2px; }
|
|
159
|
+
/* Capitalize the first letter of every option description/blurb in the dashboard
|
|
160
|
+
(presentation only; the shared registry keeps its lowercase TUI/CLI convention). */
|
|
161
|
+
.set-hint::first-letter, .set-cat-b::first-letter, .lnone::first-letter { text-transform: uppercase; }
|
|
159
162
|
.set-ctl { flex-shrink: 0; }
|
|
160
163
|
.toggle {
|
|
161
164
|
background: var(--surface2); color: var(--muted); border: 1px solid var(--border);
|
|
@@ -357,6 +360,7 @@
|
|
|
357
360
|
transform: translateY(10px) scale(.98); opacity: 0; transition: transform .18s ease, opacity .18s ease;
|
|
358
361
|
}
|
|
359
362
|
.modal-back.show .modal { transform: none; opacity: 1; }
|
|
363
|
+
.modal.wide { max-width: 900px; }
|
|
360
364
|
.modal-title { font-family: var(--mono); font-size: 14px; font-weight: 600; color: var(--text); }
|
|
361
365
|
.modal-msg { color: var(--muted); font-size: 13px; line-height: 1.5; margin-top: 8px; word-break: break-word; }
|
|
362
366
|
.modal-input {
|
|
@@ -628,6 +632,11 @@
|
|
|
628
632
|
<div class="set-cat-h">Skill settings</div>
|
|
629
633
|
<div id="skillSettings" class="set-grid"></div>
|
|
630
634
|
</div>
|
|
635
|
+
<div class="panel" id="memPanel">
|
|
636
|
+
<div class="set-cat-h">Agent memory</div>
|
|
637
|
+
<div class="set-cat-b">Customize the instruction files enigma deploys to each agent (CLAUDE.md / AGENTS.md). Your edits follow the Customized-skill updates policy on the next sync: overwrite restores the managed version, keep preserves them.</div>
|
|
638
|
+
<div id="memBody" class="set-grid"><div class="empty" style="padding:12px 0">Loading...</div></div>
|
|
639
|
+
</div>
|
|
631
640
|
<div class="panel">
|
|
632
641
|
<div id="skillsBody"><div class="empty" style="padding:24px 0">Loading skills...</div></div>
|
|
633
642
|
<div id="skillsNote" class="set-note"></div>
|
|
@@ -2614,6 +2623,93 @@ export {
|
|
|
2614
2623
|
} catch { setNote("settingsNote", "Could not reach the server to set the port.", "err"); }
|
|
2615
2624
|
}
|
|
2616
2625
|
|
|
2626
|
+
// --- agent memory editor (CLAUDE.md / AGENTS.md), global or per project ----------
|
|
2627
|
+
// Global edits each agent's home memory file; project scope edits <project>/CLAUDE.md
|
|
2628
|
+
// and <project>/AGENTS.md. Writes go through /api/memory, which marks the edit so the
|
|
2629
|
+
// overwrite/keep policy (Customized-skill updates) can preserve it on the next sync.
|
|
2630
|
+
function memProject() { return isProjectScope() ? currentScope : undefined; }
|
|
2631
|
+
|
|
2632
|
+
async function postMemory(id, action, content, project) {
|
|
2633
|
+
const body = { id, action };
|
|
2634
|
+
if (content !== undefined) body.content = content;
|
|
2635
|
+
if (project) body.path = project;
|
|
2636
|
+
return (await fetch("/api/memory", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) })).json();
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
function memoryRow(g) {
|
|
2640
|
+
const apps = (g.agents || []).map((a) => '<span class="tag">' + esc(a.label) + "</span>").join(" ");
|
|
2641
|
+
const state = !g.deployed ? '<span class="tag">not deployed</span>'
|
|
2642
|
+
: g.edited ? '<span class="tag exp">edited</span>'
|
|
2643
|
+
: g.managed ? '<span class="tag meas">managed</span>' : '<span class="tag">custom</span>';
|
|
2644
|
+
const reset = (g.deployed && g.edited) ? ' <button type="button" class="iconbtn" data-mem-reset="' + esc(g.id) + '" title="Restore the managed version">reset</button>' : "";
|
|
2645
|
+
return '<div class="set-row"><div class="set-meta"><div class="set-name">' + esc(g.file) + " " + apps + " " + state + "</div>"
|
|
2646
|
+
+ '<div class="set-hint">' + (g.deployed ? "Deployed - edit to customize" : "Not deployed yet - editing creates it") + "</div></div>"
|
|
2647
|
+
+ '<div class="set-ctl ladd" style="align-items:center"><button type="button" class="toggle on" data-mem-edit="' + esc(g.id) + '">Edit</button>' + reset + "</div></div>";
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
async function loadMemory(project) {
|
|
2651
|
+
const el = $("memBody"); // global + project share this panel (one scope shown at a time)
|
|
2652
|
+
if (!el) return;
|
|
2653
|
+
try {
|
|
2654
|
+
const q = project ? "/api/memory?path=" + encodeURIComponent(project) : "/api/memory";
|
|
2655
|
+
const data = await (await fetch(q, { cache: "no-store" })).json();
|
|
2656
|
+
const groups = data.groups || [];
|
|
2657
|
+
el.innerHTML = groups.length ? groups.map(memoryRow).join("")
|
|
2658
|
+
: '<div class="empty" style="padding:12px 0">No agents detected to deploy memory to.</div>';
|
|
2659
|
+
} catch { el.innerHTML = '<div class="empty" style="padding:12px 0">Memory unavailable.</div>'; }
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
async function openMemoryEditor(id, project) {
|
|
2663
|
+
let out;
|
|
2664
|
+
try { out = await postMemory(id, "read", undefined, project); }
|
|
2665
|
+
catch { toast("Could not reach the server.", "err"); return; }
|
|
2666
|
+
if (!out.ok) { toast(out.error || "Could not read the memory file.", "err"); return; }
|
|
2667
|
+
const back = document.createElement("div");
|
|
2668
|
+
back.className = "modal-back";
|
|
2669
|
+
back.innerHTML = '<div class="modal wide" role="dialog" aria-modal="true">'
|
|
2670
|
+
+ '<div class="modal-title">Editing ' + esc(id) + " memory</div>"
|
|
2671
|
+
+ '<div class="modal-msg">Saved to every agent that reads this file. On the next sync the Customized-skill updates policy decides whether your edit is kept or replaced by the managed version.</div>'
|
|
2672
|
+
+ '<textarea class="editor" spellcheck="false" style="margin-top:14px"></textarea>'
|
|
2673
|
+
+ '<div class="modal-acts"><button type="button" class="toggle modal-cancel">Cancel</button>'
|
|
2674
|
+
+ '<button type="button" class="toggle on modal-ok">Save</button></div></div>';
|
|
2675
|
+
document.body.appendChild(back);
|
|
2676
|
+
requestAnimationFrame(() => back.classList.add("show"));
|
|
2677
|
+
const ta = back.querySelector("textarea");
|
|
2678
|
+
ta.value = out.content || "";
|
|
2679
|
+
let done = false;
|
|
2680
|
+
const close = () => { if (done) return; done = true; back.classList.remove("show"); setTimeout(() => back.remove(), 200); };
|
|
2681
|
+
back.querySelector(".modal-cancel").addEventListener("click", close);
|
|
2682
|
+
back.addEventListener("mousedown", (e) => { if (e.target === back) close(); });
|
|
2683
|
+
back.addEventListener("keydown", (e) => { if (e.key === "Escape") { e.preventDefault(); close(); } });
|
|
2684
|
+
back.querySelector(".modal-ok").addEventListener("click", async () => {
|
|
2685
|
+
const btn = back.querySelector(".modal-ok"); btn.disabled = true;
|
|
2686
|
+
try {
|
|
2687
|
+
const r = await postMemory(id, "save", ta.value, project);
|
|
2688
|
+
if (r.ok) { toast(r.note || "Saved.", "ok"); close(); loadMemory(project); }
|
|
2689
|
+
else { toast(r.error || "Could not save.", "err"); btn.disabled = false; }
|
|
2690
|
+
} catch { toast("Could not reach the server.", "err"); btn.disabled = false; }
|
|
2691
|
+
});
|
|
2692
|
+
ta.focus();
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
async function resetMemory(id, project) {
|
|
2696
|
+
if (!(await askConfirm("Restore managed memory?", "This replaces your edits with enigma's managed version.", true))) return;
|
|
2697
|
+
try {
|
|
2698
|
+
const r = await postMemory(id, "reset", undefined, project);
|
|
2699
|
+
if (r.ok) { toast(r.note || "Restored.", "ok"); loadMemory(project); }
|
|
2700
|
+
else toast(r.error || "Could not restore.", "err");
|
|
2701
|
+
} catch { toast("Could not reach the server.", "err"); }
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
// The memory editor lives in the Skills tab (#memBody, scope-aware via memProject());
|
|
2705
|
+
// a document-level delegate handles its edit/reset buttons in global and project scope.
|
|
2706
|
+
document.addEventListener("click", (e) => {
|
|
2707
|
+
const ed = e.target.closest && e.target.closest("[data-mem-edit]");
|
|
2708
|
+
if (ed) { openMemoryEditor(ed.dataset.memEdit, memProject()); return; }
|
|
2709
|
+
const rs = e.target.closest && e.target.closest("[data-mem-reset]");
|
|
2710
|
+
if (rs) { resetMemory(rs.dataset.memReset, memProject()); }
|
|
2711
|
+
});
|
|
2712
|
+
|
|
2617
2713
|
// --- "Enigma systems" overview (factual state, never invented savings) ---
|
|
2618
2714
|
function pill(state, text) { return '<span class="pill ' + state + '">' + esc(text) + "</span>"; }
|
|
2619
2715
|
function boolPill(b) { return b ? pill("on", "on") : pill("off", "off"); }
|
|
@@ -2971,6 +3067,7 @@ export {
|
|
|
2971
3067
|
if (isProjectScope()) return loadProjectSkills();
|
|
2972
3068
|
skillScope = "global";
|
|
2973
3069
|
loadSkillSettings();
|
|
3070
|
+
loadMemory();
|
|
2974
3071
|
try {
|
|
2975
3072
|
const res = await fetch("/api/skills", { cache: "no-store" });
|
|
2976
3073
|
renderSkills((await res.json()).skills || []);
|
|
@@ -3373,6 +3470,7 @@ export {
|
|
|
3373
3470
|
skillScope = "project";
|
|
3374
3471
|
const el = $("skillsBody");
|
|
3375
3472
|
const ss = $("skillSettings"); if (ss) ss.innerHTML = '<div class="set-cat-b" style="padding:0 0 4px">Skill settings are global - switch Scope to Global to change them.</div>';
|
|
3473
|
+
loadMemory(currentScope);
|
|
3376
3474
|
el.innerHTML = '<div class="empty" style="padding:24px 0">Loading...</div>';
|
|
3377
3475
|
let d; try { d = await fetchProjectDetail(); } catch { el.innerHTML = '<div class="empty" style="padding:24px 0">Project unavailable.</div>'; return; }
|
|
3378
3476
|
if (d.error) { el.innerHTML = '<div class="empty" style="padding:24px 0">' + esc(d.error) + "</div>"; return; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/dashboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
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": [
|