@fenglimg/fabric-server 1.5.1 → 1.5.2

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.js CHANGED
@@ -1,23 +1,30 @@
1
1
  import {
2
2
  AGENTS_MD_RESOURCE_URI,
3
3
  FABRIC_DIR,
4
+ LEDGER_PATH,
5
+ LEGACY_LEDGER_PATH,
4
6
  appendEditIntentAuditEvents,
5
7
  appendLedgerEntry,
6
8
  approveHumanLock,
7
9
  atomicWriteText,
10
+ buildRulesPayload,
8
11
  contextCache,
12
+ getLedgerPath,
13
+ getLegacyLedgerPath,
9
14
  getRules,
10
15
  loadGetRulesContext,
16
+ loadMatchedRules,
17
+ matchRuleNodes,
11
18
  normalizeRulesPath,
12
19
  readAgentsMeta,
13
20
  readHumanLock,
14
21
  readHumanLockEntry,
15
22
  resolveProjectRoot,
16
- resolveRulesForPath,
17
23
  runDoctorAuditReport,
24
+ runDoctorFix,
18
25
  runDoctorReport,
19
26
  sha256
20
- } from "./chunk-E3RZ276F.js";
27
+ } from "./chunk-4G6VFG5N.js";
21
28
 
22
29
  // src/index.ts
23
30
  import { readFile } from "fs/promises";
@@ -149,16 +156,30 @@ async function planContext(projectRoot, input) {
149
156
  const context = await loadGetRulesContext(projectRoot);
150
157
  const stale = input.client_hash !== void 0 && input.client_hash !== context.meta.revision;
151
158
  const uniquePaths = dedupePaths(input.paths);
152
- const entries = await Promise.all(
153
- uniquePaths.map(async (path) => ({
154
- path,
155
- rules: await resolveRulesForPath(projectRoot, context, path, { dedupeByPath: true })
156
- }))
159
+ const fileContentCache = /* @__PURE__ */ new Map();
160
+ const matchedNodesByPath = new Map(
161
+ uniquePaths.map((path) => [path, matchRuleNodes(context.meta, path)])
157
162
  );
163
+ const loadedByPath = new Map(
164
+ await Promise.all(
165
+ uniquePaths.map(async (path) => [
166
+ path,
167
+ await loadMatchedRules(projectRoot, matchedNodesByPath.get(path) ?? [], fileContentCache)
168
+ ])
169
+ )
170
+ );
171
+ const entries = uniquePaths.map((path) => ({
172
+ path,
173
+ rules: buildRulesPayload(context, loadedByPath.get(path) ?? { rules: [], stubs: [] }, {
174
+ dedupeByPath: true
175
+ })
176
+ }));
177
+ const shared = buildSharedView(context.meta.revision, uniquePaths, matchedNodesByPath, loadedByPath);
158
178
  return {
159
179
  revision_hash: context.meta.revision,
160
180
  stale,
161
- entries
181
+ entries,
182
+ shared
162
183
  };
163
184
  }
164
185
  function dedupePaths(paths) {
@@ -172,6 +193,96 @@ function dedupePaths(paths) {
172
193
  return [normalizedPath];
173
194
  });
174
195
  }
196
+ function buildSharedView(revision, uniquePaths, matchedNodesByPath, loadedByPath) {
197
+ const sharedEntriesByStableId = /* @__PURE__ */ new Map();
198
+ const descriptionStubByStableId = /* @__PURE__ */ new Map();
199
+ const derivedStableIds = /* @__PURE__ */ new Set();
200
+ const bundleStableIds = /* @__PURE__ */ new Set();
201
+ const fileMap = Object.fromEntries(
202
+ uniquePaths.map((path) => {
203
+ const matchedNodes = matchedNodesByPath.get(path) ?? [];
204
+ const loaded = loadedByPath.get(path) ?? { rules: [], stubs: [] };
205
+ const l1 = collectPerPathStableIds(loaded.rules, "L1");
206
+ const l2 = collectPerPathStableIds(loaded.rules, "L2");
207
+ const descriptionStubs = dedupeStableIds(loaded.stubs.map((stub) => stub.stable_id));
208
+ for (const matchedNode of matchedNodes) {
209
+ bundleStableIds.add(matchedNode.stable_id);
210
+ if (matchedNode.identity_source === "derived") {
211
+ derivedStableIds.add(matchedNode.stable_id);
212
+ }
213
+ }
214
+ for (const rule of loaded.rules) {
215
+ sharedEntriesByStableId.set(rule.stable_id, {
216
+ stable_id: rule.stable_id,
217
+ identity_source: rule.identity_source,
218
+ level: rule.level,
219
+ path: rule.entry.path,
220
+ content: rule.entry.content
221
+ });
222
+ }
223
+ for (const stub of loaded.stubs) {
224
+ descriptionStubByStableId.set(stub.stable_id, stub);
225
+ }
226
+ return [
227
+ path,
228
+ {
229
+ L1: l1,
230
+ L2: l2,
231
+ description_stubs: descriptionStubs
232
+ }
233
+ ];
234
+ })
235
+ );
236
+ const descriptionStubUnion = Array.from(descriptionStubByStableId.values()).sort(compareStableIds);
237
+ const sharedEntries = Array.from(sharedEntriesByStableId.values()).sort(compareStableIds);
238
+ const preflightDiagnostics = [];
239
+ for (const path of uniquePaths) {
240
+ const slice = fileMap[path];
241
+ if (slice !== void 0 && slice.L1.length === 0 && slice.L2.length === 0 && slice.description_stubs.length > 0) {
242
+ preflightDiagnostics.push({
243
+ code: "description_stub_only",
244
+ severity: "info",
245
+ path,
246
+ stable_ids: slice.description_stubs,
247
+ message: `Path ${path} only matched description stubs and no loadable L1/L2 rules. Run fab_get_rules on the final target before editing if you need the full rule text.`
248
+ });
249
+ }
250
+ }
251
+ if (derivedStableIds.size > 0) {
252
+ const stableIds = Array.from(derivedStableIds).sort();
253
+ preflightDiagnostics.push({
254
+ code: "derived_identity",
255
+ severity: "warn",
256
+ stable_ids: stableIds,
257
+ message: `Resolved bundle includes ${stableIds.length} rule node${stableIds.length === 1 ? "" : "s"} that still rely on derived identities. Declare \`<!-- fab:rule-id ... -->\` in the source rule file to stabilize audit references.`
258
+ });
259
+ }
260
+ return {
261
+ resolved_bundle_id: sha256([revision, ...Array.from(bundleStableIds).sort()].join("\n")),
262
+ shared_entries: sharedEntries,
263
+ file_map: fileMap,
264
+ description_stub_union: descriptionStubUnion,
265
+ preflight_diagnostics: preflightDiagnostics
266
+ };
267
+ }
268
+ function dedupeStableIds(stableIds) {
269
+ return Array.from(new Set(stableIds));
270
+ }
271
+ function collectPerPathStableIds(rules, level) {
272
+ const seenPaths = /* @__PURE__ */ new Set();
273
+ const stableIds = [];
274
+ for (const rule of rules) {
275
+ if (rule.level !== level || seenPaths.has(rule.entry.path)) {
276
+ continue;
277
+ }
278
+ seenPaths.add(rule.entry.path);
279
+ stableIds.push(rule.stable_id);
280
+ }
281
+ return stableIds;
282
+ }
283
+ function compareStableIds(left, right) {
284
+ return left.stable_id.localeCompare(right.stable_id);
285
+ }
175
286
 
176
287
  // src/tools/plan-context.ts
177
288
  var inputSchema3 = {
@@ -180,11 +291,13 @@ var inputSchema3 = {
180
291
  };
181
292
  var rulesEntrySchema2 = z3.object({ path: z3.string(), content: z3.string() });
182
293
  var humanLockedSchema2 = z3.object({ file: z3.string(), excerpt: z3.string() });
294
+ var descriptionStubSchema2 = z3.object({ path: z3.string(), description: z3.string() });
183
295
  var rulesPayloadSchema = z3.object({
184
296
  L0: z3.string(),
185
297
  L1: z3.array(rulesEntrySchema2),
186
298
  L2: z3.array(rulesEntrySchema2),
187
- human_locked_nearby: z3.array(humanLockedSchema2)
299
+ human_locked_nearby: z3.array(humanLockedSchema2),
300
+ description_stubs: z3.array(descriptionStubSchema2).optional()
188
301
  });
189
302
  var outputSchema3 = z3.object({
190
303
  revision_hash: z3.string(),
@@ -194,7 +307,44 @@ var outputSchema3 = z3.object({
194
307
  path: z3.string(),
195
308
  rules: rulesPayloadSchema
196
309
  })
197
- )
310
+ ),
311
+ shared: z3.object({
312
+ resolved_bundle_id: z3.string(),
313
+ shared_entries: z3.array(
314
+ z3.object({
315
+ stable_id: z3.string(),
316
+ identity_source: z3.enum(["declared", "derived"]),
317
+ level: z3.enum(["L1", "L2"]),
318
+ path: z3.string(),
319
+ content: z3.string()
320
+ })
321
+ ),
322
+ file_map: z3.record(
323
+ z3.object({
324
+ L1: z3.array(z3.string()),
325
+ L2: z3.array(z3.string()),
326
+ description_stubs: z3.array(z3.string())
327
+ })
328
+ ),
329
+ description_stub_union: z3.array(
330
+ z3.object({
331
+ stable_id: z3.string(),
332
+ identity_source: z3.enum(["declared", "derived"]),
333
+ level: z3.enum(["L1", "L2"]),
334
+ path: z3.string(),
335
+ description: z3.string()
336
+ })
337
+ ),
338
+ preflight_diagnostics: z3.array(
339
+ z3.object({
340
+ code: z3.enum(["description_stub_only", "derived_identity"]),
341
+ severity: z3.enum(["info", "warn"]),
342
+ message: z3.string(),
343
+ path: z3.string().optional(),
344
+ stable_ids: z3.array(z3.string()).optional()
345
+ })
346
+ )
347
+ })
198
348
  });
199
349
  function registerPlanContext(server) {
200
350
  server.registerTool(
@@ -339,7 +489,7 @@ function formatError(error) {
339
489
  function createFabricServer() {
340
490
  const server = new McpServer({
341
491
  name: "fabric-context-server",
342
- version: "1.5.1"
492
+ version: "1.5.2"
343
493
  });
344
494
  registerGetRules(server);
345
495
  registerPlanContext(server);
@@ -374,7 +524,7 @@ async function startStdioServer() {
374
524
  await server.connect(transport);
375
525
  }
376
526
  async function startHttpServer(options) {
377
- const { createFabricHttpApp } = await import("./http-BVF4GWIM.js");
527
+ const { createFabricHttpApp } = await import("./http-U4S7BUP4.js");
378
528
  const { port, projectRoot, host = "127.0.0.1", authToken, dashboardDistPath, dev } = options;
379
529
  const app = createFabricHttpApp({ projectRoot, host, authToken, dashboardDistPath, dev });
380
530
  return await new Promise((resolveServer, rejectServer) => {
@@ -401,11 +551,16 @@ if (isMainModule) {
401
551
  }
402
552
  export {
403
553
  AGENTS_MD_RESOURCE_URI,
554
+ LEDGER_PATH,
555
+ LEGACY_LEDGER_PATH,
404
556
  approveHumanLock,
405
557
  createFabricServer,
558
+ getLedgerPath,
559
+ getLegacyLedgerPath,
406
560
  readHumanLock,
407
561
  readHumanLockEntry,
408
562
  runDoctorAuditReport,
563
+ runDoctorFix,
409
564
  runDoctorReport,
410
565
  startHttpServer,
411
566
  startStdioServer