@vue-skuilder/db 0.2.2 → 0.2.3

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 (39) hide show
  1. package/dist/{contentSource-Ht3N2f-y.d.ts → contentSource-Cplhv3bJ.d.ts} +1 -1
  2. package/dist/{contentSource-BMlMwSiG.d.cts → contentSource-kI9_jwTu.d.cts} +1 -1
  3. package/dist/core/index.d.cts +5 -5
  4. package/dist/core/index.d.ts +5 -5
  5. package/dist/core/index.js +2 -1
  6. package/dist/core/index.js.map +1 -1
  7. package/dist/core/index.mjs +2 -1
  8. package/dist/core/index.mjs.map +1 -1
  9. package/dist/{dataLayerProvider-BEqB8VBR.d.cts → dataLayerProvider-CiA2Rr0v.d.cts} +1 -1
  10. package/dist/{dataLayerProvider-DObSXjnf.d.ts → dataLayerProvider-DrBqOUa3.d.ts} +1 -1
  11. package/dist/impl/couch/index.d.cts +3 -3
  12. package/dist/impl/couch/index.d.ts +3 -3
  13. package/dist/impl/couch/index.js +2 -1
  14. package/dist/impl/couch/index.js.map +1 -1
  15. package/dist/impl/couch/index.mjs +2 -1
  16. package/dist/impl/couch/index.mjs.map +1 -1
  17. package/dist/impl/static/index.d.cts +4 -4
  18. package/dist/impl/static/index.d.ts +4 -4
  19. package/dist/impl/static/index.js +2 -1
  20. package/dist/impl/static/index.js.map +1 -1
  21. package/dist/impl/static/index.mjs +2 -1
  22. package/dist/impl/static/index.mjs.map +1 -1
  23. package/dist/{index-BWvO-_rJ.d.ts → index-BLLT5BYE.d.ts} +1 -1
  24. package/dist/{index-Ba7hYbHj.d.cts → index-k9NFHpS1.d.cts} +1 -1
  25. package/dist/index.d.cts +164 -10
  26. package/dist/index.d.ts +164 -10
  27. package/dist/index.js +141 -8
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +141 -8
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/{types-W8n-B6HG.d.cts → types-BFUa1pa3.d.cts} +1 -1
  32. package/dist/{types-CJrLM1Ew.d.ts → types-CHgpWQAY.d.ts} +1 -1
  33. package/dist/{types-legacy-JXDxinpU.d.cts → types-legacy-4tlwHnXo.d.cts} +1 -1
  34. package/dist/{types-legacy-JXDxinpU.d.ts → types-legacy-4tlwHnXo.d.ts} +1 -1
  35. package/dist/util/packer/index.d.cts +3 -3
  36. package/dist/util/packer/index.d.ts +3 -3
  37. package/package.json +3 -3
  38. package/src/core/navigators/Pipeline.ts +1 -1
  39. package/src/study/SessionController.ts +262 -13
package/dist/index.js CHANGED
@@ -4207,7 +4207,8 @@ var init_orchestration = __esm({
4207
4207
  // src/core/navigators/Pipeline.ts
4208
4208
  var Pipeline_exports = {};
4209
4209
  __export(Pipeline_exports, {
4210
- Pipeline: () => Pipeline
4210
+ Pipeline: () => Pipeline,
4211
+ mergeHints: () => mergeHints2
4211
4212
  });
4212
4213
  function globToRegex(pattern) {
4213
4214
  const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
@@ -11344,6 +11345,7 @@ var ItemQueue = class {
11344
11345
 
11345
11346
  // src/study/SessionController.ts
11346
11347
  init_couch();
11348
+ init_core();
11347
11349
  init_recording();
11348
11350
 
11349
11351
  // src/util/index.ts
@@ -12770,6 +12772,7 @@ init_dataDirectory();
12770
12772
 
12771
12773
  // src/study/SessionController.ts
12772
12774
  init_navigators();
12775
+ init_Pipeline();
12773
12776
 
12774
12777
  // src/study/SourceMixer.ts
12775
12778
  var QuotaRoundRobinMixer = class {
@@ -13481,6 +13484,32 @@ var SessionController = class _SessionController extends Loggable {
13481
13484
  * each nextCard() draw. Set by replans that include `minFollowUpCards`.
13482
13485
  */
13483
13486
  _minCardsGuarantee = 0;
13487
+ /**
13488
+ * Session-durable scoring hints. Re-merged into every pipeline run for
13489
+ * the rest of the session (initial plan + every replan, including bare
13490
+ * auto-replans and the wedge-breaker), via `_applyHintsToSources`.
13491
+ *
13492
+ * Set by `setSessionHints()` (e.g. session-start post-lesson boost) or by
13493
+ * any replan carrying `ReplanOptions.sessionHints` (e.g. a just-failed
13494
+ * concept boost). Replace semantics, no decay — lives until overwritten
13495
+ * or session end. See `ReplanOptions.sessionHints` for rationale.
13496
+ *
13497
+ * Note: the controller-managed auto-excludes (current card, session
13498
+ * record, imminent draw) are intentionally NOT folded in here — those are
13499
+ * recomputed per-run in `_runReplan` and would otherwise go stale.
13500
+ */
13501
+ _sessionHints = null;
13502
+ /**
13503
+ * Consumer-supplied hooks invoked after each question response is processed.
13504
+ * Seeded from constructor options (threaded from
13505
+ * `StudySessionConfig.outcomeObservers`). See {@link OutcomeObserver}.
13506
+ */
13507
+ _outcomeObservers = [];
13508
+ /**
13509
+ * Lazily-built, stable capability object handed to observers. Bound to
13510
+ * `this`; constructed once so observers can rely on referential identity.
13511
+ */
13512
+ _sessionControls = null;
13484
13513
  startTime;
13485
13514
  endTime;
13486
13515
  _secondsRemaining;
@@ -13540,6 +13569,9 @@ var SessionController = class _SessionController extends Loggable {
13540
13569
  if (options?.initialReviewCap !== void 0) {
13541
13570
  this._initialReviewCap = options.initialReviewCap;
13542
13571
  }
13572
+ if (options?.outcomeObservers?.length) {
13573
+ this._outcomeObservers = [...options.outcomeObservers];
13574
+ }
13543
13575
  this.log(`Session constructed:
13544
13576
  startTime: ${this.startTime}
13545
13577
  endTime: ${this.endTime}
@@ -13667,6 +13699,7 @@ var SessionController = class _SessionController extends Loggable {
13667
13699
  if (opts.minFollowUpCards !== void 0) return true;
13668
13700
  if (opts.mode && opts.mode !== "replace") return true;
13669
13701
  if (opts.hints && Object.keys(opts.hints).length > 0) return true;
13702
+ if (opts.sessionHints !== void 0) return true;
13670
13703
  return false;
13671
13704
  }
13672
13705
  /**
@@ -13695,12 +13728,13 @@ var SessionController = class _SessionController extends Loggable {
13695
13728
  excludeSet.add(this.newQ.peek(0).cardID);
13696
13729
  }
13697
13730
  hints.excludeCards = [...excludeSet];
13698
- if (opts.hints) {
13699
- const hintsWithLabel = opts.label ? { ...opts.hints, _label: opts.label } : opts.hints;
13700
- for (const source of this.sources) {
13701
- source.setEphemeralHints?.(hintsWithLabel);
13702
- }
13731
+ if (opts.sessionHints !== void 0) {
13732
+ this._sessionHints = opts.sessionHints;
13733
+ this.log(
13734
+ `[Replan] Session hints ${opts.sessionHints ? "set" : "cleared"}: ${JSON.stringify(opts.sessionHints)}`
13735
+ );
13703
13736
  }
13737
+ this._applyHintsToSources(opts.hints, opts.label);
13704
13738
  const labelTag = opts.label ? ` [${opts.label}]` : "";
13705
13739
  this.log(
13706
13740
  `Mid-session replan requested${labelTag} (limit: ${opts.limit ?? "default"}, mode: ${opts.mode ?? "replace"}${opts.hints ? ", with hints" : ""})`
@@ -13711,6 +13745,100 @@ var SessionController = class _SessionController extends Loggable {
13711
13745
  }
13712
13746
  await this._executeReplan(opts);
13713
13747
  }
13748
+ /**
13749
+ * Set the session-durable scoring hints (replace semantics, no decay).
13750
+ *
13751
+ * Unlike a one-shot replan hint, these are re-merged into every pipeline
13752
+ * run for the rest of the session — including the initial plan when set
13753
+ * before `prepareSession()`, every replan, the bare auto-replans, and the
13754
+ * wedge-breaker. Pass `null` to clear.
13755
+ *
13756
+ * Typical callers:
13757
+ * - `StudySession` at session start, threading `StudySessionConfig.initHints`
13758
+ * (e.g. a post-lesson concept boost) — so the boost outlives the first
13759
+ * queue rebuild instead of being clobbered by the first auto-replan.
13760
+ * - A consumer view on a failure, boosting the just-failed concept tag.
13761
+ *
13762
+ * Does not itself trigger a replan; the next plan/replan picks it up.
13763
+ */
13764
+ setSessionHints(hints) {
13765
+ this._sessionHints = hints;
13766
+ this.log(`Session hints ${hints ? "set" : "cleared"}: ${JSON.stringify(hints)}`);
13767
+ }
13768
+ /**
13769
+ * Read the current session-durable hints (for read-modify-write callers,
13770
+ * e.g. an outcome observer that clamps a compounding boost).
13771
+ */
13772
+ getSessionHints() {
13773
+ return this._sessionHints;
13774
+ }
13775
+ /**
13776
+ * Merge `hints` into the durable session hints via the pipeline's
13777
+ * `mergeHints` (boosts multiply, require/exclude lists concat-dedup).
13778
+ * Convenience over get-then-set for the common additive case. Note the
13779
+ * multiplicative, no-decay semantics — clamp boost factors at the call
13780
+ * site if a repeatedly-emphasised tag could compound unboundedly.
13781
+ */
13782
+ mergeSessionHints(hints) {
13783
+ this._sessionHints = mergeHints2([this._sessionHints, hints]) ?? null;
13784
+ this.log(`Session hints merged: ${JSON.stringify(this._sessionHints)}`);
13785
+ }
13786
+ /**
13787
+ * Merge the durable `_sessionHints` with this run's one-shot hints and
13788
+ * push the result to every source for consumption on the next pipeline
13789
+ * run. Centralised so the initial plan and all replan paths apply session
13790
+ * emphasis identically. No-op when there are no hints of either kind.
13791
+ */
13792
+ _applyHintsToSources(oneShot, label) {
13793
+ const oneShotWithLabel = oneShot && label ? { ...oneShot, _label: label } : oneShot;
13794
+ const merged = mergeHints2([this._sessionHints, oneShotWithLabel]);
13795
+ if (!merged) return;
13796
+ for (const source of this.sources) {
13797
+ source.setEphemeralHints?.(merged);
13798
+ }
13799
+ }
13800
+ /**
13801
+ * Build (once) the stable capability object handed to outcome observers.
13802
+ * Methods are bound to `this`; the object identity is stable across calls
13803
+ * so observers may key off it.
13804
+ */
13805
+ _getSessionControls() {
13806
+ if (!this._sessionControls) {
13807
+ this._sessionControls = {
13808
+ getSessionHints: () => this.getSessionHints(),
13809
+ setSessionHints: (h) => this.setSessionHints(h),
13810
+ mergeSessionHints: (h) => this.mergeSessionHints(h),
13811
+ requestReplan: (opts) => this.requestReplan(opts)
13812
+ };
13813
+ }
13814
+ return this._sessionControls;
13815
+ }
13816
+ /**
13817
+ * Notify registered outcome observers about a processed response.
13818
+ *
13819
+ * Only question records are surfaced (non-question dismisses are skipped).
13820
+ * Observers run after ELO/SRS are recorded and before navigation. Each is
13821
+ * awaited but isolated in try/catch — a throwing observer is logged and
13822
+ * skipped, never wedging the session. Keep observers cheap and `void` any
13823
+ * long work (e.g. a triggered replan) to avoid stalling the draw.
13824
+ */
13825
+ async _notifyOutcomeObservers(record, currentCard, result) {
13826
+ if (this._outcomeObservers.length === 0) return;
13827
+ if (!isQuestionRecord(record)) return;
13828
+ const outcome = {
13829
+ record,
13830
+ card: currentCard.card,
13831
+ result
13832
+ };
13833
+ const controls = this._getSessionControls();
13834
+ for (const observer of this._outcomeObservers) {
13835
+ try {
13836
+ await observer(outcome, controls);
13837
+ } catch (e) {
13838
+ this.error("[OutcomeObserver] observer threw; ignoring", e);
13839
+ }
13840
+ }
13841
+ }
13714
13842
  /**
13715
13843
  * Run a replan, bypassing requestReplan()'s coalesce logic.
13716
13844
  *
@@ -13738,7 +13866,7 @@ var SessionController = class _SessionController extends Loggable {
13738
13866
  */
13739
13867
  normalizeReplanOptions(input) {
13740
13868
  if (!input) return {};
13741
- const replanKeys = ["hints", "limit", "mode", "label", "minFollowUpCards"];
13869
+ const replanKeys = ["hints", "sessionHints", "limit", "mode", "label", "minFollowUpCards"];
13742
13870
  const inputKeys = Object.keys(input);
13743
13871
  if (inputKeys.some((k) => replanKeys.includes(k))) {
13744
13872
  return input;
@@ -13890,6 +14018,9 @@ var SessionController = class _SessionController extends Loggable {
13890
14018
  const additive = options?.additive ?? false;
13891
14019
  const newLimit = options?.limit ?? this._defaultBatchLimit;
13892
14020
  const fetchLimit = replan ? newLimit : newLimit + this._initialReviewCap;
14021
+ if (!replan) {
14022
+ this._applyHintsToSources();
14023
+ }
13893
14024
  const batches = [];
13894
14025
  for (let i = 0; i < this.sources.length; i++) {
13895
14026
  const source = this.sources[i];
@@ -14170,7 +14301,7 @@ var SessionController = class _SessionController extends Loggable {
14170
14301
  const studySessionItem = {
14171
14302
  ...currentCard.item
14172
14303
  };
14173
- return await this.services.response.processResponse(
14304
+ const result = await this.services.response.processResponse(
14174
14305
  cardRecord,
14175
14306
  cardHistory,
14176
14307
  studySessionItem,
@@ -14182,6 +14313,8 @@ var SessionController = class _SessionController extends Loggable {
14182
14313
  maxSessionViews,
14183
14314
  sessionViews
14184
14315
  );
14316
+ await this._notifyOutcomeObservers(cardRecord, currentCard, result);
14317
+ return result;
14185
14318
  }
14186
14319
  dismissCurrentCard(action = "dismiss-success") {
14187
14320
  if (this._currentCard) {