@vue-skuilder/standalone-ui 0.2.3 → 0.2.5

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.
@@ -8662,7 +8662,7 @@ var stack$1, isWarning, ErrorCodes$1, ErrorTypeStrings$1, queue$1, flushIndex, p
8662
8662
  readonly: () => readonly,
8663
8663
  ref: () => ref,
8664
8664
  registerRuntimeCompiler: () => registerRuntimeCompiler,
8665
- render: () => render,
8665
+ render: () => render$1,
8666
8666
  renderList: () => renderList,
8667
8667
  renderSlot: () => renderSlot,
8668
8668
  resolveComponent: () => resolveComponent,
@@ -9165,7 +9165,7 @@ function normalizeContainer(t) {
9165
9165
  }
9166
9166
  return process.env.NODE_ENV !== "production" && window.ShadowRoot && t instanceof window.ShadowRoot && t.mode === "closed" && warn$2("mounting on a ShadowRoot with `{mode: \"closed\"}` may lead to unpredictable bugs"), t;
9167
9167
  }
9168
- var policy, tt$3, unsafeToTrustedHTML, svgNS, mathmlNS, doc, templateContainer, nodeOps, TRANSITION$1, ANIMATION, vtcKey, DOMTransitionPropsValidators, TransitionPropsValidators, decorate$1, Transition, callHook, hasExplicitCallback, endId, vShowOriginalDisplay, vShowHidden, vShow, CSS_VAR_TEXT, displayRE, semicolonRE, importantRE, prefixes, prefixCache, xlinkNS, veiKey, optionsModifierRE, cachedNow, p, getNow, isNativeOn, patchProp, REMOVAL, defineSSRCustomElement, BaseClass, VueElement, positionMap, newPositionMap, moveCbKey, enterCbKey, decorate, TransitionGroup, getModelAssigner, assignKey, vModelText, vModelCheckbox, vModelRadio, vModelSelect, vModelDynamic, systemModifiers, modifierGuards, withModifiers, keyNames, withKeys, rendererOptions, renderer, enabledHydration, render, hydrate, createApp, createSSRApp, ssrDirectiveInitialized, initDirectivesForSSR, init_runtime_dom_esm_bundler = __esmMin((() => {
9168
+ var policy, tt$3, unsafeToTrustedHTML, svgNS, mathmlNS, doc, templateContainer, nodeOps, TRANSITION$1, ANIMATION, vtcKey, DOMTransitionPropsValidators, TransitionPropsValidators, decorate$1, Transition, callHook, hasExplicitCallback, endId, vShowOriginalDisplay, vShowHidden, vShow, CSS_VAR_TEXT, displayRE, semicolonRE, importantRE, prefixes, prefixCache, xlinkNS, veiKey, optionsModifierRE, cachedNow, p, getNow, isNativeOn, patchProp, REMOVAL, defineSSRCustomElement, BaseClass, VueElement, positionMap, newPositionMap, moveCbKey, enterCbKey, decorate, TransitionGroup, getModelAssigner, assignKey, vModelText, vModelCheckbox, vModelRadio, vModelSelect, vModelDynamic, systemModifiers, modifierGuards, withModifiers, keyNames, withKeys, rendererOptions, renderer, enabledHydration, render$1, hydrate, createApp, createSSRApp, ssrDirectiveInitialized, initDirectivesForSSR, init_runtime_dom_esm_bundler = __esmMin((() => {
9169
9169
  if (init_runtime_core_esm_bundler(), init_runtime_core_esm_bundler(), init_shared_esm_bundler(), policy = void 0, tt$3 = typeof window < "u" && window.trustedTypes, tt$3) try {
9170
9170
  policy = /* @__PURE__ */ tt$3.createPolicy("vue", { createHTML: (t) => t });
9171
9171
  } catch (t) {
@@ -9330,7 +9330,7 @@ var policy, tt$3, unsafeToTrustedHTML, svgNS, mathmlNS, doc, templateContainer,
9330
9330
  }
9331
9331
  }
9332
9332
  _update() {
9333
- render(this._createVNode(), this._root);
9333
+ render$1(this._createVNode(), this._root);
9334
9334
  }
9335
9335
  _createVNode() {
9336
9336
  let t = {};
@@ -9563,9 +9563,9 @@ var policy, tt$3, unsafeToTrustedHTML, svgNS, mathmlNS, doc, templateContainer,
9563
9563
  let d = hyphenate(u.key);
9564
9564
  if (c.some((t) => t === d || keyNames[t] === d)) return t(u);
9565
9565
  });
9566
- }, rendererOptions = /* @__PURE__ */ extend$2({ patchProp }, nodeOps), enabledHydration = !1, render = (...t) => {
9566
+ }, rendererOptions = /* @__PURE__ */ extend$2({ patchProp }, nodeOps), enabledHydration = !1, render$1 = /* @__PURE__ */ __name$2((...t) => {
9567
9567
  ensureRenderer().render(...t);
9568
- }, hydrate = (...t) => {
9568
+ }, "render"), hydrate = (...t) => {
9569
9569
  ensureHydrationRenderer().hydrate(...t);
9570
9570
  }, createApp = (...t) => {
9571
9571
  let c = ensureRenderer().createApp(...t);
@@ -11790,7 +11790,7 @@ var activePinia, setActivePinia, piniaSymbol, MutationType, IS_CLIENT, _global,
11790
11790
  init_lib(), setActivePinia = (t) => activePinia = t, piniaSymbol = process.env.NODE_ENV === "production" ? Symbol() : Symbol("pinia"), __name$2(isPlainObject$2, "isPlainObject"), (function(t) {
11791
11791
  t.direct = "direct", t.patchObject = "patch object", t.patchFunction = "patch function";
11792
11792
  })(MutationType || (MutationType = {})), IS_CLIENT = typeof window < "u", _global = typeof window == "object" && window.window === window ? window : typeof self == "object" && self.self === self ? self : typeof window == "object" && window.global === window ? window : typeof globalThis == "object" ? globalThis : { HTMLElement: null }, _navigator = typeof navigator == "object" ? navigator : { userAgent: "" }, isMacOSWebView = /Macintosh/.test(_navigator.userAgent) && /AppleWebKit/.test(_navigator.userAgent) && !/Safari/.test(_navigator.userAgent), saveAs = IS_CLIENT ? typeof HTMLAnchorElement < "u" && "download" in HTMLAnchorElement.prototype && !isMacOSWebView ? downloadSaveAs : "msSaveOrOpenBlob" in _navigator ? msSaveAs : fileSaverSaveAs : () => {}, {assign: assign$1} = Object, noop = () => {}, fallbackRunWithContext = (t) => t(), ACTION_MARKER = Symbol(), ACTION_NAME = Symbol(), skipHydrateSymbol = process.env.NODE_ENV === "production" ? Symbol() : Symbol("pinia:skipHydration"), {assign} = Object;
11793
- })), MarkdownRenderer_DoVbFpA6_exports = /* @__PURE__ */ __exportAll$1({
11793
+ })), MarkdownRenderer_kStoDRNE_exports = /* @__PURE__ */ __exportAll$1({
11794
11794
  C: () => I$2,
11795
11795
  E: () => __name,
11796
11796
  S: () => useViewable,
@@ -12036,9 +12036,12 @@ function splitByDelimiters(t, c, u) {
12036
12036
  else return [t];
12037
12037
  return d;
12038
12038
  }
12039
+ function stripTrailingNewlines(t) {
12040
+ return t.replace(/[\r\n]+$/, "");
12041
+ }
12039
12042
  function splitTextToken(t) {
12040
12043
  if (containsComponent(t)) {
12041
- let c = splitByDelimiters(t.text, "{{", "}}"), u = splitByDelimiters(t.raw, "{{", "}}");
12044
+ let c = splitByDelimiters(stripTrailingNewlines(t.text), "{{", "}}"), u = splitByDelimiters(stripTrailingNewlines(t.raw), "{{", "}}");
12042
12045
  if (c.length === u.length) return c.map((t, d) => ({
12043
12046
  type: "text",
12044
12047
  text: c[d],
@@ -12050,7 +12053,7 @@ function splitTextToken(t) {
12050
12053
  function splitParagraphToken(t) {
12051
12054
  let c = [];
12052
12055
  if (containsComponent(t)) {
12053
- let u = splitByDelimiters(t.text, "{{", "}}"), d = splitByDelimiters(t.raw, "{{", "}}");
12056
+ let u = splitByDelimiters(stripTrailingNewlines(t.text), "{{", "}}"), d = splitByDelimiters(stripTrailingNewlines(t.raw), "{{", "}}");
12054
12057
  if (u.length === d.length) {
12055
12058
  for (let t = 0; t < u.length; t++) {
12056
12059
  let m = {
@@ -13793,7 +13796,7 @@ function _sfc_render$29(t, c, u, d, m, g) {
13793
13796
  src: c.audio
13794
13797
  }, null, 8, ["src"])) : createCommentVNode("", !0)]))), 128))]);
13795
13798
  }
13796
- var j$3, M$3, __name, N$3, te$2, P$2, ne$3, __commonJSMin, __exportAll, __copyProps, __toESM, F$3, re$3, ie$3, I$2, ae$3, setPinia, getPinia, oe$3, useCardPreviewModeStore, se$3, ce$3, le$3, ue$2, de$2, fe$2, pe$3, me$2, L$2, R$2, z$2, he$2, ge$2, _e$1, B$2, ve$2, V$2, ye$2, be$1, xe$1, H$2, Se$1, U$2, Ce$1, we$1, W$3, Te$2, Ee$2, De$2, Oe$2, ke$3, Ae$2, je$2, Me$2, Ne$2, Pe$2, Fe$2, G$3, Ie$2, Le$2, Re$2, ze$2, Be$2, Ve$2, He$2, Ue$2, We$2, Ge$2, Ke$2, qe$2, Je$2, Ye$2, Xe$2, Ze$2, Qe$2, $e$2, K$3, et$2, tt$2, nt$2, rt$2, it$2, at$2, ot$2, q$3, J$3, st$2, getEscapeReplacement, _Tokenizer, Y$3, _Renderer, _TextRenderer, X$3, _Hooks, Marked, Z$4, ct$2, lt$2, ut$2, Q$3, dt$2, ft$2, pt$2, mt$2, ht$2, gt$2, _t$1, vt$2, yt$1, bt$1, $$4, xt$1, St$1, Ct$1, wt$1, Tt$1, Et$1, Dt$1, MODES, Ot$1, kt$1, At$1, jt$1, Mt$1, Nt$1, Pt$1, Ft$1, It$1, Lt$1, Rt$1, zt$1, Bt$1, Vt$1, Ht$1, Ut$1, Wt$1, Gt$1, Kt$1, qt$1, Jt$1, Yt$1, Xt$1, Zt$1, Qt$1, $t$1, en$1, tn$1, nn$1, rn$1, an$1, on$2, sn$1, cn$1, ln$1, un$1, dn$1, fn$1, pn$1, mn$1, hn$1, gn$1, _n$1, vn$1, yn$1, init_MarkdownRenderer_DoVbFpA6 = __esmMin((() => {
13799
+ var j$3, M$3, __name, N$3, te$2, P$2, ne$3, __commonJSMin, __exportAll, __copyProps, __toESM, F$3, re$3, ie$3, I$2, ae$3, setPinia, getPinia, oe$3, useCardPreviewModeStore, se$3, ce$3, le$3, ue$2, de$2, fe$2, pe$3, me$2, L$2, R$2, z$2, he$2, ge$2, _e$1, B$2, ve$2, V$2, ye$2, be$1, xe$1, H$2, Se$1, U$2, Ce$1, we$1, W$3, Te$2, Ee$2, De$2, Oe$2, ke$3, Ae$2, je$2, Me$2, Ne$2, Pe$2, Fe$2, G$3, Ie$2, Le$2, Re$2, ze$2, Be$2, Ve$2, He$2, Ue$2, We$2, Ge$2, Ke$2, qe$2, Je$2, Ye$2, Xe$2, Ze$2, Qe$2, $e$2, K$3, et$2, tt$2, nt$2, rt$2, it$2, at$2, ot$2, q$3, J$3, st$2, getEscapeReplacement, _Tokenizer, Y$3, _Renderer, _TextRenderer, X$3, _Hooks, Marked, Z$4, ct$2, lt$2, ut$2, Q$3, dt$2, ft$2, pt$2, mt$2, ht$2, gt$2, _t$1, vt$2, yt$1, bt$1, $$4, xt$1, St$1, Ct$1, wt$1, Tt$1, Et$1, Dt$1, MODES, Ot$1, kt$1, At$1, jt$1, Mt$1, Nt$1, Pt$1, Ft$1, It$1, Lt$1, Rt$1, zt$1, Bt$1, Vt$1, Ht$1, Ut$1, Wt$1, Gt$1, Kt$1, qt$1, Jt$1, Yt$1, Xt$1, Zt$1, Qt$1, $t$1, en$1, tn$1, nn$1, rn$1, an$1, on$2, sn$1, cn$1, ln$1, un$1, dn$1, fn$1, pn$1, mn$1, hn$1, gn$1, _n$1, vn$1, yn$1, init_MarkdownRenderer_kStoDRNE = __esmMin((() => {
13797
13800
  init_vue_runtime_esm_bundler(), init_moment(), init_dist$1(), init_pinia(), j$3 = Object.create, M$3 = Object.defineProperty, __name = (t, c) => M$3(t, "name", {
13798
13801
  value: c,
13799
13802
  configurable: !0
@@ -26489,6 +26492,147 @@ function mountMixerDebugger() {
26489
26492
  let t = window;
26490
26493
  t.skuilder = t.skuilder || {}, t.skuilder.mixer = mixerDebugAPI;
26491
26494
  }
26495
+ function registerActiveController(t) {
26496
+ activeController = t;
26497
+ }
26498
+ function getActiveController() {
26499
+ return activeController;
26500
+ }
26501
+ function toggleSessionOverlay() {
26502
+ if (typeof document > "u") {
26503
+ logger.info("[Session Overlay] No DOM available (non-browser host); overlay unavailable.");
26504
+ return;
26505
+ }
26506
+ overlayEl ? (teardown(), logger.info("[Session Overlay] Hidden.")) : (mount(), logger.info("[Session Overlay] Shown. Toggle off with window.skuilder.session.dbgOverlay()."));
26507
+ }
26508
+ function mount() {
26509
+ minified = !1, overlayEl = document.createElement("div"), overlayEl.id = OVERLAY_ID, Object.assign(overlayEl.style, {
26510
+ position: "fixed",
26511
+ top: "8px",
26512
+ left: "8px",
26513
+ zIndex: "2147483647",
26514
+ maxWidth: "320px",
26515
+ maxHeight: "90vh",
26516
+ overflowY: "auto",
26517
+ padding: "8px 10px",
26518
+ background: "rgba(17, 24, 39, 0.92)",
26519
+ color: "#e5e7eb",
26520
+ font: "11px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace",
26521
+ borderRadius: "6px",
26522
+ boxShadow: "0 4px 16px rgba(0,0,0,0.4)",
26523
+ pointerEvents: "auto",
26524
+ userSelect: "none"
26525
+ }), document.body.appendChild(overlayEl), render(), pollHandle = setInterval(render, POLL_MS);
26526
+ }
26527
+ function teardown() {
26528
+ pollHandle !== null && (clearInterval(pollHandle), pollHandle = null), overlayEl?.parentNode && overlayEl.parentNode.removeChild(overlayEl), overlayEl = null;
26529
+ }
26530
+ function render() {
26531
+ if (!overlayEl) return;
26532
+ spinnerFrame++;
26533
+ let t = getActiveController();
26534
+ if (!t) {
26535
+ lastSnapshot = null, overlayEl.innerHTML = headerHtml() + (minified ? "" : "<div style=\"opacity:.65\">No active session.</div>"), attachHandlers();
26536
+ return;
26537
+ }
26538
+ let c = t.getDebugSnapshot();
26539
+ if (lastSnapshot = c, minified) {
26540
+ overlayEl.innerHTML = headerHtml(), attachHandlers();
26541
+ return;
26542
+ }
26543
+ overlayEl.innerHTML = headerHtml() + replanHtml(c) + metaHtml(c) + hintsHtml(c.sessionHints) + queueHtml("reviewQ", "reviewQ", c.reviewQ) + queueHtml("newQ", "newQ", c.newQ) + queueHtml("failedQ", "failedQ", c.failedQ) + drawnHtml("drawn", c.drawnCards), attachHandlers();
26544
+ }
26545
+ function attachHandlers() {
26546
+ if (!overlayEl) return;
26547
+ overlayEl.querySelectorAll("[data-q]").forEach((t) => {
26548
+ t.onclick = () => {
26549
+ let c = t.dataset.q;
26550
+ c && (expanded[c] = !expanded[c], render());
26551
+ };
26552
+ });
26553
+ let t = overlayEl.querySelector("[data-copy]");
26554
+ t && (t.onclick = (t) => {
26555
+ t.stopPropagation(), copySnapshot();
26556
+ });
26557
+ let c = overlayEl.querySelector("[data-min]");
26558
+ c && (c.onclick = (t) => {
26559
+ t.stopPropagation(), minified = !minified, render();
26560
+ });
26561
+ }
26562
+ function copySnapshot() {
26563
+ let t = snapshotToText(lastSnapshot), flash = () => {
26564
+ copyFlashUntil = Date.now() + 1200, render();
26565
+ }, c = typeof navigator < "u" ? navigator.clipboard : void 0;
26566
+ c?.writeText ? c.writeText(t).then(flash, (t) => {
26567
+ logger.warn(`[Session Overlay] Clipboard write failed: ${String(t)}`);
26568
+ }) : logger.info(`[Session Overlay] Clipboard unavailable; snapshot follows:
26569
+ ${t}`);
26570
+ }
26571
+ function headerHtml() {
26572
+ let t = Date.now() < copyFlashUntil;
26573
+ return `<div style="font-weight:600;color:#93c5fd;margin-bottom:${minified ? 0 : 4}px">${`<span data-copy style="cursor:pointer;float:right;font-weight:400;color:${t ? "#86efac" : "#93c5fd"};border:1px solid currentColor;border-radius:4px;padding:0 4px;line-height:1.3">${t ? "✓ copied" : "⎘ copy"}</span>`}${`<span data-min title="${minified ? "Restore" : "Minify"}" style="cursor:pointer;float:right;font-weight:400;color:#93c5fd;border:1px solid currentColor;border-radius:4px;padding:0 5px;margin-right:4px;line-height:1.3">${minified ? "▢" : "—"}</span>`}\u2699 SessionController</div>`;
26574
+ }
26575
+ function replanHtml(t) {
26576
+ return t.replanActive ? `<div style="margin-bottom:6px;color:#fde047">${SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length]} replanning <span style="opacity:.85">[${esc(t.replanLabel ?? "(auto)")}]</span></div>` : "<div style=\"margin-bottom:6px;opacity:.45\">○ idle</div>";
26577
+ }
26578
+ function metaHtml(t) {
26579
+ return `<div style="margin-bottom:6px">${[
26580
+ `time ${formatTime(t.secondsRemaining)}${t.hasCardGuarantee ? ` \xB7 <span style="color:#fbbf24">guarantee ${t.minCardsGuarantee}</span>` : ""}`,
26581
+ `well-indicated left: ${t.wellIndicatedRemaining}`,
26582
+ `current: ${t.currentCard ? esc(t.currentCard) : "<span style=\"opacity:.6\">—</span>"}`
26583
+ ].map((t) => `<div>${t}</div>`).join("")}</div>`;
26584
+ }
26585
+ function hintsHtml(t) {
26586
+ let c = [];
26587
+ return t && (t.boostTags && Object.keys(t.boostTags).length && c.push("boost: " + Object.entries(t.boostTags).map(([t, c]) => `${esc(t)}<span style="opacity:.6">\xD7${c}</span>`).join(", ")), t.boostCards && Object.keys(t.boostCards).length && c.push("boostCards: " + Object.entries(t.boostCards).map(([t, c]) => `${esc(t)}<span style="opacity:.6">\xD7${c}</span>`).join(", ")), t.requireCards?.length && c.push(`require: ${t.requireCards.map(esc).join(", ")}`), t.requireTags?.length && c.push(`requireTags: ${t.requireTags.map(esc).join(", ")}`), t.excludeTags?.length && c.push(`exclude: ${t.excludeTags.map(esc).join(", ")}`), t.excludeCards?.length && c.push(`excludeCards: ${t.excludeCards.map(esc).join(", ")}`)), `<div style="margin-bottom:6px"><div style="color:#86efac">sessionHints</div>${c.length ? c.map((t) => `<div style="margin-left:6px">${t}</div>`).join("") : "<div style=\"margin-left:6px;opacity:.6\">none</div>"}</div>`;
26588
+ }
26589
+ function queueHtml(t, c, u) {
26590
+ let d = u.length > INLINE_THRESHOLD, m = d && expanded[t], g = d ? expanded[t] ? "▾ " : "▸ " : "", b = u.dequeueCount ? ` <span style="opacity:.5">drawn ${u.dequeueCount}</span>` : "", S = d ? "cursor:pointer;color:#f9a8d4" : "color:#f9a8d4", C = `<div${d ? ` data-q="${t}"` : ""} style="${S}">${g}${c}: ${u.length}${b}</div>`;
26591
+ if (!u.cards.length) return C + "<div style=\"margin:1px 0 6px 6px;opacity:.5\">empty</div>";
26592
+ let w = m ? u.cards : u.cards.slice(0, INLINE_THRESHOLD), T = u.length - w.length, E = `<ol style="margin:2px 0 ${d ? 2 : 6}px 0;padding-left:20px">` + w.map((t) => `<li style="white-space:nowrap">${esc(t)}</li>`).join("") + "</ol>";
26593
+ if (d) {
26594
+ let c = m ? "▾ show less" : `\u2026 +${T} more`;
26595
+ E += `<div data-q="${t}" style="cursor:pointer;margin:0 0 6px 20px;opacity:.6">${c}</div>`;
26596
+ }
26597
+ return C + E;
26598
+ }
26599
+ function outcomeGlyph(t) {
26600
+ return t === !0 ? "<span style=\"color:#86efac\">✓</span>" : t === !1 ? "<span style=\"color:#fca5a5\">✗</span>" : "<span style=\"opacity:.5\">·</span>";
26601
+ }
26602
+ function drawnHtml(t, c) {
26603
+ let u = c.length > INLINE_THRESHOLD, d = u && expanded[t], m = u ? expanded[t] ? "▾ " : "▸ " : "", g = u ? "cursor:pointer;color:#c4b5fd" : "color:#c4b5fd", b = `<div${u ? ` data-q="${t}"` : ""} style="${g}">${m}drawn: ${c.length}</div>`;
26604
+ if (!c.length) return b + "<div style=\"margin:1px 0 6px 6px;opacity:.5\">none yet</div>";
26605
+ let S = d ? c : c.slice(0, INLINE_THRESHOLD), C = c.length - S.length, w = `<ol style="margin:2px 0 ${u ? 2 : 6}px 0;padding-left:20px">${S.map((t) => {
26606
+ let c = t.attempts > 1 ? `<span style="opacity:.5"> \xD7${t.attempts}</span>` : "", u = `<span style="opacity:.45"> ${Math.round(t.timeSpentMs / 100) / 10}s</span>`;
26607
+ return `<li style="white-space:nowrap">${outcomeGlyph(t.correct)} ${esc(t.cardID)}<span style="opacity:.5"> [${esc(t.status)}]</span>${c}${u}</li>`;
26608
+ }).join("")}</ol>`;
26609
+ if (u) {
26610
+ let c = d ? "▾ show less" : `\u2026 +${C} more`;
26611
+ w += `<div data-q="${t}" style="cursor:pointer;margin:0 0 6px 20px;opacity:.6">${c}</div>`;
26612
+ }
26613
+ return b + w;
26614
+ }
26615
+ function snapshotToText(t) {
26616
+ if (!t) return "SessionController — no active session.";
26617
+ let c = [];
26618
+ c.push("=== SessionController ==="), c.push(`time ${formatTime(t.secondsRemaining)}`), t.hasCardGuarantee && c.push(`guarantee: ${t.minCardsGuarantee}`), c.push(`well-indicated left: ${t.wellIndicatedRemaining}`), c.push(`current: ${t.currentCard ?? "—"}`), c.push(t.replanActive ? `replan: ACTIVE [${t.replanLabel ?? "(auto)"}]` : "replan: idle"), c.push(""), c.push("sessionHints:");
26619
+ let u = t.sessionHints, d = [];
26620
+ u && (u.boostTags && Object.keys(u.boostTags).length && d.push(` boost: ${Object.entries(u.boostTags).map(([t, c]) => `${t}\xD7${c}`).join(", ")}`), u.boostCards && Object.keys(u.boostCards).length && d.push(` boostCards: ${Object.entries(u.boostCards).map(([t, c]) => `${t}\xD7${c}`).join(", ")}`), u.requireCards?.length && d.push(` require: ${u.requireCards.join(", ")}`), u.requireTags?.length && d.push(` requireTags: ${u.requireTags.join(", ")}`), u.excludeTags?.length && d.push(` exclude: ${u.excludeTags.join(", ")}`), u.excludeCards?.length && d.push(` excludeCards: ${u.excludeCards.join(", ")}`)), c.push(d.length ? d.join("\n") : " none");
26621
+ let queueText = (t, u) => {
26622
+ c.push(""), c.push(`${t}: ${u.length} (drawn ${u.dequeueCount})`), u.cards.forEach((t, u) => c.push(` ${u + 1}. ${t}`));
26623
+ };
26624
+ return queueText("reviewQ", t.reviewQ), queueText("newQ", t.newQ), queueText("failedQ", t.failedQ), c.push(""), c.push(`drawn: ${t.drawnCards.length}`), t.drawnCards.forEach((t, u) => {
26625
+ let d = t.correct === !0 ? "✓" : t.correct === !1 ? "✗" : "·", m = `${Math.round(t.timeSpentMs / 100) / 10}s`;
26626
+ c.push(` ${u + 1}. ${d} ${t.cardID} [${t.status}] \xD7${t.attempts} ${m}`);
26627
+ }), c.join("\n");
26628
+ }
26629
+ function formatTime(t) {
26630
+ let c = Math.max(0, Math.round(t));
26631
+ return `${Math.floor(c / 60)}:${(c % 60).toString().padStart(2, "0")}`;
26632
+ }
26633
+ function esc(t) {
26634
+ return t.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
26635
+ }
26492
26636
  function startSessionTracking(t, c, u) {
26493
26637
  clearRunHistory();
26494
26638
  let d = `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
@@ -26599,7 +26743,7 @@ function mountSessionDebugger() {
26599
26743
  let t = window;
26600
26744
  t.skuilder = t.skuilder || {}, t.skuilder.session = sessionDebugAPI;
26601
26745
  }
26602
- var import___vite_browser_external, import___vite_browser_external$1, import___vite_browser_external$2, import_browser_ponyfill, import_browser_ponyfill$1, import_browser, _SessionController2, __defProp, __getOwnPropNames, __glob, __esm, __export, init_adminDB, init_classroomDB, init_SyncStrategy, isDevelopment, logger, init_logger, GuestUsername, log, DocType, DocTypePrefixes, init_types_legacy, init_util, pouchdb_setup_default, init_pouchdb_setup, init_dataDirectory, REVIEW_TIME_FORMAT, log2, init_userDBHelpers, Loggable, init_Loggable, UpdateQueue, init_updateQueue, UsrCrsData, init_user_course_relDB, CLIENT_CACHE, init_clientCache, AlreadyTaggedErr, init_courseAPI, courseLookupDBTitle, CourseLookup, init_courseLookupDB, PipelineDebugger_exports, _activePipeline, MAX_RUNS, runHistory, DISCARDED_KEEP_TOP, _uiContainer, _selectedRunIndex, _cardSearchQuery, pipelineDebugAPI, init_PipelineDebugger, CompositeGenerator_exports, AggregationMode, DEFAULT_AGGREGATION_MODE, FREQUENCY_BOOST_FACTOR, CompositeGenerator, init_CompositeGenerator, elo_exports, ELONavigator, init_elo, generators_exports, init_generators, prescribed_exports, DEFAULT_FRESHNESS_WINDOW, DEFAULT_MAX_DIRECT_PER_RUN, DEFAULT_MAX_SUPPORT_PER_RUN, DEFAULT_HIERARCHY_DEPTH, DEFAULT_MIN_COUNT, BASE_TARGET_SCORE, BASE_SUPPORT_SCORE, DISCOVERED_SUPPORT_SCORE, MAX_TARGET_MULTIPLIER, MAX_SUPPORT_MULTIPLIER, PRESCRIBED_DEBUG_VERSION, PrescribedCardsGenerator, init_prescribed, srs_exports, DEFAULT_HEALTHY_BACKLOG, MAX_BACKLOG_PRESSURE, SRSNavigator, init_srs, types_exports, init_types, globImport_generators, init_, DEFAULT_LEARNABLE_WEIGHT, init_contentNavigationStrategy, WeightedFilter_exports, WeightedFilter, init_WeightedFilter, eloDistance_exports, DEFAULT_HALF_LIFE, DEFAULT_MIN_MULTIPLIER, DEFAULT_MAX_MULTIPLIER, init_eloDistance, hierarchyDefinition_exports, DEFAULT_MIN_COUNT2, HierarchyDefinitionNavigator, init_hierarchyDefinition, userTagPreference_exports, UserTagPreferenceFilter, init_userTagPreference, filters_exports, init_filters, inferredPreferenceStub_exports, INFERRED_PREFERENCE_NAVIGATOR_STUB, init_inferredPreferenceStub, interferenceMitigator_exports, DEFAULT_MIN_COUNT3, DEFAULT_MIN_ELAPSED_DAYS, DEFAULT_INTERFERENCE_DECAY, InterferenceMitigatorNavigator, init_interferenceMitigator, relativePriority_exports, DEFAULT_PRIORITY, DEFAULT_PRIORITY_INFLUENCE, DEFAULT_COMBINE_MODE, RelativePriorityNavigator, init_relativePriority, types_exports2, init_types2, userGoalStub_exports, USER_GOAL_NAVIGATOR_STUB, init_userGoalStub, globImport_filters, init_2, init_gradient, MIN_OBSERVATIONS_FOR_UPDATE, LEARNING_RATE, MAX_WEIGHT_DELTA, MIN_R_SQUARED_FOR_GRADIENT, FLAT_GRADIENT_THRESHOLD, MAX_HISTORY_LENGTH, init_learning, init_signal, init_recording, MIN_SPREAD, MAX_SPREAD, MIN_WEIGHT, MAX_WEIGHT, init_orchestration, Pipeline_exports, VERBOSE_RESULTS, Pipeline, init_Pipeline, defaults_exports, init_defaults, PipelineAssembler_exports, PipelineAssembler, init_PipelineAssembler, globImport, init_3, navigators_exports, navigatorRegistry, Navigators, NavigatorRole, NavigatorRoles, ContentNavigator, init_navigators, CoursesDB, CourseDB, init_courseDB, classroomLookupDBTitle, CLASSROOM_CONFIG, ClassroomDBBase, StudentClassroomDB, TeacherClassroomDB, ClassroomLookupDB, init_classroomDB2, AdminDB, init_adminDB2, CourseSyncService_exports, DEFAULT_REPLICATION, CourseSyncService, init_CourseSyncService, init_auth, CouchDBSyncStrategy_exports, log3, CouchDBSyncStrategy, init_CouchDBSyncStrategy, isBrowser, GUEST_LOCAL_DB, localUserDB, pouchDBincludeCredentialsConfig, REVIEW_TIME_FORMAT2, init_couch, log4, BaseUser, userCoursesDoc, userClassroomsDoc, init_BaseUserDB, init_common, PouchDataLayerProvider_exports, CouchDataLayerProvider, init_PouchDataLayerProvider, pathUtils, nodeFS, StaticDataUnpacker, init_StaticDataUnpacker, StaticCourseDB, init_courseDB2, StaticCoursesDB, init_coursesDB, NoOpSyncStrategy, init_NoOpSyncStrategy, StaticDataLayerProvider_exports, StaticDataLayerProvider, init_StaticDataLayerProvider, NOT_SET, ENV, dataLayerInstance, init_factory, TagFilteredContentSource, init_TagFilteredContentSource, init_contentSource, init_courseDB3, init_dataLayerProvider, init_userDB, init_interfaces, init_user, init_strategyState, init_userOutcome, init_cardProcessor, init_types3, init_bulkImport, userDBDebugAPI, init_UserDBDebugger, init_core, duration, SrsService, EloService, ResponseProcessor, CardHydrationService, ItemQueue, CouchDBToStaticPacker, DEFAULT_MIGRATION_OPTIONS, FileSystemError, nodeFS2, nodeFS3, nodePath, StaticToCouchDBMigrator, QuotaRoundRobinMixer, MAX_RUNS2, runHistory2, mixerDebugAPI, activeSession, sessionHistory, MAX_HISTORY, sessionDebugAPI, SessionController, init_dist = __esmMin((() => {
26746
+ var import___vite_browser_external, import___vite_browser_external$1, import___vite_browser_external$2, import_browser_ponyfill, import_browser_ponyfill$1, import_browser, _SessionController2, __defProp, __getOwnPropNames, __glob, __esm, __export, init_adminDB, init_classroomDB, init_SyncStrategy, isDevelopment, logger, init_logger, GuestUsername, log, DocType, DocTypePrefixes, init_types_legacy, init_util, pouchdb_setup_default, init_pouchdb_setup, init_dataDirectory, REVIEW_TIME_FORMAT, log2, init_userDBHelpers, Loggable, init_Loggable, UpdateQueue, init_updateQueue, UsrCrsData, init_user_course_relDB, CLIENT_CACHE, init_clientCache, AlreadyTaggedErr, init_courseAPI, courseLookupDBTitle, CourseLookup, init_courseLookupDB, PipelineDebugger_exports, _activePipeline, MAX_RUNS, runHistory, DISCARDED_KEEP_TOP, _uiContainer, _selectedRunIndex, _cardSearchQuery, pipelineDebugAPI, init_PipelineDebugger, CompositeGenerator_exports, AggregationMode, DEFAULT_AGGREGATION_MODE, FREQUENCY_BOOST_FACTOR, CompositeGenerator, init_CompositeGenerator, elo_exports, ELO_RELEVANCE_SIGMA, ELONavigator, init_elo, generators_exports, init_generators, prescribed_exports, DEFAULT_FRESHNESS_WINDOW, DEFAULT_MAX_DIRECT_PER_RUN, DEFAULT_MAX_SUPPORT_PER_RUN, DEFAULT_HIERARCHY_DEPTH, DEFAULT_MIN_COUNT, BASE_TARGET_SCORE, BASE_SUPPORT_SCORE, DISCOVERED_SUPPORT_SCORE, MAX_TARGET_MULTIPLIER, MAX_SUPPORT_MULTIPLIER, PRESCRIBED_DEBUG_VERSION, PrescribedCardsGenerator, init_prescribed, srs_exports, DEFAULT_HEALTHY_BACKLOG, MAX_BACKLOG_PRESSURE, SRSNavigator, init_srs, types_exports, init_types, globImport_generators, init_, DEFAULT_LEARNABLE_WEIGHT, init_contentNavigationStrategy, WeightedFilter_exports, WeightedFilter, init_WeightedFilter, eloDistance_exports, DEFAULT_HALF_LIFE, DEFAULT_MIN_MULTIPLIER, DEFAULT_MAX_MULTIPLIER, init_eloDistance, hierarchyDefinition_exports, DEFAULT_MIN_COUNT2, HierarchyDefinitionNavigator, init_hierarchyDefinition, userTagPreference_exports, UserTagPreferenceFilter, init_userTagPreference, filters_exports, init_filters, inferredPreferenceStub_exports, INFERRED_PREFERENCE_NAVIGATOR_STUB, init_inferredPreferenceStub, interferenceMitigator_exports, DEFAULT_MIN_COUNT3, DEFAULT_MIN_ELAPSED_DAYS, DEFAULT_INTERFERENCE_DECAY, InterferenceMitigatorNavigator, init_interferenceMitigator, relativePriority_exports, DEFAULT_PRIORITY, DEFAULT_PRIORITY_INFLUENCE, DEFAULT_COMBINE_MODE, RelativePriorityNavigator, init_relativePriority, types_exports2, init_types2, userGoalStub_exports, USER_GOAL_NAVIGATOR_STUB, init_userGoalStub, globImport_filters, init_2, init_gradient, MIN_OBSERVATIONS_FOR_UPDATE, LEARNING_RATE, MAX_WEIGHT_DELTA, MIN_R_SQUARED_FOR_GRADIENT, FLAT_GRADIENT_THRESHOLD, MAX_HISTORY_LENGTH, init_learning, init_signal, init_recording, MIN_SPREAD, MAX_SPREAD, MIN_WEIGHT, MAX_WEIGHT, init_orchestration, Pipeline_exports, VERBOSE_RESULTS, Pipeline, init_Pipeline, defaults_exports, init_defaults, PipelineAssembler_exports, PipelineAssembler, init_PipelineAssembler, globImport, init_3, navigators_exports, navigatorRegistry, Navigators, NavigatorRole, NavigatorRoles, ContentNavigator, init_navigators, CoursesDB, CourseDB, init_courseDB, classroomLookupDBTitle, CLASSROOM_CONFIG, ClassroomDBBase, StudentClassroomDB, TeacherClassroomDB, ClassroomLookupDB, init_classroomDB2, AdminDB, init_adminDB2, CourseSyncService_exports, DEFAULT_REPLICATION, CourseSyncService, init_CourseSyncService, init_auth, CouchDBSyncStrategy_exports, log3, CouchDBSyncStrategy, init_CouchDBSyncStrategy, isBrowser, GUEST_LOCAL_DB, localUserDB, pouchDBincludeCredentialsConfig, REVIEW_TIME_FORMAT2, init_couch, log4, BaseUser, userCoursesDoc, userClassroomsDoc, init_BaseUserDB, init_common, PouchDataLayerProvider_exports, CouchDataLayerProvider, init_PouchDataLayerProvider, pathUtils, nodeFS, StaticDataUnpacker, init_StaticDataUnpacker, StaticCourseDB, init_courseDB2, StaticCoursesDB, init_coursesDB, NoOpSyncStrategy, init_NoOpSyncStrategy, StaticDataLayerProvider_exports, StaticDataLayerProvider, init_StaticDataLayerProvider, NOT_SET, ENV, dataLayerInstance, init_factory, TagFilteredContentSource, init_TagFilteredContentSource, init_contentSource, init_courseDB3, init_dataLayerProvider, init_userDB, init_interfaces, init_user, init_strategyState, init_userOutcome, init_cardProcessor, init_types3, init_bulkImport, userDBDebugAPI, init_UserDBDebugger, init_core, duration, SrsService, EloService, ResponseProcessor, CardHydrationService, ItemQueue, CouchDBToStaticPacker, DEFAULT_MIGRATION_OPTIONS, FileSystemError, nodeFS2, nodeFS3, nodePath, StaticToCouchDBMigrator, QuotaRoundRobinMixer, MAX_RUNS2, runHistory2, mixerDebugAPI, activeController, OVERLAY_ID, POLL_MS, INLINE_THRESHOLD, SPINNER_FRAMES, spinnerFrame, overlayEl, pollHandle, lastSnapshot, copyFlashUntil, minified, expanded, activeSession, sessionHistory, MAX_HISTORY, sessionDebugAPI, SessionController, init_dist = __esmMin((() => {
26603
26747
  init_defineProperty(), init_index_browser_es$5(), init_index_browser_es(), init_index_es(), import___vite_browser_external = /* @__PURE__ */ __toESM$2(require___vite_browser_external(), 1), import___vite_browser_external$1 = /* @__PURE__ */ __toESM$2(require___vite_browser_external(), 1), import___vite_browser_external$2 = /* @__PURE__ */ __toESM$2(require___vite_browser_external(), 1), init_moment(), init_dist$1(), init_esm_browser(), import_browser_ponyfill = /* @__PURE__ */ __toESM$2(require_browser_ponyfill(), 1), import_browser_ponyfill$1 = /* @__PURE__ */ __toESM$2(require_browser_ponyfill(), 1), import_browser = /* @__PURE__ */ __toESM$2(require_browser(), 1), __defProp = Object.defineProperty, __getOwnPropNames = Object.getOwnPropertyNames, __glob = (t) => (c) => {
26604
26748
  var u = t[c];
26605
26749
  if (u) return u();
@@ -27115,7 +27259,7 @@ var import___vite_browser_external, import___vite_browser_external$1, import___v
27115
27259
  }
27116
27260
  };
27117
27261
  } }), elo_exports = {}, __export(elo_exports, { default: () => ELONavigator }), init_elo = __esm({ "src/core/navigators/generators/elo.ts"() {
27118
- init_navigators(), init_logger(), ELONavigator = class extends ContentNavigator {
27262
+ init_navigators(), init_logger(), ELO_RELEVANCE_SIGMA = 300, ELONavigator = class extends ContentNavigator {
27119
27263
  constructor(t, c, u) {
27120
27264
  super(t, c, u), _defineProperty$2(this, "name", void 0), this.name = u?.name || "ELO";
27121
27265
  }
@@ -27129,7 +27273,7 @@ var import___vite_browser_external, import___vite_browser_external$1, import___v
27129
27273
  ...t,
27130
27274
  status: "new"
27131
27275
  })).map((t) => {
27132
- let c = t.elo ?? 1e3, d = Math.abs(c - u), m = Math.max(0, 1 - d / 500), g = m > 0 ? Math.random() ** (1 / m) : 0;
27276
+ let c = t.elo ?? 1e3, d = Math.abs(c - u), m = Math.exp(-((d / ELO_RELEVANCE_SIGMA) ** 2)), g = m * (.5 + .5 * Math.random());
27133
27277
  return {
27134
27278
  cardId: t.cardID,
27135
27279
  courseId: t.courseID,
@@ -27140,7 +27284,7 @@ var import___vite_browser_external, import___vite_browser_external$1, import___v
27140
27284
  strategyId: this.strategyId || "NAVIGATION_STRATEGY-ELO-default",
27141
27285
  action: "generated",
27142
27286
  score: g,
27143
- reason: `ELO distance ${Math.round(d)} (card: ${Math.round(c)}, user: ${Math.round(u)}), raw ${m.toFixed(3)}, key ${g.toFixed(3)}`
27287
+ reason: `ELO distance ${Math.round(d)} (card: ${Math.round(c)}, user: ${Math.round(u)}), relevance ${m.toFixed(3)}, key ${g.toFixed(3)}`
27144
27288
  }]
27145
27289
  };
27146
27290
  });
@@ -31690,7 +31834,23 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
31690
31834
  help() {
31691
31835
  logger.info("\n🎨 Mixer Debug API\n\nCommands:\n .showLastMix() Show summary of most recent mixer run\n .showRun(id|index) Show summary of a specific run (by index or ID suffix)\n .explainSourceBalance() Analyze source balance and selection patterns\n .compareScores() Compare score distributions across sources\n .showCard(cardId) Show mixer decisions for a specific card\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.mixer.showLastMix()\n window.skuilder.mixer.explainSourceBalance()\n window.skuilder.mixer.compareScores()\n");
31692
31836
  }
31693
- }, mountMixerDebugger(), init_logger(), init_PipelineDebugger(), activeSession = null, sessionHistory = [], MAX_HISTORY = 5, sessionDebugAPI = {
31837
+ }, mountMixerDebugger(), init_logger(), init_PipelineDebugger(), init_logger(), activeController = null, OVERLAY_ID = "skuilder-session-overlay", POLL_MS = 300, INLINE_THRESHOLD = 5, SPINNER_FRAMES = [
31838
+ "⠋",
31839
+ "⠙",
31840
+ "⠹",
31841
+ "⠸",
31842
+ "⠼",
31843
+ "⠴",
31844
+ "⠦",
31845
+ "⠧",
31846
+ "⠇",
31847
+ "⠏"
31848
+ ], spinnerFrame = 0, overlayEl = null, pollHandle = null, lastSnapshot = null, copyFlashUntil = 0, minified = !1, expanded = {
31849
+ reviewQ: !1,
31850
+ newQ: !1,
31851
+ failedQ: !1,
31852
+ drawn: !1
31853
+ }, activeSession = null, sessionHistory = [], MAX_HISTORY = 5, sessionDebugAPI = {
31694
31854
  get sessions() {
31695
31855
  return [...sessionHistory];
31696
31856
  },
@@ -31700,6 +31860,9 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
31700
31860
  showQueue() {
31701
31861
  showCurrentQueue();
31702
31862
  },
31863
+ dbgOverlay() {
31864
+ toggleSessionOverlay();
31865
+ },
31703
31866
  showHistory(t = 0) {
31704
31867
  showPresentationHistory(t);
31705
31868
  },
@@ -31730,7 +31893,7 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
31730
31893
  sessionHistory.length = 0, logger.info("[Session Debug] Session history cleared.");
31731
31894
  },
31732
31895
  help() {
31733
- logger.info("\n🎯 Session Debug API\n\nCommands:\n .showQueue() Show current queue state (active session only)\n .showHistory(index?) Show presentation history (0=current/last, 1=previous, etc)\n .showInterleaving(index?) Analyze course interleaving pattern\n .listSessions() List all tracked sessions\n .export() Export session data as JSON for bug reports\n .clear() Clear session history\n .sessions Access raw session history array\n .active Access active session (if any)\n .help() Show this help message\n\nExample:\n window.skuilder.session.showHistory()\n window.skuilder.session.showInterleaving()\n window.skuilder.session.showQueue()\n");
31896
+ logger.info("\n🎯 Session Debug API\n\nCommands:\n .dbgOverlay() Toggle the pinned live overlay (queues, hints, timer)\n .showQueue() Show current queue state (active session only)\n .showHistory(index?) Show presentation history (0=current/last, 1=previous, etc)\n .showInterleaving(index?) Analyze course interleaving pattern\n .listSessions() List all tracked sessions\n .export() Export session data as JSON for bug reports\n .clear() Clear session history\n .sessions Access raw session history array\n .active Access active session (if any)\n .help() Show this help message\n\nExample:\n window.skuilder.session.showHistory()\n window.skuilder.session.showInterleaving()\n window.skuilder.session.showQueue()\n");
31734
31897
  }
31735
31898
  }, mountSessionDebugger(), init_logger(), SessionController = (_SessionController2 = class _SessionController extends Loggable {
31736
31899
  set sessionRecord(t) {
@@ -31750,11 +31913,11 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
31750
31913
  return this.newQ.toString + "\n" + this.reviewQ.toString + "\n" + this.failedQ.toString;
31751
31914
  }
31752
31915
  constructor(t, c, u, d, m, g) {
31753
- super(), _defineProperty$2(this, "_className", "SessionController"), _defineProperty$2(this, "services", void 0), _defineProperty$2(this, "srsService", void 0), _defineProperty$2(this, "eloService", void 0), _defineProperty$2(this, "hydrationService", void 0), _defineProperty$2(this, "mixer", void 0), _defineProperty$2(this, "dataLayer", void 0), _defineProperty$2(this, "courseNameCache", /* @__PURE__ */ new Map()), _defineProperty$2(this, "_defaultBatchLimit", 20), _defineProperty$2(this, "_initialReviewCap", 200), _defineProperty$2(this, "sources", void 0), _defineProperty$2(this, "_sessionRecord", []), _defineProperty$2(this, "_currentCard", null), _defineProperty$2(this, "reviewQ", new ItemQueue()), _defineProperty$2(this, "newQ", new ItemQueue()), _defineProperty$2(this, "failedQ", new ItemQueue()), _defineProperty$2(this, "_replanPromise", null), _defineProperty$2(this, "_wellIndicatedRemaining", 0), _defineProperty$2(this, "_suppressQualityReplan", !1), _defineProperty$2(this, "_minCardsGuarantee", 0), _defineProperty$2(this, "_sessionHints", null), _defineProperty$2(this, "_outcomeObservers", []), _defineProperty$2(this, "_sessionControls", null), _defineProperty$2(this, "startTime", void 0), _defineProperty$2(this, "endTime", void 0), _defineProperty$2(this, "_secondsRemaining", void 0), _defineProperty$2(this, "_intervalHandle", void 0), this.dataLayer = u, this.mixer = m || new QuotaRoundRobinMixer(), this.srsService = new SrsService(u.getUserDB()), this.eloService = new EloService(u, u.getUserDB()), this.hydrationService = new CardHydrationService(d, (t) => u.getCourseDB(t), () => this._getItemsToHydrate()), this.services = { response: new ResponseProcessor(this.srsService, this.eloService) }, this.sources = t, this.startTime = /* @__PURE__ */ new Date(), this._secondsRemaining = c, this.endTime = new Date(this.startTime.valueOf() + 1e3 * this._secondsRemaining), g?.defaultBatchLimit !== void 0 && (this._defaultBatchLimit = g.defaultBatchLimit), g?.initialReviewCap !== void 0 && (this._initialReviewCap = g.initialReviewCap), g?.outcomeObservers?.length && (this._outcomeObservers = [...g.outcomeObservers]), this.log(`Session constructed:
31916
+ super(), _defineProperty$2(this, "_className", "SessionController"), _defineProperty$2(this, "services", void 0), _defineProperty$2(this, "srsService", void 0), _defineProperty$2(this, "eloService", void 0), _defineProperty$2(this, "hydrationService", void 0), _defineProperty$2(this, "mixer", void 0), _defineProperty$2(this, "dataLayer", void 0), _defineProperty$2(this, "courseNameCache", /* @__PURE__ */ new Map()), _defineProperty$2(this, "_defaultBatchLimit", 20), _defineProperty$2(this, "_initialReviewCap", 200), _defineProperty$2(this, "sources", void 0), _defineProperty$2(this, "_sessionRecord", []), _defineProperty$2(this, "_currentCard", null), _defineProperty$2(this, "reviewQ", new ItemQueue()), _defineProperty$2(this, "newQ", new ItemQueue()), _defineProperty$2(this, "failedQ", new ItemQueue()), _defineProperty$2(this, "_replanPromise", null), _defineProperty$2(this, "_activeReplanLabel", null), _defineProperty$2(this, "_wellIndicatedRemaining", 0), _defineProperty$2(this, "_suppressQualityReplan", !1), _defineProperty$2(this, "_minCardsGuarantee", 0), _defineProperty$2(this, "_sessionHints", null), _defineProperty$2(this, "_servedCardIds", /* @__PURE__ */ new Set()), _defineProperty$2(this, "_outcomeObservers", []), _defineProperty$2(this, "_sessionControls", null), _defineProperty$2(this, "startTime", void 0), _defineProperty$2(this, "endTime", void 0), _defineProperty$2(this, "_secondsRemaining", void 0), _defineProperty$2(this, "_intervalHandle", void 0), this.dataLayer = u, this.mixer = m || new QuotaRoundRobinMixer(), this.srsService = new SrsService(u.getUserDB()), this.eloService = new EloService(u, u.getUserDB()), this.hydrationService = new CardHydrationService(d, (t) => u.getCourseDB(t), () => this._getItemsToHydrate()), this.services = { response: new ResponseProcessor(this.srsService, this.eloService) }, this.sources = t, this.startTime = /* @__PURE__ */ new Date(), this._secondsRemaining = c, this.endTime = new Date(this.startTime.valueOf() + 1e3 * this._secondsRemaining), g?.defaultBatchLimit !== void 0 && (this._defaultBatchLimit = g.defaultBatchLimit), g?.initialReviewCap !== void 0 && (this._initialReviewCap = g.initialReviewCap), g?.outcomeObservers?.length && (this._outcomeObservers = [...g.outcomeObservers]), this.log(`Session constructed:
31754
31917
  startTime: ${this.startTime}
31755
31918
  endTime: ${this.endTime}
31756
31919
  defaultBatchLimit: ${this._defaultBatchLimit}
31757
- initialReviewCap: ${this._initialReviewCap}`);
31920
+ initialReviewCap: ${this._initialReviewCap}`), registerActiveController(this);
31758
31921
  }
31759
31922
  tick() {
31760
31923
  this._secondsRemaining = Math.floor((this.endTime.valueOf() - Date.now()) / 1e3), this._secondsRemaining <= 0 && clearInterval(this._intervalHandle);
@@ -31788,25 +31951,25 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
31788
31951
  if (!u) return this.log("Replan already in progress, coalescing unhinted auto-replan"), this._replanPromise;
31789
31952
  let t = c.label ? ` [${c.label}]` : "";
31790
31953
  this.log(`Replan in progress; queueing hint-bearing replan${t} behind in-flight run`);
31791
- let d = this._replanPromise.catch(() => void 0).then(() => this._runReplan(c));
31792
- return this._replanPromise = d.finally(() => {
31793
- this._replanPromise === d && (this._replanPromise = null);
31794
- }), d;
31954
+ let d = this._replanPromise.catch(() => void 0).then(() => this._runReplan(c)), m = d.finally(() => {
31955
+ this._replanPromise === m && (this._replanPromise = null, this._activeReplanLabel = null);
31956
+ });
31957
+ return this._replanPromise = m, d;
31795
31958
  }
31796
- let d = this._runReplan(c);
31797
- this._replanPromise = d.finally(() => {
31798
- this._replanPromise === d && (this._replanPromise = null);
31799
- }), await d;
31959
+ let d = this._runReplan(c), m = d.finally(() => {
31960
+ this._replanPromise === m && (this._replanPromise = null, this._activeReplanLabel = null);
31961
+ });
31962
+ this._replanPromise = m, await d;
31800
31963
  }
31801
31964
  _replanHasIntent(t) {
31802
- return !!(t.label || t.limit !== void 0 || t.minFollowUpCards !== void 0 || t.mode && t.mode !== "replace" || t.hints && Object.keys(t.hints).length > 0 || t.sessionHints !== void 0);
31965
+ return !!(t.limit !== void 0 || t.minFollowUpCards !== void 0 || t.mode && t.mode !== "replace" || t.hints && Object.keys(t.hints).length > 0 || t.sessionHints !== void 0 || t.mergeSessionHints !== void 0);
31803
31966
  }
31804
31967
  async _runReplan(t) {
31805
- t.hints || (t.hints = {});
31968
+ this._activeReplanLabel = t.label ?? "(auto)", t.hints || (t.hints = {});
31806
31969
  let c = t.hints, u = new Set(c.excludeCards ?? []);
31807
31970
  this._currentCard?.item.cardID && u.add(this._currentCard.item.cardID);
31808
31971
  for (let t of this._sessionRecord) u.add(t.card.card_id);
31809
- this.newQ.length > 0 && u.add(this.newQ.peek(0).cardID), c.excludeCards = [...u], t.sessionHints !== void 0 && (this._sessionHints = t.sessionHints, this.log(`[Replan] Session hints ${t.sessionHints ? "set" : "cleared"}: ${JSON.stringify(t.sessionHints)}`)), this._applyHintsToSources(t.hints, t.label);
31972
+ this.newQ.length > 0 && u.add(this.newQ.peek(0).cardID), c.excludeCards = [...u], t.sessionHints !== void 0 && (this._sessionHints = t.sessionHints, this.log(`[Replan] Session hints ${t.sessionHints ? "set" : "cleared"}: ${JSON.stringify(t.sessionHints)}`)), t.mergeSessionHints !== void 0 && (this._sessionHints = mergeHints2([this._sessionHints, t.mergeSessionHints]) ?? null, this.log(`[Replan] Session hints merged: ${JSON.stringify(this._sessionHints)}`)), this._applyHintsToSources(t.hints, t.label);
31810
31973
  let d = t.label ? ` [${t.label}]` : "";
31811
31974
  this.log(`Mid-session replan requested${d} (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}`)), await this._executeReplan(t);
31812
31975
  }
@@ -31816,6 +31979,40 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
31816
31979
  getSessionHints() {
31817
31980
  return this._sessionHints;
31818
31981
  }
31982
+ getDebugSnapshot() {
31983
+ let describe = (t) => {
31984
+ let c = [];
31985
+ for (let u = 0; u < t.length; u++) c.push(t.peek(u).cardID);
31986
+ return {
31987
+ length: t.length,
31988
+ dequeueCount: t.dequeueCount,
31989
+ cards: c
31990
+ };
31991
+ }, t = this._sessionRecord.map((t) => {
31992
+ let c = t.records[t.records.length - 1];
31993
+ return {
31994
+ cardID: t.item.cardID,
31995
+ status: t.item.status,
31996
+ attempts: t.records.length,
31997
+ correct: c && isQuestionRecord(c) ? c.isCorrect : null,
31998
+ timeSpentMs: t.records.reduce((t, c) => t + c.timeSpent, 0)
31999
+ };
32000
+ });
32001
+ return {
32002
+ secondsRemaining: this.secondsRemaining,
32003
+ hasCardGuarantee: this.hasCardGuarantee,
32004
+ minCardsGuarantee: this._minCardsGuarantee,
32005
+ wellIndicatedRemaining: this._wellIndicatedRemaining,
32006
+ currentCard: this._currentCard?.item.cardID ?? null,
32007
+ sessionHints: this._sessionHints,
32008
+ replanActive: this._replanPromise !== null,
32009
+ replanLabel: this._activeReplanLabel,
32010
+ reviewQ: describe(this.reviewQ),
32011
+ newQ: describe(this.newQ),
32012
+ failedQ: describe(this.failedQ),
32013
+ drawnCards: t
32014
+ };
32015
+ }
31819
32016
  mergeSessionHints(t) {
31820
32017
  this._sessionHints = mergeHints2([this._sessionHints, t]) ?? null, this.log(`Session hints merged: ${JSON.stringify(this._sessionHints)}`);
31821
32018
  }
@@ -31848,10 +32045,10 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
31848
32045
  }
31849
32046
  }
31850
32047
  async _replanUncoalesced(t) {
31851
- let c = this._runReplan(t);
31852
- this._replanPromise = c.finally(() => {
31853
- this._replanPromise === c && (this._replanPromise = null);
31854
- }), await c;
32048
+ let c = this._runReplan(t), u = c.finally(() => {
32049
+ this._replanPromise === u && (this._replanPromise = null, this._activeReplanLabel = null);
32050
+ });
32051
+ this._replanPromise = u, await c;
31855
32052
  }
31856
32053
  normalizeReplanOptions(t) {
31857
32054
  if (!t) return {};
@@ -31961,7 +32158,7 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
31961
32158
  }));
31962
32159
  let C = S.map((t) => this.courseNameCache.get(t)), w = this.mixer instanceof QuotaRoundRobinMixer ? Math.ceil(m * this.sources.length / g.length) : void 0;
31963
32160
  captureMixerRun(this.mixer.constructor.name, g, S, C, m * this.sources.length, w, b);
31964
- let T = b.filter((t) => getCardOrigin(t) === "review").slice(0, this._initialReviewCap), E = b.filter((t) => getCardOrigin(t) === "new").slice(0, d);
32161
+ let T = b.filter((t) => getCardOrigin(t) === "review").slice(0, this._initialReviewCap), E = b.filter((t) => getCardOrigin(t) === "new" && !this._servedCardIds.has(t.cardId)).slice(0, d);
31965
32162
  logger.debug(`[reviews] got ${T.length} reviews from mixer`);
31966
32163
  let D = c ? "Replan content:\n" : "Mixed content session created with:\n";
31967
32164
  if (!c) for (let t of T) {
@@ -32015,9 +32212,12 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
32015
32212
  if (this.dismissCurrentCard(t), this._minCardsGuarantee > 0 && (this._minCardsGuarantee--, this.log(`[CardGuarantee] ${this._minCardsGuarantee} guaranteed cards remaining`)), this._replanPromise && this.newQ.length === 0 && this.reviewQ.length === 0 && this.failedQ.length === 0 && (this.log("nextCard: queues empty, awaiting in-flight replan before drawing"), await this._replanPromise), this.newQ.length <= _SessionController.DEPLETION_PREFETCH_THRESHOLD && this._secondsRemaining > 0 && !this._replanPromise) {
32016
32213
  this._suppressQualityReplan = !1;
32017
32214
  let t = this.reviewQ.length + this.failedQ.length;
32018
- this.log(`[AutoReplan:depletion] newQ has ${this.newQ.length} card(s) (${t} in other queues) with ${this._secondsRemaining}s remaining. Triggering background replan.`), this.requestReplan();
32215
+ this.log(`[AutoReplan:depletion] newQ has ${this.newQ.length} card(s) (${t} in other queues) with ${this._secondsRemaining}s remaining. Triggering background replan.`), this.requestReplan({
32216
+ label: "auto:depletion",
32217
+ mode: "merge"
32218
+ });
32019
32219
  }
32020
- if (!this._suppressQualityReplan && this._wellIndicatedRemaining <= 3 && this.newQ.length > 0 && !this._replanPromise && (this.log(`[AutoReplan:quality] ${this._wellIndicatedRemaining} well-indicated cards remaining (newQ: ${this.newQ.length}). Triggering background replan.`), this.requestReplan()), this._secondsRemaining <= 0 && this.failedQ.length === 0 && this._minCardsGuarantee <= 0) return this._currentCard = null, endSessionTracking(), null;
32220
+ if (!this._suppressQualityReplan && this._wellIndicatedRemaining <= 3 && this.newQ.length > 0 && !this._replanPromise && (this.log(`[AutoReplan:quality] ${this._wellIndicatedRemaining} well-indicated cards remaining (newQ: ${this.newQ.length}). Triggering background replan.`), this.requestReplan({ label: "auto:quality" })), this._secondsRemaining <= 0 && this.failedQ.length === 0 && this._minCardsGuarantee <= 0) return this._currentCard = null, endSessionTracking(), null;
32021
32221
  let c = 3, u = 250, d = 0;
32022
32222
  for (; this._secondsRemaining > 0 && this.newQ.length === 0 && this.reviewQ.length === 0 && this.failedQ.length === 0;) if (this.log(`[WedgeBreaker] All queues empty with ${this._secondsRemaining}s remaining. Running pipeline (attempt ${d + 1}/3).`), await this._replanUncoalesced({ label: "wedge-breaker" }), this.newQ.length === 0 && this.reviewQ.length === 0 && this.failedQ.length === 0) {
32023
32223
  if (d++, d >= 3) {
@@ -32065,7 +32265,16 @@ ${c.id}:`), logger.info(JSON.stringify(c.doc, null, 2));
32065
32265
  } else (t === "dismiss-error" || t === "dismiss-failed") && this.hydrationService.removeCard(this._currentCard.item.cardID);
32066
32266
  }
32067
32267
  removeItemFromQueue(t) {
32068
- this.reviewQ.peek(0)?.cardID === t.cardID ? this.reviewQ.dequeue((t) => t.cardID) : this.newQ.peek(0)?.cardID === t.cardID ? (this.newQ.dequeue((t) => t.cardID), this._wellIndicatedRemaining > 0 && this._wellIndicatedRemaining--) : this.failedQ.peek(0)?.cardID === t.cardID && this.failedQ.dequeue((t) => t.cardID);
32268
+ this._clearDurableRequirement(t.cardID), this._servedCardIds.add(t.cardID), this.reviewQ.peek(0)?.cardID === t.cardID ? this.reviewQ.dequeue((t) => t.cardID) : this.newQ.peek(0)?.cardID === t.cardID ? (this.newQ.dequeue((t) => t.cardID), this._wellIndicatedRemaining > 0 && this._wellIndicatedRemaining--) : this.failedQ.peek(0)?.cardID === t.cardID && this.failedQ.dequeue((t) => t.cardID);
32269
+ }
32270
+ _clearDurableRequirement(t) {
32271
+ let c = this._sessionHints?.requireCards;
32272
+ if (!c || c.length === 0) return;
32273
+ let u = c.filter((c) => c !== t);
32274
+ u.length !== c.length && (this._sessionHints = {
32275
+ ...this._sessionHints,
32276
+ requireCards: u.length > 0 ? u : void 0
32277
+ }, this.log(`[Replan] Durable requirement satisfied & cleared on draw: ${t}`));
32069
32278
  }
32070
32279
  async endSession() {
32071
32280
  if (!this._sessionRecord || this._sessionRecord.length === 0) return;
@@ -41730,7 +41939,7 @@ function _sfc_render$27(t, c, u, d, m, g) {
41730
41939
  }, 8, ["loading"]);
41731
41940
  }
41732
41941
  var Ee$1, De$1, Oe$1, ke$1, Ae$1, je$1, Me$1, Ne$1, Pe$1, Fe$1, Ie$1, Le$1, Z$2, Re$1, ze$1, Be$1, Ve$1, He$1, Ue$1, We$1, Ge$1, Ke$1, qe$1, Je$1, Ye$1, Xe$1, Ze$1, Qe$1, $e$1, et$1, tt$1, nt$1, rt$1, it$1, at$1, Displayable, Question, getApiBase, ot$1, st$1, ct$1, Q$1, lt$1, ut$1, dt$1, ft$1, pt$1, mt$1, ht$1, gt$1, _t, vt$1, yt, bt, xt, St, Ct, wt, Tt, Et, Dt, Ot, kt, At, jt, Mt, Nt, Pt, Ft, It, Lt, Rt, zt, Bt, Vt, Ht, Ut, Wt, Gt, Kt, qt, Jt, Yt, Xt, Zt, Qt, $t, en, tn, nn, rn, an, on, sn, cn, ln, un, dn, fn, pn, mn, hn, gn, _n, vn, yn, useAuthStore, useConfigStore, bn, xn, Sn, Cn, wn, Tn, En, Dn, On, kn, An, jn, Mn, Nn, Pn, Fn, In, Ln, Rn, zn, Bn, Vn, Hn, Un, Wn, Gn, Kn, qn, Jn, Yn, Xn, Zn, Qn, $n, er, tr, nr, rr, ir, ar, or, sr, cr, lr, ur, dr, fr, pr, mr, hr, gr, _r, vr, $$2, yr, br, xr, Sr, Cr, wr, Tr, Er, Dr, init_common_ui_es = __esmMin((() => {
41733
- init_MarkdownRenderer_DoVbFpA6(), init_vue_runtime_esm_bundler(), init_moment(), init_dist$1(), init_dist(), init_pinia(), init_vue_router(), init_vue_tags_input(), Ee$1 = /* @__PURE__ */ defineComponent({
41942
+ init_MarkdownRenderer_kStoDRNE(), init_vue_runtime_esm_bundler(), init_moment(), init_dist$1(), init_dist(), init_pinia(), init_vue_router(), init_vue_tags_input(), Ee$1 = /* @__PURE__ */ defineComponent({
41734
41943
  name: "HeatMap",
41735
41944
  props: {
41736
41945
  activityRecords: {
@@ -43110,7 +43319,7 @@ var Ee$1, De$1, Oe$1, ke$1, Ae$1, je$1, Me$1, Ne$1, Pe$1, Fe$1, Ie$1, Le$1, Z$2,
43110
43319
  class: "card-transition-container"
43111
43320
  }, on = { key: 0 }, __name(_sfc_render$15, "_sfc_render"), sn = /* @__PURE__ */ F$3(Qt, [["render", _sfc_render$15], ["__scopeId", "data-v-de7119e9"]]), cn = /* @__PURE__ */ defineComponent({
43112
43321
  name: "MultipleChoiceOption",
43113
- components: { MarkdownRenderer: /* @__PURE__ */ defineAsyncComponent(() => Promise.resolve().then(() => (init_MarkdownRenderer_DoVbFpA6(), MarkdownRenderer_DoVbFpA6_exports)).then((t) => t.n)) },
43322
+ components: { MarkdownRenderer: /* @__PURE__ */ defineAsyncComponent(() => Promise.resolve().then(() => (init_MarkdownRenderer_kStoDRNE(), MarkdownRenderer_kStoDRNE_exports)).then((t) => t.n)) },
43114
43323
  props: {
43115
43324
  content: {
43116
43325
  type: String,