@fenglimg/fabric-server 2.0.0-rc.35 → 2.0.0-rc.36

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.
@@ -1741,6 +1741,7 @@ var HINT_SILENCE_COUNTER_FILE_REL = posix.join(
1741
1741
  var MS_PER_DAY = 24 * 60 * 60 * 1e3;
1742
1742
  var MATURITY_LINE_PATTERN = /^maturity:\s*("?)(stable|endorsed|draft)\1\s*$/mu;
1743
1743
  var CREATED_AT_LINE_PATTERN = /^created_at:\s*("?)([^"\n]+)\1\s*$/mu;
1744
+ var TAGS_LINE_PATTERN = /^tags:\s*\[(.*)\]\s*$/mu;
1744
1745
  var RELEVANCE_SCOPE_LINE_PATTERN = /^relevance_scope:\s*("?)(narrow|broad)\1\s*$/mu;
1745
1746
  var RELEVANCE_PATHS_LINE_PATTERN = /^relevance_paths:\s*\[([^\]]*)\]\s*$/mu;
1746
1747
  var RELEVANCE_PATHS_DRIFT_WINDOW_DAYS = 90;
@@ -1830,6 +1831,8 @@ async function runDoctorReport(target) {
1830
1831
  const skillDescription = inspectSkillDescription(projectRoot);
1831
1832
  const citeGoodhart = await inspectCiteGoodhart(projectRoot);
1832
1833
  const draftBacklog = inspectDraftBacklog(projectRoot);
1834
+ const knowledgeTagsEmpty = inspectKnowledgeTagsEmpty(projectRoot);
1835
+ const driftUnconsumed = await inspectDriftUnconsumed(projectRoot);
1833
1836
  const metaManuallyDiverged = await inspectMetaManuallyDiverged(projectRoot);
1834
1837
  const knowledgeDirUnindexed = inspectKnowledgeDirUnindexed(projectRoot, meta);
1835
1838
  const knowledgeDirMissing = inspectKnowledgeDirMissing(projectRoot);
@@ -1904,6 +1907,8 @@ async function runDoctorReport(target) {
1904
1907
  createSkillDescriptionCheck(t, skillDescription),
1905
1908
  createCiteGoodhartCheck(t, citeGoodhart),
1906
1909
  createDraftBacklogCheck(t, draftBacklog),
1910
+ createKnowledgeTagsEmptyCheck(t, knowledgeTagsEmpty),
1911
+ createDriftUnconsumedCheck(t, driftUnconsumed),
1907
1912
  createMcpConfigInWrongFileCheck(t, mcpConfigInWrongFile),
1908
1913
  createMetaManuallyDivergedCheck(t, metaManuallyDiverged),
1909
1914
  createKnowledgeDirUnindexedCheck(t, knowledgeDirUnindexed),
@@ -2980,6 +2985,35 @@ function inspectDraftBacklog(projectRoot) {
2980
2985
  ratio
2981
2986
  };
2982
2987
  }
2988
+ function inspectKnowledgeTagsEmpty(projectRoot) {
2989
+ const EMPTY_TAGS_RATIO_THRESHOLD = 0.5;
2990
+ const MIN_TOTAL_FOR_RATIO = 10;
2991
+ let emptyCount = 0;
2992
+ let totalCount = 0;
2993
+ for (const entry of iterateCanonicalEntries(projectRoot, /* @__PURE__ */ new Map())) {
2994
+ let source;
2995
+ try {
2996
+ source = readFileSync3(entry.absPath, "utf8");
2997
+ } catch {
2998
+ continue;
2999
+ }
3000
+ const isEmpty = isKnowledgeFrontmatterTagsEmpty(source);
3001
+ if (isEmpty === null || isEmpty === true) {
3002
+ emptyCount += 1;
3003
+ }
3004
+ totalCount += 1;
3005
+ }
3006
+ if (totalCount < MIN_TOTAL_FOR_RATIO) {
3007
+ return { status: "ok", emptyCount, totalCount, ratio: 0 };
3008
+ }
3009
+ const ratio = emptyCount / totalCount;
3010
+ return {
3011
+ status: ratio > EMPTY_TAGS_RATIO_THRESHOLD ? "warn" : "ok",
3012
+ emptyCount,
3013
+ totalCount,
3014
+ ratio
3015
+ };
3016
+ }
2983
3017
  async function inspectKnowledgeTestIndex(projectRoot) {
2984
3018
  const path2 = join7(projectRoot, ".fabric", ".cache", "knowledge-test.index.json");
2985
3019
  const built = await tryBuildRuleMeta(projectRoot);
@@ -3395,15 +3429,15 @@ function createMetaCheck(t, meta, globalCli) {
3395
3429
  );
3396
3430
  }
3397
3431
  if (meta.stale) {
3432
+ const revision = meta.revision;
3433
+ const computedRevision = meta.computedRevision ?? "<unknown>";
3434
+ const messageKey = revision !== null && revision === meta.computedRevision ? "doctor.check.agents_meta.message.stale_hash_equal" : "doctor.check.agents_meta.message.stale";
3398
3435
  return issueCheck(
3399
3436
  t("doctor.check.agents_meta.name"),
3400
3437
  "warn",
3401
3438
  "warning",
3402
3439
  "agents_meta_stale",
3403
- t("doctor.check.agents_meta.message.stale", {
3404
- revision: meta.revision,
3405
- computedRevision: meta.computedRevision ?? "<unknown>"
3406
- }),
3440
+ t(messageKey, { revision, computedRevision }),
3407
3441
  t("doctor.check.agents_meta.remediation.stale")
3408
3442
  );
3409
3443
  }
@@ -3645,6 +3679,71 @@ function createDraftBacklogCheck(t, inspection) {
3645
3679
  t("doctor.check.draft_backlog.remediation")
3646
3680
  );
3647
3681
  }
3682
+ async function inspectDriftUnconsumed(projectRoot) {
3683
+ const WINDOW_MS = 30 * 24 * 60 * 60 * 1e3;
3684
+ const MIN_DRIFT_FOR_WARN = 5;
3685
+ const cutoffMs = Date.now() - WINDOW_MS;
3686
+ let events = [];
3687
+ try {
3688
+ const result = await readEventLedger(projectRoot);
3689
+ events = result.events;
3690
+ } catch {
3691
+ return { status: "ok", driftCount: 0, demoteCount: 0 };
3692
+ }
3693
+ let driftCount = 0;
3694
+ let demoteCount = 0;
3695
+ for (const e of events) {
3696
+ if (e.ts < cutoffMs) continue;
3697
+ if (e.event_type === "knowledge_drift_detected") driftCount += 1;
3698
+ else if (e.event_type === "knowledge_demoted") demoteCount += 1;
3699
+ }
3700
+ const unconsumed = driftCount - demoteCount;
3701
+ return {
3702
+ status: unconsumed >= MIN_DRIFT_FOR_WARN ? "warn" : "ok",
3703
+ driftCount,
3704
+ demoteCount
3705
+ };
3706
+ }
3707
+ function createDriftUnconsumedCheck(t, inspection) {
3708
+ if (inspection.status === "ok") {
3709
+ return okCheck(
3710
+ t("doctor.check.drift_unconsumed.name"),
3711
+ t("doctor.check.drift_unconsumed.ok")
3712
+ );
3713
+ }
3714
+ return issueCheck(
3715
+ t("doctor.check.drift_unconsumed.name"),
3716
+ "warn",
3717
+ "warning",
3718
+ "knowledge_drift_unconsumed",
3719
+ t("doctor.check.drift_unconsumed.message", {
3720
+ driftCount: String(inspection.driftCount),
3721
+ demoteCount: String(inspection.demoteCount)
3722
+ }),
3723
+ t("doctor.check.drift_unconsumed.remediation")
3724
+ );
3725
+ }
3726
+ function createKnowledgeTagsEmptyCheck(t, inspection) {
3727
+ if (inspection.status === "ok") {
3728
+ return okCheck(
3729
+ t("doctor.check.knowledge_tags_empty.name"),
3730
+ t("doctor.check.knowledge_tags_empty.ok")
3731
+ );
3732
+ }
3733
+ const pct = Math.round(inspection.ratio * 100);
3734
+ return issueCheck(
3735
+ t("doctor.check.knowledge_tags_empty.name"),
3736
+ "warn",
3737
+ "warning",
3738
+ "knowledge_tags_empty_ratio",
3739
+ t("doctor.check.knowledge_tags_empty.message", {
3740
+ emptyCount: String(inspection.emptyCount),
3741
+ totalCount: String(inspection.totalCount),
3742
+ pct: String(pct)
3743
+ }),
3744
+ t("doctor.check.knowledge_tags_empty.remediation")
3745
+ );
3746
+ }
3648
3747
  function createCiteGoodhartCheck(t, inspection) {
3649
3748
  if (inspection.status === "ok") {
3650
3749
  return okCheck(
@@ -4565,6 +4664,19 @@ function extractKnowledgeFrontmatterMaturity(source) {
4565
4664
  const match = MATURITY_LINE_PATTERN.exec(fm[1]);
4566
4665
  return match === null ? null : match[2];
4567
4666
  }
4667
+ function isKnowledgeFrontmatterTagsEmpty(source) {
4668
+ const FM_PATTERN = /^(?:)?---\r?\n([\s\S]*?)\r?\n---/u;
4669
+ const fm = FM_PATTERN.exec(source);
4670
+ if (fm === null) {
4671
+ return null;
4672
+ }
4673
+ const match = TAGS_LINE_PATTERN.exec(fm[1]);
4674
+ if (match === null) {
4675
+ return null;
4676
+ }
4677
+ const inner = match[1].replace(/[\s,]/g, "");
4678
+ return inner === "";
4679
+ }
4568
4680
  function extractKnowledgeFrontmatterCreatedAt(source) {
4569
4681
  const FM_PATTERN = /^(?:\uFEFF)?---\r?\n([\s\S]*?)\r?\n---/u;
4570
4682
  const fm = FM_PATTERN.exec(source);
@@ -14,7 +14,7 @@ import {
14
14
  readEventLedger,
15
15
  runDoctorReport,
16
16
  sha256
17
- } from "./chunk-DRIWYXFP.js";
17
+ } from "./chunk-5XXH2VZZ.js";
18
18
 
19
19
  // src/http.ts
20
20
  import { randomUUID as randomUUID2 } from "crypto";
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  sha256,
40
40
  stableStringify,
41
41
  writeKnowledgeMeta
42
- } from "./chunk-DRIWYXFP.js";
42
+ } from "./chunk-5XXH2VZZ.js";
43
43
 
44
44
  // src/index.ts
45
45
  import { existsSync as existsSync3 } from "fs";
@@ -2091,7 +2091,7 @@ function formatPreexistingRootMessage(projectRoot) {
2091
2091
  function createFabricServer(tracker) {
2092
2092
  const server = new McpServer({
2093
2093
  name: "fabric-knowledge-server",
2094
- version: "2.0.0-rc.35"
2094
+ version: "2.0.0-rc.36"
2095
2095
  });
2096
2096
  registerPlanContext(server, tracker);
2097
2097
  registerKnowledgeSections(server, tracker);
@@ -2199,7 +2199,7 @@ function createShutdownHandler(deps) {
2199
2199
  };
2200
2200
  }
2201
2201
  async function startHttpServer(options) {
2202
- const { createFabricHttpApp } = await import("./http-OHY2I6ZY.js");
2202
+ const { createFabricHttpApp } = await import("./http-ZRVOXE6C.js");
2203
2203
  const { port, projectRoot, host = "127.0.0.1", authToken, allowLoopbackNoAuth } = options;
2204
2204
  const app = createFabricHttpApp({ projectRoot, host, authToken, allowLoopbackNoAuth });
2205
2205
  return await new Promise((resolveServer, rejectServer) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fenglimg/fabric-server",
3
- "version": "2.0.0-rc.35",
3
+ "version": "2.0.0-rc.36",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -13,7 +13,7 @@
13
13
  "express": "^5.2.1",
14
14
  "minimatch": "^10.0.1",
15
15
  "zod": "^3.25.0",
16
- "@fenglimg/fabric-shared": "2.0.0-rc.35"
16
+ "@fenglimg/fabric-shared": "2.0.0-rc.36"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/express": "^5.0.6",