@fenglimg/fabric-server 2.2.0-rc.8 → 2.2.0-rc.9

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.
package/dist/index.d.ts CHANGED
@@ -538,6 +538,37 @@ declare function extractKnowledge(projectRoot: string, input: FabExtractKnowledg
538
538
  */
539
539
  declare function reviewKnowledge(projectRoot: string, input: FabReviewInput): Promise<FabReviewOutput>;
540
540
 
541
+ /** A summary to be cold-judged, keyed by its stable_id. */
542
+ interface ColdEvalCandidate {
543
+ stable_id: string;
544
+ summary: string;
545
+ }
546
+ /** The verdict the external cold-eval judge returns per candidate. */
547
+ interface ColdEvalVerdict {
548
+ stable_id: string;
549
+ /** true when the summary alone is act-on sufficient without the body. */
550
+ self_sufficient: boolean;
551
+ /** When not self-sufficient, the judge's suggested act-on rewrite. */
552
+ suggested_summary?: string;
553
+ /** Short rationale (pointer-vs-thesis) for the verdict. */
554
+ reason?: string;
555
+ }
556
+ /** The batch request handed to the external (maestro delegate) cold-eval judge. */
557
+ interface ColdEvalBatch {
558
+ rubric: string;
559
+ candidates: ColdEvalCandidate[];
560
+ }
561
+ declare const COLD_EVAL_RUBRIC: string;
562
+ /**
563
+ * Build the cold-eval batch request for the external judge. Pure + deterministic:
564
+ * drops blank summaries (nothing to judge) and pairs the candidates with the
565
+ * zero-context rubric. The fabric-review skill hands the result to
566
+ * `maestro delegate` and applies the returned {@link ColdEvalVerdict}[] via
567
+ * fab_review modify. Returns a batch with an empty candidate list when nothing is
568
+ * judgeable, so callers can short-circuit without a delegate round-trip.
569
+ */
570
+ declare function buildColdEvalBatch(candidates: ColdEvalCandidate[]): ColdEvalBatch;
571
+
541
572
  type StoredEventLedgerEvent = EventLedgerEvent;
542
573
  type ReadEventLedgerOptions = {
543
574
  event_type?: EventLedgerEvent["event_type"];
@@ -823,4 +854,4 @@ interface ShutdownHandlerDeps {
823
854
  */
824
855
  declare function createShutdownHandler(deps: ShutdownHandlerDeps): () => void;
825
856
 
826
- export { AGENTS_MD_RESOURCE_URI, type AlwaysActiveBody, type ArchiveHistoryEntry, type ArchiveHistoryReport, type CiteCoverageReport, type ConflictEntry, type ConflictJudge, type ConflictLintReport, type ConflictPair, type ConflictVerdict, DEFAULT_CONFLICT_SIMILARITY_THRESHOLD, type DoctorApplyLintMutation, type DoctorApplyLintMutationKind, type DoctorApplyLintReport, type DoctorFixReport, type DoctorIssue, type DoctorReport, EVENT_LEDGER_PATH, type EnrichDescriptionsCandidate, type EnrichDescriptionsMode, type EnrichDescriptionsReport, FABRIC_SERVER_INSTRUCTIONS, type HistoryAllReport, type HistoryDayRow, type InFlightTracker, type KnowledgeCensus, LEDGER_PATH, LEGACY_LEDGER_PATH, METRICS_LEDGER_PATH, METRIC_COUNTER_NAMES, type MetricCounterName, type MetricsRow, type PlanContextInput, type PlanContextResult, type RecallInput, type RecallResult, type RequirementProfile, type SelectionTokenState, type ShutdownHandlerDeps, type UnboundProjectViolation, appendEventLedgerEvent, buildAlwaysActiveBodies, buildKnowledgeCensus, bumpCounter, contextCache, createFabricServer, createInFlightTracker, createShutdownHandler, detectUnboundProject, drainCounters, enrichDescriptions, extractKnowledge, findConflictCandidates, flushAndSyncEventLedger, flushMetrics, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, getMetricsLedgerPath, lintConflicts, loadConflictEntries, pairSimilarity, planContext, readEventLedger, readLedger, readMetrics, readSelectionToken, recall, rehydrateAgentsMetaAt, resolveLedgerPaths, reviewKnowledge, runDoctorApplyLint, runDoctorArchiveHistory, runDoctorCiteCoverage, runDoctorConflictLint, runDoctorFix, runDoctorHistoryAll, runDoctorReport, startMetricsFlush, startRotationTick, startStdioServer, stopMetricsFlush, stopRotationTick };
857
+ export { AGENTS_MD_RESOURCE_URI, type AlwaysActiveBody, type ArchiveHistoryEntry, type ArchiveHistoryReport, COLD_EVAL_RUBRIC, type CiteCoverageReport, type ColdEvalBatch, type ColdEvalCandidate, type ColdEvalVerdict, type ConflictEntry, type ConflictJudge, type ConflictLintReport, type ConflictPair, type ConflictVerdict, DEFAULT_CONFLICT_SIMILARITY_THRESHOLD, type DoctorApplyLintMutation, type DoctorApplyLintMutationKind, type DoctorApplyLintReport, type DoctorFixReport, type DoctorIssue, type DoctorReport, EVENT_LEDGER_PATH, type EnrichDescriptionsCandidate, type EnrichDescriptionsMode, type EnrichDescriptionsReport, FABRIC_SERVER_INSTRUCTIONS, type HistoryAllReport, type HistoryDayRow, type InFlightTracker, type KnowledgeCensus, LEDGER_PATH, LEGACY_LEDGER_PATH, METRICS_LEDGER_PATH, METRIC_COUNTER_NAMES, type MetricCounterName, type MetricsRow, type PlanContextInput, type PlanContextResult, type RecallInput, type RecallResult, type RequirementProfile, type SelectionTokenState, type ShutdownHandlerDeps, type UnboundProjectViolation, appendEventLedgerEvent, buildAlwaysActiveBodies, buildColdEvalBatch, buildKnowledgeCensus, bumpCounter, contextCache, createFabricServer, createInFlightTracker, createShutdownHandler, detectUnboundProject, drainCounters, enrichDescriptions, extractKnowledge, findConflictCandidates, flushAndSyncEventLedger, flushMetrics, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, getMetricsLedgerPath, lintConflicts, loadConflictEntries, pairSimilarity, planContext, readEventLedger, readLedger, readMetrics, readSelectionToken, recall, rehydrateAgentsMetaAt, resolveLedgerPaths, reviewKnowledge, runDoctorApplyLint, runDoctorArchiveHistory, runDoctorCiteCoverage, runDoctorConflictLint, runDoctorFix, runDoctorHistoryAll, runDoctorReport, startMetricsFlush, startRotationTick, startStdioServer, stopMetricsFlush, stopRotationTick };
package/dist/index.js CHANGED
@@ -700,13 +700,9 @@ function appendPayloadWarning(warnings, guardResult, actionHint) {
700
700
  // src/config-loader.ts
701
701
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
702
702
  import { join as join4 } from "path";
703
- import { selectionTokenTtlMsSchema, planContextTopKSchema, resolveRetrievalBudget } from "@fenglimg/fabric-shared";
704
- var RETRIEVAL_BUDGET_PROFILES = ["conservative", "balanced", "generous"];
705
- function readRetrievalBudgetProfile(config) {
706
- const raw = config.retrieval_budget_profile;
707
- return typeof raw === "string" && RETRIEVAL_BUDGET_PROFILES.includes(raw) ? raw : void 0;
708
- }
703
+ import { selectionTokenTtlMsSchema, planContextTopKSchema } from "@fenglimg/fabric-shared";
709
704
  var PLAN_CONTEXT_TOP_K_DEFAULT = 24;
705
+ var RECALL_RELEVANCE_RATIO_DEFAULT = 0.25;
710
706
  function readFabricConfig(projectRoot) {
711
707
  const configPath = join4(projectRoot, ".fabric", "fabric-config.json");
712
708
  if (!existsSync2(configPath)) {
@@ -719,18 +715,7 @@ function readFabricConfig(projectRoot) {
719
715
  return parsed;
720
716
  }
721
717
  function readPayloadLimits(projectRoot) {
722
- const config = readFabricConfig(projectRoot);
723
- const explicit = config.mcpPayloadLimits;
724
- const profile = readRetrievalBudgetProfile(config);
725
- if (profile === void 0 && explicit === void 0) {
726
- return void 0;
727
- }
728
- const resolved = resolveRetrievalBudget({
729
- profile,
730
- payloadWarnBytes: explicit?.warnBytes,
731
- payloadHardBytes: explicit?.hardBytes
732
- });
733
- return { warnBytes: resolved.payloadWarnBytes, hardBytes: resolved.payloadHardBytes };
718
+ return readFabricConfig(projectRoot).mcpPayloadLimits;
734
719
  }
735
720
  function readSelectionTokenTtlMs(projectRoot) {
736
721
  try {
@@ -776,17 +761,27 @@ function readDefaultLayerFilter(projectRoot) {
776
761
  }
777
762
  function readPlanContextTopK(projectRoot) {
778
763
  try {
779
- const config = readFabricConfig(projectRoot);
780
- const raw = config.plan_context_top_k;
764
+ const raw = readFabricConfig(projectRoot).plan_context_top_k;
781
765
  if (raw !== void 0) {
782
766
  const parsed = planContextTopKSchema.safeParse(raw);
783
767
  if (parsed.success) return parsed.data;
784
768
  }
785
- return resolveRetrievalBudget({ profile: readRetrievalBudgetProfile(config) }).topK;
769
+ return PLAN_CONTEXT_TOP_K_DEFAULT;
786
770
  } catch {
787
771
  return PLAN_CONTEXT_TOP_K_DEFAULT;
788
772
  }
789
773
  }
774
+ function readRecallRelevanceRatio(projectRoot) {
775
+ try {
776
+ const raw = readFabricConfig(projectRoot).recall_relevance_ratio;
777
+ if (typeof raw === "number" && Number.isFinite(raw) && raw >= 0 && raw <= 1) {
778
+ return raw;
779
+ }
780
+ return RECALL_RELEVANCE_RATIO_DEFAULT;
781
+ } catch {
782
+ return RECALL_RELEVANCE_RATIO_DEFAULT;
783
+ }
784
+ }
790
785
  function readOrphanDemoteThresholdDays(projectRoot) {
791
786
  try {
792
787
  const cfg = readFabricConfig(projectRoot);
@@ -2643,11 +2638,23 @@ async function planContext(projectRoot, input) {
2643
2638
  scoringContext.vectorWeight = embedConfig.weight;
2644
2639
  }
2645
2640
  }
2646
- const builtItems = sortDescriptionItems(rawItems, scoringContext);
2647
- const rankedCandidates = dedupeDescriptionIndex(builtItems);
2641
+ const scoredSorted = sortDescriptionItems(rawItems, scoringContext);
2642
+ const seenStableIds = /* @__PURE__ */ new Set();
2643
+ const rankedScored = scoredSorted.filter(({ item }) => {
2644
+ if (seenStableIds.has(item.stable_id)) return false;
2645
+ seenStableIds.add(item.stable_id);
2646
+ return true;
2647
+ });
2648
+ const rankedCandidates = rankedScored.map((entry) => entry.item);
2648
2649
  const topK = readPlanContextTopK(projectRoot);
2649
- const omittedCandidateCount = Math.max(0, rankedCandidates.length - topK);
2650
- const topKCandidates = omittedCandidateCount > 0 ? rankedCandidates.slice(0, topK) : rankedCandidates;
2650
+ const cappedScored = rankedScored.slice(0, topK);
2651
+ const relevanceRatio = readRecallRelevanceRatio(projectRoot);
2652
+ const hasQuery = scoringContext.queryTerms.length > 0;
2653
+ const maxScore = rankedScored.length > 0 ? rankedScored[0].score : 0;
2654
+ const relevanceFloor = maxScore * relevanceRatio;
2655
+ const survivingScored = hasQuery && maxScore > 0 && relevanceRatio > 0 ? cappedScored.filter((entry) => entry.score >= relevanceFloor) : cappedScored;
2656
+ const topKCandidates = survivingScored.map((entry) => entry.item);
2657
+ const omittedCandidateCount = Math.max(0, rankedCandidates.length - topKCandidates.length);
2651
2658
  let candidates = topKCandidates;
2652
2659
  const relatedAppended = {};
2653
2660
  if (input.include_related === true) {
@@ -2889,7 +2896,7 @@ function compareScopeThenId(left, right, scopeRank) {
2889
2896
  }
2890
2897
  function sortDescriptionItems(rawItems, scoringContext) {
2891
2898
  if (scoringContext === void 0) {
2892
- return [...rawItems].sort((left, right) => compareStableIds(left.stable_id, right.stable_id));
2899
+ return [...rawItems].sort((left, right) => compareStableIds(left.stable_id, right.stable_id)).map((item) => ({ item, score: 0 }));
2893
2900
  }
2894
2901
  const scored = rawItems.map((item) => ({
2895
2902
  item,
@@ -2899,7 +2906,7 @@ function sortDescriptionItems(rawItems, scoringContext) {
2899
2906
  (left, right) => left.score !== right.score ? right.score - left.score : compareScopeThenId(left.item, right.item, scoringContext.scopeRank)
2900
2907
  // W2/A4 scope tie-break
2901
2908
  );
2902
- return scored.map((entry) => entry.item);
2909
+ return scored;
2903
2910
  }
2904
2911
  function documentTextForItem(description) {
2905
2912
  return [
@@ -2930,16 +2937,6 @@ function buildPreflightDiagnostics(suppressedStableIds) {
2930
2937
  function dedupeStableIds(stableIds) {
2931
2938
  return Array.from(new Set(stableIds));
2932
2939
  }
2933
- function dedupeDescriptionIndex(items) {
2934
- const seenStableIds = /* @__PURE__ */ new Set();
2935
- return items.filter((item) => {
2936
- if (seenStableIds.has(item.stable_id)) {
2937
- return false;
2938
- }
2939
- seenStableIds.add(item.stable_id);
2940
- return true;
2941
- });
2942
- }
2943
2940
  var RECENCY_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
2944
2941
  var RECENCY_BOOST = 25;
2945
2942
  var LOCALITY_SAME_FILE = 100;
@@ -3091,7 +3088,7 @@ function buildNextSteps(planResult, paths, candidateById, candidateLookup) {
3091
3088
  const omitted = planResult.omitted_candidate_count ?? 0;
3092
3089
  if (omitted > 0) {
3093
3090
  nextSteps.push(
3094
- `${omitted} lower-ranked candidate(s) were omitted by the retrieval budget \u2014 pass a narrower intent (or raise plan_context_top_k / the retrieval_budget_profile) to surface them.`
3091
+ `${omitted} lower-ranked candidate(s) were omitted by the retrieval budget \u2014 pass a narrower intent (or raise plan_context_top_k) to surface them.`
3095
3092
  );
3096
3093
  }
3097
3094
  const surfacedPaths = new Set(paths.map((p) => p.stable_id));
@@ -5660,6 +5657,15 @@ async function inspectEventsJsonlGates(projectRoot, options = {}) {
5660
5657
  import { readdir as readdir2, readFile as readFile9 } from "fs/promises";
5661
5658
  import { join as join16, posix as posix2 } from "path";
5662
5659
  var FABRIC_SKILL_SLUGS = ["fabric-archive", "fabric-review", "fabric-import"];
5660
+ var ROUTER_VALID_LEAF_SLUGS = /* @__PURE__ */ new Set([
5661
+ "fabric-archive",
5662
+ "fabric-review",
5663
+ "fabric-import",
5664
+ "fabric-sync",
5665
+ "fabric-store",
5666
+ "fabric-audit",
5667
+ "fabric-connect"
5668
+ ]);
5663
5669
  var SKILL_MD_FRONTMATTER_ROOTS = [".claude/skills", ".codex/skills"];
5664
5670
  var SKILL_FRONTMATTER_KEY_PATTERN = /^([A-Za-z_][A-Za-z0-9_-]*):[ \t]+(.+?)[ \t]*$/u;
5665
5671
  var SKILL_QUOTED_VALUE_LEADS = /* @__PURE__ */ new Set(['"', "'", "[", "{", ">", "|"]);
@@ -5844,6 +5850,68 @@ function extractSkillFrontmatterLines(raw) {
5844
5850
  }
5845
5851
  return null;
5846
5852
  }
5853
+ function extractMarkdownSectionBody(markdown, sectionName) {
5854
+ const lines = markdown.split(/\r?\n/u);
5855
+ const headingRe = /^(#{2,3})\s+(.+?)\s*$/u;
5856
+ let start = -1;
5857
+ for (let i = 0; i < lines.length; i++) {
5858
+ const h = headingRe.exec(lines[i]);
5859
+ if (h && h[2] === sectionName) {
5860
+ start = i + 1;
5861
+ break;
5862
+ }
5863
+ }
5864
+ if (start === -1) return null;
5865
+ const out = [];
5866
+ for (let i = start; i < lines.length; i++) {
5867
+ if (headingRe.test(lines[i])) break;
5868
+ out.push(lines[i]);
5869
+ }
5870
+ return out.join("\n");
5871
+ }
5872
+ async function inspectRouterChainRef(projectRoot) {
5873
+ const candidatePaths = [
5874
+ join16(projectRoot, ".claude", "skills", "fabric", "SKILL.md"),
5875
+ join16(projectRoot, ".codex", "skills", "fabric", "SKILL.md")
5876
+ ];
5877
+ let body = null;
5878
+ for (const candidate of candidatePaths) {
5879
+ try {
5880
+ body = await readFile9(candidate, "utf8");
5881
+ break;
5882
+ } catch {
5883
+ }
5884
+ }
5885
+ if (body === null) return { status: "ok", unknownRefs: [] };
5886
+ const chainSection = extractMarkdownSectionBody(body, "S_CHAIN");
5887
+ if (chainSection === null) return { status: "ok", unknownRefs: [] };
5888
+ const refs = /* @__PURE__ */ new Set();
5889
+ const tokenRe = /`(fabric-[a-z]+)`/gu;
5890
+ let match;
5891
+ while ((match = tokenRe.exec(chainSection)) !== null) {
5892
+ refs.add(match[1]);
5893
+ }
5894
+ const unknownRefs = [...refs].filter((slug) => !ROUTER_VALID_LEAF_SLUGS.has(slug)).sort();
5895
+ return unknownRefs.length === 0 ? { status: "ok", unknownRefs: [] } : { status: "drift", unknownRefs };
5896
+ }
5897
+ function createRouterChainRefCheck(t, inspection) {
5898
+ if (inspection.status === "ok") {
5899
+ return okCheck(t("doctor.check.router_chain_ref.name"), t("doctor.check.router_chain_ref.ok"));
5900
+ }
5901
+ const count = inspection.unknownRefs.length;
5902
+ return issueCheck(
5903
+ t("doctor.check.router_chain_ref.name"),
5904
+ "warn",
5905
+ "warning",
5906
+ "router_chain_ref_drift",
5907
+ t(`doctor.check.router_chain_ref.message.${count === 1 ? "singular" : "plural"}`, {
5908
+ count: String(count),
5909
+ list: inspection.unknownRefs.join(", ")
5910
+ }),
5911
+ t("doctor.check.router_chain_ref.remediation"),
5912
+ "maintainer"
5913
+ );
5914
+ }
5847
5915
  function createSkillRefMirrorCheck(t, inspection) {
5848
5916
  if (inspection.status === "ok") {
5849
5917
  return okCheck(t("doctor.check.skill_ref_mirror.name"), t("doctor.check.skill_ref_mirror.ok"));
@@ -7565,6 +7633,7 @@ async function runDoctorReport(target) {
7565
7633
  const hookCacheWritability = await inspectHookCacheWritability(projectRoot);
7566
7634
  const staleServeLock = inspectStaleServeLock(projectRoot, lintNow);
7567
7635
  const skillMdYamlInvalid = await inspectSkillMdYamlInvalid(projectRoot);
7636
+ const routerChainRef = await inspectRouterChainRef(projectRoot);
7568
7637
  const onboardCoverage = await inspectOnboardCoverage(projectRoot);
7569
7638
  const [hooksWired, hooksRuntime, hooksContentDrift] = await Promise.all([
7570
7639
  inspectHooksWired(projectRoot),
@@ -7641,6 +7710,9 @@ async function runDoctorReport(target) {
7641
7710
  // rc.12 lint #29: skill_md_yaml_invalid. Warning kind — surfaces
7642
7711
  // SKILL.md frontmatter that Codex CLI silently drops at load.
7643
7712
  createSkillMdYamlInvalidCheck(t, skillMdYamlInvalid),
7713
+ // B2 skill-router (A4): S_CHAIN reference backstop. Warning kind — flags an
7714
+ // S_CHAIN `fabric-*` reference to a leaf no longer in the install set.
7715
+ createRouterChainRefCheck(t, routerChainRef),
7644
7716
  // v2.0.0-rc.23 TASK-014 (F8c): Onboard coverage advisory. Info kind.
7645
7717
  // Surfaces uncovered S5 onboard slots and recommends /fabric-archive
7646
7718
  // first-run phase. Sits adjacent to Skill markdown YAML — both are
@@ -9340,6 +9412,25 @@ async function runDoctorConflictLint(projectRoot, opts = {}) {
9340
9412
  };
9341
9413
  }
9342
9414
 
9415
+ // src/services/summary-cold-eval.ts
9416
+ var COLD_EVAL_RUBRIC = [
9417
+ "You are a ZERO-CONTEXT judge. You are shown ONLY a one-line knowledge summary \u2014",
9418
+ "never the full entry body. For each summary decide: could a reader who has NOT",
9419
+ "seen the body ACT on this line alone (apply the decision / avoid the pitfall /",
9420
+ "follow the rule)?",
9421
+ "",
9422
+ "PASS (self_sufficient=true): the line states the thesis \u2014 the what + the",
9423
+ "operative so-what. FAIL (self_sufficient=false): the line only POINTS at the",
9424
+ "body ('explains the approach', 'covers the edge cases') without stating it.",
9425
+ "When you FAIL one, return a suggested_summary that states the thesis in one line."
9426
+ ].join("\n");
9427
+ function buildColdEvalBatch(candidates) {
9428
+ const judgeable = candidates.filter(
9429
+ (c) => typeof c.summary === "string" && c.summary.trim().length > 0
9430
+ );
9431
+ return { rubric: COLD_EVAL_RUBRIC, candidates: judgeable };
9432
+ }
9433
+
9343
9434
  // src/services/rotation-tick.ts
9344
9435
  var DEFAULT_TICK_INTERVAL_MS = 6 * 60 * 60 * 1e3;
9345
9436
  var tickTimers = /* @__PURE__ */ new Map();
@@ -9685,7 +9776,7 @@ function createFabricServer(tracker) {
9685
9776
  const server = new McpServer(
9686
9777
  {
9687
9778
  name: "fabric-knowledge-server",
9688
- version: "2.2.0-rc.8"
9779
+ version: "2.2.0-rc.9"
9689
9780
  },
9690
9781
  {
9691
9782
  instructions: FABRIC_SERVER_INSTRUCTIONS
@@ -9797,6 +9888,7 @@ if (isMainModule) {
9797
9888
  }
9798
9889
  export {
9799
9890
  AGENTS_MD_RESOURCE_URI,
9891
+ COLD_EVAL_RUBRIC,
9800
9892
  DEFAULT_CONFLICT_SIMILARITY_THRESHOLD,
9801
9893
  EVENT_LEDGER_PATH,
9802
9894
  FABRIC_SERVER_INSTRUCTIONS,
@@ -9806,6 +9898,7 @@ export {
9806
9898
  METRIC_COUNTER_NAMES,
9807
9899
  appendEventLedgerEvent,
9808
9900
  buildAlwaysActiveBodies,
9901
+ buildColdEvalBatch,
9809
9902
  buildKnowledgeCensus,
9810
9903
  bumpCounter,
9811
9904
  contextCache,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fenglimg/fabric-server",
3
- "version": "2.2.0-rc.8",
3
+ "version": "2.2.0-rc.9",
4
4
  "description": "Fabric MCP knowledge server — stdio transport for Claude Code / Codex CLI, manages .fabric/ knowledge base + agents.meta.json + event ledger.",
5
5
  "license": "MIT",
6
6
  "author": "wangzhichao <fenglimg90@gmail.com>",
@@ -37,7 +37,7 @@
37
37
  "@modelcontextprotocol/sdk": "^1.29.0",
38
38
  "minimatch": "^10.0.1",
39
39
  "zod": "^3.25.0",
40
- "@fenglimg/fabric-shared": "2.2.0-rc.8"
40
+ "@fenglimg/fabric-shared": "2.2.0-rc.9"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^22.15.0",