@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.
@@ -617,6 +617,7 @@ __export(PipelineDebugger_exports, {
617
617
  buildRunReport: () => buildRunReport,
618
618
  captureRun: () => captureRun,
619
619
  clearRunHistory: () => clearRunHistory,
620
+ getActivePipeline: () => getActivePipeline,
620
621
  mountPipelineDebugger: () => mountPipelineDebugger,
621
622
  pipelineDebugAPI: () => pipelineDebugAPI,
622
623
  registerPipelineForDebug: () => registerPipelineForDebug
@@ -624,6 +625,9 @@ __export(PipelineDebugger_exports, {
624
625
  function registerPipelineForDebug(pipeline) {
625
626
  _activePipeline = pipeline;
626
627
  }
628
+ function getActivePipeline() {
629
+ return _activePipeline;
630
+ }
627
631
  function clearRunHistory() {
628
632
  runHistory.length = 0;
629
633
  }
@@ -4410,6 +4414,68 @@ var init_Pipeline = __esm({
4410
4414
  // ---------------------------------------------------------------------------
4411
4415
  // Card-space diagnostic
4412
4416
  // ---------------------------------------------------------------------------
4417
+ /**
4418
+ * Commit-free forecast: score the user's full card space through the filter
4419
+ * chain and return the cards that are currently *reachable* (score >=
4420
+ * threshold), optionally nudged by caller-supplied hints and/or restricted
4421
+ * to cards the user hasn't seen yet.
4422
+ *
4423
+ * This is a GENERIC primitive — it returns scored, tag-hydrated cards and
4424
+ * stops there. It has no knowledge of any particular tag convention; callers
4425
+ * decide what the surviving cards mean (e.g. filter to their own "intro"
4426
+ * tag family). Nothing is written and no session is started.
4427
+ *
4428
+ * The optional `hints` are the "out-of-band kick": they run through the same
4429
+ * {@link applyHints} path a live replan uses, so the two semantics carry over —
4430
+ * - `boostTags`/`boostCards` reweight *within* gating (a gated score-0 card
4431
+ * stays out), and
4432
+ * - `requireTags`/`requireCards` inject from the full pre-filter pool,
4433
+ * *bypassing* gating (use when you want a card regardless of reachability).
4434
+ * Note `unseenOnly` is applied LAST, so it can drop a `require`d card that the
4435
+ * user has already seen — pass `unseenOnly: false` if that matters.
4436
+ *
4437
+ * Cost note: like {@link diagnoseCardSpace}, this scans every card through the
4438
+ * filters, so it's heavier than a normal replan. Intended for one-shot
4439
+ * out-of-band use (e.g. a session-end "what's next" snapshot), not the hot path.
4440
+ *
4441
+ * @param opts.hints Optional ephemeral hints to apply after the filter chain.
4442
+ * @param opts.unseenOnly Only return cards the user hasn't encountered (default true).
4443
+ * @param opts.threshold Min score to count as reachable (default 0.10).
4444
+ * @param opts.limit Optional cap on results (already sorted desc).
4445
+ */
4446
+ async forecast(opts) {
4447
+ const threshold = opts?.threshold ?? 0.1;
4448
+ const unseenOnly = opts?.unseenOnly ?? true;
4449
+ const courseId = this.course.getCourseID();
4450
+ const allCardIds = await this.course.getAllCardIds();
4451
+ let cards = allCardIds.map((cardId) => ({
4452
+ cardId,
4453
+ courseId,
4454
+ score: 1,
4455
+ provenance: []
4456
+ }));
4457
+ cards = await this.hydrateTags(cards);
4458
+ const fullPool = cards.slice();
4459
+ const context = await this.buildContext();
4460
+ for (const filter of this.filters) {
4461
+ cards = await filter.transform(cards, context);
4462
+ }
4463
+ if (opts?.hints) {
4464
+ cards = this.applyHints(cards, opts.hints, fullPool);
4465
+ }
4466
+ cards = cards.filter((c) => c.score >= threshold);
4467
+ if (unseenOnly) {
4468
+ let encountered;
4469
+ try {
4470
+ encountered = new Set(await this.user.getSeenCards(courseId));
4471
+ } catch {
4472
+ encountered = /* @__PURE__ */ new Set();
4473
+ }
4474
+ cards = cards.filter((c) => !encountered.has(c.cardId));
4475
+ }
4476
+ cards.sort((a, b) => b.score - a.score);
4477
+ return opts?.limit ? cards.slice(0, opts.limit) : cards;
4478
+ }
4413
4479
  /**
4414
4480
  * Scan every card in the course through the filter chain and report
4415
4481
  * how many are "well indicated" (score >= threshold) for the current user.
@@ -4707,6 +4773,7 @@ __export(navigators_exports, {
4707
4773
  NavigatorRoles: () => NavigatorRoles,
4708
4774
  Navigators: () => Navigators,
4709
4775
  diversityRerank: () => diversityRerank,
4776
+ getActivePipeline: () => getActivePipeline,
4710
4777
  getCardOrigin: () => getCardOrigin,
4711
4778
  getRegisteredNavigator: () => getRegisteredNavigator,
4712
4779
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,