@fenglimg/fabric-server 2.0.0-rc.23 → 2.0.0-rc.25
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.
|
@@ -428,6 +428,27 @@ import {
|
|
|
428
428
|
parseKnowledgeId
|
|
429
429
|
} from "@fenglimg/fabric-shared";
|
|
430
430
|
import { atomicWriteText as atomicWriteText3 } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
431
|
+
async function loadKbIdTypeMap(projectRootInput) {
|
|
432
|
+
const projectRoot = normalizeProjectRoot(projectRootInput);
|
|
433
|
+
const metaPath = join4(projectRoot, ".fabric", "agents.meta.json");
|
|
434
|
+
const meta = await readExistingMeta(metaPath);
|
|
435
|
+
const map = /* @__PURE__ */ new Map();
|
|
436
|
+
if (meta === void 0) {
|
|
437
|
+
return map;
|
|
438
|
+
}
|
|
439
|
+
for (const node of Object.values(meta.nodes)) {
|
|
440
|
+
const stableId = node.stable_id;
|
|
441
|
+
if (stableId === void 0 || !isKnowledgeStableId(stableId)) {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
const knowledgeType = node.description?.knowledge_type;
|
|
445
|
+
if (knowledgeType === void 0) {
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
map.set(stableId, knowledgeType);
|
|
449
|
+
}
|
|
450
|
+
return map;
|
|
451
|
+
}
|
|
431
452
|
async function buildKnowledgeMeta(projectRootInput) {
|
|
432
453
|
const projectRoot = normalizeProjectRoot(projectRootInput);
|
|
433
454
|
assertExistingDirectory(projectRoot);
|
|
@@ -4963,6 +4984,40 @@ async function ensureCitePolicyActivatedMarker(projectRoot) {
|
|
|
4963
4984
|
return { marker_ts: 0, emitted_now: false };
|
|
4964
4985
|
}
|
|
4965
4986
|
}
|
|
4987
|
+
async function ensureCiteContractPolicyActivatedMarker(projectRoot) {
|
|
4988
|
+
let driftStatus;
|
|
4989
|
+
try {
|
|
4990
|
+
const inspection = await inspectL1BootstrapSnapshotDrift(projectRoot);
|
|
4991
|
+
driftStatus = inspection.status;
|
|
4992
|
+
} catch {
|
|
4993
|
+
driftStatus = "drift";
|
|
4994
|
+
}
|
|
4995
|
+
if (driftStatus !== "ok") {
|
|
4996
|
+
return { marker_ts: 0, emitted_now: false, blocked_by: "bootstrap_drift" };
|
|
4997
|
+
}
|
|
4998
|
+
let existing;
|
|
4999
|
+
try {
|
|
5000
|
+
const { events } = await readEventLedger(projectRoot, {
|
|
5001
|
+
event_type: "cite_contract_policy_activated"
|
|
5002
|
+
});
|
|
5003
|
+
if (events.length > 0) {
|
|
5004
|
+
existing = events[0];
|
|
5005
|
+
}
|
|
5006
|
+
} catch {
|
|
5007
|
+
return { marker_ts: 0, emitted_now: false, blocked_by: null };
|
|
5008
|
+
}
|
|
5009
|
+
if (existing !== void 0) {
|
|
5010
|
+
return { marker_ts: existing.ts, emitted_now: false, blocked_by: null };
|
|
5011
|
+
}
|
|
5012
|
+
try {
|
|
5013
|
+
const stored = await appendEventLedgerEvent(projectRoot, {
|
|
5014
|
+
event_type: "cite_contract_policy_activated"
|
|
5015
|
+
});
|
|
5016
|
+
return { marker_ts: stored.ts, emitted_now: true, blocked_by: null };
|
|
5017
|
+
} catch {
|
|
5018
|
+
return { marker_ts: 0, emitted_now: false, blocked_by: null };
|
|
5019
|
+
}
|
|
5020
|
+
}
|
|
4966
5021
|
function parseNoneSentinel(kbLineRaw) {
|
|
4967
5022
|
if (typeof kbLineRaw !== "string" || kbLineRaw.length === 0) return "unspecified";
|
|
4968
5023
|
const m = kbLineRaw.match(/^KB:\s*none\b\s*(?:\[([^\]]*)\])?\s*$/i);
|
|
@@ -5000,7 +5055,10 @@ function matchesRelevancePath(editPath, relevancePaths) {
|
|
|
5000
5055
|
return false;
|
|
5001
5056
|
}
|
|
5002
5057
|
async function runDoctorCiteCoverage(projectRoot, options) {
|
|
5058
|
+
const layerFilter = options.layer ?? "all";
|
|
5003
5059
|
const marker = await ensureCitePolicyActivatedMarker(projectRoot);
|
|
5060
|
+
const contractMarker = await ensureCiteContractPolicyActivatedMarker(projectRoot);
|
|
5061
|
+
const idTypeMap = await loadKbIdTypeMap(projectRoot);
|
|
5004
5062
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5005
5063
|
const zeroMetrics = {
|
|
5006
5064
|
edits_touched: 0,
|
|
@@ -5009,6 +5067,20 @@ async function runDoctorCiteCoverage(projectRoot, options) {
|
|
|
5009
5067
|
expected_but_missed: 0,
|
|
5010
5068
|
total_turns: 0
|
|
5011
5069
|
};
|
|
5070
|
+
const contractStatus = contractMarker.blocked_by === "bootstrap_drift" ? "skipped:bootstrap_drift" : contractMarker.marker_ts === 0 ? "awaiting_marker" : "ok";
|
|
5071
|
+
const zeroContractMetrics = {
|
|
5072
|
+
decisions_cited: 0,
|
|
5073
|
+
pitfalls_cited: 0,
|
|
5074
|
+
contract_with: 0,
|
|
5075
|
+
contract_missing: 0,
|
|
5076
|
+
hard_violated: 0,
|
|
5077
|
+
cite_id_unresolved: 0,
|
|
5078
|
+
skip_count: {}
|
|
5079
|
+
};
|
|
5080
|
+
const zeroLayerType = {
|
|
5081
|
+
team: {},
|
|
5082
|
+
personal: {}
|
|
5083
|
+
};
|
|
5012
5084
|
if (marker.marker_ts === 0) {
|
|
5013
5085
|
return {
|
|
5014
5086
|
status: "skipped",
|
|
@@ -5016,11 +5088,17 @@ async function runDoctorCiteCoverage(projectRoot, options) {
|
|
|
5016
5088
|
marker_emitted_now: false,
|
|
5017
5089
|
since_ts: options.since,
|
|
5018
5090
|
client_filter: options.client,
|
|
5091
|
+
layer_filter: layerFilter,
|
|
5019
5092
|
metrics: zeroMetrics,
|
|
5093
|
+
contract_metrics_status: contractStatus,
|
|
5094
|
+
contract_metrics: zeroContractMetrics,
|
|
5095
|
+
per_layer_type: zeroLayerType,
|
|
5096
|
+
contract_marker_ts: contractMarker.marker_ts,
|
|
5020
5097
|
generated_at: generatedAt
|
|
5021
5098
|
};
|
|
5022
5099
|
}
|
|
5023
5100
|
const effectiveSince = Math.max(marker.marker_ts, options.since);
|
|
5101
|
+
const contractEffectiveSince = contractStatus === "ok" ? Math.max(contractMarker.marker_ts, options.since) : Number.POSITIVE_INFINITY;
|
|
5024
5102
|
let ledgerEvents = [];
|
|
5025
5103
|
try {
|
|
5026
5104
|
const result = await readEventLedger(projectRoot, { since: effectiveSince });
|
|
@@ -5032,7 +5110,12 @@ async function runDoctorCiteCoverage(projectRoot, options) {
|
|
|
5032
5110
|
marker_emitted_now: marker.emitted_now,
|
|
5033
5111
|
since_ts: effectiveSince,
|
|
5034
5112
|
client_filter: options.client,
|
|
5113
|
+
layer_filter: layerFilter,
|
|
5035
5114
|
metrics: zeroMetrics,
|
|
5115
|
+
contract_metrics_status: contractStatus,
|
|
5116
|
+
contract_metrics: zeroContractMetrics,
|
|
5117
|
+
per_layer_type: zeroLayerType,
|
|
5118
|
+
contract_marker_ts: contractMarker.marker_ts,
|
|
5036
5119
|
generated_at: generatedAt
|
|
5037
5120
|
};
|
|
5038
5121
|
}
|
|
@@ -5125,6 +5208,80 @@ async function runDoctorCiteCoverage(projectRoot, options) {
|
|
|
5125
5208
|
perClientAccum.set(client, existing);
|
|
5126
5209
|
};
|
|
5127
5210
|
const sessionCitedKbs = /* @__PURE__ */ new Map();
|
|
5211
|
+
const sessionEditPaths = /* @__PURE__ */ new Map();
|
|
5212
|
+
for (const edit of editEvents) {
|
|
5213
|
+
const sid = edit.session_id;
|
|
5214
|
+
if (typeof sid !== "string" || sid.length === 0) continue;
|
|
5215
|
+
const list = sessionEditPaths.get(sid) ?? [];
|
|
5216
|
+
list.push(normalizePath(edit.path));
|
|
5217
|
+
sessionEditPaths.set(sid, list);
|
|
5218
|
+
}
|
|
5219
|
+
let decisionsCited = 0;
|
|
5220
|
+
let pitfallsCited = 0;
|
|
5221
|
+
let contractWith = 0;
|
|
5222
|
+
let contractMissing = 0;
|
|
5223
|
+
let hardViolated = 0;
|
|
5224
|
+
let citeIdUnresolved = 0;
|
|
5225
|
+
const skipCount = {};
|
|
5226
|
+
const layerTypeAccum = { team: {}, personal: {} };
|
|
5227
|
+
const bumpLayerType = (citeId, type) => {
|
|
5228
|
+
const layer = citeId.startsWith("KP-") ? "personal" : citeId.startsWith("KT-") ? "team" : null;
|
|
5229
|
+
if (layer === null) return;
|
|
5230
|
+
layerTypeAccum[layer][type] = (layerTypeAccum[layer][type] ?? 0) + 1;
|
|
5231
|
+
};
|
|
5232
|
+
const passesLayerFilter = (citeId) => {
|
|
5233
|
+
if (layerFilter === "all") return true;
|
|
5234
|
+
if (layerFilter === "team") return citeId.startsWith("KT-");
|
|
5235
|
+
return citeId.startsWith("KP-");
|
|
5236
|
+
};
|
|
5237
|
+
const evaluateOperatorViolation = (sessionId, operators) => {
|
|
5238
|
+
const editPaths = typeof sessionId === "string" && sessionId.length > 0 ? sessionEditPaths.get(sessionId) ?? [] : [];
|
|
5239
|
+
for (const op of operators) {
|
|
5240
|
+
switch (op.kind) {
|
|
5241
|
+
case "edit": {
|
|
5242
|
+
let matched = false;
|
|
5243
|
+
for (const p of editPaths) {
|
|
5244
|
+
if (minimatch(p, op.target, { dot: true, matchBase: false })) {
|
|
5245
|
+
matched = true;
|
|
5246
|
+
break;
|
|
5247
|
+
}
|
|
5248
|
+
}
|
|
5249
|
+
if (!matched) return true;
|
|
5250
|
+
break;
|
|
5251
|
+
}
|
|
5252
|
+
case "not_edit": {
|
|
5253
|
+
for (const p of editPaths) {
|
|
5254
|
+
if (minimatch(p, op.target, { dot: true, matchBase: false })) {
|
|
5255
|
+
return true;
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
break;
|
|
5259
|
+
}
|
|
5260
|
+
case "require": {
|
|
5261
|
+
let found = false;
|
|
5262
|
+
for (const p of editPaths) {
|
|
5263
|
+
if (p.includes(op.target)) {
|
|
5264
|
+
found = true;
|
|
5265
|
+
break;
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
if (!found) return true;
|
|
5269
|
+
break;
|
|
5270
|
+
}
|
|
5271
|
+
case "forbid": {
|
|
5272
|
+
for (const p of editPaths) {
|
|
5273
|
+
if (p.includes(op.target)) {
|
|
5274
|
+
return true;
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
5277
|
+
break;
|
|
5278
|
+
}
|
|
5279
|
+
default:
|
|
5280
|
+
break;
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
return false;
|
|
5284
|
+
};
|
|
5128
5285
|
let totalTurns = 0;
|
|
5129
5286
|
let qualifyingCites = 0;
|
|
5130
5287
|
let recalledUnverified = 0;
|
|
@@ -5174,6 +5331,40 @@ async function runDoctorCiteCoverage(projectRoot, options) {
|
|
|
5174
5331
|
m.recalled_unverified += 1;
|
|
5175
5332
|
});
|
|
5176
5333
|
}
|
|
5334
|
+
if (contractStatus === "ok" && turn.ts >= contractEffectiveSince) {
|
|
5335
|
+
const commitments = turn.cite_commitments ?? [];
|
|
5336
|
+
for (let i = 0; i < turn.cite_ids.length; i += 1) {
|
|
5337
|
+
const citeId = turn.cite_ids[i];
|
|
5338
|
+
if (typeof citeId !== "string" || citeId.length === 0) continue;
|
|
5339
|
+
if (!passesLayerFilter(citeId)) continue;
|
|
5340
|
+
const kbType = idTypeMap.get(citeId);
|
|
5341
|
+
if (kbType === void 0) {
|
|
5342
|
+
citeIdUnresolved += 1;
|
|
5343
|
+
bumpLayerType(citeId, "unresolved");
|
|
5344
|
+
continue;
|
|
5345
|
+
}
|
|
5346
|
+
bumpLayerType(citeId, kbType);
|
|
5347
|
+
if (kbType === "decision" || kbType === "pitfall") {
|
|
5348
|
+
if (kbType === "decision") decisionsCited += 1;
|
|
5349
|
+
else pitfallsCited += 1;
|
|
5350
|
+
const commitment = commitments[i];
|
|
5351
|
+
const operators = commitment?.operators ?? [];
|
|
5352
|
+
const skipReason = commitment?.skip_reason ?? null;
|
|
5353
|
+
if (skipReason !== null) {
|
|
5354
|
+
skipCount[skipReason] = (skipCount[skipReason] ?? 0) + 1;
|
|
5355
|
+
continue;
|
|
5356
|
+
}
|
|
5357
|
+
if (operators.length === 0) {
|
|
5358
|
+
contractMissing += 1;
|
|
5359
|
+
continue;
|
|
5360
|
+
}
|
|
5361
|
+
contractWith += 1;
|
|
5362
|
+
if (evaluateOperatorViolation(sid, operators)) {
|
|
5363
|
+
hardViolated += 1;
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5177
5368
|
}
|
|
5178
5369
|
let editsTouched = 0;
|
|
5179
5370
|
let expectedButMissed = 0;
|
|
@@ -5208,19 +5399,96 @@ async function runDoctorCiteCoverage(projectRoot, options) {
|
|
|
5208
5399
|
perClient[client] = m;
|
|
5209
5400
|
}
|
|
5210
5401
|
}
|
|
5402
|
+
const contractMetrics = {
|
|
5403
|
+
decisions_cited: decisionsCited,
|
|
5404
|
+
pitfalls_cited: pitfallsCited,
|
|
5405
|
+
contract_with: contractWith,
|
|
5406
|
+
contract_missing: contractMissing,
|
|
5407
|
+
hard_violated: hardViolated,
|
|
5408
|
+
cite_id_unresolved: citeIdUnresolved,
|
|
5409
|
+
skip_count: skipCount
|
|
5410
|
+
};
|
|
5211
5411
|
return {
|
|
5212
5412
|
status: "ok",
|
|
5213
5413
|
marker_ts: marker.marker_ts,
|
|
5214
5414
|
marker_emitted_now: marker.emitted_now,
|
|
5215
5415
|
since_ts: effectiveSince,
|
|
5216
5416
|
client_filter: options.client,
|
|
5417
|
+
layer_filter: layerFilter,
|
|
5217
5418
|
metrics,
|
|
5218
5419
|
...perClient !== void 0 ? { per_client: perClient } : {},
|
|
5219
5420
|
...Object.keys(dismissedHistogram).length > 0 ? { dismissed_reason_histogram: dismissedHistogram } : {},
|
|
5220
5421
|
...Object.keys(noneHistogram).length > 0 ? { none_reason_histogram: noneHistogram } : {},
|
|
5422
|
+
contract_metrics_status: contractStatus,
|
|
5423
|
+
contract_metrics: contractMetrics,
|
|
5424
|
+
per_layer_type: layerTypeAccum,
|
|
5425
|
+
contract_marker_ts: contractMarker.marker_ts,
|
|
5221
5426
|
generated_at: generatedAt
|
|
5222
5427
|
};
|
|
5223
5428
|
}
|
|
5429
|
+
async function runDoctorArchiveHistory(projectRoot, options) {
|
|
5430
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5431
|
+
const nowMs = Date.now();
|
|
5432
|
+
let events = [];
|
|
5433
|
+
try {
|
|
5434
|
+
const result = await readEventLedger(projectRoot, {
|
|
5435
|
+
event_type: "session_archive_attempted",
|
|
5436
|
+
since: options.since
|
|
5437
|
+
});
|
|
5438
|
+
events = result.events;
|
|
5439
|
+
} catch {
|
|
5440
|
+
return {
|
|
5441
|
+
entries: [],
|
|
5442
|
+
total: 0,
|
|
5443
|
+
since_ms: options.since,
|
|
5444
|
+
generated_at: generatedAt
|
|
5445
|
+
};
|
|
5446
|
+
}
|
|
5447
|
+
const mostRecentBySession = /* @__PURE__ */ new Map();
|
|
5448
|
+
for (const event of events) {
|
|
5449
|
+
if (event.event_type !== "session_archive_attempted") {
|
|
5450
|
+
continue;
|
|
5451
|
+
}
|
|
5452
|
+
const sessionId = event.session_id;
|
|
5453
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
5454
|
+
continue;
|
|
5455
|
+
}
|
|
5456
|
+
const prior = mostRecentBySession.get(sessionId);
|
|
5457
|
+
if (prior === void 0 || event.ts > prior.ts) {
|
|
5458
|
+
mostRecentBySession.set(sessionId, event);
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
const entries = [];
|
|
5462
|
+
for (const [sessionId, event] of mostRecentBySession.entries()) {
|
|
5463
|
+
const ageHours = Math.max(
|
|
5464
|
+
0,
|
|
5465
|
+
Math.floor((nowMs - event.covered_through_ts) / 36e5)
|
|
5466
|
+
);
|
|
5467
|
+
entries.push({
|
|
5468
|
+
session_id_short: truncateSessionId(sessionId),
|
|
5469
|
+
last_attempted_at: new Date(event.ts).toISOString(),
|
|
5470
|
+
outcome: event.outcome,
|
|
5471
|
+
candidates_proposed: event.candidates_proposed,
|
|
5472
|
+
covered_through_ts: event.covered_through_ts,
|
|
5473
|
+
age_since_covered_hours: ageHours
|
|
5474
|
+
});
|
|
5475
|
+
}
|
|
5476
|
+
entries.sort(
|
|
5477
|
+
(a, b) => a.last_attempted_at < b.last_attempted_at ? 1 : a.last_attempted_at > b.last_attempted_at ? -1 : 0
|
|
5478
|
+
);
|
|
5479
|
+
return {
|
|
5480
|
+
entries,
|
|
5481
|
+
total: entries.length,
|
|
5482
|
+
since_ms: options.since,
|
|
5483
|
+
generated_at: generatedAt
|
|
5484
|
+
};
|
|
5485
|
+
}
|
|
5486
|
+
function truncateSessionId(sessionId) {
|
|
5487
|
+
if (sessionId.length <= 8) {
|
|
5488
|
+
return sessionId;
|
|
5489
|
+
}
|
|
5490
|
+
return `${sessionId.slice(0, 8)}...`;
|
|
5491
|
+
}
|
|
5224
5492
|
function createFixMessage(fixed, report) {
|
|
5225
5493
|
const fixedText = fixed.length === 0 ? "No deterministic doctor fixes were needed." : `Applied ${fixed.length} deterministic doctor fix${fixed.length === 1 ? "" : "es"}.`;
|
|
5226
5494
|
const manualText = report.manual_errors.length === 0 ? "No manual errors remain." : `${report.manual_errors.length} manual error${report.manual_errors.length === 1 ? "" : "s"} remain.`;
|
|
@@ -5734,6 +6002,7 @@ export {
|
|
|
5734
6002
|
appendEventLedgerEvent,
|
|
5735
6003
|
readEventLedger,
|
|
5736
6004
|
flushAndSyncEventLedger,
|
|
6005
|
+
loadKbIdTypeMap,
|
|
5737
6006
|
buildKnowledgeMeta,
|
|
5738
6007
|
writeKnowledgeMeta,
|
|
5739
6008
|
computeKnowledgeBasedAgentsMeta,
|
|
@@ -5758,5 +6027,6 @@ export {
|
|
|
5758
6027
|
runDoctorFix,
|
|
5759
6028
|
runDoctorApplyLint,
|
|
5760
6029
|
runDoctorCiteCoverage,
|
|
6030
|
+
runDoctorArchiveHistory,
|
|
5761
6031
|
enrichDescriptions
|
|
5762
6032
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Server } from 'node:http';
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
import { AgentsMeta, KnowledgeTestIndex, AgentsLayer, AgentsTopologyType,
|
|
3
|
+
import { AgentsMeta, KnowledgeTestIndex, AgentsLayer, AgentsTopologyType, KnowledgeType, Layer, StableId, AgentsMetaCounters, EventLedgerEventInput, EventLedgerEvent, RuleDescriptionIndexItem } from '@fenglimg/fabric-shared';
|
|
4
4
|
import { FabExtractKnowledgeInput, FabExtractKnowledgeOutput, FabReviewInput, FabReviewOutput } from '@fenglimg/fabric-shared/schemas/api-contracts';
|
|
5
5
|
import { IOFabricError } from '@fenglimg/fabric-shared/errors';
|
|
6
6
|
|
|
@@ -97,12 +97,26 @@ type DoctorApplyLintReport = {
|
|
|
97
97
|
declare function runDoctorReport(target: string): Promise<DoctorReport>;
|
|
98
98
|
declare function runDoctorFix(target: string): Promise<DoctorFixReport>;
|
|
99
99
|
declare function runDoctorApplyLint(target: string): Promise<DoctorApplyLintReport>;
|
|
100
|
+
type CiteContractMetrics = {
|
|
101
|
+
decisions_cited: number;
|
|
102
|
+
pitfalls_cited: number;
|
|
103
|
+
contract_with: number;
|
|
104
|
+
contract_missing: number;
|
|
105
|
+
hard_violated: number;
|
|
106
|
+
cite_id_unresolved: number;
|
|
107
|
+
skip_count: Record<string, number>;
|
|
108
|
+
};
|
|
109
|
+
type CiteLayerTypeBreakdown = {
|
|
110
|
+
team: Record<string, number>;
|
|
111
|
+
personal: Record<string, number>;
|
|
112
|
+
};
|
|
100
113
|
type CiteCoverageReport = {
|
|
101
114
|
status: "ok" | "skipped";
|
|
102
115
|
marker_ts: number;
|
|
103
116
|
marker_emitted_now: boolean;
|
|
104
117
|
since_ts: number;
|
|
105
118
|
client_filter: "cc" | "codex" | "cursor" | "all";
|
|
119
|
+
layer_filter?: "team" | "personal" | "all";
|
|
106
120
|
metrics: {
|
|
107
121
|
edits_touched: number;
|
|
108
122
|
qualifying_cites: number;
|
|
@@ -113,12 +127,34 @@ type CiteCoverageReport = {
|
|
|
113
127
|
per_client?: Record<string, Partial<CiteCoverageReport["metrics"]>>;
|
|
114
128
|
dismissed_reason_histogram?: Record<string, number>;
|
|
115
129
|
none_reason_histogram?: Record<string, number>;
|
|
130
|
+
contract_metrics_status?: "ok" | "skipped:bootstrap_drift" | "awaiting_marker";
|
|
131
|
+
contract_metrics?: CiteContractMetrics;
|
|
132
|
+
per_layer_type?: CiteLayerTypeBreakdown;
|
|
133
|
+
contract_marker_ts?: number;
|
|
116
134
|
generated_at: string;
|
|
117
135
|
};
|
|
118
136
|
declare function runDoctorCiteCoverage(projectRoot: string, options: {
|
|
119
137
|
since: number;
|
|
120
138
|
client: "cc" | "codex" | "cursor" | "all";
|
|
139
|
+
layer?: "team" | "personal" | "all";
|
|
121
140
|
}): Promise<CiteCoverageReport>;
|
|
141
|
+
type ArchiveHistoryEntry = {
|
|
142
|
+
session_id_short: string;
|
|
143
|
+
last_attempted_at: string;
|
|
144
|
+
outcome: "proposed" | "viability_failed" | "user_dismissed" | "skipped_no_signal";
|
|
145
|
+
candidates_proposed: number;
|
|
146
|
+
covered_through_ts: number;
|
|
147
|
+
age_since_covered_hours: number;
|
|
148
|
+
};
|
|
149
|
+
type ArchiveHistoryReport = {
|
|
150
|
+
entries: ArchiveHistoryEntry[];
|
|
151
|
+
total: number;
|
|
152
|
+
since_ms: number;
|
|
153
|
+
generated_at: string;
|
|
154
|
+
};
|
|
155
|
+
declare function runDoctorArchiveHistory(projectRoot: string, options: {
|
|
156
|
+
since: number;
|
|
157
|
+
}): Promise<ArchiveHistoryReport>;
|
|
122
158
|
type EnrichDescriptionsMode = "auto" | "interactive";
|
|
123
159
|
type EnrichDescriptionsCandidate = {
|
|
124
160
|
path: string;
|
|
@@ -149,6 +185,31 @@ type KnowledgeMetaBuildResult = {
|
|
|
149
185
|
type WriteKnowledgeMetaOptions = {
|
|
150
186
|
source: KnowledgeMetaBuildSource;
|
|
151
187
|
};
|
|
188
|
+
/**
|
|
189
|
+
* v2.0-rc.24 TASK-07: Load a Map<stable_id, knowledge_type> from the
|
|
190
|
+
* project's `.fabric/agents.meta.json`. Consumed by the doctor cite-coverage
|
|
191
|
+
* routing (TASK-08) to dispatch cites to the correct policy bucket
|
|
192
|
+
* (decision/pitfall = strict contract / model = reference-only /
|
|
193
|
+
* guideline+process = deferred to rc.25 LLM-judge). Cited ids absent from
|
|
194
|
+
* this map fall into the `cite_id_unresolved` bucket.
|
|
195
|
+
*
|
|
196
|
+
* **Singular knowledge_type contract (rc.24 lock):** the returned map values
|
|
197
|
+
* are the SINGULAR `KnowledgeType` enum (`"model" | "decision" | "guideline"
|
|
198
|
+
* | "pitfall" | "process"`) — matching both the on-disk `agents.meta.json`
|
|
199
|
+
* storage AND the canonical `KnowledgeTypeSchema` exported from
|
|
200
|
+
* `@fenglimg/fabric-shared`. No normalization happens at this boundary; the
|
|
201
|
+
* loader is a thin extract over engine-maintained meta. Downstream callers
|
|
202
|
+
* (TASK-08 doctor) must match against the singular enum.
|
|
203
|
+
*
|
|
204
|
+
* Both team (KT-*) and personal (KP-*) entries are included — they live in
|
|
205
|
+
* the same `meta.nodes` map.
|
|
206
|
+
*
|
|
207
|
+
* Graceful on failure: a missing meta file, malformed JSON, or schema
|
|
208
|
+
* validation failure all yield an empty Map (no throw). The doctor will then
|
|
209
|
+
* surface every cite as `cite_id_unresolved`, which is the safe degraded
|
|
210
|
+
* mode.
|
|
211
|
+
*/
|
|
212
|
+
declare function loadKbIdTypeMap(projectRootInput: string): Promise<Map<string, KnowledgeType>>;
|
|
152
213
|
declare function buildKnowledgeMeta(projectRootInput: string): Promise<KnowledgeMetaBuildResult>;
|
|
153
214
|
declare function writeKnowledgeMeta(projectRootInput: string, options: WriteKnowledgeMetaOptions): Promise<KnowledgeMetaBuildResult>;
|
|
154
215
|
declare function computeKnowledgeBasedAgentsMeta(projectRootInput: string, existingMeta?: AgentsMeta): Promise<AgentsMeta>;
|
|
@@ -435,4 +496,4 @@ declare function startHttpServer(options: {
|
|
|
435
496
|
authToken?: string;
|
|
436
497
|
}): Promise<Server>;
|
|
437
498
|
|
|
438
|
-
export { AGENTS_MD_RESOURCE_URI, type AcquireOptions, type CiteCoverageReport, type DoctorApplyLintMutation, type DoctorApplyLintMutationKind, type DoctorApplyLintReport, type DoctorFixReport, type DoctorIssue, type DoctorReport, EVENT_LEDGER_PATH, type EnrichDescriptionsCandidate, type EnrichDescriptionsMode, type EnrichDescriptionsReport, type InFlightTracker, KnowledgeIdAllocator, type KnowledgeMetaBuildResult, type KnowledgeMetaBuildSource, type KnowledgeSyncLedgerEvent, type KnowledgeSyncOptions, type KnowledgeSyncReport, LEDGER_PATH, LEGACY_LEDGER_PATH, type LedgerEvent, type LockState, type PlanContextInput, type PlanContextResult, type ReconcileKnowledgeOptions, type RequirementProfile, type SelectionTokenState, ServeLockHeldError, type ShutdownHandlerDeps, type StructuredWarning, type WriteKnowledgeMetaOptions, acquireLock, appendEventLedgerEvent, buildKnowledgeMeta, checkLockOrThrow, computeKnowledgeBasedAgentsMeta, computeKnowledgeTestIndex, createFabricServer, createInFlightTracker, createShutdownHandler, deriveKnowledgeMetaLayer, deriveKnowledgeMetaTopologyType, enrichDescriptions, ensureKnowledgeFresh, extractKnowledge, flushAndSyncEventLedger, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, isSameKnowledgeTestIndex, planContext, readLockState, readSelectionToken, reconcileKnowledge, releaseLock, reviewKnowledge, runDoctorApplyLint, runDoctorCiteCoverage, runDoctorFix, runDoctorReport, stableStringify, startHttpServer, startStdioServer, writeKnowledgeMeta };
|
|
499
|
+
export { AGENTS_MD_RESOURCE_URI, type AcquireOptions, type ArchiveHistoryEntry, type ArchiveHistoryReport, type CiteCoverageReport, type DoctorApplyLintMutation, type DoctorApplyLintMutationKind, type DoctorApplyLintReport, type DoctorFixReport, type DoctorIssue, type DoctorReport, EVENT_LEDGER_PATH, type EnrichDescriptionsCandidate, type EnrichDescriptionsMode, type EnrichDescriptionsReport, type InFlightTracker, KnowledgeIdAllocator, type KnowledgeMetaBuildResult, type KnowledgeMetaBuildSource, type KnowledgeSyncLedgerEvent, type KnowledgeSyncOptions, type KnowledgeSyncReport, LEDGER_PATH, LEGACY_LEDGER_PATH, type LedgerEvent, type LockState, type PlanContextInput, type PlanContextResult, type ReconcileKnowledgeOptions, type RequirementProfile, type SelectionTokenState, ServeLockHeldError, type ShutdownHandlerDeps, type StructuredWarning, type WriteKnowledgeMetaOptions, acquireLock, appendEventLedgerEvent, buildKnowledgeMeta, checkLockOrThrow, computeKnowledgeBasedAgentsMeta, computeKnowledgeTestIndex, createFabricServer, createInFlightTracker, createShutdownHandler, deriveKnowledgeMetaLayer, deriveKnowledgeMetaTopologyType, enrichDescriptions, ensureKnowledgeFresh, extractKnowledge, flushAndSyncEventLedger, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, isSameKnowledgeTestIndex, loadKbIdTypeMap, planContext, readLockState, readSelectionToken, reconcileKnowledge, releaseLock, reviewKnowledge, runDoctorApplyLint, runDoctorArchiveHistory, runDoctorCiteCoverage, runDoctorFix, runDoctorReport, stableStringify, startHttpServer, startStdioServer, writeKnowledgeMeta };
|
package/dist/index.js
CHANGED
|
@@ -23,19 +23,21 @@ import {
|
|
|
23
23
|
isSameKnowledgeTestIndex,
|
|
24
24
|
loadActiveMeta,
|
|
25
25
|
loadActiveMetaOrStale,
|
|
26
|
+
loadKbIdTypeMap,
|
|
26
27
|
normalizeKnowledgePath,
|
|
27
28
|
readLockState,
|
|
28
29
|
reconcileKnowledge,
|
|
29
30
|
releaseLock,
|
|
30
31
|
resolveProjectRoot,
|
|
31
32
|
runDoctorApplyLint,
|
|
33
|
+
runDoctorArchiveHistory,
|
|
32
34
|
runDoctorCiteCoverage,
|
|
33
35
|
runDoctorFix,
|
|
34
36
|
runDoctorReport,
|
|
35
37
|
sha256,
|
|
36
38
|
stableStringify,
|
|
37
39
|
writeKnowledgeMeta
|
|
38
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-HAXROPQM.js";
|
|
39
41
|
|
|
40
42
|
// src/index.ts
|
|
41
43
|
import { existsSync as existsSync4 } from "fs";
|
|
@@ -1892,7 +1894,7 @@ function formatPreexistingRootMessage(projectRoot) {
|
|
|
1892
1894
|
function createFabricServer(tracker) {
|
|
1893
1895
|
const server = new McpServer({
|
|
1894
1896
|
name: "fabric-knowledge-server",
|
|
1895
|
-
version: "2.0.0-rc.
|
|
1897
|
+
version: "2.0.0-rc.25"
|
|
1896
1898
|
});
|
|
1897
1899
|
registerPlanContext(server, tracker);
|
|
1898
1900
|
registerKnowledgeSections(server, tracker);
|
|
@@ -2000,7 +2002,7 @@ function createShutdownHandler(deps) {
|
|
|
2000
2002
|
};
|
|
2001
2003
|
}
|
|
2002
2004
|
async function startHttpServer(options) {
|
|
2003
|
-
const { createFabricHttpApp } = await import("./http-
|
|
2005
|
+
const { createFabricHttpApp } = await import("./http-QBGLHCHA.js");
|
|
2004
2006
|
const { port, projectRoot, host = "127.0.0.1", authToken } = options;
|
|
2005
2007
|
const app = createFabricHttpApp({ projectRoot, host, authToken });
|
|
2006
2008
|
return await new Promise((resolveServer, rejectServer) => {
|
|
@@ -2052,6 +2054,7 @@ export {
|
|
|
2052
2054
|
getLedgerPath,
|
|
2053
2055
|
getLegacyLedgerPath,
|
|
2054
2056
|
isSameKnowledgeTestIndex,
|
|
2057
|
+
loadKbIdTypeMap,
|
|
2055
2058
|
planContext,
|
|
2056
2059
|
readLockState,
|
|
2057
2060
|
readSelectionToken,
|
|
@@ -2059,6 +2062,7 @@ export {
|
|
|
2059
2062
|
releaseLock,
|
|
2060
2063
|
reviewKnowledge,
|
|
2061
2064
|
runDoctorApplyLint,
|
|
2065
|
+
runDoctorArchiveHistory,
|
|
2062
2066
|
runDoctorCiteCoverage,
|
|
2063
2067
|
runDoctorFix,
|
|
2064
2068
|
runDoctorReport,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fenglimg/fabric-server",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.25",
|
|
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.
|
|
16
|
+
"@fenglimg/fabric-shared": "2.0.0-rc.25"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/express": "^5.0.6",
|