@fenglimg/fabric-server 1.5.2 → 1.7.0

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,347 +1,102 @@
1
1
  import {
2
2
  AGENTS_MD_RESOURCE_URI,
3
- FABRIC_DIR,
3
+ EVENT_LEDGER_PATH,
4
4
  LEDGER_PATH,
5
5
  LEGACY_LEDGER_PATH,
6
- appendEditIntentAuditEvents,
7
- appendLedgerEntry,
8
- approveHumanLock,
9
- atomicWriteText,
10
- buildRulesPayload,
11
- contextCache,
6
+ RULE_SECTION_NAMES,
7
+ buildRuleMeta,
8
+ computeRuleTestIndex,
9
+ computeRulesBasedAgentsMeta,
10
+ deriveRuleMetaLayer,
11
+ deriveRuleMetaTopologyType,
12
+ getEventLedgerPath,
12
13
  getLedgerPath,
13
14
  getLegacyLedgerPath,
14
- getRules,
15
- loadGetRulesContext,
16
- loadMatchedRules,
17
- matchRuleNodes,
18
- normalizeRulesPath,
19
- readAgentsMeta,
20
- readHumanLock,
21
- readHumanLockEntry,
15
+ getRuleSections,
16
+ isSameRuleTestIndex,
17
+ planContext,
22
18
  resolveProjectRoot,
23
- runDoctorAuditReport,
24
19
  runDoctorFix,
25
20
  runDoctorReport,
26
- sha256
27
- } from "./chunk-4G6VFG5N.js";
21
+ stableStringify,
22
+ writeRuleMeta
23
+ } from "./chunk-PTFSYO4Y.js";
28
24
 
29
25
  // src/index.ts
30
26
  import { readFile } from "fs/promises";
31
- import { join as join2, resolve } from "path";
27
+ import { join, resolve } from "path";
32
28
  import { fileURLToPath } from "url";
33
29
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
34
30
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
35
31
 
36
- // src/tools/append-intent.ts
37
- import { aiLedgerEntrySchema } from "@fenglimg/fabric-shared";
32
+ // src/tools/plan-context.ts
38
33
  import { z } from "zod";
39
-
40
- // src/services/append-intent.ts
41
- async function appendIntent(projectRoot, input) {
42
- const ts = Date.now();
43
- const entry = await appendLedgerEntry(projectRoot, {
44
- ...input.entry,
45
- ts,
46
- source: "ai"
47
- });
48
- let compliance;
49
- try {
50
- const auditResult = await appendEditIntentAuditEvents(projectRoot, {
51
- affected_paths: entry.affected_paths,
52
- intent: entry.intent,
53
- ledger_entry_id: entry.id,
54
- ts
55
- });
56
- compliance = auditResult.compliance;
57
- } catch {
58
- }
59
- return {
60
- success: true,
61
- timestamp: ts,
62
- entry,
63
- compliance
64
- };
65
- }
66
-
67
- // src/tools/append-intent.ts
68
34
  var inputSchema = {
69
- entry: aiLedgerEntrySchema.omit({
70
- id: true,
71
- source: true,
72
- ts: true
73
- })
35
+ paths: z.array(z.string()).min(1).describe("Candidate file paths to build neutral rule selection context for"),
36
+ intent: z.string().optional().describe("User-stated requirement or implementation intent; used only to build a neutral requirement profile"),
37
+ known_tech: z.array(z.string()).optional().describe("Known technologies involved in the requirement profile"),
38
+ detected_entities: z.record(z.array(z.string())).optional().describe("Optional path-keyed detected entities for the requirement profile"),
39
+ client_hash: z.string().optional().describe("Revision hash from a prior fab_plan_context response; enables stale detection"),
40
+ correlation_id: z.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
41
+ session_id: z.string().optional().describe("Optional caller-provided session id for Event Ledger records")
74
42
  };
75
- var outputSchema = z.object({
76
- success: z.boolean(),
77
- timestamp: z.number(),
78
- entry: z.record(z.unknown()),
79
- compliance: z.object({
80
- compliant: z.boolean(),
81
- matched_get_rules_ts: z.string().nullable(),
82
- window_ms: z.number()
83
- }).optional()
43
+ var ruleDescriptionSchema = z.object({
44
+ summary: z.string(),
45
+ intent_clues: z.array(z.string()),
46
+ tech_stack: z.array(z.string()),
47
+ impact: z.array(z.string()),
48
+ must_read_if: z.string(),
49
+ entities: z.array(z.string()).optional()
84
50
  });
85
- function registerAppendIntent(server) {
86
- server.registerTool(
87
- "fab_append_intent",
88
- {
89
- description: "Call after a completed task to append an intent ledger entry for Fabric.",
90
- inputSchema,
91
- outputSchema,
92
- annotations: { readOnlyHint: false }
93
- },
94
- async ({ entry }) => {
95
- const projectRoot = resolveProjectRoot();
96
- const result = await appendIntent(projectRoot, { entry });
97
- const structuredContent = {
98
- success: result.success,
99
- timestamp: result.timestamp,
100
- entry: { ...result.entry },
101
- compliance: result.compliance
102
- };
103
- return {
104
- content: [{ type: "text", text: JSON.stringify(result) }],
105
- structuredContent
106
- };
107
- }
108
- );
109
- }
110
-
111
- // src/tools/get-rules.ts
112
- import { z as z2 } from "zod";
113
- var inputSchema2 = {
114
- path: z2.string().describe("Target file path to query rules for"),
115
- client_hash: z2.string().optional().describe("Revision hash from prior fab_get_rules response; enables stale detection")
116
- };
117
- var rulesEntrySchema = z2.object({ path: z2.string(), content: z2.string() });
118
- var humanLockedSchema = z2.object({ file: z2.string(), excerpt: z2.string() });
119
- var descriptionStubSchema = z2.object({ path: z2.string(), description: z2.string() });
120
- var outputSchema2 = z2.object({
121
- revision_hash: z2.string(),
122
- stale: z2.boolean(),
123
- rules: z2.object({
124
- L0: z2.string(),
125
- L1: z2.array(rulesEntrySchema),
126
- L2: z2.array(rulesEntrySchema),
127
- human_locked_nearby: z2.array(humanLockedSchema),
128
- description_stubs: z2.array(descriptionStubSchema).optional()
129
- })
51
+ var descriptionIndexItemSchema = z.object({
52
+ stable_id: z.string(),
53
+ level: z.enum(["L0", "L1", "L2"]),
54
+ required: z.boolean(),
55
+ selectable: z.boolean(),
56
+ description: ruleDescriptionSchema
130
57
  });
131
- function registerGetRules(server) {
132
- server.registerTool(
133
- "fab_get_rules",
134
- {
135
- description: "Call before modifying any file to retrieve Fabric rules for a target path.",
136
- inputSchema: inputSchema2,
137
- outputSchema: outputSchema2,
138
- annotations: { readOnlyHint: true }
139
- },
140
- async ({ path, client_hash }) => {
141
- const projectRoot = resolveProjectRoot();
142
- const result = await getRules(projectRoot, { path, client_hash });
143
- return {
144
- content: [{ type: "text", text: JSON.stringify(result) }],
145
- structuredContent: result
146
- };
147
- }
148
- );
149
- }
150
-
151
- // src/tools/plan-context.ts
152
- import { z as z3 } from "zod";
153
-
154
- // src/services/plan-context.ts
155
- async function planContext(projectRoot, input) {
156
- const context = await loadGetRulesContext(projectRoot);
157
- const stale = input.client_hash !== void 0 && input.client_hash !== context.meta.revision;
158
- const uniquePaths = dedupePaths(input.paths);
159
- const fileContentCache = /* @__PURE__ */ new Map();
160
- const matchedNodesByPath = new Map(
161
- uniquePaths.map((path) => [path, matchRuleNodes(context.meta, path)])
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);
178
- return {
179
- revision_hash: context.meta.revision,
180
- stale,
181
- entries,
182
- shared
183
- };
184
- }
185
- function dedupePaths(paths) {
186
- const seenPaths = /* @__PURE__ */ new Set();
187
- return paths.flatMap((path) => {
188
- const normalizedPath = normalizeRulesPath(path);
189
- if (seenPaths.has(normalizedPath)) {
190
- return [];
191
- }
192
- seenPaths.add(normalizedPath);
193
- return [normalizedPath];
194
- });
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
- }
286
-
287
- // src/tools/plan-context.ts
288
- var inputSchema3 = {
289
- paths: z3.array(z3.string()).min(2).describe("Candidate file paths to query rules for during planning or architecture review"),
290
- client_hash: z3.string().optional().describe("Revision hash from a prior fab_plan_context response; enables stale detection")
291
- };
292
- var rulesEntrySchema2 = z3.object({ path: z3.string(), content: z3.string() });
293
- var humanLockedSchema2 = z3.object({ file: z3.string(), excerpt: z3.string() });
294
- var descriptionStubSchema2 = z3.object({ path: z3.string(), description: z3.string() });
295
- var rulesPayloadSchema = z3.object({
296
- L0: z3.string(),
297
- L1: z3.array(rulesEntrySchema2),
298
- L2: z3.array(rulesEntrySchema2),
299
- human_locked_nearby: z3.array(humanLockedSchema2),
300
- description_stubs: z3.array(descriptionStubSchema2).optional()
58
+ var requirementProfileSchema = z.object({
59
+ target_path: z.string(),
60
+ path_segments: z.array(z.string()),
61
+ extension: z.string(),
62
+ inferred_domain: z.array(z.string()),
63
+ known_tech: z.array(z.string()),
64
+ user_intent: z.string(),
65
+ intent_tokens: z.array(z.string()),
66
+ impact_hints: z.array(z.string()),
67
+ detected_entities: z.array(z.string())
301
68
  });
302
- var outputSchema3 = z3.object({
303
- revision_hash: z3.string(),
304
- stale: z3.boolean(),
305
- entries: z3.array(
306
- z3.object({
307
- path: z3.string(),
308
- rules: rulesPayloadSchema
69
+ var selectionPolicySchema = z.object({
70
+ required_levels: z.tuple([z.literal("L0"), z.literal("L2")]),
71
+ ai_selectable_levels: z.tuple([z.literal("L1")]),
72
+ final_fetch_rule: z.literal("required_stable_ids + ai_selected_l1_stable_ids")
73
+ });
74
+ var outputSchema = z.object({
75
+ revision_hash: z.string(),
76
+ stale: z.boolean(),
77
+ selection_token: z.string(),
78
+ entries: z.array(
79
+ z.object({
80
+ path: z.string(),
81
+ requirement_profile: requirementProfileSchema,
82
+ description_index: z.array(descriptionIndexItemSchema),
83
+ required_stable_ids: z.array(z.string()),
84
+ ai_selectable_stable_ids: z.array(z.string()),
85
+ initial_selected_stable_ids: z.array(z.string()),
86
+ selection_policy: selectionPolicySchema
309
87
  })
310
88
  ),
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()
89
+ shared: z.object({
90
+ required_stable_ids: z.array(z.string()),
91
+ ai_selectable_stable_ids: z.array(z.string()),
92
+ description_index: z.array(descriptionIndexItemSchema),
93
+ preflight_diagnostics: z.array(
94
+ z.object({
95
+ code: z.literal("missing_description"),
96
+ severity: z.literal("warn"),
97
+ message: z.string(),
98
+ stable_ids: z.array(z.string()).optional(),
99
+ path: z.string().optional()
345
100
  })
346
101
  )
347
102
  })
@@ -350,14 +105,22 @@ function registerPlanContext(server) {
350
105
  server.registerTool(
351
106
  "fab_plan_context",
352
107
  {
353
- description: "Use during plan or architecture phases to batch-query Fabric rules for multiple candidate paths in one round-trip. Use fab_get_rules for single-file queries; use fab_plan_context for 2+ files.",
354
- inputSchema: inputSchema3,
355
- outputSchema: outputSchema3,
108
+ description: "Use during plan or architecture phases to build a neutral Fabric rule description index and selection token before fetching rule sections.",
109
+ inputSchema,
110
+ outputSchema,
356
111
  annotations: { readOnlyHint: true }
357
112
  },
358
- async ({ paths, client_hash }) => {
113
+ async ({ paths, intent, known_tech, detected_entities, client_hash, correlation_id, session_id }) => {
359
114
  const projectRoot = resolveProjectRoot();
360
- const result = await planContext(projectRoot, { paths, client_hash });
115
+ const result = await planContext(projectRoot, {
116
+ paths,
117
+ intent,
118
+ known_tech,
119
+ detected_entities,
120
+ client_hash,
121
+ correlation_id,
122
+ session_id
123
+ });
361
124
  return {
362
125
  content: [{ type: "text", text: JSON.stringify(result) }],
363
126
  structuredContent: result
@@ -366,107 +129,50 @@ function registerPlanContext(server) {
366
129
  );
367
130
  }
368
131
 
369
- // src/tools/update-registry.ts
370
- import { agentsLayerSchema, agentsTopologyTypeSchema } from "@fenglimg/fabric-shared";
371
- import { z as z4 } from "zod";
372
-
373
- // src/services/update-registry.ts
374
- import { agentsMetaNodeSchema } from "@fenglimg/fabric-shared";
375
- import { join } from "path";
376
- async function updateRegistry(projectRoot, input) {
377
- const metaPath = join(projectRoot, FABRIC_DIR, "agents.meta.json");
378
- const currentMeta = await readAgentsMeta(projectRoot);
379
- const nextMeta = applyRegistryOperation(currentMeta, input.op, input.node_id, input.data);
380
- const newRevision = computeRevision(nextMeta);
381
- await atomicWriteText(
382
- metaPath,
383
- `${JSON.stringify(
384
- {
385
- ...nextMeta,
386
- revision: newRevision
387
- },
388
- null,
389
- 2
390
- )}
391
- `
392
- );
393
- contextCache.invalidate("meta_write", projectRoot);
394
- return {
395
- revision_hash: newRevision,
396
- success: true
397
- };
398
- }
399
- function computeRevision(meta) {
400
- const joinedHashes = Object.entries(meta.nodes).sort(([leftId], [rightId]) => leftId.localeCompare(rightId)).map(([, node]) => node.hash).join("");
401
- return sha256(joinedHashes);
402
- }
403
- function assertNodeData(data, message) {
404
- if (data === void 0) {
405
- throw new Error(message);
406
- }
407
- return agentsMetaNodeSchema.parse(data);
408
- }
409
- function applyRegistryOperation(meta, op, nodeId, data) {
410
- const nextNodes = { ...meta.nodes };
411
- if (op === "remove-node") {
412
- delete nextNodes[nodeId];
413
- return {
414
- ...meta,
415
- nodes: nextNodes
416
- };
417
- }
418
- if (op === "add-node") {
419
- nextNodes[nodeId] = assertNodeData(data, `fab_update_registry requires data for ${op}`);
420
- return {
421
- ...meta,
422
- nodes: nextNodes
423
- };
424
- }
425
- const currentNode = nextNodes[nodeId];
426
- if (currentNode === void 0) {
427
- throw new Error(`Cannot update missing Fabric registry node: ${nodeId}`);
428
- }
429
- nextNodes[nodeId] = agentsMetaNodeSchema.parse({
430
- ...currentNode,
431
- ...data
432
- });
433
- return {
434
- ...meta,
435
- nodes: nextNodes
436
- };
437
- }
438
-
439
- // src/tools/update-registry.ts
440
- var nodeInputSchema = z4.object({
441
- file: z4.string().optional(),
442
- scope_glob: z4.string().optional(),
443
- deps: z4.array(z4.string()).optional(),
444
- priority: z4.enum(["high", "medium", "low"]).optional(),
445
- layer: agentsLayerSchema.optional(),
446
- topology_type: agentsTopologyTypeSchema.optional(),
447
- hash: z4.string().optional()
448
- });
449
- var inputSchema4 = {
450
- op: z4.enum(["add-node", "remove-node", "update-node"]),
451
- node_id: z4.string(),
452
- data: nodeInputSchema.optional()
132
+ // src/tools/rule-sections.ts
133
+ import { z as z2 } from "zod";
134
+ var inputSchema2 = {
135
+ selection_token: z2.string().min(1).describe("Selection token returned by fab_plan_context"),
136
+ sections: z2.array(z2.enum(RULE_SECTION_NAMES)).min(1).describe("Structured rule sections to fetch"),
137
+ ai_selected_stable_ids: z2.array(z2.string()).describe("AI-selected L1 stable_ids chosen from fab_plan_context ai_selectable_stable_ids"),
138
+ ai_selection_reasons: z2.record(z2.string().min(1)).describe("Reason for each AI-selected L1 stable_id"),
139
+ correlation_id: z2.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
140
+ session_id: z2.string().optional().describe("Optional caller-provided session id for Event Ledger records")
453
141
  };
454
- var outputSchema4 = z4.object({
455
- success: z4.boolean(),
456
- revision_hash: z4.string()
142
+ var outputSchema2 = z2.object({
143
+ revision_hash: z2.string(),
144
+ precedence: z2.tuple([z2.literal("L2"), z2.literal("L1"), z2.literal("L0")]),
145
+ selected_stable_ids: z2.array(z2.string()),
146
+ rules: z2.array(
147
+ z2.object({
148
+ stable_id: z2.string(),
149
+ level: z2.enum(["L0", "L1", "L2"]),
150
+ path: z2.string(),
151
+ sections: z2.record(z2.string())
152
+ })
153
+ ),
154
+ diagnostics: z2.array(
155
+ z2.object({
156
+ code: z2.literal("missing_section"),
157
+ severity: z2.literal("warn"),
158
+ stable_id: z2.string(),
159
+ section: z2.enum(RULE_SECTION_NAMES),
160
+ message: z2.string()
161
+ })
162
+ )
457
163
  });
458
- function registerUpdateRegistry(server) {
164
+ function registerRuleSections(server) {
459
165
  server.registerTool(
460
- "fab_update_registry",
166
+ "fab_get_rule_sections",
461
167
  {
462
- description: "Call to add, remove, or update Fabric registry nodes. Use instead of editing .fabric/agents.meta.json directly.",
463
- inputSchema: inputSchema4,
464
- outputSchema: outputSchema4,
465
- annotations: { destructiveHint: true }
168
+ description: "Fetch structured Fabric rule sections after fab_plan_context. Required L0/L2 rules are merged with AI-selected L1 rules server-side.",
169
+ inputSchema: inputSchema2,
170
+ outputSchema: outputSchema2,
171
+ annotations: { readOnlyHint: true }
466
172
  },
467
- async ({ op, node_id, data }) => {
173
+ async (input) => {
468
174
  const projectRoot = resolveProjectRoot();
469
- const result = await updateRegistry(projectRoot, { op, node_id, data });
175
+ const result = await getRuleSections(projectRoot, input);
470
176
  return {
471
177
  content: [{ type: "text", text: JSON.stringify(result) }],
472
178
  structuredContent: result
@@ -489,12 +195,10 @@ function formatError(error) {
489
195
  function createFabricServer() {
490
196
  const server = new McpServer({
491
197
  name: "fabric-context-server",
492
- version: "1.5.2"
198
+ version: "1.7.0"
493
199
  });
494
- registerGetRules(server);
495
200
  registerPlanContext(server);
496
- registerAppendIntent(server);
497
- registerUpdateRegistry(server);
201
+ registerRuleSections(server);
498
202
  server.registerResource(
499
203
  "bootstrap README",
500
204
  AGENTS_MD_RESOURCE_URI,
@@ -504,7 +208,7 @@ function createFabricServer() {
504
208
  },
505
209
  async (_uri) => {
506
210
  const projectRoot = process.env.FABRIC_PROJECT_ROOT ?? process.cwd();
507
- const content = await readFile(join2(projectRoot, ".fabric", "bootstrap", "README.md"), "utf8");
211
+ const content = await readFile(join(projectRoot, ".fabric", "bootstrap", "README.md"), "utf8");
508
212
  return {
509
213
  contents: [
510
214
  {
@@ -524,7 +228,7 @@ async function startStdioServer() {
524
228
  await server.connect(transport);
525
229
  }
526
230
  async function startHttpServer(options) {
527
- const { createFabricHttpApp } = await import("./http-U4S7BUP4.js");
231
+ const { createFabricHttpApp } = await import("./http-6LFZLHCN.js");
528
232
  const { port, projectRoot, host = "127.0.0.1", authToken, dashboardDistPath, dev } = options;
529
233
  const app = createFabricHttpApp({ projectRoot, host, authToken, dashboardDistPath, dev });
530
234
  return await new Promise((resolveServer, rejectServer) => {
@@ -551,17 +255,23 @@ if (isMainModule) {
551
255
  }
552
256
  export {
553
257
  AGENTS_MD_RESOURCE_URI,
258
+ EVENT_LEDGER_PATH,
554
259
  LEDGER_PATH,
555
260
  LEGACY_LEDGER_PATH,
556
- approveHumanLock,
261
+ buildRuleMeta,
262
+ computeRuleTestIndex,
263
+ computeRulesBasedAgentsMeta,
557
264
  createFabricServer,
265
+ deriveRuleMetaLayer,
266
+ deriveRuleMetaTopologyType,
267
+ getEventLedgerPath,
558
268
  getLedgerPath,
559
269
  getLegacyLedgerPath,
560
- readHumanLock,
561
- readHumanLockEntry,
562
- runDoctorAuditReport,
270
+ isSameRuleTestIndex,
563
271
  runDoctorFix,
564
272
  runDoctorReport,
273
+ stableStringify,
565
274
  startHttpServer,
566
- startStdioServer
275
+ startStdioServer,
276
+ writeRuleMeta
567
277
  };