@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.
@@ -716,6 +716,7 @@ __export(PipelineDebugger_exports, {
716
716
  buildRunReport: () => buildRunReport,
717
717
  captureRun: () => captureRun,
718
718
  clearRunHistory: () => clearRunHistory,
719
+ getActivePipeline: () => getActivePipeline,
719
720
  mountPipelineDebugger: () => mountPipelineDebugger,
720
721
  pipelineDebugAPI: () => pipelineDebugAPI,
721
722
  registerPipelineForDebug: () => registerPipelineForDebug
@@ -723,6 +724,9 @@ __export(PipelineDebugger_exports, {
723
724
  function registerPipelineForDebug(pipeline) {
724
725
  _activePipeline = pipeline;
725
726
  }
727
+ function getActivePipeline() {
728
+ return _activePipeline;
729
+ }
726
730
  function clearRunHistory() {
727
731
  runHistory.length = 0;
728
732
  }
@@ -4509,6 +4513,68 @@ var init_Pipeline = __esm({
4509
4513
  // ---------------------------------------------------------------------------
4510
4514
  // Card-space diagnostic
4511
4515
  // ---------------------------------------------------------------------------
4516
+ /**
4517
+ * Commit-free forecast: score the user's full card space through the filter
4518
+ * chain and return the cards that are currently *reachable* (score >=
4519
+ * threshold), optionally nudged by caller-supplied hints and/or restricted
4520
+ * to cards the user hasn't seen yet.
4521
+ *
4522
+ * This is a GENERIC primitive — it returns scored, tag-hydrated cards and
4523
+ * stops there. It has no knowledge of any particular tag convention; callers
4524
+ * decide what the surviving cards mean (e.g. filter to their own "intro"
4525
+ * tag family). Nothing is written and no session is started.
4526
+ *
4527
+ * The optional `hints` are the "out-of-band kick": they run through the same
4528
+ * {@link applyHints} path a live replan uses, so the two semantics carry over —
4529
+ * - `boostTags`/`boostCards` reweight *within* gating (a gated score-0 card
4530
+ * stays out), and
4531
+ * - `requireTags`/`requireCards` inject from the full pre-filter pool,
4532
+ * *bypassing* gating (use when you want a card regardless of reachability).
4533
+ * Note `unseenOnly` is applied LAST, so it can drop a `require`d card that the
4534
+ * user has already seen — pass `unseenOnly: false` if that matters.
4535
+ *
4536
+ * Cost note: like {@link diagnoseCardSpace}, this scans every card through the
4537
+ * filters, so it's heavier than a normal replan. Intended for one-shot
4538
+ * out-of-band use (e.g. a session-end "what's next" snapshot), not the hot path.
4539
+ *
4540
+ * @param opts.hints Optional ephemeral hints to apply after the filter chain.
4541
+ * @param opts.unseenOnly Only return cards the user hasn't encountered (default true).
4542
+ * @param opts.threshold Min score to count as reachable (default 0.10).
4543
+ * @param opts.limit Optional cap on results (already sorted desc).
4544
+ */
4545
+ async forecast(opts) {
4546
+ const threshold = opts?.threshold ?? 0.1;
4547
+ const unseenOnly = opts?.unseenOnly ?? true;
4548
+ const courseId = this.course.getCourseID();
4549
+ const allCardIds = await this.course.getAllCardIds();
4550
+ let cards = allCardIds.map((cardId) => ({
4551
+ cardId,
4552
+ courseId,
4553
+ score: 1,
4554
+ provenance: []
4555
+ }));
4556
+ cards = await this.hydrateTags(cards);
4557
+ const fullPool = cards.slice();
4558
+ const context = await this.buildContext();
4559
+ for (const filter of this.filters) {
4560
+ cards = await filter.transform(cards, context);
4561
+ }
4562
+ if (opts?.hints) {
4563
+ cards = this.applyHints(cards, opts.hints, fullPool);
4564
+ }
4565
+ cards = cards.filter((c) => c.score >= threshold);
4566
+ if (unseenOnly) {
4567
+ let encountered;
4568
+ try {
4569
+ encountered = new Set(await this.user.getSeenCards(courseId));
4570
+ } catch {
4571
+ encountered = /* @__PURE__ */ new Set();
4572
+ }
4573
+ cards = cards.filter((c) => !encountered.has(c.cardId));
4574
+ }
4575
+ cards.sort((a, b) => b.score - a.score);
4576
+ return opts?.limit ? cards.slice(0, opts.limit) : cards;
4577
+ }
4512
4578
  /**
4513
4579
  * Scan every card in the course through the filter chain and report
4514
4580
  * how many are "well indicated" (score >= threshold) for the current user.
@@ -4806,6 +4872,7 @@ __export(navigators_exports, {
4806
4872
  NavigatorRoles: () => NavigatorRoles,
4807
4873
  Navigators: () => Navigators,
4808
4874
  diversityRerank: () => diversityRerank,
4875
+ getActivePipeline: () => getActivePipeline,
4809
4876
  getCardOrigin: () => getCardOrigin,
4810
4877
  getRegisteredNavigator: () => getRegisteredNavigator,
4811
4878
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,