@vue-skuilder/standalone-ui 0.1.35 → 0.1.36

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 (27) hide show
  1. package/dist/assets/{TagViewer-BPkaxyIU.js → TagViewer-DYPKSc3Z.js} +2 -2
  2. package/dist/assets/{TagViewer-BPkaxyIU.js.map → TagViewer-DYPKSc3Z.js.map} +1 -1
  3. package/dist/assets/common-ui.es-3rfUYt9S.js +1 -0
  4. package/dist/assets/{common-ui.es-DxZNthuJ.js → common-ui.es-DfgaTZ4z.js} +4 -4
  5. package/dist/assets/{common-ui.es-DxZNthuJ.js.map → common-ui.es-DfgaTZ4z.js.map} +1 -1
  6. package/dist/assets/{dist-BC_KquM-.js → dist-BcZ1gsNX.js} +33 -11
  7. package/dist/assets/dist-BcZ1gsNX.js.map +1 -0
  8. package/dist/assets/index-CwbD9tGY.css +1 -0
  9. package/dist/assets/{index-C6NB1IPv.js → index-e8XolFvR.js} +5 -5
  10. package/dist/assets/index-e8XolFvR.js.map +1 -0
  11. package/dist/index.html +4 -4
  12. package/dist-lib/assets/index.css +1 -1
  13. package/dist-lib/{common-ui.es-BndKNv1Z.js → common-ui.es-B8Tew0sr.js} +3 -3
  14. package/dist-lib/{common-ui.es-BndKNv1Z.js.map → common-ui.es-B8Tew0sr.js.map} +1 -1
  15. package/dist-lib/{common-ui.es-CXj4fGMG.js → common-ui.es-Be_EI6up.js} +2 -2
  16. package/dist-lib/{dist-D3TZHmH5.js → dist-BP0_sJdJ.js} +144 -34
  17. package/dist-lib/dist-BP0_sJdJ.js.map +1 -0
  18. package/dist-lib/questions.cjs.js +37 -15
  19. package/dist-lib/questions.cjs.js.map +1 -1
  20. package/dist-lib/questions.mjs +3 -3
  21. package/dist-lib/questions.mjs.map +1 -1
  22. package/package.json +6 -6
  23. package/dist/assets/common-ui.es-CWLWg2GC.js +0 -1
  24. package/dist/assets/dist-BC_KquM-.js.map +0 -1
  25. package/dist/assets/index-C6NB1IPv.js.map +0 -1
  26. package/dist/assets/index-DEb1MxOC.css +0 -1
  27. package/dist-lib/dist-D3TZHmH5.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import "./moment-BW3a6Jo4.js";
2
2
  import { w as e } from "./MarkdownRenderer-DoVbFpA6-BjR5e6Al.js";
3
- import "./dist-D3TZHmH5.js";
4
- import "./common-ui.es-BndKNv1Z.js";
3
+ import "./dist-BP0_sJdJ.js";
4
+ import "./common-ui.es-B8Tew0sr.js";
5
5
  export { e as MarkdownRenderer };
@@ -8496,6 +8496,7 @@ var AlreadyTaggedErr, init_courseAPI = __esm({ "src/impl/couch/courseAPI.ts"() {
8496
8496
  __export(PipelineDebugger_exports, {
8497
8497
  buildRunReport: () => buildRunReport,
8498
8498
  captureRun: () => captureRun,
8499
+ clearRunHistory: () => clearRunHistory,
8499
8500
  mountPipelineDebugger: () => mountPipelineDebugger,
8500
8501
  pipelineDebugAPI: () => pipelineDebugAPI,
8501
8502
  registerPipelineForDebug: () => registerPipelineForDebug
@@ -8503,6 +8504,9 @@ __export(PipelineDebugger_exports, {
8503
8504
  function registerPipelineForDebug(e) {
8504
8505
  _activePipeline = e;
8505
8506
  }
8507
+ function clearRunHistory() {
8508
+ runHistory.length = 0;
8509
+ }
8506
8510
  function getOrigin(e) {
8507
8511
  let t = e.provenance[0];
8508
8512
  if (!t) return "unknown";
@@ -8524,7 +8528,7 @@ function parseCardElo(e) {
8524
8528
  return n ? parseInt(n[1], 10) : void 0;
8525
8529
  }
8526
8530
  function buildRunReport(e, t, n, r, a, o, s, c, l, u) {
8527
- let d = new Set(c.map((e) => e.cardId)), p = s.map((e) => ({
8531
+ let d = new Set(c.map((e) => e.cardId)), toReport = (e) => ({
8528
8532
  cardId: e.cardId,
8529
8533
  courseId: e.courseId,
8530
8534
  origin: getOrigin(e),
@@ -8534,7 +8538,25 @@ function buildRunReport(e, t, n, r, a, o, s, c, l, u) {
8534
8538
  provenance: e.provenance,
8535
8539
  tags: e.tags,
8536
8540
  selected: d.has(e.cardId)
8537
- })), m = c.filter((e) => getOrigin(e) === "review").length, g = c.filter((e) => getOrigin(e) === "new").length;
8541
+ }), p = [], m = [], g = [], _ = 0;
8542
+ for (let e of s) d.has(e.cardId) ? p.push(toReport(e)) : _ < DISCARDED_KEEP_TOP ? (m.push(toReport(e)), _++) : g.push(e);
8543
+ let v = [...p, ...m], y;
8544
+ if (g.length > 0) {
8545
+ let e = Infinity, t = -Infinity, n = Infinity, r = -Infinity, a = !1;
8546
+ for (let o of g) {
8547
+ o.score < e && (e = o.score), o.score > t && (t = o.score);
8548
+ let s = parseCardElo(o.provenance);
8549
+ s !== void 0 && (a = !0, s < n && (n = s), s > r && (r = s));
8550
+ }
8551
+ let o = a ? `, ELO ${n}\u2013${r}` : "";
8552
+ y = {
8553
+ count: g.length,
8554
+ scoreRange: [e, t],
8555
+ eloRange: a ? [n, r] : void 0,
8556
+ note: `${g.length} additional candidate(s) scored below the top ${DISCARDED_KEEP_TOP} near-misses and were not retained (score ${e.toExponential(2)}\u2013${t.toExponential(2)}${o}). Likely ELO-window pull remnants filtered out by hierarchy/lesson/priority gates.`
8557
+ };
8558
+ }
8559
+ let b = c.filter((e) => getOrigin(e) === "review").length, x = c.filter((e) => getOrigin(e) === "new").length;
8538
8560
  return {
8539
8561
  courseId: e,
8540
8562
  courseName: t,
@@ -8545,9 +8567,10 @@ function buildRunReport(e, t, n, r, a, o, s, c, l, u) {
8545
8567
  filters: o,
8546
8568
  hints: u,
8547
8569
  finalCount: c.length,
8548
- reviewsSelected: m,
8549
- newSelected: g,
8550
- cards: p
8570
+ reviewsSelected: b,
8571
+ newSelected: x,
8572
+ cards: v,
8573
+ discardedTail: y
8551
8574
  };
8552
8575
  }
8553
8576
  function formatProvenance(e) {
@@ -8566,22 +8589,49 @@ function printRunSummary(e) {
8566
8589
  }
8567
8590
  logger.info(`Result: ${e.finalCount} cards selected (${e.newSelected} new, ${e.reviewsSelected} reviews)`), console.groupEnd();
8568
8591
  }
8592
+ function escapeHtml(e) {
8593
+ return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
8594
+ }
8595
+ function escapeAttr(e) {
8596
+ return escapeHtml(e).replace(/"/g, "&quot;");
8597
+ }
8598
+ function copyTextToClipboard(e, t) {
8599
+ let done = () => {
8600
+ if (!t) return;
8601
+ let e = t.textContent ?? "Copy";
8602
+ t.textContent = "Copied!", t.classList.add("copied"), setTimeout(() => {
8603
+ t.textContent = e, t.classList.remove("copied");
8604
+ }, 1200);
8605
+ }, fallback = () => {
8606
+ let t = document.createElement("textarea");
8607
+ t.value = e, t.style.position = "fixed", t.style.opacity = "0", document.body.appendChild(t), t.select();
8608
+ try {
8609
+ document.execCommand("copy");
8610
+ } catch (e) {
8611
+ logger.warn(`[Pipeline Debug] Copy failed: ${e}`);
8612
+ }
8613
+ document.body.removeChild(t), done();
8614
+ };
8615
+ navigator.clipboard?.writeText ? navigator.clipboard.writeText(e).then(done).catch(fallback) : fallback();
8616
+ }
8569
8617
  function renderUI() {
8570
8618
  if (!_uiContainer) return;
8571
- let e = runHistory, t = _selectedRunIndex === null ? null : e[_selectedRunIndex], n = "\n #sk-pipeline-debugger {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: #f8f9fa;\n color: #212529;\n z-index: 999999;\n display: flex;\n flex-direction: column;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 14px;\n }\n #sk-pipeline-debugger header {\n padding: 1rem;\n background: #343a40;\n color: white;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n #sk-pipeline-debugger .container {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n #sk-pipeline-debugger .sidebar {\n width: 300px;\n border-right: 1px solid #dee2e6;\n overflow-y: auto;\n background: white;\n }\n #sk-pipeline-debugger .main-content {\n flex: 1;\n overflow-y: auto;\n padding: 1.5rem;\n }\n #sk-pipeline-debugger .run-item {\n padding: 0.75rem 1rem;\n border-bottom: 1px solid #eee;\n cursor: pointer;\n }\n #sk-pipeline-debugger .run-item:hover { background: #f1f3f5; }\n #sk-pipeline-debugger .run-item.active { background: #e9ecef; border-left: 4px solid #007bff; }\n #sk-pipeline-debugger h2, #sk-pipeline-debugger h3 { margin-top: 0; }\n #sk-pipeline-debugger table { width: 100%; border-collapse: collapse; margin-bottom: 1rem; background: white; }\n #sk-pipeline-debugger th, #sk-pipeline-debugger td { border: 1px solid #dee2e6; padding: 0.5rem; text-align: left; }\n #sk-pipeline-debugger th { background: #f1f3f5; }\n #sk-pipeline-debugger code { background: #f1f3f5; padding: 0.1rem 0.3rem; border-radius: 3px; font-family: monospace; }\n #sk-pipeline-debugger .close-btn { background: #dc3545; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; }\n #sk-pipeline-debugger .search-box { margin-bottom: 1rem; width: 100%; padding: 0.5rem; border: 1px solid #ced4da; border-radius: 4px; }\n #sk-pipeline-debugger .provenance { font-size: 12px; color: #666; margin-top: 0.25rem; white-space: pre-wrap; font-family: monospace; background: #f8f9fa; padding: 0.5rem; border-radius: 4px; }\n ", r = e.length === 0 ? "<div style=\"padding: 1rem;\">No runs captured yet.</div>" : e.map((e, t) => `
8619
+ let e = runHistory, t = _selectedRunIndex === null ? null : e[_selectedRunIndex], n = "\n #sk-pipeline-debugger {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: #f8f9fa;\n color: #212529;\n z-index: 999999;\n display: flex;\n flex-direction: column;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 14px;\n }\n #sk-pipeline-debugger header {\n padding: 1rem;\n background: #343a40;\n color: white;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n #sk-pipeline-debugger .container {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n #sk-pipeline-debugger .sidebar {\n width: 300px;\n border-right: 1px solid #dee2e6;\n overflow-y: auto;\n background: white;\n }\n #sk-pipeline-debugger .main-content {\n flex: 1;\n overflow-y: auto;\n padding: 1.5rem;\n }\n #sk-pipeline-debugger .run-item {\n padding: 0.75rem 1rem;\n border-bottom: 1px solid #eee;\n cursor: pointer;\n }\n #sk-pipeline-debugger .run-item:hover { background: #f1f3f5; }\n #sk-pipeline-debugger .run-item.active { background: #e9ecef; border-left: 4px solid #007bff; }\n #sk-pipeline-debugger h2, #sk-pipeline-debugger h3 { margin-top: 0; }\n #sk-pipeline-debugger table { width: 100%; border-collapse: collapse; margin-bottom: 1rem; background: white; }\n #sk-pipeline-debugger th, #sk-pipeline-debugger td { border: 1px solid #dee2e6; padding: 0.5rem; text-align: left; }\n #sk-pipeline-debugger th { background: #f1f3f5; }\n #sk-pipeline-debugger code { background: #f1f3f5; padding: 0.1rem 0.3rem; border-radius: 3px; font-family: monospace; }\n #sk-pipeline-debugger .close-btn { background: #dc3545; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; }\n #sk-pipeline-debugger .search-box { margin-bottom: 1rem; width: 100%; padding: 0.5rem; border: 1px solid #ced4da; border-radius: 4px; }\n #sk-pipeline-debugger .provenance { font-size: 12px; color: #666; margin-top: 0.25rem; white-space: pre-wrap; font-family: monospace; background: #f8f9fa; padding: 0.5rem; border-radius: 4px; }\n #sk-pipeline-debugger .run-label { display: inline-block; margin-top: 0.25rem; padding: 0.1rem 0.4rem; background: #fff3cd; color: #664d03; border-radius: 3px; font-family: monospace; font-size: 11px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }\n #sk-pipeline-debugger .label-banner { display: inline-block; padding: 0.25rem 0.6rem; background: #fff3cd; color: #664d03; border-radius: 4px; font-family: monospace; font-size: 13px; margin: 0 0 0.75rem 0; }\n #sk-pipeline-debugger .copy-btn { background: #0d6efd; color: white; border: none; padding: 0.25rem 0.6rem; border-radius: 3px; cursor: pointer; font-size: 12px; margin-left: 0.5rem; }\n #sk-pipeline-debugger .copy-btn:hover { background: #0b5ed7; }\n #sk-pipeline-debugger .copy-btn.copied { background: #198754; }\n #sk-pipeline-debugger .section-head { display: flex; align-items: center; justify-content: space-between; margin-top: 1rem; }\n #sk-pipeline-debugger .section-head h3 { margin: 0; }\n ", r = e.length === 0 ? "<div style=\"padding: 1rem;\">No runs captured yet.</div>" : e.map((e, t) => `
8572
8620
  <div class="run-item ${t === _selectedRunIndex ? "active" : ""}" onclick="window.skuilder.pipeline._selectRun(${t})">
8573
8621
  <strong>${e.timestamp.toLocaleTimeString()}</strong><br/>
8574
8622
  <small>${e.courseName || e.courseId.slice(0, 8)}</small><br/>
8575
8623
  <small>${e.finalCount} cards selected</small>
8624
+ ${e.hints?._label ? `<br/><span class="run-label" title="${escapeAttr(e.hints._label)}">${escapeHtml(e.hints._label)}</span>` : ""}
8576
8625
  </div>
8577
8626
  `).join(""), a = "<div style=\"color: #6c757d; text-align: center; margin-top: 5rem;\">Select a run to see details</div>";
8578
8627
  if (t) {
8579
- let e = t.cards.filter((e) => !_cardSearchQuery || e.cardId.toLowerCase().includes(_cardSearchQuery.toLowerCase()));
8628
+ let e = t.cards.filter((e) => !_cardSearchQuery || e.cardId.toLowerCase().includes(_cardSearchQuery.toLowerCase())), n = t.hints?._label ?? "(no label)";
8580
8629
  a = `
8581
8630
  <h2>Run: ${t.runId}</h2>
8631
+ <div class="label-banner" title="${escapeAttr(n)}">${escapeHtml(n)}</div>
8582
8632
  <p>
8583
- <strong>Time:</strong> ${t.timestamp.toLocaleString()} |
8584
- <strong>Course:</strong> ${t.courseName || t.courseId} |
8633
+ <strong>Time:</strong> ${t.timestamp.toLocaleString()} |
8634
+ <strong>Course:</strong> ${t.courseName || t.courseId} |
8585
8635
  <strong>User ELO:</strong> ${t.userElo ?? "unknown"}
8586
8636
  </p>
8587
8637
 
@@ -8594,7 +8644,10 @@ function renderUI() {
8594
8644
  </table>
8595
8645
 
8596
8646
  ${t.hints ? `
8597
- <h3>Ephemeral Hints</h3>
8647
+ <div class="section-head">
8648
+ <h3>Ephemeral Hints</h3>
8649
+ <button class="copy-btn" onclick="window.skuilder.pipeline._copyConfig('${t.runId}', this)">Copy config</button>
8650
+ </div>
8598
8651
  <table>
8599
8652
  ${t.hints._label ? `<tr><th>Label</th><td>${t.hints._label}</td></tr>` : ""}
8600
8653
  ${t.hints.boostTags ? `<tr><th>Boost Tags</th><td><pre style="margin:0">${JSON.stringify(t.hints.boostTags, null, 2)}</pre></td></tr>` : ""}
@@ -8616,7 +8669,10 @@ function renderUI() {
8616
8669
  </tbody>
8617
8670
  </table>
8618
8671
 
8619
- <h3>Cards (${t.finalCount} selected / ${t.cards.length} total)</h3>
8672
+ <div class="section-head">
8673
+ <h3>Cards (${t.finalCount} selected / ${t.cards.length} total)</h3>
8674
+ <button class="copy-btn" onclick="window.skuilder.pipeline._copyResults('${t.runId}', this)">Copy results</button>
8675
+ </div>
8620
8676
  <input type="text" class="search-box" placeholder="Search Card ID..." value="${_cardSearchQuery}" oninput="window.skuilder.pipeline._setSearch(this.value)">
8621
8677
 
8622
8678
  <table>
@@ -8697,6 +8753,13 @@ function renderUI() {
8697
8753
  #sk-pipeline-debugger .close-btn { background: #dc3545; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; }
8698
8754
  #sk-pipeline-debugger .search-box { margin-bottom: 1rem; width: 100%; padding: 0.5rem; border: 1px solid #ced4da; border-radius: 4px; }
8699
8755
  #sk-pipeline-debugger .provenance { font-size: 12px; color: #666; margin-top: 0.25rem; white-space: pre-wrap; font-family: monospace; background: #f8f9fa; padding: 0.5rem; border-radius: 4px; }
8756
+ #sk-pipeline-debugger .run-label { display: inline-block; margin-top: 0.25rem; padding: 0.1rem 0.4rem; background: #fff3cd; color: #664d03; border-radius: 3px; font-family: monospace; font-size: 11px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
8757
+ #sk-pipeline-debugger .label-banner { display: inline-block; padding: 0.25rem 0.6rem; background: #fff3cd; color: #664d03; border-radius: 4px; font-family: monospace; font-size: 13px; margin: 0 0 0.75rem 0; }
8758
+ #sk-pipeline-debugger .copy-btn { background: #0d6efd; color: white; border: none; padding: 0.25rem 0.6rem; border-radius: 3px; cursor: pointer; font-size: 12px; margin-left: 0.5rem; }
8759
+ #sk-pipeline-debugger .copy-btn:hover { background: #0b5ed7; }
8760
+ #sk-pipeline-debugger .copy-btn.copied { background: #198754; }
8761
+ #sk-pipeline-debugger .section-head { display: flex; align-items: center; justify-content: space-between; margin-top: 1rem; }
8762
+ #sk-pipeline-debugger .section-head h3 { margin: 0; }
8700
8763
  </style>
8701
8764
  <header>
8702
8765
  <strong>Pipeline Debugger</strong>
@@ -8713,8 +8776,8 @@ function mountPipelineDebugger() {
8713
8776
  let e = window;
8714
8777
  e.skuilder = e.skuilder || {}, e.skuilder.pipeline = pipelineDebugAPI;
8715
8778
  }
8716
- var _activePipeline, MAX_RUNS, runHistory, _uiContainer, _selectedRunIndex, _cardSearchQuery, pipelineDebugAPI, init_PipelineDebugger = __esm({ "src/core/navigators/PipelineDebugger.ts"() {
8717
- init_navigators(), init_logger(), _activePipeline = null, MAX_RUNS = 10, runHistory = [], _uiContainer = null, _selectedRunIndex = null, _cardSearchQuery = "", pipelineDebugAPI = {
8779
+ var _activePipeline, MAX_RUNS, runHistory, DISCARDED_KEEP_TOP, _uiContainer, _selectedRunIndex, _cardSearchQuery, pipelineDebugAPI, init_PipelineDebugger = __esm({ "src/core/navigators/PipelineDebugger.ts"() {
8780
+ init_navigators(), init_logger(), _activePipeline = null, MAX_RUNS = 10, runHistory = [], DISCARDED_KEEP_TOP = 25, _uiContainer = null, _selectedRunIndex = null, _cardSearchQuery = "", pipelineDebugAPI = {
8718
8781
  get runs() {
8719
8782
  return [...runHistory];
8720
8783
  },
@@ -8746,7 +8809,8 @@ var _activePipeline, MAX_RUNS, runHistory, _uiContainer, _selectedRunIndex, _car
8746
8809
  return;
8747
8810
  }
8748
8811
  }
8749
- logger.info(`[Pipeline Debug] Card '${e}' not found in recent runs.`);
8812
+ let t = runHistory.filter((e) => e.discardedTail && e.discardedTail.count > 0);
8813
+ t.length > 0 ? logger.info(`[Pipeline Debug] Card '${e}' not found in retained cards. ${t.length} run(s) have discarded tails that were not retained \u2014 the card may have been a low-score candidate. See run.discardedTail for ranges.`) : logger.info(`[Pipeline Debug] Card '${e}' not found in recent runs.`);
8750
8814
  },
8751
8815
  explainReviews() {
8752
8816
  if (runHistory.length === 0) {
@@ -8891,6 +8955,37 @@ var _activePipeline, MAX_RUNS, runHistory, _uiContainer, _selectedRunIndex, _car
8891
8955
  _setSearch(e) {
8892
8956
  _cardSearchQuery = e, renderUI();
8893
8957
  },
8958
+ _copyConfig(e, t) {
8959
+ let n = runHistory.find((t) => t.runId === e);
8960
+ if (!n) return;
8961
+ let r = {
8962
+ runId: n.runId,
8963
+ timestamp: n.timestamp.toISOString(),
8964
+ courseId: n.courseId,
8965
+ courseName: n.courseName,
8966
+ hints: n.hints ?? null
8967
+ };
8968
+ copyTextToClipboard(JSON.stringify(r, null, 2), t);
8969
+ },
8970
+ _copyResults(e, t) {
8971
+ let n = runHistory.find((t) => t.runId === e);
8972
+ if (!n) return;
8973
+ let r = n.cards.filter((e) => e.selected).sort((e, t) => t.finalScore - e.finalScore).map((e) => ({
8974
+ cardId: e.cardId,
8975
+ generator: e.generator,
8976
+ origin: e.origin,
8977
+ score: Number(e.finalScore.toFixed(3)),
8978
+ topReason: e.provenance[0]?.reason ?? ""
8979
+ })), a = {
8980
+ runId: n.runId,
8981
+ label: n.hints?._label ?? null,
8982
+ finalCount: n.finalCount,
8983
+ newSelected: n.newSelected,
8984
+ reviewsSelected: n.reviewsSelected,
8985
+ selected: r
8986
+ };
8987
+ copyTextToClipboard(JSON.stringify(a, null, 2), t);
8988
+ },
8894
8989
  help() {
8895
8990
  logger.info("\n🔧 Pipeline Debug API\n\nCommands:\n .ui() Toggle full-screen UI debugger\n .showLastRun() Show summary of most recent pipeline run\n .showRun(id|index) Show summary of a specific run (by index or ID suffix)\n .showCard(cardId) Show provenance trail for a specific card\n .showTagElo(pattern) Show user's tag ELO data (async). E.g. 'gpc:expose:*'\n .explainReviews() Analyze why reviews were/weren't selected\n .diagnoseCardSpace() Scan full card space through filters (async)\n .showRegistry() Show navigator registry (classes + roles)\n .showStrategies() Show registry + strategy mapping from last run\n .showPrescribed(id?) Show prescribed-generated cards and blocked/support details from last run\n .listRuns() List all captured runs in table format\n .export() Export run history as JSON for bug reports\n .clear() Clear run history\n .runs Access raw run history array\n .help() Show this help message\n\nExample:\n window.skuilder.pipeline.ui()\n window.skuilder.pipeline.showLastRun()\n window.skuilder.pipeline.showRun(1)\n await window.skuilder.pipeline.diagnoseCardSpace()\n");
8896
8991
  }
@@ -14888,9 +14983,10 @@ function mountMixerDebugger() {
14888
14983
  let e = window;
14889
14984
  e.skuilder = e.skuilder || {}, e.skuilder.mixer = mixerDebugAPI;
14890
14985
  }
14891
- mountMixerDebugger(), init_logger();
14986
+ mountMixerDebugger(), init_logger(), init_PipelineDebugger();
14892
14987
  var activeSession = null, sessionHistory = [], MAX_HISTORY = 5;
14893
14988
  function startSessionTracking(e, t, n) {
14989
+ clearRunHistory();
14894
14990
  let r = `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
14895
14991
  activeSession = {
14896
14992
  sessionId: r,
@@ -15095,25 +15191,39 @@ var SessionController = (_SessionController2 = class _SessionController extends
15095
15191
  }
15096
15192
  async requestReplan(e) {
15097
15193
  let t = this.normalizeReplanOptions(e);
15098
- if ((t.hints || t.label || t.limit) && (this._depletionReplanAttempted = !1), this._replanPromise) return this.log("Replan already in progress, awaiting existing replan"), this._replanPromise;
15099
- t.hints || (t.hints = {});
15100
- let n = t.hints, r = new Set(n.excludeCards ?? []);
15101
- this._currentCard?.item.cardID && r.add(this._currentCard.item.cardID);
15102
- for (let e of this._sessionRecord) r.add(e.card.card_id);
15103
- if (this.newQ.length > 0 && r.add(this.newQ.peek(0).cardID), n.excludeCards = [...r], t.hints) {
15104
- let e = t.label ? {
15105
- ...t.hints,
15106
- _label: t.label
15107
- } : t.hints;
15108
- for (let t of this.sources) t.setEphemeralHints?.(e);
15109
- }
15110
- let a = t.label ? ` [${t.label}]` : "";
15111
- this.log(`Mid-session replan requested${a} (limit: ${t.limit ?? "default"}, mode: ${t.mode ?? "replace"}${t.hints ? ", with hints" : ""})`), t.minFollowUpCards !== void 0 && t.minFollowUpCards > 0 && (this._minCardsGuarantee = Math.max(this._minCardsGuarantee, t.minFollowUpCards), this.log(`[Replan] Card guarantee set to ${this._minCardsGuarantee}`)), this._replanPromise = this._executeReplan(t);
15112
- try {
15113
- await this._replanPromise;
15114
- } finally {
15115
- this._replanPromise = null;
15194
+ (t.hints || t.label || t.limit) && (this._depletionReplanAttempted = !1);
15195
+ let n = this._replanHasIntent(t);
15196
+ if (this._replanPromise) {
15197
+ if (!n) return this.log("Replan already in progress, coalescing unhinted auto-replan"), this._replanPromise;
15198
+ let e = t.label ? ` [${t.label}]` : "";
15199
+ this.log(`Replan in progress; queueing hint-bearing replan${e} behind in-flight run`);
15200
+ let r = this._replanPromise.catch(() => void 0).then(() => this._runReplan(t));
15201
+ return this._replanPromise = r.finally(() => {
15202
+ this._replanPromise === r && (this._replanPromise = null);
15203
+ }), r;
15116
15204
  }
15205
+ let r = this._runReplan(t);
15206
+ this._replanPromise = r.finally(() => {
15207
+ this._replanPromise === r && (this._replanPromise = null);
15208
+ }), await r;
15209
+ }
15210
+ _replanHasIntent(e) {
15211
+ return !!(e.label || e.limit !== void 0 || e.minFollowUpCards !== void 0 || e.mode && e.mode !== "replace" || e.hints && Object.keys(e.hints).length > 0);
15212
+ }
15213
+ async _runReplan(e) {
15214
+ e.hints || (e.hints = {});
15215
+ let t = e.hints, n = new Set(t.excludeCards ?? []);
15216
+ this._currentCard?.item.cardID && n.add(this._currentCard.item.cardID);
15217
+ for (let e of this._sessionRecord) n.add(e.card.card_id);
15218
+ if (this.newQ.length > 0 && n.add(this.newQ.peek(0).cardID), t.excludeCards = [...n], e.hints) {
15219
+ let t = e.label ? {
15220
+ ...e.hints,
15221
+ _label: e.label
15222
+ } : e.hints;
15223
+ for (let e of this.sources) e.setEphemeralHints?.(t);
15224
+ }
15225
+ let r = e.label ? ` [${e.label}]` : "";
15226
+ this.log(`Mid-session replan requested${r} (limit: ${e.limit ?? "default"}, mode: ${e.mode ?? "replace"}${e.hints ? ", with hints" : ""})`), e.minFollowUpCards !== void 0 && e.minFollowUpCards > 0 && (this._minCardsGuarantee = Math.max(this._minCardsGuarantee, e.minFollowUpCards), this.log(`[Replan] Card guarantee set to ${this._minCardsGuarantee}`)), await this._executeReplan(e);
15117
15227
  }
15118
15228
  normalizeReplanOptions(e) {
15119
15229
  if (!e) return {};
@@ -15343,4 +15453,4 @@ init_TagFilteredContentSource(), init_factory();
15343
15453
  //#endregion
15344
15454
  export { getStudySource as a, getDataLayer as i, dist_exports as n, getCardHistoryID as r, SessionController as t };
15345
15455
 
15346
- //# sourceMappingURL=dist-D3TZHmH5.js.map
15456
+ //# sourceMappingURL=dist-BP0_sJdJ.js.map