@vue-skuilder/db 0.2.7 → 0.2.8

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.
@@ -791,6 +791,7 @@ __export(PipelineDebugger_exports, {
791
791
  buildRunReport: () => buildRunReport,
792
792
  captureRun: () => captureRun,
793
793
  clearRunHistory: () => clearRunHistory,
794
+ getActivePipeline: () => getActivePipeline,
794
795
  mountPipelineDebugger: () => mountPipelineDebugger,
795
796
  pipelineDebugAPI: () => pipelineDebugAPI,
796
797
  registerPipelineForDebug: () => registerPipelineForDebug
@@ -798,6 +799,9 @@ __export(PipelineDebugger_exports, {
798
799
  function registerPipelineForDebug(pipeline) {
799
800
  _activePipeline = pipeline;
800
801
  }
802
+ function getActivePipeline() {
803
+ return _activePipeline;
804
+ }
801
805
  function clearRunHistory() {
802
806
  runHistory.length = 0;
803
807
  }
@@ -4830,6 +4834,68 @@ var init_Pipeline = __esm({
4830
4834
  // ---------------------------------------------------------------------------
4831
4835
  // Card-space diagnostic
4832
4836
  // ---------------------------------------------------------------------------
4837
+ /**
4838
+ * Commit-free forecast: score the user's full card space through the filter
4839
+ * chain and return the cards that are currently *reachable* (score >=
4840
+ * threshold), optionally nudged by caller-supplied hints and/or restricted
4841
+ * to cards the user hasn't seen yet.
4842
+ *
4843
+ * This is a GENERIC primitive — it returns scored, tag-hydrated cards and
4844
+ * stops there. It has no knowledge of any particular tag convention; callers
4845
+ * decide what the surviving cards mean (e.g. filter to their own "intro"
4846
+ * tag family). Nothing is written and no session is started.
4847
+ *
4848
+ * The optional `hints` are the "out-of-band kick": they run through the same
4849
+ * {@link applyHints} path a live replan uses, so the two semantics carry over —
4850
+ * - `boostTags`/`boostCards` reweight *within* gating (a gated score-0 card
4851
+ * stays out), and
4852
+ * - `requireTags`/`requireCards` inject from the full pre-filter pool,
4853
+ * *bypassing* gating (use when you want a card regardless of reachability).
4854
+ * Note `unseenOnly` is applied LAST, so it can drop a `require`d card that the
4855
+ * user has already seen — pass `unseenOnly: false` if that matters.
4856
+ *
4857
+ * Cost note: like {@link diagnoseCardSpace}, this scans every card through the
4858
+ * filters, so it's heavier than a normal replan. Intended for one-shot
4859
+ * out-of-band use (e.g. a session-end "what's next" snapshot), not the hot path.
4860
+ *
4861
+ * @param opts.hints Optional ephemeral hints to apply after the filter chain.
4862
+ * @param opts.unseenOnly Only return cards the user hasn't encountered (default true).
4863
+ * @param opts.threshold Min score to count as reachable (default 0.10).
4864
+ * @param opts.limit Optional cap on results (already sorted desc).
4865
+ */
4866
+ async forecast(opts) {
4867
+ const threshold = opts?.threshold ?? 0.1;
4868
+ const unseenOnly = opts?.unseenOnly ?? true;
4869
+ const courseId = this.course.getCourseID();
4870
+ const allCardIds = await this.course.getAllCardIds();
4871
+ let cards = allCardIds.map((cardId) => ({
4872
+ cardId,
4873
+ courseId,
4874
+ score: 1,
4875
+ provenance: []
4876
+ }));
4877
+ cards = await this.hydrateTags(cards);
4878
+ const fullPool = cards.slice();
4879
+ const context = await this.buildContext();
4880
+ for (const filter of this.filters) {
4881
+ cards = await filter.transform(cards, context);
4882
+ }
4883
+ if (opts?.hints) {
4884
+ cards = this.applyHints(cards, opts.hints, fullPool);
4885
+ }
4886
+ cards = cards.filter((c) => c.score >= threshold);
4887
+ if (unseenOnly) {
4888
+ let encountered;
4889
+ try {
4890
+ encountered = new Set(await this.user.getSeenCards(courseId));
4891
+ } catch {
4892
+ encountered = /* @__PURE__ */ new Set();
4893
+ }
4894
+ cards = cards.filter((c) => !encountered.has(c.cardId));
4895
+ }
4896
+ cards.sort((a, b) => b.score - a.score);
4897
+ return opts?.limit ? cards.slice(0, opts.limit) : cards;
4898
+ }
4833
4899
  /**
4834
4900
  * Scan every card in the course through the filter chain and report
4835
4901
  * how many are "well indicated" (score >= threshold) for the current user.
@@ -5127,6 +5193,7 @@ __export(navigators_exports, {
5127
5193
  NavigatorRoles: () => NavigatorRoles,
5128
5194
  Navigators: () => Navigators,
5129
5195
  diversityRerank: () => diversityRerank,
5196
+ getActivePipeline: () => getActivePipeline,
5130
5197
  getCardOrigin: () => getCardOrigin,
5131
5198
  getRegisteredNavigator: () => getRegisteredNavigator,
5132
5199
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,
@@ -8254,6 +8321,7 @@ export {
8254
8321
  createOrchestrationContext,
8255
8322
  diversityRerank,
8256
8323
  docIsDeleted,
8324
+ getActivePipeline,
8257
8325
  getCardHistoryID,
8258
8326
  getCardOrigin,
8259
8327
  getDefaultLearnableWeight,