@enigmax/dashboard 0.1.99 → 0.1.101

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 +108 -11
  2. package/package.json +1 -1
package/assets/index.html CHANGED
@@ -720,6 +720,10 @@
720
720
  .modal-ok.danger { background: var(--accent2); border-color: var(--accent2); color: #2a0f08; }
721
721
  .modal-ok:disabled { opacity: .45; cursor: not-allowed; }
722
722
  .modal-err { color: var(--bad); font-size: 12px; margin-top: 8px; }
723
+ /* The default value printed beside a setting hint: quiet, so it reads as an annotation
724
+ rather than a second label competing with the name. */
725
+ .set-def{opacity:.72;font-variant-numeric:tabular-nums;white-space:nowrap}
726
+ .set-ctl .gate-reset{flex:none}
723
727
  </style>
724
728
  </head>
725
729
  <body>
@@ -1118,7 +1122,7 @@
1118
1122
  <div class="set-grid">
1119
1123
  <div class="set-row">
1120
1124
  <div class="set-meta"><div class="set-name">Agent</div><div class="set-hint" id="gateAgentHint">which coding agent the pipeline drives</div></div>
1121
- <div class="set-ctl"><select id="gateAgent" class="linput"><option value="auto">auto</option><option value="claude">claude</option><option value="codex">codex</option><option value="opencode">opencode</option><option value="rovodev">rovodev</option><option value="pi">pi</option></select></div>
1125
+ <div class="set-ctl ladd" style="align-items:center"><select id="gateAgent" class="linput"><option value="auto">auto</option><option value="claude">claude</option><option value="codex">codex</option><option value="opencode">opencode</option><option value="rovodev">rovodev</option><option value="pi">pi</option></select></div>
1122
1126
  </div>
1123
1127
  <div class="set-row" id="gateModelRow">
1124
1128
  <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>
@@ -1130,11 +1134,11 @@
1130
1134
  </div>
1131
1135
  <div class="set-row">
1132
1136
  <div class="set-meta"><div class="set-name">Log level</div><div class="set-hint">daemon output verbosity</div></div>
1133
- <div class="set-ctl"><select id="gateLogLevel" class="linput"><option value="debug">debug</option><option value="info">info</option><option value="warn">warn</option><option value="error">error</option></select></div>
1137
+ <div class="set-ctl ladd" style="align-items:center"><select id="gateLogLevel" class="linput"><option value="debug">debug</option><option value="info">info</option><option value="warn">warn</option><option value="error">error</option></select></div>
1134
1138
  </div>
1135
1139
  <div class="set-row">
1136
1140
  <div class="set-meta"><div class="set-name">Read intent from transcripts</div><div class="set-hint">feeds what you were trying to do to every step; off makes the agents work from the diff alone</div></div>
1137
- <div class="set-ctl"><button id="gateIntent" type="button" class="toggle" data-kind="bool" role="switch" aria-checked="false" aria-label="Read intent from transcripts"></button></div>
1141
+ <div class="set-ctl ladd" style="align-items:center"><button id="gateIntent" type="button" class="toggle" data-kind="bool" role="switch" aria-checked="false" aria-label="Read intent from transcripts"></button></div>
1138
1142
  </div>
1139
1143
  </div>
1140
1144
  <div class="set-cat-h" style="margin-top:18px">Auto-fix attempts</div>
@@ -4467,6 +4471,57 @@ export {
4467
4471
  btn.dataset.on = on ? "1" : "0";
4468
4472
  btn.setAttribute("aria-checked", on ? "true" : "false");
4469
4473
  }
4474
+ // Defaults for every gate setting, straight from the gate's own config loader (the
4475
+ // server resolves an empty config rather than keeping a second copy of the numbers).
4476
+ // They drive the "default N" hint and the per-row reset below.
4477
+ let gateDefaults = null;
4478
+ // A per-setting reset. These values are mostly small integers that get nudged once and
4479
+ // then forgotten, and nothing on screen said what they started as - so the default is
4480
+ // printed in the hint AND made one click away. Icon-only with a name, per the icon
4481
+ // action rules; the title carries the value so a disabled reset still answers "what
4482
+ // was it?" without the user opening the YAML.
4483
+ function resetBtn(key, def, label) {
4484
+ if (def === null || def === undefined) return "";
4485
+ return '<button type="button" class="iconbtn gate-reset" data-gate-reset="' + esc(key) + '" data-gate-def="' + esc(String(def)) + '" data-gate-label="' + esc(label) + '"'
4486
+ + ' title="Reset to the default (' + esc(String(def)) + ')" aria-label="Reset ' + esc(label) + ' to the default (' + esc(String(def)) + ')">'
4487
+ + '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 2v6h6"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L3 8"/></svg></button>';
4488
+ }
4489
+ /** Put (or refresh) a reset button in the cell of a control rendered by the static markup. */
4490
+ function mountGateReset(key, label, def) {
4491
+ const el = gateCtlFor(key);
4492
+ if (!el || def === null || def === undefined || def === "") return;
4493
+ const cell = el.parentElement;
4494
+ if (!cell) return;
4495
+ const old = cell.querySelector("[data-gate-reset]");
4496
+ if (old) old.remove();
4497
+ cell.insertAdjacentHTML("beforeend", resetBtn(key, def, label));
4498
+ }
4499
+ /** The control a reset key writes, so the button can compare against what is on screen. */
4500
+ function gateCtlFor(key) {
4501
+ if (key.indexOf("auto_fix.") === 0) return document.querySelector('[data-gate-af="' + key.slice("auto_fix.".length) + '"]');
4502
+ if (key === "agent") return $("gateAgent");
4503
+ if (key === "log_level") return $("gateLogLevel");
4504
+ if (key === "ci_timeout") return $("gateCiTimeout");
4505
+ if (key === "intent.enabled") return $("gateIntent");
4506
+ return null;
4507
+ }
4508
+ /** Current value of a reset-able control, as the string its default is compared against. */
4509
+ function gateCtlValue(key, el) {
4510
+ if (!el) return null;
4511
+ if (key === "intent.enabled") return el.dataset.on === "1" ? "true" : "false";
4512
+ return String(el.value).trim();
4513
+ }
4514
+ // Nothing to reset is not the same as nothing to say: the button stays visible and
4515
+ // disabled (never hidden), because its title is where the default value is written.
4516
+ function syncGateResets() {
4517
+ for (const b of document.querySelectorAll("[data-gate-reset]")) {
4518
+ const key = b.dataset.gateReset;
4519
+ const cur = gateCtlValue(key, gateCtlFor(key));
4520
+ const isDefault = cur !== null && cur === b.dataset.gateDef;
4521
+ b.disabled = isDefault || !gateWritable;
4522
+ b.title = isDefault ? "Already the default (" + b.dataset.gateDef + ")" : "Reset to the default (" + b.dataset.gateDef + ")";
4523
+ }
4524
+ }
4470
4525
  const GATE_AUTOFIX = [
4471
4526
  ["rebase", "conflicts and stale-base failures"],
4472
4527
  ["review", "0 by default: review findings are yours to approve"],
@@ -4489,7 +4544,7 @@ export {
4489
4544
  ],
4490
4545
  };
4491
4546
  const GATE_MODEL_CUSTOM = "__custom__";
4492
- let gateSavedModel = "";
4547
+ let gateSavedModel = "", gateModelAgent = "";
4493
4548
 
4494
4549
  /**
4495
4550
  * Rebuilds the model dropdown for `agent` and selects `model` (empty = the agent default).
@@ -4499,7 +4554,10 @@ export {
4499
4554
  */
4500
4555
  function renderGateModel(agent, model) {
4501
4556
  const sel = $("gateModelSel"), inp = $("gateModel");
4502
- const opts = [["", "auto (agent default)"]].concat(GATE_MODELS[agent] || [], [[GATE_MODEL_CUSTOM, "Custom model id..."]]);
4557
+ gateModelAgent = agent || "";
4558
+ // Naming the agent in the default option is the whole point of it: clearing the model
4559
+ // drops the `--model` flag, so the step runs on whatever that agent picks for itself.
4560
+ const opts = [["", "auto (" + (agent || "agent") + " default)"]].concat(GATE_MODELS[agent] || [], [[GATE_MODEL_CUSTOM, "Custom model id..."]]);
4503
4561
  sel.innerHTML = opts.map(([v, label]) => '<option value="' + esc(v) + '">' + esc(label) + "</option>").join("");
4504
4562
  const listed = opts.some(([v]) => v === model && v !== GATE_MODEL_CUSTOM);
4505
4563
  sel.value = listed ? model : GATE_MODEL_CUSTOM;
@@ -4515,8 +4573,16 @@ export {
4515
4573
  $("gateModelSave").style.display = custom ? "" : "none";
4516
4574
  // Select + field + Save is wider than one settings column; the row takes the full width.
4517
4575
  $("gateModelRow").classList.toggle("wide", custom);
4576
+ syncGateModelHint();
4518
4577
  syncGateModelSave();
4519
4578
  }
4579
+ /** The hint has to follow the selection: on auto, nothing is passed to the agent at all. */
4580
+ function syncGateModelHint() {
4581
+ const agent = gateModelAgent || "the agent";
4582
+ $("gateModelHint").textContent = $("gateModelSel").value === ""
4583
+ ? "auto: " + agent + " runs on its own default model"
4584
+ : "passed to " + agent + " on every step; a smaller model cuts run time and tokens";
4585
+ }
4520
4586
  /** No-op rule: nothing to save while the typed id still equals the stored one. */
4521
4587
  function syncGateModelSave() {
4522
4588
  const btn = $("gateModelSave"), dirty = $("gateModel").value.trim() !== gateSavedModel;
@@ -4540,19 +4606,31 @@ export {
4540
4606
  ? "auto: first agent found on PATH - currently " + s.agentResolved
4541
4607
  : "which coding agent the pipeline drives";
4542
4608
  $("gateModelRow").style.display = s.modelSupported ? "" : "none";
4543
- renderGateModel(s.agentResolved || s.agent, s.model || "");
4544
- $("gateModelHint").textContent = "passed to " + s.agentResolved
4545
- + " on every step; a smaller model is the one change that cuts both run time and tokens";
4609
+ renderGateModel(s.agentResolved || s.agent, s.model || ""); // also writes the hint
4546
4610
  $("gateCiTimeout").value = s.ciTimeout || "";
4547
4611
  $("gateLogLevel").value = s.logLevel;
4548
4612
  syncDD($("gateLogLevel"));
4549
4613
  gateBool($("gateIntent"), s.intentEnabled);
4550
- $("gateAutoFix").innerHTML = GATE_AUTOFIX.map(([step, hint]) =>
4551
- '<div class="set-row"><div class="set-meta"><div class="set-name">' + esc(step) + '</div><div class="set-hint">' + esc(hint) + "</div></div>"
4552
- + '<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("");
4614
+ gateDefaults = s.defaults || null;
4615
+ $("gateAutoFix").innerHTML = GATE_AUTOFIX.map(([step, hint]) => {
4616
+ const def = gateDefaults && gateDefaults.autoFix ? Number(gateDefaults.autoFix[step] || 0) : null;
4617
+ return '<div class="set-row"><div class="set-meta"><div class="set-name">' + esc(step) + '</div><div class="set-hint">' + esc(hint)
4618
+ + (def === null ? "" : ' <span class="set-def">default ' + def + "</span>") + "</div></div>"
4619
+ + '<div class="set-ctl ladd" style="align-items:center"><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) + '">'
4620
+ + resetBtn("auto_fix." + step, def, "the " + step + " limit") + "</div></div>";
4621
+ }).join("");
4622
+ // The fixed rows get their reset mounted here rather than in the static markup,
4623
+ // because only the payload knows what each default actually is.
4624
+ if (gateDefaults) {
4625
+ mountGateReset("agent", "the agent", gateDefaults.agent);
4626
+ mountGateReset("log_level", "the log level", gateDefaults.logLevel);
4627
+ mountGateReset("ci_timeout", "the CI timeout", gateDefaults.ciTimeout);
4628
+ mountGateReset("intent.enabled", "intent extraction", String(gateDefaults.intentEnabled));
4629
+ }
4553
4630
  const ctls = panel.querySelectorAll("input, select, button");
4554
4631
  for (const c of ctls) c.disabled = !gateWritable;
4555
4632
  syncGateModelSave(); // after the sweep, which would otherwise re-enable a clean Save
4633
+ syncGateResets(); // likewise: the sweep would re-enable a reset with nothing to reset
4556
4634
  }
4557
4635
  // `live` marks a poll refresh: it repaints the run strip and the two switches, and leaves
4558
4636
  // every editor alone so a poll can never overwrite what is being typed.
@@ -4710,6 +4788,25 @@ export {
4710
4788
  const step = e.target.dataset && e.target.dataset.gateAf;
4711
4789
  if (step) saveGateSetting("auto_fix." + step, Number(e.target.value), "the " + step + " limit");
4712
4790
  });
4791
+ // Live feedback while typing: the reset greys out the moment the value is back to the
4792
+ // default, so the row answers "am I still overriding this?" without a save.
4793
+ $("gateAutoFix").addEventListener("input", syncGateResets);
4794
+ $("gateCiTimeout").addEventListener("input", syncGateResets);
4795
+ // One delegated handler for every reset in the panel. The write goes through the same
4796
+ // saveGateSetting as the control itself, so it reloads the gate afterwards - which is
4797
+ // what reconciles the optimistic paint and rolls it back if the save did not land.
4798
+ $("gateSetPanel").addEventListener("click", (e) => {
4799
+ const b = e.target.closest && e.target.closest("[data-gate-reset]");
4800
+ if (!b || b.disabled) return;
4801
+ const key = b.dataset.gateReset, def = b.dataset.gateDef, el = gateCtlFor(key);
4802
+ if (el) {
4803
+ if (key === "intent.enabled") gateBool(el, def === "true");
4804
+ else { el.value = def; if (el.tagName === "SELECT") syncDD(el); }
4805
+ syncGateResets();
4806
+ }
4807
+ const value = key.indexOf("auto_fix.") === 0 ? Number(def) : (key === "intent.enabled" ? def === "true" : def);
4808
+ saveGateSetting(key, value, b.dataset.gateLabel);
4809
+ });
4713
4810
 
4714
4811
  // --- section rail (a full-screen drawer below 900px) ---
4715
4812
  const sidebarEl = $("sidebar"), navScrimEl = $("navScrim"), navOpenBtn = $("navOpen");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enigmax/dashboard",
3
- "version": "0.1.99",
3
+ "version": "0.1.101",
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": [