@fenglimg/fabric-server 2.0.0-rc.15 → 2.0.0-rc.21
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.
|
@@ -1281,7 +1281,12 @@ import {
|
|
|
1281
1281
|
AgentsMetaCountersSchema,
|
|
1282
1282
|
forensicReportSchema,
|
|
1283
1283
|
parseKnowledgeId as parseKnowledgeId2,
|
|
1284
|
-
knowledgeTestIndexSchema as knowledgeTestIndexSchema2
|
|
1284
|
+
knowledgeTestIndexSchema as knowledgeTestIndexSchema2,
|
|
1285
|
+
LEGACY_KB_REGEX,
|
|
1286
|
+
BOOTSTRAP_CANONICAL,
|
|
1287
|
+
BOOTSTRAP_MARKER_BEGIN,
|
|
1288
|
+
BOOTSTRAP_MARKER_END,
|
|
1289
|
+
BOOTSTRAP_REGEX
|
|
1285
1290
|
} from "@fenglimg/fabric-shared";
|
|
1286
1291
|
import { detectFramework } from "@fenglimg/fabric-shared/node";
|
|
1287
1292
|
import { atomicWriteJson as atomicWriteJson2, atomicWriteText as atomicWriteText3 } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
@@ -1342,7 +1347,13 @@ var TARGET_FILE_PATHS = [
|
|
|
1342
1347
|
".fabric/agents.meta.json",
|
|
1343
1348
|
".fabric/.cache/knowledge-test.index.json",
|
|
1344
1349
|
".fabric/events.jsonl",
|
|
1345
|
-
".fabric/knowledge"
|
|
1350
|
+
".fabric/knowledge",
|
|
1351
|
+
// v2.0.0-rc.19 bootstrap-consolidation TASK-005: L1 canonical snapshot
|
|
1352
|
+
// (.fabric/AGENTS.md) and optional project-rules concat source
|
|
1353
|
+
// (.fabric/project-rules.md). Surfaced in summary.targetFiles so --json
|
|
1354
|
+
// consumers can confirm L1 presence at a glance.
|
|
1355
|
+
".fabric/AGENTS.md",
|
|
1356
|
+
".fabric/project-rules.md"
|
|
1346
1357
|
];
|
|
1347
1358
|
async function runDoctorReport(target) {
|
|
1348
1359
|
const projectRoot = normalizeTarget(target);
|
|
@@ -1352,12 +1363,24 @@ async function runDoctorReport(target) {
|
|
|
1352
1363
|
forensic,
|
|
1353
1364
|
meta,
|
|
1354
1365
|
eventLedger,
|
|
1355
|
-
knowledgeTestIndex
|
|
1366
|
+
knowledgeTestIndex,
|
|
1367
|
+
bootstrapMarkerMigration,
|
|
1368
|
+
l1BootstrapSnapshotDrift,
|
|
1369
|
+
l2ManagedBlockDrift
|
|
1356
1370
|
] = await Promise.all([
|
|
1357
1371
|
inspectForensic(projectRoot),
|
|
1358
1372
|
inspectMeta(projectRoot),
|
|
1359
1373
|
inspectEventLedger(projectRoot),
|
|
1360
|
-
inspectKnowledgeTestIndex(projectRoot)
|
|
1374
|
+
inspectKnowledgeTestIndex(projectRoot),
|
|
1375
|
+
// v2.0.0-rc.19 TASK-004: one-time fabric:knowledge-base → fabric:bootstrap
|
|
1376
|
+
// marker migration scan. Inspect runs in this Promise.all block to keep
|
|
1377
|
+
// performance parity with the other I/O-bound inspections.
|
|
1378
|
+
inspectBootstrapMarkerMigration(projectRoot),
|
|
1379
|
+
// v2.0.0-rc.19 TASK-005: L1 + L2 byte-level drift detection. Both are
|
|
1380
|
+
// I/O-bound (small file reads + buffer compare) so they live in the same
|
|
1381
|
+
// Promise.all block as the other bootstrap inspections.
|
|
1382
|
+
inspectL1BootstrapSnapshotDrift(projectRoot),
|
|
1383
|
+
inspectL2ManagedBlockDrift(projectRoot)
|
|
1361
1384
|
]);
|
|
1362
1385
|
const mcpConfigInWrongFile = inspectMcpConfigInWrongFile(projectRoot);
|
|
1363
1386
|
const metaManuallyDiverged = await inspectMetaManuallyDiverged(projectRoot);
|
|
@@ -1385,6 +1408,15 @@ async function runDoctorReport(target) {
|
|
|
1385
1408
|
const skillMdYamlInvalid = inspectSkillMdYamlInvalid(projectRoot);
|
|
1386
1409
|
const checks = [
|
|
1387
1410
|
createBootstrapAnchorCheck(bootstrapAnchor),
|
|
1411
|
+
// v2.0.0-rc.19 TASK-004: bootstrap marker migration check sits adjacent to
|
|
1412
|
+
// the anchor check — both are bootstrap-file invariants. fixable_error
|
|
1413
|
+
// when any of the four target paths still carries the legacy marker.
|
|
1414
|
+
createBootstrapMarkerMigrationCheck(bootstrapMarkerMigration),
|
|
1415
|
+
// v2.0.0-rc.19 TASK-005: L1 + L2 byte-level drift detection sit immediately
|
|
1416
|
+
// after the marker migration check. Order: anchor existence → migration →
|
|
1417
|
+
// L1 (canonical ↔ snapshot) → L2 (snapshot+rules ↔ three-end blocks).
|
|
1418
|
+
createL1BootstrapSnapshotDriftCheck(l1BootstrapSnapshotDrift),
|
|
1419
|
+
createL2ManagedBlockDriftCheck(l2ManagedBlockDrift),
|
|
1388
1420
|
createKnowledgeDirMissingCheck(knowledgeDirMissing),
|
|
1389
1421
|
createForensicCheck(forensic, framework.kind, entryPoints.length),
|
|
1390
1422
|
// v2.0: removed `createInitContextCheck` — `.fabric/init-context.json`
|
|
@@ -1494,6 +1526,33 @@ async function runDoctorFix(target) {
|
|
|
1494
1526
|
const projectRoot = normalizeTarget(target);
|
|
1495
1527
|
const before = await runDoctorReport(projectRoot);
|
|
1496
1528
|
const fixed = [];
|
|
1529
|
+
if (before.fixable_errors.some(
|
|
1530
|
+
(issue) => issue.code === "bootstrap_marker_migration_required"
|
|
1531
|
+
)) {
|
|
1532
|
+
const migrated = await migrateBootstrapMarkers(projectRoot);
|
|
1533
|
+
fixed.push(findIssue(before.fixable_errors, "bootstrap_marker_migration_required"));
|
|
1534
|
+
for (const path of migrated.paths) {
|
|
1535
|
+
await appendEventLedgerEvent(projectRoot, {
|
|
1536
|
+
event_type: "bootstrap_marker_migrated",
|
|
1537
|
+
path,
|
|
1538
|
+
migrated_count: migrated.countPerPath[path] ?? 1,
|
|
1539
|
+
legacy_marker: "fabric:knowledge-base",
|
|
1540
|
+
new_marker: "fabric:bootstrap",
|
|
1541
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1542
|
+
}).catch(() => {
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
if (before.fixable_errors.some((issue) => issue.code === "bootstrap_snapshot_drift")) {
|
|
1547
|
+
const snapshotPath = join5(projectRoot, ".fabric", "AGENTS.md");
|
|
1548
|
+
await ensureParentDirectory(snapshotPath);
|
|
1549
|
+
await atomicWriteText3(snapshotPath, BOOTSTRAP_CANONICAL);
|
|
1550
|
+
fixed.push(findIssue(before.fixable_errors, "bootstrap_snapshot_drift"));
|
|
1551
|
+
}
|
|
1552
|
+
if (before.fixable_errors.some((issue) => issue.code === "managed_block_drift")) {
|
|
1553
|
+
await rewriteThreeEndManagedBlocks(projectRoot);
|
|
1554
|
+
fixed.push(findIssue(before.fixable_errors, "managed_block_drift"));
|
|
1555
|
+
}
|
|
1497
1556
|
if (before.fixable_errors.some((issue) => issue.code === "knowledge_dir_missing")) {
|
|
1498
1557
|
await ensureKnowledgeSubdirs(projectRoot);
|
|
1499
1558
|
fixed.push(findIssue(before.fixable_errors, "knowledge_dir_missing"));
|
|
@@ -2124,6 +2183,186 @@ function inspectBootstrapAnchor(projectRoot) {
|
|
|
2124
2183
|
hasClaudeMd: existsSync4(join5(projectRoot, "CLAUDE.md"))
|
|
2125
2184
|
};
|
|
2126
2185
|
}
|
|
2186
|
+
var BOOTSTRAP_MARKER_MIGRATION_TARGETS = [
|
|
2187
|
+
"CLAUDE.md",
|
|
2188
|
+
"AGENTS.md",
|
|
2189
|
+
".cursor/rules",
|
|
2190
|
+
".cursor/rules/fabric-bootstrap.mdc"
|
|
2191
|
+
];
|
|
2192
|
+
async function inspectBootstrapMarkerMigration(target) {
|
|
2193
|
+
const filesNeedingMigration = [];
|
|
2194
|
+
for (const rel of BOOTSTRAP_MARKER_MIGRATION_TARGETS) {
|
|
2195
|
+
const abs = join5(target, rel);
|
|
2196
|
+
if (!existsSync4(abs)) {
|
|
2197
|
+
continue;
|
|
2198
|
+
}
|
|
2199
|
+
let content;
|
|
2200
|
+
try {
|
|
2201
|
+
content = await readFile5(abs, "utf8");
|
|
2202
|
+
} catch {
|
|
2203
|
+
continue;
|
|
2204
|
+
}
|
|
2205
|
+
if (LEGACY_KB_REGEX.test(content)) {
|
|
2206
|
+
filesNeedingMigration.push(abs);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
return { filesNeedingMigration };
|
|
2210
|
+
}
|
|
2211
|
+
function createBootstrapMarkerMigrationCheck(inspection) {
|
|
2212
|
+
if (inspection.filesNeedingMigration.length === 0) {
|
|
2213
|
+
return okCheck(
|
|
2214
|
+
"Bootstrap marker migration",
|
|
2215
|
+
"No legacy fabric:knowledge-base markers detected in bootstrap target files."
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
const list = inspection.filesNeedingMigration.join(", ");
|
|
2219
|
+
return issueCheck(
|
|
2220
|
+
"Bootstrap marker migration",
|
|
2221
|
+
"error",
|
|
2222
|
+
"fixable_error",
|
|
2223
|
+
"bootstrap_marker_migration_required",
|
|
2224
|
+
`${inspection.filesNeedingMigration.length} file${inspection.filesNeedingMigration.length === 1 ? "" : "s"} still carry the legacy fabric:knowledge-base bootstrap marker: ${list}.`,
|
|
2225
|
+
"Run `fab doctor --fix` to migrate to fabric:bootstrap marker"
|
|
2226
|
+
);
|
|
2227
|
+
}
|
|
2228
|
+
async function inspectL1BootstrapSnapshotDrift(target) {
|
|
2229
|
+
const abs = join5(target, ".fabric", "AGENTS.md");
|
|
2230
|
+
if (!existsSync4(abs)) {
|
|
2231
|
+
return { status: "missing", canonical: BOOTSTRAP_CANONICAL, onDisk: null };
|
|
2232
|
+
}
|
|
2233
|
+
let onDisk;
|
|
2234
|
+
try {
|
|
2235
|
+
onDisk = await readFile5(abs, "utf8");
|
|
2236
|
+
} catch {
|
|
2237
|
+
return { status: "missing", canonical: BOOTSTRAP_CANONICAL, onDisk: null };
|
|
2238
|
+
}
|
|
2239
|
+
if (onDisk === BOOTSTRAP_CANONICAL) {
|
|
2240
|
+
return { status: "ok", canonical: BOOTSTRAP_CANONICAL, onDisk };
|
|
2241
|
+
}
|
|
2242
|
+
return { status: "drift", canonical: BOOTSTRAP_CANONICAL, onDisk };
|
|
2243
|
+
}
|
|
2244
|
+
function createL1BootstrapSnapshotDriftCheck(inspection) {
|
|
2245
|
+
if (inspection.status === "drift") {
|
|
2246
|
+
return issueCheck(
|
|
2247
|
+
"Bootstrap snapshot drift",
|
|
2248
|
+
"error",
|
|
2249
|
+
"fixable_error",
|
|
2250
|
+
"bootstrap_snapshot_drift",
|
|
2251
|
+
".fabric/AGENTS.md content diverges byte-for-byte from BOOTSTRAP_CANONICAL.",
|
|
2252
|
+
"Run `fab doctor --fix` to restore canonical bootstrap snapshot"
|
|
2253
|
+
);
|
|
2254
|
+
}
|
|
2255
|
+
return okCheck(
|
|
2256
|
+
"Bootstrap snapshot drift",
|
|
2257
|
+
inspection.status === "ok" ? ".fabric/AGENTS.md byte-equals BOOTSTRAP_CANONICAL." : ".fabric/AGENTS.md absent \u2014 delegated to bootstrap_anchor_missing."
|
|
2258
|
+
);
|
|
2259
|
+
}
|
|
2260
|
+
async function inspectL2ManagedBlockDrift(target) {
|
|
2261
|
+
const snapshotPath = join5(target, ".fabric", "AGENTS.md");
|
|
2262
|
+
if (!existsSync4(snapshotPath)) {
|
|
2263
|
+
return { status: "ok", drifted: [] };
|
|
2264
|
+
}
|
|
2265
|
+
let snapshot;
|
|
2266
|
+
try {
|
|
2267
|
+
snapshot = await readFile5(snapshotPath, "utf8");
|
|
2268
|
+
} catch {
|
|
2269
|
+
return { status: "ok", drifted: [] };
|
|
2270
|
+
}
|
|
2271
|
+
const projectRulesPath = join5(target, ".fabric", "project-rules.md");
|
|
2272
|
+
let expectedBody = snapshot;
|
|
2273
|
+
if (existsSync4(projectRulesPath)) {
|
|
2274
|
+
try {
|
|
2275
|
+
const projectRules = await readFile5(projectRulesPath, "utf8");
|
|
2276
|
+
expectedBody = `${snapshot}
|
|
2277
|
+
---
|
|
2278
|
+
${projectRules}`;
|
|
2279
|
+
} catch {
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
const drifted = [];
|
|
2283
|
+
let anyManagedBlockFound = false;
|
|
2284
|
+
const blockTargets = [
|
|
2285
|
+
join5(target, "AGENTS.md"),
|
|
2286
|
+
join5(target, ".cursor", "rules", "fabric-bootstrap.mdc")
|
|
2287
|
+
];
|
|
2288
|
+
for (const abs of blockTargets) {
|
|
2289
|
+
if (!existsSync4(abs)) {
|
|
2290
|
+
continue;
|
|
2291
|
+
}
|
|
2292
|
+
let content;
|
|
2293
|
+
try {
|
|
2294
|
+
content = await readFile5(abs, "utf8");
|
|
2295
|
+
} catch {
|
|
2296
|
+
continue;
|
|
2297
|
+
}
|
|
2298
|
+
if (!BOOTSTRAP_REGEX.test(content) && LEGACY_KB_REGEX.test(content)) {
|
|
2299
|
+
continue;
|
|
2300
|
+
}
|
|
2301
|
+
const match = content.match(BOOTSTRAP_REGEX);
|
|
2302
|
+
if (match === null) {
|
|
2303
|
+
continue;
|
|
2304
|
+
}
|
|
2305
|
+
anyManagedBlockFound = true;
|
|
2306
|
+
const region = match[0];
|
|
2307
|
+
const beginIdx = region.indexOf(BOOTSTRAP_MARKER_BEGIN);
|
|
2308
|
+
const bodyStart = beginIdx + BOOTSTRAP_MARKER_BEGIN.length;
|
|
2309
|
+
const endIdx = region.indexOf(BOOTSTRAP_MARKER_END, bodyStart);
|
|
2310
|
+
if (bodyStart < 0 || endIdx < 0) {
|
|
2311
|
+
continue;
|
|
2312
|
+
}
|
|
2313
|
+
let body = region.slice(bodyStart, endIdx);
|
|
2314
|
+
if (body.startsWith("\n")) body = body.slice(1);
|
|
2315
|
+
if (body.endsWith("\n")) body = body.slice(0, -1);
|
|
2316
|
+
if (body !== expectedBody) {
|
|
2317
|
+
drifted.push({ path: abs, expected: expectedBody, actual: body });
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
const claudeMdPath = join5(target, "CLAUDE.md");
|
|
2321
|
+
if (existsSync4(claudeMdPath)) {
|
|
2322
|
+
let claudeContent;
|
|
2323
|
+
try {
|
|
2324
|
+
claudeContent = await readFile5(claudeMdPath, "utf8");
|
|
2325
|
+
if (!BOOTSTRAP_REGEX.test(claudeContent) && LEGACY_KB_REGEX.test(claudeContent)) {
|
|
2326
|
+
} else {
|
|
2327
|
+
anyManagedBlockFound = true;
|
|
2328
|
+
const lines = claudeContent.split(/\r?\n/u);
|
|
2329
|
+
const hasAtImport = lines.some((line) => line.trim() === "@.fabric/AGENTS.md");
|
|
2330
|
+
if (!hasAtImport) {
|
|
2331
|
+
drifted.push({
|
|
2332
|
+
path: claudeMdPath,
|
|
2333
|
+
expected: "@.fabric/AGENTS.md",
|
|
2334
|
+
actual: "(line missing)"
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
} catch {
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
if (!anyManagedBlockFound) {
|
|
2342
|
+
return { status: "no-managed-block", drifted: [] };
|
|
2343
|
+
}
|
|
2344
|
+
if (drifted.length === 0) {
|
|
2345
|
+
return { status: "ok", drifted: [] };
|
|
2346
|
+
}
|
|
2347
|
+
return { status: "drift", drifted };
|
|
2348
|
+
}
|
|
2349
|
+
function createL2ManagedBlockDriftCheck(inspection) {
|
|
2350
|
+
if (inspection.status === "drift") {
|
|
2351
|
+
const list = inspection.drifted.map((d) => d.path).join(", ");
|
|
2352
|
+
return issueCheck(
|
|
2353
|
+
"Managed block drift",
|
|
2354
|
+
"error",
|
|
2355
|
+
"fixable_error",
|
|
2356
|
+
"managed_block_drift",
|
|
2357
|
+
`${inspection.drifted.length} three-end managed block${inspection.drifted.length === 1 ? "" : "s"} diverge from expected body (snapshot + optional project-rules concat): ${list}.`,
|
|
2358
|
+
"Run `fab doctor --fix` to restore three-end managed blocks from canonical"
|
|
2359
|
+
);
|
|
2360
|
+
}
|
|
2361
|
+
return okCheck(
|
|
2362
|
+
"Managed block drift",
|
|
2363
|
+
inspection.status === "ok" ? "Three-end managed blocks byte-equal expectedBody." : "No three-end managed blocks detected \u2014 propagation pending or legacy-marker state."
|
|
2364
|
+
);
|
|
2365
|
+
}
|
|
2127
2366
|
function createBootstrapAnchorCheck(inspection) {
|
|
2128
2367
|
if (!inspection.hasAgentsMd && !inspection.hasClaudeMd) {
|
|
2129
2368
|
return issueCheck(
|
|
@@ -3953,6 +4192,125 @@ function createIndexDriftCheck(inspection) {
|
|
|
3953
4192
|
"Run `fab doctor --apply-lint` (rc.4 TASK-003) to bump agents.meta.json counters to max_observed + 1."
|
|
3954
4193
|
);
|
|
3955
4194
|
}
|
|
4195
|
+
async function migrateBootstrapMarkers(projectRoot) {
|
|
4196
|
+
const paths = [];
|
|
4197
|
+
const countPerPath = {};
|
|
4198
|
+
for (const rel of BOOTSTRAP_MARKER_MIGRATION_TARGETS) {
|
|
4199
|
+
const abs = join5(projectRoot, rel);
|
|
4200
|
+
if (!existsSync4(abs)) {
|
|
4201
|
+
continue;
|
|
4202
|
+
}
|
|
4203
|
+
let original;
|
|
4204
|
+
try {
|
|
4205
|
+
original = await readFile5(abs, "utf8");
|
|
4206
|
+
} catch {
|
|
4207
|
+
continue;
|
|
4208
|
+
}
|
|
4209
|
+
const beginMatches = original.match(/<!-- fabric:knowledge-base:begin -->/g);
|
|
4210
|
+
const endMatches = original.match(/<!-- fabric:knowledge-base:end -->/g);
|
|
4211
|
+
const replacedCount = (beginMatches?.length ?? 0) + (endMatches?.length ?? 0);
|
|
4212
|
+
if (replacedCount === 0) {
|
|
4213
|
+
continue;
|
|
4214
|
+
}
|
|
4215
|
+
const rewritten = original.replace(/<!-- fabric:knowledge-base:begin -->/g, BOOTSTRAP_MARKER_BEGIN).replace(/<!-- fabric:knowledge-base:end -->/g, BOOTSTRAP_MARKER_END);
|
|
4216
|
+
if (rewritten === original) {
|
|
4217
|
+
continue;
|
|
4218
|
+
}
|
|
4219
|
+
await atomicWriteText3(abs, rewritten);
|
|
4220
|
+
paths.push(abs);
|
|
4221
|
+
countPerPath[abs] = replacedCount;
|
|
4222
|
+
}
|
|
4223
|
+
return { paths, countPerPath };
|
|
4224
|
+
}
|
|
4225
|
+
async function rewriteThreeEndManagedBlocks(projectRoot) {
|
|
4226
|
+
const snapshotPath = join5(projectRoot, ".fabric", "AGENTS.md");
|
|
4227
|
+
if (!existsSync4(snapshotPath)) {
|
|
4228
|
+
return;
|
|
4229
|
+
}
|
|
4230
|
+
let snapshot;
|
|
4231
|
+
try {
|
|
4232
|
+
snapshot = await readFile5(snapshotPath, "utf8");
|
|
4233
|
+
} catch {
|
|
4234
|
+
return;
|
|
4235
|
+
}
|
|
4236
|
+
const projectRulesPath = join5(projectRoot, ".fabric", "project-rules.md");
|
|
4237
|
+
const hasProjectRules = existsSync4(projectRulesPath);
|
|
4238
|
+
let expectedBody = snapshot;
|
|
4239
|
+
if (hasProjectRules) {
|
|
4240
|
+
try {
|
|
4241
|
+
const projectRules = await readFile5(projectRulesPath, "utf8");
|
|
4242
|
+
expectedBody = `${snapshot}
|
|
4243
|
+
---
|
|
4244
|
+
${projectRules}`;
|
|
4245
|
+
} catch {
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
const managedBlock = `${BOOTSTRAP_MARKER_BEGIN}
|
|
4249
|
+
${expectedBody}
|
|
4250
|
+
${BOOTSTRAP_MARKER_END}`;
|
|
4251
|
+
const blockTargets = [
|
|
4252
|
+
join5(projectRoot, "AGENTS.md"),
|
|
4253
|
+
join5(projectRoot, ".cursor", "rules", "fabric-bootstrap.mdc")
|
|
4254
|
+
];
|
|
4255
|
+
for (const abs of blockTargets) {
|
|
4256
|
+
if (!existsSync4(abs)) {
|
|
4257
|
+
continue;
|
|
4258
|
+
}
|
|
4259
|
+
let existing;
|
|
4260
|
+
try {
|
|
4261
|
+
existing = await readFile5(abs, "utf8");
|
|
4262
|
+
} catch {
|
|
4263
|
+
continue;
|
|
4264
|
+
}
|
|
4265
|
+
let next;
|
|
4266
|
+
const match = existing.match(BOOTSTRAP_REGEX);
|
|
4267
|
+
if (match !== null) {
|
|
4268
|
+
const before = existing.slice(0, match.index ?? 0);
|
|
4269
|
+
const after = existing.slice((match.index ?? 0) + match[0].length);
|
|
4270
|
+
const stripped = `${before}${after.replace(/^\r?\n/, "")}`;
|
|
4271
|
+
const trailingNewline = stripped.length === 0 || stripped.endsWith("\n") ? "" : "\n";
|
|
4272
|
+
next = `${stripped}${trailingNewline}
|
|
4273
|
+
${managedBlock}
|
|
4274
|
+
`;
|
|
4275
|
+
} else {
|
|
4276
|
+
const trailingNewline = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
|
|
4277
|
+
next = `${existing}${trailingNewline}
|
|
4278
|
+
${managedBlock}
|
|
4279
|
+
`;
|
|
4280
|
+
}
|
|
4281
|
+
if (next === existing) {
|
|
4282
|
+
continue;
|
|
4283
|
+
}
|
|
4284
|
+
await atomicWriteText3(abs, next);
|
|
4285
|
+
}
|
|
4286
|
+
const claudeMdPath = join5(projectRoot, "CLAUDE.md");
|
|
4287
|
+
if (existsSync4(claudeMdPath)) {
|
|
4288
|
+
let claudeContent;
|
|
4289
|
+
try {
|
|
4290
|
+
claudeContent = await readFile5(claudeMdPath, "utf8");
|
|
4291
|
+
} catch {
|
|
4292
|
+
return;
|
|
4293
|
+
}
|
|
4294
|
+
const lines = claudeContent.split(/\r?\n/u);
|
|
4295
|
+
let updated = claudeContent;
|
|
4296
|
+
const ensureLine = (line) => {
|
|
4297
|
+
if (lines.some((existingLine) => existingLine.trim() === line)) {
|
|
4298
|
+
return;
|
|
4299
|
+
}
|
|
4300
|
+
const trailingNewline = updated.length === 0 || updated.endsWith("\n") ? "" : "\n";
|
|
4301
|
+
updated = `${updated}${trailingNewline}${line}
|
|
4302
|
+
`;
|
|
4303
|
+
lines.push(line);
|
|
4304
|
+
};
|
|
4305
|
+
ensureLine("@.fabric/AGENTS.md");
|
|
4306
|
+
if (hasProjectRules) {
|
|
4307
|
+
ensureLine("@.fabric/project-rules.md");
|
|
4308
|
+
}
|
|
4309
|
+
if (updated !== claudeContent) {
|
|
4310
|
+
await atomicWriteText3(claudeMdPath, updated);
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
3956
4314
|
async function fixMcpConfigInWrongFile(projectRoot) {
|
|
3957
4315
|
const settingsPath = join5(projectRoot, ".claude", "settings.json");
|
|
3958
4316
|
if (!existsSync4(settingsPath)) {
|
|
@@ -4026,6 +4384,275 @@ async function ensureEventLedger(projectRoot) {
|
|
|
4026
4384
|
await ensureParentDirectory(path);
|
|
4027
4385
|
await writeFile2(path, "", { encoding: "utf8", flag: "a" });
|
|
4028
4386
|
}
|
|
4387
|
+
var CITE_POLICY_VERSION = "2.0.0-rc.20";
|
|
4388
|
+
async function ensureCitePolicyActivatedMarker(projectRoot) {
|
|
4389
|
+
let existing;
|
|
4390
|
+
try {
|
|
4391
|
+
const { events } = await readEventLedger(projectRoot, { event_type: "cite_policy_activated" });
|
|
4392
|
+
if (events.length > 0) {
|
|
4393
|
+
existing = events[0];
|
|
4394
|
+
}
|
|
4395
|
+
} catch {
|
|
4396
|
+
return { marker_ts: 0, emitted_now: false };
|
|
4397
|
+
}
|
|
4398
|
+
if (existing !== void 0) {
|
|
4399
|
+
return { marker_ts: existing.ts, emitted_now: false };
|
|
4400
|
+
}
|
|
4401
|
+
try {
|
|
4402
|
+
const stored = await appendEventLedgerEvent(projectRoot, {
|
|
4403
|
+
event_type: "cite_policy_activated",
|
|
4404
|
+
policy_version: CITE_POLICY_VERSION,
|
|
4405
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4406
|
+
});
|
|
4407
|
+
return { marker_ts: stored.ts, emitted_now: true };
|
|
4408
|
+
} catch {
|
|
4409
|
+
return { marker_ts: 0, emitted_now: false };
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
function categorizeCiteTag(tag) {
|
|
4413
|
+
if (tag === "planned" || tag === "recalled" || tag === "chained-from" || tag === "none") {
|
|
4414
|
+
return { category: tag };
|
|
4415
|
+
}
|
|
4416
|
+
if (tag === "dismissed") {
|
|
4417
|
+
return { category: "dismissed", reason: "unspecified" };
|
|
4418
|
+
}
|
|
4419
|
+
if (tag.startsWith("dismissed:")) {
|
|
4420
|
+
const remainder = tag.slice("dismissed:".length);
|
|
4421
|
+
if (remainder.startsWith("other:")) {
|
|
4422
|
+
return { category: "dismissed", reason: remainder.slice("other:".length) || "other" };
|
|
4423
|
+
}
|
|
4424
|
+
return { category: "dismissed", reason: remainder || "unspecified" };
|
|
4425
|
+
}
|
|
4426
|
+
return { category: "none" };
|
|
4427
|
+
}
|
|
4428
|
+
function matchesRelevancePath(editPath, relevancePaths) {
|
|
4429
|
+
if (relevancePaths.length === 0) {
|
|
4430
|
+
return false;
|
|
4431
|
+
}
|
|
4432
|
+
const normalized = normalizePath(editPath);
|
|
4433
|
+
for (const glob of relevancePaths) {
|
|
4434
|
+
if (minimatch(normalized, glob, { dot: true, matchBase: false })) {
|
|
4435
|
+
return true;
|
|
4436
|
+
}
|
|
4437
|
+
}
|
|
4438
|
+
return false;
|
|
4439
|
+
}
|
|
4440
|
+
async function runDoctorCiteCoverage(projectRoot, options) {
|
|
4441
|
+
const marker = await ensureCitePolicyActivatedMarker(projectRoot);
|
|
4442
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4443
|
+
const zeroMetrics = {
|
|
4444
|
+
edits_touched: 0,
|
|
4445
|
+
qualifying_cites: 0,
|
|
4446
|
+
recalled_unverified: 0,
|
|
4447
|
+
expected_but_missed: 0,
|
|
4448
|
+
total_turns: 0
|
|
4449
|
+
};
|
|
4450
|
+
if (marker.marker_ts === 0) {
|
|
4451
|
+
return {
|
|
4452
|
+
status: "skipped",
|
|
4453
|
+
marker_ts: 0,
|
|
4454
|
+
marker_emitted_now: false,
|
|
4455
|
+
since_ts: options.since,
|
|
4456
|
+
client_filter: options.client,
|
|
4457
|
+
metrics: zeroMetrics,
|
|
4458
|
+
generated_at: generatedAt
|
|
4459
|
+
};
|
|
4460
|
+
}
|
|
4461
|
+
const effectiveSince = Math.max(marker.marker_ts, options.since);
|
|
4462
|
+
let ledgerEvents = [];
|
|
4463
|
+
try {
|
|
4464
|
+
const result = await readEventLedger(projectRoot, { since: effectiveSince });
|
|
4465
|
+
ledgerEvents = result.events;
|
|
4466
|
+
} catch {
|
|
4467
|
+
return {
|
|
4468
|
+
status: "ok",
|
|
4469
|
+
marker_ts: marker.marker_ts,
|
|
4470
|
+
marker_emitted_now: marker.emitted_now,
|
|
4471
|
+
since_ts: effectiveSince,
|
|
4472
|
+
client_filter: options.client,
|
|
4473
|
+
metrics: zeroMetrics,
|
|
4474
|
+
generated_at: generatedAt
|
|
4475
|
+
};
|
|
4476
|
+
}
|
|
4477
|
+
const assistantTurns = [];
|
|
4478
|
+
const editEvents = [];
|
|
4479
|
+
const fetchEvents = [];
|
|
4480
|
+
for (const event of ledgerEvents) {
|
|
4481
|
+
switch (event.event_type) {
|
|
4482
|
+
case "assistant_turn_observed":
|
|
4483
|
+
assistantTurns.push(event);
|
|
4484
|
+
break;
|
|
4485
|
+
case "edit_intent_checked":
|
|
4486
|
+
editEvents.push(event);
|
|
4487
|
+
break;
|
|
4488
|
+
case "knowledge_sections_fetched":
|
|
4489
|
+
fetchEvents.push(event);
|
|
4490
|
+
break;
|
|
4491
|
+
default:
|
|
4492
|
+
break;
|
|
4493
|
+
}
|
|
4494
|
+
}
|
|
4495
|
+
const filteredTurns = options.client === "all" ? assistantTurns : assistantTurns.filter((t) => t.client === options.client);
|
|
4496
|
+
let clientSessionIds = null;
|
|
4497
|
+
if (options.client !== "all") {
|
|
4498
|
+
clientSessionIds = /* @__PURE__ */ new Set();
|
|
4499
|
+
for (const turn of assistantTurns) {
|
|
4500
|
+
if (turn.client === options.client) {
|
|
4501
|
+
const sid = turn.session_id;
|
|
4502
|
+
if (typeof sid === "string" && sid.length > 0) {
|
|
4503
|
+
clientSessionIds.add(sid);
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
}
|
|
4508
|
+
const kbIndex = /* @__PURE__ */ new Map();
|
|
4509
|
+
try {
|
|
4510
|
+
const meta = await readAgentsMeta(projectRoot);
|
|
4511
|
+
for (const node of Object.values(meta.nodes)) {
|
|
4512
|
+
const stableId = node.stable_id;
|
|
4513
|
+
if (typeof stableId !== "string" || stableId.length === 0) continue;
|
|
4514
|
+
const description = node.description;
|
|
4515
|
+
if (description === void 0) continue;
|
|
4516
|
+
const paths = description.relevance_paths ?? [];
|
|
4517
|
+
const scope = description.relevance_scope ?? "broad";
|
|
4518
|
+
kbIndex.set(stableId, {
|
|
4519
|
+
relevance_paths: paths,
|
|
4520
|
+
// A broad entry with no paths is the safe default. A narrow entry must
|
|
4521
|
+
// carry at least one path; an empty-paths narrow is treated as broad.
|
|
4522
|
+
relevance_scope: scope === "narrow" && paths.length > 0 ? "narrow" : "broad"
|
|
4523
|
+
});
|
|
4524
|
+
}
|
|
4525
|
+
} catch {
|
|
4526
|
+
}
|
|
4527
|
+
const fetchesBySession = /* @__PURE__ */ new Map();
|
|
4528
|
+
for (const fetch of fetchEvents) {
|
|
4529
|
+
const sid = fetch.session_id;
|
|
4530
|
+
if (typeof sid !== "string" || sid.length === 0) continue;
|
|
4531
|
+
const list = fetchesBySession.get(sid) ?? [];
|
|
4532
|
+
list.push(fetch.ts);
|
|
4533
|
+
fetchesBySession.set(sid, list);
|
|
4534
|
+
}
|
|
4535
|
+
for (const list of fetchesBySession.values()) {
|
|
4536
|
+
list.sort((a, b) => a - b);
|
|
4537
|
+
}
|
|
4538
|
+
const RECALL_WINDOW_MS = 6e4;
|
|
4539
|
+
const isRecallVerified = (turn) => {
|
|
4540
|
+
const sid = turn.session_id;
|
|
4541
|
+
if (typeof sid !== "string" || sid.length === 0) return false;
|
|
4542
|
+
const fetches = fetchesBySession.get(sid);
|
|
4543
|
+
if (fetches === void 0 || fetches.length === 0) return false;
|
|
4544
|
+
for (const ft of fetches) {
|
|
4545
|
+
if (Math.abs(ft - turn.ts) <= RECALL_WINDOW_MS) return true;
|
|
4546
|
+
}
|
|
4547
|
+
return false;
|
|
4548
|
+
};
|
|
4549
|
+
const dismissedHistogram = {};
|
|
4550
|
+
const perClientAccum = /* @__PURE__ */ new Map();
|
|
4551
|
+
const emptyMetrics = () => ({
|
|
4552
|
+
edits_touched: 0,
|
|
4553
|
+
qualifying_cites: 0,
|
|
4554
|
+
recalled_unverified: 0,
|
|
4555
|
+
expected_but_missed: 0,
|
|
4556
|
+
total_turns: 0
|
|
4557
|
+
});
|
|
4558
|
+
const bumpClient = (client, mut) => {
|
|
4559
|
+
if (typeof client !== "string" || client.length === 0) return;
|
|
4560
|
+
const existing = perClientAccum.get(client) ?? emptyMetrics();
|
|
4561
|
+
mut(existing);
|
|
4562
|
+
perClientAccum.set(client, existing);
|
|
4563
|
+
};
|
|
4564
|
+
const sessionCitedKbs = /* @__PURE__ */ new Map();
|
|
4565
|
+
let totalTurns = 0;
|
|
4566
|
+
let qualifyingCites = 0;
|
|
4567
|
+
let recalledUnverified = 0;
|
|
4568
|
+
for (const turn of filteredTurns) {
|
|
4569
|
+
totalTurns += 1;
|
|
4570
|
+
bumpClient(turn.client, (m) => {
|
|
4571
|
+
m.total_turns += 1;
|
|
4572
|
+
});
|
|
4573
|
+
const sid = turn.session_id;
|
|
4574
|
+
if (typeof sid === "string" && sid.length > 0) {
|
|
4575
|
+
const set = sessionCitedKbs.get(sid) ?? /* @__PURE__ */ new Set();
|
|
4576
|
+
for (const id of turn.cite_ids) {
|
|
4577
|
+
set.add(id);
|
|
4578
|
+
}
|
|
4579
|
+
sessionCitedKbs.set(sid, set);
|
|
4580
|
+
}
|
|
4581
|
+
let turnHadRecalled = false;
|
|
4582
|
+
for (const tag of turn.cite_tags) {
|
|
4583
|
+
const { category, reason } = categorizeCiteTag(tag);
|
|
4584
|
+
switch (category) {
|
|
4585
|
+
case "planned":
|
|
4586
|
+
case "recalled":
|
|
4587
|
+
case "chained-from":
|
|
4588
|
+
qualifyingCites += 1;
|
|
4589
|
+
bumpClient(turn.client, (m) => {
|
|
4590
|
+
m.qualifying_cites += 1;
|
|
4591
|
+
});
|
|
4592
|
+
if (category === "recalled") turnHadRecalled = true;
|
|
4593
|
+
break;
|
|
4594
|
+
case "dismissed": {
|
|
4595
|
+
const key = reason ?? "unspecified";
|
|
4596
|
+
dismissedHistogram[key] = (dismissedHistogram[key] ?? 0) + 1;
|
|
4597
|
+
break;
|
|
4598
|
+
}
|
|
4599
|
+
case "none":
|
|
4600
|
+
default:
|
|
4601
|
+
break;
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
if (turnHadRecalled && !isRecallVerified(turn)) {
|
|
4605
|
+
recalledUnverified += 1;
|
|
4606
|
+
bumpClient(turn.client, (m) => {
|
|
4607
|
+
m.recalled_unverified += 1;
|
|
4608
|
+
});
|
|
4609
|
+
}
|
|
4610
|
+
}
|
|
4611
|
+
let editsTouched = 0;
|
|
4612
|
+
let expectedButMissed = 0;
|
|
4613
|
+
for (const edit of editEvents) {
|
|
4614
|
+
const sid = edit.session_id;
|
|
4615
|
+
if (clientSessionIds !== null) {
|
|
4616
|
+
if (typeof sid !== "string" || sid.length === 0) continue;
|
|
4617
|
+
if (!clientSessionIds.has(sid)) continue;
|
|
4618
|
+
}
|
|
4619
|
+
editsTouched += 1;
|
|
4620
|
+
if (typeof sid !== "string" || sid.length === 0) continue;
|
|
4621
|
+
const citedSet = sessionCitedKbs.get(sid) ?? /* @__PURE__ */ new Set();
|
|
4622
|
+
for (const [kbId, kb] of kbIndex) {
|
|
4623
|
+
if (kb.relevance_scope !== "narrow") continue;
|
|
4624
|
+
if (!matchesRelevancePath(edit.path, kb.relevance_paths)) continue;
|
|
4625
|
+
if (!citedSet.has(kbId)) {
|
|
4626
|
+
expectedButMissed += 1;
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
const metrics = {
|
|
4631
|
+
edits_touched: editsTouched,
|
|
4632
|
+
qualifying_cites: qualifyingCites,
|
|
4633
|
+
recalled_unverified: recalledUnverified,
|
|
4634
|
+
expected_but_missed: expectedButMissed,
|
|
4635
|
+
total_turns: totalTurns
|
|
4636
|
+
};
|
|
4637
|
+
let perClient;
|
|
4638
|
+
if (options.client === "all" && perClientAccum.size > 0) {
|
|
4639
|
+
perClient = {};
|
|
4640
|
+
for (const [client, m] of perClientAccum) {
|
|
4641
|
+
perClient[client] = m;
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
return {
|
|
4645
|
+
status: "ok",
|
|
4646
|
+
marker_ts: marker.marker_ts,
|
|
4647
|
+
marker_emitted_now: marker.emitted_now,
|
|
4648
|
+
since_ts: effectiveSince,
|
|
4649
|
+
client_filter: options.client,
|
|
4650
|
+
metrics,
|
|
4651
|
+
...perClient !== void 0 ? { per_client: perClient } : {},
|
|
4652
|
+
...Object.keys(dismissedHistogram).length > 0 ? { dismissed_reason_histogram: dismissedHistogram } : {},
|
|
4653
|
+
generated_at: generatedAt
|
|
4654
|
+
};
|
|
4655
|
+
}
|
|
4029
4656
|
function createFixMessage(fixed, report) {
|
|
4030
4657
|
const fixedText = fixed.length === 0 ? "No deterministic doctor fixes were needed." : `Applied ${fixed.length} deterministic doctor fix${fixed.length === 1 ? "" : "es"}.`;
|
|
4031
4658
|
const manualText = report.manual_errors.length === 0 ? "No manual errors remain." : `${report.manual_errors.length} manual error${report.manual_errors.length === 1 ? "" : "s"} remain.`;
|
|
@@ -4332,5 +4959,6 @@ export {
|
|
|
4332
4959
|
normalizeKnowledgePath,
|
|
4333
4960
|
runDoctorReport,
|
|
4334
4961
|
runDoctorFix,
|
|
4335
|
-
runDoctorApplyLint
|
|
4962
|
+
runDoctorApplyLint,
|
|
4963
|
+
runDoctorCiteCoverage
|
|
4336
4964
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -97,6 +97,27 @@ 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 CiteCoverageReport = {
|
|
101
|
+
status: "ok" | "skipped";
|
|
102
|
+
marker_ts: number;
|
|
103
|
+
marker_emitted_now: boolean;
|
|
104
|
+
since_ts: number;
|
|
105
|
+
client_filter: "cc" | "codex" | "cursor" | "all";
|
|
106
|
+
metrics: {
|
|
107
|
+
edits_touched: number;
|
|
108
|
+
qualifying_cites: number;
|
|
109
|
+
recalled_unverified: number;
|
|
110
|
+
expected_but_missed: number;
|
|
111
|
+
total_turns: number;
|
|
112
|
+
};
|
|
113
|
+
per_client?: Record<string, Partial<CiteCoverageReport["metrics"]>>;
|
|
114
|
+
dismissed_reason_histogram?: Record<string, number>;
|
|
115
|
+
generated_at: string;
|
|
116
|
+
};
|
|
117
|
+
declare function runDoctorCiteCoverage(projectRoot: string, options: {
|
|
118
|
+
since: number;
|
|
119
|
+
client: "cc" | "codex" | "cursor" | "all";
|
|
120
|
+
}): Promise<CiteCoverageReport>;
|
|
100
121
|
|
|
101
122
|
type KnowledgeMetaBuildSource = "doctor_fix" | "sync_meta";
|
|
102
123
|
type KnowledgeMetaBuildResult = {
|
|
@@ -382,4 +403,4 @@ declare function startHttpServer(options: {
|
|
|
382
403
|
authToken?: string;
|
|
383
404
|
}): Promise<Server>;
|
|
384
405
|
|
|
385
|
-
export { AGENTS_MD_RESOURCE_URI, type AcquireOptions, type DoctorApplyLintMutation, type DoctorApplyLintMutationKind, type DoctorApplyLintReport, type DoctorFixReport, type DoctorIssue, type DoctorReport, EVENT_LEDGER_PATH, 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, ensureKnowledgeFresh, extractKnowledge, flushAndSyncEventLedger, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, isSameKnowledgeTestIndex, planContext, readLockState, readSelectionToken, reconcileKnowledge, releaseLock, reviewKnowledge, runDoctorApplyLint, runDoctorFix, runDoctorReport, stableStringify, startHttpServer, startStdioServer, writeKnowledgeMeta };
|
|
406
|
+
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 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, ensureKnowledgeFresh, extractKnowledge, flushAndSyncEventLedger, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, isSameKnowledgeTestIndex, planContext, readLockState, readSelectionToken, reconcileKnowledge, releaseLock, reviewKnowledge, runDoctorApplyLint, runDoctorCiteCoverage, runDoctorFix, runDoctorReport, stableStringify, startHttpServer, startStdioServer, writeKnowledgeMeta };
|
package/dist/index.js
CHANGED
|
@@ -21,12 +21,13 @@ import {
|
|
|
21
21
|
reconcileKnowledge,
|
|
22
22
|
resolveProjectRoot,
|
|
23
23
|
runDoctorApplyLint,
|
|
24
|
+
runDoctorCiteCoverage,
|
|
24
25
|
runDoctorFix,
|
|
25
26
|
runDoctorReport,
|
|
26
27
|
sha256,
|
|
27
28
|
stableStringify,
|
|
28
29
|
writeKnowledgeMeta
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-7R6MFA7Y.js";
|
|
30
31
|
|
|
31
32
|
// src/index.ts
|
|
32
33
|
import { existsSync as existsSync4 } from "fs";
|
|
@@ -1892,7 +1893,7 @@ function formatPreexistingRootMessage(projectRoot) {
|
|
|
1892
1893
|
function createFabricServer(tracker) {
|
|
1893
1894
|
const server = new McpServer({
|
|
1894
1895
|
name: "fabric-knowledge-server",
|
|
1895
|
-
version: "2.0.0-rc.
|
|
1896
|
+
version: "2.0.0-rc.21"
|
|
1896
1897
|
});
|
|
1897
1898
|
registerPlanContext(server, tracker);
|
|
1898
1899
|
registerKnowledgeSections(server, tracker);
|
|
@@ -1992,7 +1993,7 @@ function createShutdownHandler(deps) {
|
|
|
1992
1993
|
};
|
|
1993
1994
|
}
|
|
1994
1995
|
async function startHttpServer(options) {
|
|
1995
|
-
const { createFabricHttpApp } = await import("./http-
|
|
1996
|
+
const { createFabricHttpApp } = await import("./http-JGWQGUZS.js");
|
|
1996
1997
|
const { port, projectRoot, host = "127.0.0.1", authToken } = options;
|
|
1997
1998
|
const app = createFabricHttpApp({ projectRoot, host, authToken });
|
|
1998
1999
|
return await new Promise((resolveServer, rejectServer) => {
|
|
@@ -2050,6 +2051,7 @@ export {
|
|
|
2050
2051
|
releaseLock,
|
|
2051
2052
|
reviewKnowledge,
|
|
2052
2053
|
runDoctorApplyLint,
|
|
2054
|
+
runDoctorCiteCoverage,
|
|
2053
2055
|
runDoctorFix,
|
|
2054
2056
|
runDoctorReport,
|
|
2055
2057
|
stableStringify,
|
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.21",
|
|
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.21"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/express": "^5.0.6",
|