@fenglimg/fabric-server 2.3.0-rc.7 → 2.3.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
@@ -745,36 +745,6 @@ interface RelatedGraphNode {
745
745
  * id index carries both forms for every node.
746
746
  */
747
747
  declare function buildRelatedGraph(nodes: RelatedGraphNode[]): RelatedGraphInspection;
748
- /** A richer node carrying the text/metadata signals the suggestion heuristic reads. */
749
- interface RelatedGraphNodeRich {
750
- /** Store-qualified id (`<alias>:<stableId>`). */
751
- qualifiedId: string;
752
- summary: string;
753
- /** RuleDescription.intent_clues (NOT `keywords` — RuleDescription has no such field). */
754
- intentClues: string[];
755
- tags: string[];
756
- relevancePaths: string[];
757
- /** Existing declared `related` edges — a pair already connected here is never re-proposed. */
758
- related: string[];
759
- }
760
- /** A proposed related edge: an ordered id pair, a confidence, and the signals that fired. */
761
- interface SuggestedRelatedEdge {
762
- source: string;
763
- target: string;
764
- confidence: number;
765
- provenance: string[];
766
- }
767
- /**
768
- * Propose related edges the corpus is missing. For every unordered pair NOT already
769
- * connected via existing `related`, score:
770
- * - token Jaccard over tokenize(summary + intent_clues) — the DOMINANT signal
771
- * - tag-set intersection — an INDEPENDENT boolean bonus (never folded into tokens)
772
- * - shared relevance_paths — an INDEPENDENT boolean bonus
773
- * confidence = jaccard + bonuses, clamped [0,1]. Only pairs >= 0.6 are returned, each
774
- * with a non-empty provenance[] naming the firing signals. Pure + deterministic
775
- * (same input → same output; sorted confidence desc, then source, then target).
776
- */
777
- declare function suggestRelatedEdges(nodes: RelatedGraphNodeRich[]): SuggestedRelatedEdge[];
778
748
  /**
779
749
  * Walk the store canonical corpus and build the related graph. Never throws —
780
750
  * collectStoreCanonicalEntries degrades to [] when no store is in the read-set.
@@ -786,13 +756,6 @@ declare function suggestRelatedEdges(nodes: RelatedGraphNodeRich[]): SuggestedRe
786
756
  * read `description.related` directly (the single source the recall path uses).
787
757
  */
788
758
  declare function inspectRelatedGraph(projectRoot: string): Promise<RelatedGraphInspection>;
789
- /**
790
- * Walk the store canonical corpus and PROPOSE the top-N missing related edges via the
791
- * pure suggestRelatedEdges heuristic. Never throws — collectStoreCanonicalEntries
792
- * degrades to [] when no store is in the read-set. READ-ONLY: it computes suggestions
793
- * and writes nothing; edge creation stays on the fabric-review modify path.
794
- */
795
- declare function inspectSuggestedRelatedEdges(projectRoot: string): Promise<SuggestedRelatedEdge[]>;
796
759
 
797
760
  interface StoreReachability {
798
761
  uuid: string;
@@ -1186,4 +1149,4 @@ interface ShutdownHandlerDeps {
1186
1149
  */
1187
1150
  declare function createShutdownHandler(deps: ShutdownHandlerDeps): () => void;
1188
1151
 
1189
- 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, type ConsumptionEntry, type ConsumptionInspection, type ConsumptionLintConfig, 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, OPTIONAL_EMBED_PACKAGE, type PlanContextInput, type PlanContextResult, type PrecheckResult, RETIRED_TOKENS, type RecallInput, type RecallResult, type RelatedBrokenLink, type RelatedGraphInspection, type RelatedGraphNode, type RelatedGraphNodeRich, type RelatedHubEntry, type RequirementProfile, type RetiredReferenceHit, type RetiredReferenceInspection, type RetiredToken, type SelectionTokenState, type ShutdownHandlerDeps, type StoreCanonicalEntry, type StoreReachability, type SuggestedRelatedEdge, type SurfaceVerdict, type UnboundProjectViolation, type WhyNotSurfacedResult, aggregateConsumption, appendEventLedgerEvent, buildAlwaysActiveBodies, buildColdEvalBatch, buildKnowledgeCensus, buildRelatedGraph, bumpCounter, clearPrecheckCache, collectStoreCanonicalEntries, contextCache, createFabricServer, createInFlightTracker, createShutdownHandler, defaultEmbedCacheDir, detectUnboundProject, drainCounters, enrichDescriptions, evaluateStoreDir, explainWhyNotSurfaced, extractKnowledge, findConflictCandidates, flushAndSyncEventLedger, flushMetrics, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, getMetricsLedgerPath, inspectConsumption, inspectRelatedGraph, inspectRetiredReferences, inspectSuggestedRelatedEdges, isEmbedderResolvable, lintConflicts, loadConflictEntries, loadEmbedder, pairSimilarity, planContext, precheckStoreReachability, readEmbedConfig, readEventLedger, readFusion, readLedger, readMetrics, readSelectionToken, recall, rehydrateAgentsMetaAt, resolveLedgerPaths, reviewKnowledge, reviewPending, runDoctorApplyLint, runDoctorArchiveHistory, runDoctorCiteCoverage, runDoctorConflictLint, runDoctorFix, runDoctorHistoryAll, runDoctorReport, startMetricsFlush, startRotationTick, startStdioServer, stopMetricsFlush, stopRotationTick, suggestRelatedEdges };
1152
+ 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, type ConsumptionEntry, type ConsumptionInspection, type ConsumptionLintConfig, 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, OPTIONAL_EMBED_PACKAGE, type PlanContextInput, type PlanContextResult, type PrecheckResult, RETIRED_TOKENS, type RecallInput, type RecallResult, type RelatedBrokenLink, type RelatedGraphInspection, type RelatedGraphNode, type RelatedHubEntry, type RequirementProfile, type RetiredReferenceHit, type RetiredReferenceInspection, type RetiredToken, type SelectionTokenState, type ShutdownHandlerDeps, type StoreCanonicalEntry, type StoreReachability, type SurfaceVerdict, type UnboundProjectViolation, type WhyNotSurfacedResult, aggregateConsumption, appendEventLedgerEvent, buildAlwaysActiveBodies, buildColdEvalBatch, buildKnowledgeCensus, buildRelatedGraph, bumpCounter, clearPrecheckCache, collectStoreCanonicalEntries, contextCache, createFabricServer, createInFlightTracker, createShutdownHandler, defaultEmbedCacheDir, detectUnboundProject, drainCounters, enrichDescriptions, evaluateStoreDir, explainWhyNotSurfaced, extractKnowledge, findConflictCandidates, flushAndSyncEventLedger, flushMetrics, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, getMetricsLedgerPath, inspectConsumption, inspectRelatedGraph, inspectRetiredReferences, isEmbedderResolvable, lintConflicts, loadConflictEntries, loadEmbedder, pairSimilarity, planContext, precheckStoreReachability, readEmbedConfig, readEventLedger, readFusion, readLedger, readMetrics, readSelectionToken, recall, rehydrateAgentsMetaAt, resolveLedgerPaths, reviewKnowledge, reviewPending, runDoctorApplyLint, runDoctorArchiveHistory, runDoctorCiteCoverage, runDoctorConflictLint, runDoctorFix, runDoctorHistoryAll, runDoctorReport, startMetricsFlush, startRotationTick, startStdioServer, stopMetricsFlush, stopRotationTick };
package/dist/index.js CHANGED
@@ -5421,6 +5421,9 @@ ${content}`;
5421
5421
  if (patch.relevance_paths !== void 0) updates.relevance_paths = `relevance_paths: ${flowArray(patch.relevance_paths)}`;
5422
5422
  if (patch.semantic_scope !== void 0) updates.semantic_scope = `semantic_scope: ${patch.semantic_scope}`;
5423
5423
  if (patch.related !== void 0) updates.related = `related: ${flowArray(patch.related)}`;
5424
+ if (patch.must_read_if !== void 0) updates.must_read_if = `must_read_if: ${quoteIfNeeded(patch.must_read_if)}`;
5425
+ if (patch.intent_clues !== void 0) updates.intent_clues = `intent_clues: ${flowArray(patch.intent_clues)}`;
5426
+ if (patch.impact !== void 0) updates.impact = `impact: ${flowArray(patch.impact)}`;
5424
5427
  if (patch.status !== void 0) updates.status = `status: ${patch.status}`;
5425
5428
  if (patch.deferred_until !== void 0) updates.deferred_until = `deferred_until: ${quoteIfNeeded(patch.deferred_until)}`;
5426
5429
  if (patch.last_review_confirmed_at !== void 0) updates.last_review_confirmed_at = `last_review_confirmed_at: ${quoteIfNeeded(patch.last_review_confirmed_at)}`;
@@ -5458,6 +5461,9 @@ function appendPatchLines(lines, patch) {
5458
5461
  if (patch.relevance_scope !== void 0) lines.push(`relevance_scope: ${patch.relevance_scope}`);
5459
5462
  if (patch.relevance_paths !== void 0) lines.push(`relevance_paths: ${flowArray(patch.relevance_paths)}`);
5460
5463
  if (patch.related !== void 0) lines.push(`related: ${flowArray(patch.related)}`);
5464
+ if (patch.must_read_if !== void 0) lines.push(`must_read_if: ${quoteIfNeeded(patch.must_read_if)}`);
5465
+ if (patch.intent_clues !== void 0) lines.push(`intent_clues: ${flowArray(patch.intent_clues)}`);
5466
+ if (patch.impact !== void 0) lines.push(`impact: ${flowArray(patch.impact)}`);
5461
5467
  if (patch.status !== void 0) lines.push(`status: ${patch.status}`);
5462
5468
  if (patch.deferred_until !== void 0) lines.push(`deferred_until: ${quoteIfNeeded(patch.deferred_until)}`);
5463
5469
  if (patch.last_review_confirmed_at !== void 0) lines.push(`last_review_confirmed_at: ${quoteIfNeeded(patch.last_review_confirmed_at)}`);
@@ -7672,7 +7678,13 @@ async function inspectHooksWired(projectRoot) {
7672
7678
  const required = [
7673
7679
  { event: "Stop", hookFile: "fabric-hint.cjs" },
7674
7680
  { event: "SessionStart", hookFile: "knowledge-hint-broad.cjs" },
7675
- { event: "PreToolUse", hookFile: "knowledge-hint-narrow.cjs" }
7681
+ // ux-w2-6 (rc.9): PreToolUse is the SINGLE merged orchestrator
7682
+ // knowledge-pretooluse.cjs which internally requires knowledge-hint-narrow.cjs
7683
+ // (and cite-policy-evict.cjs) so a single edit produces ONE additionalContext
7684
+ // envelope instead of two. The stale reference to narrow.cjs here was the
7685
+ // rc.30 BUG-M3 false-negative source — narrow.cjs still exists on disk as a
7686
+ // lib but is NOT registered as a PreToolUse hook.
7687
+ { event: "PreToolUse", hookFile: "knowledge-pretooluse.cjs" }
7676
7688
  ];
7677
7689
  const missing = [];
7678
7690
  const hooksSection = isRecord(parsed) ? parsed.hooks : void 0;
@@ -11087,7 +11099,6 @@ function buildColdEvalBatch(candidates) {
11087
11099
  }
11088
11100
 
11089
11101
  // src/services/doctor-related-graph.ts
11090
- import { tokenize as tokenize3 } from "@fenglimg/fabric-shared";
11091
11102
  function buildRelatedGraph(nodes) {
11092
11103
  const brokenLinks = [];
11093
11104
  const inDegree = /* @__PURE__ */ new Map();
@@ -11128,66 +11139,6 @@ function extractBareStableId(qualifiedId) {
11128
11139
  }
11129
11140
  return null;
11130
11141
  }
11131
- var SUGGEST_CONFIDENCE_THRESHOLD = 0.6;
11132
- var TAG_OVERLAP_BONUS = 0.15;
11133
- var PATH_OVERLAP_BONUS = 0.15;
11134
- function suggestRelatedEdges(nodes) {
11135
- const pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
11136
- const prepared = nodes.map((node) => ({
11137
- qualifiedId: node.qualifiedId,
11138
- bareId: extractBareStableId(node.qualifiedId) ?? node.qualifiedId,
11139
- tokens: new Set(tokenize3(`${node.summary} ${node.intentClues.join(" ")}`)),
11140
- tags: new Set(node.tags),
11141
- paths: new Set(node.relevancePaths)
11142
- }));
11143
- const existing = /* @__PURE__ */ new Set();
11144
- for (const node of nodes) {
11145
- const aBare = extractBareStableId(node.qualifiedId) ?? node.qualifiedId;
11146
- for (const rel of node.related) {
11147
- existing.add(pairKey(aBare, extractBareStableId(rel) ?? rel));
11148
- }
11149
- }
11150
- const out = [];
11151
- for (let i = 0; i < prepared.length; i++) {
11152
- for (let j = i + 1; j < prepared.length; j++) {
11153
- const a = prepared[i];
11154
- const b = prepared[j];
11155
- if (a.bareId === b.bareId) continue;
11156
- if (existing.has(pairKey(a.bareId, b.bareId))) continue;
11157
- let intersection = 0;
11158
- for (const t of a.tokens) if (b.tokens.has(t)) intersection++;
11159
- const union = a.tokens.size + b.tokens.size - intersection;
11160
- const jaccard = union === 0 ? 0 : intersection / union;
11161
- let tagOverlap = false;
11162
- for (const t of a.tags)
11163
- if (b.tags.has(t)) {
11164
- tagOverlap = true;
11165
- break;
11166
- }
11167
- let pathOverlap = false;
11168
- for (const p of a.paths)
11169
- if (b.paths.has(p)) {
11170
- pathOverlap = true;
11171
- break;
11172
- }
11173
- let confidence = jaccard;
11174
- if (tagOverlap) confidence += TAG_OVERLAP_BONUS;
11175
- if (pathOverlap) confidence += PATH_OVERLAP_BONUS;
11176
- confidence = Math.min(1, confidence);
11177
- if (confidence < SUGGEST_CONFIDENCE_THRESHOLD) continue;
11178
- const provenance = [];
11179
- if (jaccard > 0) provenance.push("token-jaccard");
11180
- if (tagOverlap) provenance.push("tag-overlap");
11181
- if (pathOverlap) provenance.push("shared-path");
11182
- const [source, target] = a.qualifiedId < b.qualifiedId ? [a.qualifiedId, b.qualifiedId] : [b.qualifiedId, a.qualifiedId];
11183
- out.push({ source, target, confidence, provenance });
11184
- }
11185
- }
11186
- out.sort(
11187
- (x, y) => y.confidence - x.confidence || x.source.localeCompare(y.source) || x.target.localeCompare(y.target)
11188
- );
11189
- return out;
11190
- }
11191
11142
  async function inspectRelatedGraph(projectRoot) {
11192
11143
  const entries = await collectStoreCanonicalEntries(projectRoot);
11193
11144
  return buildRelatedGraph(
@@ -11197,24 +11148,6 @@ async function inspectRelatedGraph(projectRoot) {
11197
11148
  }))
11198
11149
  );
11199
11150
  }
11200
- var SUGGESTED_EDGES_TOP_N = 20;
11201
- async function inspectSuggestedRelatedEdges(projectRoot) {
11202
- let entries;
11203
- try {
11204
- entries = await collectStoreCanonicalEntries(projectRoot);
11205
- } catch {
11206
- return [];
11207
- }
11208
- const nodes = entries.map((entry) => ({
11209
- qualifiedId: entry.qualifiedId,
11210
- summary: entry.description.summary ?? "",
11211
- intentClues: entry.description.intent_clues ?? [],
11212
- tags: entry.description.tags ?? [],
11213
- relevancePaths: entry.description.relevance_paths ?? [],
11214
- related: entry.description.related ?? []
11215
- }));
11216
- return suggestRelatedEdges(nodes).slice(0, SUGGESTED_EDGES_TOP_N);
11217
- }
11218
11151
 
11219
11152
  // src/services/store-precheck.ts
11220
11153
  import { existsSync as existsSync9, readFileSync as readFileSync4 } from "fs";
@@ -11696,7 +11629,7 @@ function createFabricServer(tracker) {
11696
11629
  const server = new McpServer(
11697
11630
  {
11698
11631
  name: "fabric-knowledge-server",
11699
- version: "2.3.0-rc.7"
11632
+ version: "2.3.0-rc.9"
11700
11633
  },
11701
11634
  {
11702
11635
  instructions: FABRIC_SERVER_INSTRUCTIONS
@@ -11850,7 +11783,6 @@ export {
11850
11783
  inspectConsumption,
11851
11784
  inspectRelatedGraph,
11852
11785
  inspectRetiredReferences,
11853
- inspectSuggestedRelatedEdges,
11854
11786
  isEmbedderResolvable,
11855
11787
  lintConflicts,
11856
11788
  loadConflictEntries,
@@ -11880,6 +11812,5 @@ export {
11880
11812
  startRotationTick,
11881
11813
  startStdioServer,
11882
11814
  stopMetricsFlush,
11883
- stopRotationTick,
11884
- suggestRelatedEdges
11815
+ stopRotationTick
11885
11816
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fenglimg/fabric-server",
3
- "version": "2.3.0-rc.7",
3
+ "version": "2.3.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.3.0-rc.7"
40
+ "@fenglimg/fabric-shared": "2.3.0-rc.9"
41
41
  },
42
42
  "optionalDependencies": {
43
43
  "fastembed": "^2.0.0"