@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.
@@ -593,6 +593,7 @@ __export(PipelineDebugger_exports, {
593
593
  buildRunReport: () => buildRunReport,
594
594
  captureRun: () => captureRun,
595
595
  clearRunHistory: () => clearRunHistory,
596
+ getActivePipeline: () => getActivePipeline,
596
597
  mountPipelineDebugger: () => mountPipelineDebugger,
597
598
  pipelineDebugAPI: () => pipelineDebugAPI,
598
599
  registerPipelineForDebug: () => registerPipelineForDebug
@@ -600,6 +601,9 @@ __export(PipelineDebugger_exports, {
600
601
  function registerPipelineForDebug(pipeline) {
601
602
  _activePipeline = pipeline;
602
603
  }
604
+ function getActivePipeline() {
605
+ return _activePipeline;
606
+ }
603
607
  function clearRunHistory() {
604
608
  runHistory.length = 0;
605
609
  }
@@ -4386,6 +4390,68 @@ var init_Pipeline = __esm({
4386
4390
  // ---------------------------------------------------------------------------
4387
4391
  // Card-space diagnostic
4388
4392
  // ---------------------------------------------------------------------------
4393
+ /**
4394
+ * Commit-free forecast: score the user's full card space through the filter
4395
+ * chain and return the cards that are currently *reachable* (score >=
4396
+ * threshold), optionally nudged by caller-supplied hints and/or restricted
4397
+ * to cards the user hasn't seen yet.
4398
+ *
4399
+ * This is a GENERIC primitive — it returns scored, tag-hydrated cards and
4400
+ * stops there. It has no knowledge of any particular tag convention; callers
4401
+ * decide what the surviving cards mean (e.g. filter to their own "intro"
4402
+ * tag family). Nothing is written and no session is started.
4403
+ *
4404
+ * The optional `hints` are the "out-of-band kick": they run through the same
4405
+ * {@link applyHints} path a live replan uses, so the two semantics carry over —
4406
+ * - `boostTags`/`boostCards` reweight *within* gating (a gated score-0 card
4407
+ * stays out), and
4408
+ * - `requireTags`/`requireCards` inject from the full pre-filter pool,
4409
+ * *bypassing* gating (use when you want a card regardless of reachability).
4410
+ * Note `unseenOnly` is applied LAST, so it can drop a `require`d card that the
4411
+ * user has already seen — pass `unseenOnly: false` if that matters.
4412
+ *
4413
+ * Cost note: like {@link diagnoseCardSpace}, this scans every card through the
4414
+ * filters, so it's heavier than a normal replan. Intended for one-shot
4415
+ * out-of-band use (e.g. a session-end "what's next" snapshot), not the hot path.
4416
+ *
4417
+ * @param opts.hints Optional ephemeral hints to apply after the filter chain.
4418
+ * @param opts.unseenOnly Only return cards the user hasn't encountered (default true).
4419
+ * @param opts.threshold Min score to count as reachable (default 0.10).
4420
+ * @param opts.limit Optional cap on results (already sorted desc).
4421
+ */
4422
+ async forecast(opts) {
4423
+ const threshold = opts?.threshold ?? 0.1;
4424
+ const unseenOnly = opts?.unseenOnly ?? true;
4425
+ const courseId = this.course.getCourseID();
4426
+ const allCardIds = await this.course.getAllCardIds();
4427
+ let cards = allCardIds.map((cardId) => ({
4428
+ cardId,
4429
+ courseId,
4430
+ score: 1,
4431
+ provenance: []
4432
+ }));
4433
+ cards = await this.hydrateTags(cards);
4434
+ const fullPool = cards.slice();
4435
+ const context = await this.buildContext();
4436
+ for (const filter of this.filters) {
4437
+ cards = await filter.transform(cards, context);
4438
+ }
4439
+ if (opts?.hints) {
4440
+ cards = this.applyHints(cards, opts.hints, fullPool);
4441
+ }
4442
+ cards = cards.filter((c) => c.score >= threshold);
4443
+ if (unseenOnly) {
4444
+ let encountered;
4445
+ try {
4446
+ encountered = new Set(await this.user.getSeenCards(courseId));
4447
+ } catch {
4448
+ encountered = /* @__PURE__ */ new Set();
4449
+ }
4450
+ cards = cards.filter((c) => !encountered.has(c.cardId));
4451
+ }
4452
+ cards.sort((a, b) => b.score - a.score);
4453
+ return opts?.limit ? cards.slice(0, opts.limit) : cards;
4454
+ }
4389
4455
  /**
4390
4456
  * Scan every card in the course through the filter chain and report
4391
4457
  * how many are "well indicated" (score >= threshold) for the current user.
@@ -4683,6 +4749,7 @@ __export(navigators_exports, {
4683
4749
  NavigatorRoles: () => NavigatorRoles,
4684
4750
  Navigators: () => Navigators,
4685
4751
  diversityRerank: () => diversityRerank,
4752
+ getActivePipeline: () => getActivePipeline,
4686
4753
  getCardOrigin: () => getCardOrigin,
4687
4754
  getRegisteredNavigator: () => getRegisteredNavigator,
4688
4755
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,