@enigmax/dashboard 0.1.97 → 0.1.98
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 +80 -12
- package/package.json +1 -1
package/assets/index.html
CHANGED
|
@@ -128,6 +128,21 @@
|
|
|
128
128
|
.card .value.accent { color: var(--accent); }
|
|
129
129
|
.card .value.good { color: var(--good); }
|
|
130
130
|
.card .foot { position: relative; color: var(--muted); font-size: 12px; margin-top: 5px; }
|
|
131
|
+
/* Gate status strip. Two booleans and a path do not each need a 30px stat card:
|
|
132
|
+
one surface, three inline items (frontend-policy, Visual Hierarchy). */
|
|
133
|
+
.gate-bar {
|
|
134
|
+
display: flex; flex-wrap: wrap; align-items: center; gap: 12px 28px;
|
|
135
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
|
|
136
|
+
padding: 13px 18px; margin-bottom: 18px; box-shadow: var(--shadow-1);
|
|
137
|
+
}
|
|
138
|
+
.gate-stat { display: flex; align-items: center; gap: 10px; min-width: 0; }
|
|
139
|
+
.gate-stat-t { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
|
|
140
|
+
.gate-stat-n { font-family: var(--mono); color: var(--muted); font-size: 10.5px; text-transform: uppercase; letter-spacing: .8px; }
|
|
141
|
+
.gate-stat-v { font-family: var(--mono); font-size: 13px; font-weight: 600; color: var(--text); }
|
|
142
|
+
.gate-stat-v.good { color: var(--good); }
|
|
143
|
+
/* Takes the remaining width so the path truncates instead of wrapping the strip. */
|
|
144
|
+
.gate-stat-scope { flex: 1 1 220px; min-width: 0; }
|
|
145
|
+
.gate-stat-f { min-width: 0; font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
131
146
|
.panel { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px 22px; margin-bottom: 18px; box-shadow: var(--shadow-1); }
|
|
132
147
|
.panel-head { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
|
|
133
148
|
/* Section heading: a mono eyebrow led by a short accent rule (structure as signal). */
|
|
@@ -1062,16 +1077,19 @@
|
|
|
1062
1077
|
</div>
|
|
1063
1078
|
<button id="gateRefresh" type="button" class="iconbtn" title="Refresh" aria-label="Refresh the gate view"><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>
|
|
1064
1079
|
</div>
|
|
1065
|
-
<div class="
|
|
1066
|
-
<div class="
|
|
1067
|
-
<
|
|
1068
|
-
<div class="
|
|
1080
|
+
<div class="gate-bar">
|
|
1081
|
+
<div class="gate-stat">
|
|
1082
|
+
<button id="gateOnBtn" type="button" class="toggle" data-kind="bool" role="switch" aria-checked="false" aria-label="AI quality gate" title="Auto-driven after a code task"></button>
|
|
1083
|
+
<div class="gate-stat-t"><span class="gate-stat-n">Gate</span><span id="gateOn" class="gate-stat-v">-</span></div>
|
|
1084
|
+
</div>
|
|
1085
|
+
<div class="gate-stat">
|
|
1086
|
+
<button id="gateDaemonBtn" type="button" class="toggle" data-kind="bool" role="switch" aria-checked="false" aria-label="Gate daemon" title="Runs the pipeline in the background"></button>
|
|
1087
|
+
<div class="gate-stat-t"><span class="gate-stat-n">Daemon</span><span id="gateDaemon" class="gate-stat-v">-</span></div>
|
|
1069
1088
|
</div>
|
|
1070
|
-
<div class="
|
|
1071
|
-
<div class="
|
|
1072
|
-
<
|
|
1089
|
+
<div class="gate-stat gate-stat-scope">
|
|
1090
|
+
<div class="gate-stat-t"><span class="gate-stat-n">Scope</span><span id="gateRepo" class="gate-stat-v">-</span></div>
|
|
1091
|
+
<span id="gateRepoFoot" class="gate-stat-f"></span>
|
|
1073
1092
|
</div>
|
|
1074
|
-
<div class="card"><div class="label">Repository</div><div id="gateRepo" class="value">-</div><div id="gateRepoFoot" class="foot">Scope</div></div>
|
|
1075
1093
|
</div>
|
|
1076
1094
|
|
|
1077
1095
|
<div class="panel">
|
|
@@ -1089,7 +1107,7 @@
|
|
|
1089
1107
|
</div>
|
|
1090
1108
|
<div class="set-row" id="gateModelRow">
|
|
1091
1109
|
<div class="set-meta"><div class="set-name">Model</div><div class="set-hint" id="gateModelHint">the model every step runs on; a smaller one cuts run time and tokens</div></div>
|
|
1092
|
-
<div class="set-ctl ladd" style="align-items:center"><input id="gateModel" class="linput" style="flex:none;width:
|
|
1110
|
+
<div class="set-ctl ladd" style="align-items:center"><select id="gateModelSel" class="linput" style="flex:none;width:240px"></select><input id="gateModel" class="linput" style="flex:none;width:200px" spellcheck="false" autocapitalize="none" autocorrect="off" placeholder="model id"><button id="gateModelSave" type="button" class="toggle on">Save</button></div>
|
|
1093
1111
|
</div>
|
|
1094
1112
|
<div class="set-row">
|
|
1095
1113
|
<div class="set-meta"><div class="set-name">CI timeout</div><div class="set-hint">how long the CI step babysits an idle PR: 168h, 24h, or unlimited</div></div>
|
|
@@ -4375,6 +4393,46 @@ export {
|
|
|
4375
4393
|
];
|
|
4376
4394
|
// Rendered once per non-live load; the number inputs write on change, so a re-render
|
|
4377
4395
|
// mid-edit would drop what is being typed.
|
|
4396
|
+
// Model choices per agent. Claude Code's `--model` takes these aliases, so they can be
|
|
4397
|
+
// offered as a real list; codex and opencode take a provider-specific string, and a
|
|
4398
|
+
// guessed list there would be worse than none - they get auto plus Custom.
|
|
4399
|
+
const GATE_MODELS = {
|
|
4400
|
+
claude: [
|
|
4401
|
+
["claude-opus-5", "claude-opus-5 (most capable)"],
|
|
4402
|
+
["claude-sonnet-5", "claude-sonnet-5 (faster, cheaper)"],
|
|
4403
|
+
["claude-haiku-4-5", "claude-haiku-4-5 (fastest)"],
|
|
4404
|
+
["claude-opus-4-8", "claude-opus-4-8 (previous Opus)"],
|
|
4405
|
+
],
|
|
4406
|
+
};
|
|
4407
|
+
const GATE_MODEL_CUSTOM = "__custom__";
|
|
4408
|
+
let gateSavedModel = "";
|
|
4409
|
+
|
|
4410
|
+
/** Rebuilds the model dropdown for `agent` and selects `model` (empty = the agent default). */
|
|
4411
|
+
function renderGateModel(agent, model) {
|
|
4412
|
+
const sel = $("gateModelSel"), inp = $("gateModel");
|
|
4413
|
+
const opts = [["", "auto (agent default)"]].concat(GATE_MODELS[agent] || [], [[GATE_MODEL_CUSTOM, "Custom model id..."]]);
|
|
4414
|
+
sel.innerHTML = opts.map(([v, label]) => '<option value="' + esc(v) + '">' + esc(label) + "</option>").join("");
|
|
4415
|
+
const listed = opts.some(([v]) => v === model && v !== GATE_MODEL_CUSTOM);
|
|
4416
|
+
sel.value = listed ? model : GATE_MODEL_CUSTOM;
|
|
4417
|
+
syncDD(sel);
|
|
4418
|
+
inp.value = model;
|
|
4419
|
+
gateSavedModel = model;
|
|
4420
|
+
gateModelMode();
|
|
4421
|
+
}
|
|
4422
|
+
/** Shows the free-text field and its Save only while "Custom" is selected. */
|
|
4423
|
+
function gateModelMode() {
|
|
4424
|
+
const custom = $("gateModelSel").value === GATE_MODEL_CUSTOM;
|
|
4425
|
+
$("gateModel").style.display = custom ? "" : "none";
|
|
4426
|
+
$("gateModelSave").style.display = custom ? "" : "none";
|
|
4427
|
+
syncGateModelSave();
|
|
4428
|
+
}
|
|
4429
|
+
/** No-op rule: nothing to save while the typed id still equals the stored one. */
|
|
4430
|
+
function syncGateModelSave() {
|
|
4431
|
+
const btn = $("gateModelSave"), dirty = $("gateModel").value.trim() !== gateSavedModel;
|
|
4432
|
+
btn.disabled = !gateWritable || !dirty;
|
|
4433
|
+
btn.title = dirty ? "" : "No changes to save";
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4378
4436
|
function renderGateSettings(s) {
|
|
4379
4437
|
const panel = $("gateSetPanel");
|
|
4380
4438
|
if (!s) { panel.style.display = "none"; return; }
|
|
@@ -4391,7 +4449,7 @@ export {
|
|
|
4391
4449
|
? "auto: first agent found on PATH - currently " + s.agentResolved
|
|
4392
4450
|
: "which coding agent the pipeline drives";
|
|
4393
4451
|
$("gateModelRow").style.display = s.modelSupported ? "" : "none";
|
|
4394
|
-
|
|
4452
|
+
renderGateModel(s.agent, s.model || "");
|
|
4395
4453
|
$("gateModelHint").textContent = "passed to " + s.agentResolved
|
|
4396
4454
|
+ " on every step; a smaller model is the one change that cuts both run time and tokens";
|
|
4397
4455
|
$("gateCiTimeout").value = s.ciTimeout || "";
|
|
@@ -4403,6 +4461,7 @@ export {
|
|
|
4403
4461
|
+ '<div class="set-ctl"><input type="number" min="0" max="20" step="1" inputmode="numeric" class="linput" style="flex:none;width:80px" data-gate-af="' + esc(step) + '" value="' + Number(s.autoFix[step] || 0) + '"></div></div>').join("");
|
|
4404
4462
|
const ctls = panel.querySelectorAll("input, select, button");
|
|
4405
4463
|
for (const c of ctls) c.disabled = !gateWritable;
|
|
4464
|
+
syncGateModelSave(); // after the sweep, which would otherwise re-enable a clean Save
|
|
4406
4465
|
}
|
|
4407
4466
|
// `live` marks a poll refresh: it repaints the run strip and the two switches, and leaves
|
|
4408
4467
|
// every editor alone so a poll can never overwrite what is being typed.
|
|
@@ -4410,14 +4469,15 @@ export {
|
|
|
4410
4469
|
g = g || {};
|
|
4411
4470
|
if (typeof g.serverNow === "number") gateClockSkew = g.serverNow * 1000 - Date.now();
|
|
4412
4471
|
$("gateOn").textContent = g.on ? "On" : "Off";
|
|
4413
|
-
$("gateOn").className = "
|
|
4472
|
+
$("gateOn").className = "gate-stat-v " + (g.on ? "good" : "");
|
|
4414
4473
|
gateBool($("gateOnBtn"), g.on);
|
|
4415
4474
|
$("gateDaemon").textContent = g.daemon ? "Running" : "Stopped";
|
|
4416
|
-
$("gateDaemon").className = "
|
|
4475
|
+
$("gateDaemon").className = "gate-stat-v " + (g.daemon ? "good" : "");
|
|
4417
4476
|
gateBool($("gateDaemonBtn"), g.daemon);
|
|
4418
4477
|
const repo = g.repo;
|
|
4419
4478
|
$("gateRepo").textContent = repo ? (repo.initialized ? "Initialized" : "Not initialized") : "Global";
|
|
4420
4479
|
$("gateRepoFoot").textContent = repo ? repo.path : "Every active run on this machine";
|
|
4480
|
+
$("gateRepoFoot").title = $("gateRepoFoot").textContent; // the path truncates; keep it recoverable
|
|
4421
4481
|
$("gateRunsSub").textContent = repo ? "most recent first, this repository" : "active runs across every repository";
|
|
4422
4482
|
const runs = g.runs || [];
|
|
4423
4483
|
gateRuns = runs;
|
|
@@ -4539,6 +4599,14 @@ export {
|
|
|
4539
4599
|
$("gateAgent").addEventListener("change", (e) => saveGateSetting("agent", e.target.value, "the agent"));
|
|
4540
4600
|
$("gateLogLevel").addEventListener("change", (e) => saveGateSetting("log_level", e.target.value, "the log level"));
|
|
4541
4601
|
$("gateIntent").addEventListener("click", () => saveGateSetting("intent.enabled", $("gateIntent").dataset.on !== "1", "intent extraction"));
|
|
4602
|
+
// A listed model commits on pick, like the agent and log-level selects; "Custom" reveals
|
|
4603
|
+
// the field and waits for Save, since a half-typed model id must not be written.
|
|
4604
|
+
$("gateModelSel").addEventListener("change", () => {
|
|
4605
|
+
gateModelMode();
|
|
4606
|
+
if ($("gateModelSel").value === GATE_MODEL_CUSTOM) { $("gateModel").focus(); return; }
|
|
4607
|
+
saveGateSetting("model", $("gateModelSel").value, "the model");
|
|
4608
|
+
});
|
|
4609
|
+
$("gateModel").addEventListener("input", syncGateModelSave);
|
|
4542
4610
|
$("gateModelSave").addEventListener("click", () => saveGateSetting("model", $("gateModel").value.trim(), "the model"));
|
|
4543
4611
|
$("gateCiSave").addEventListener("click", () => saveGateSetting("ci_timeout", $("gateCiTimeout").value.trim(), "the CI timeout"));
|
|
4544
4612
|
// Number inputs commit on change (blur or Enter), so typing "12" is not read as "1" then "12".
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/dashboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.98",
|
|
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": [
|