@fenglimg/fabric-server 1.2.0 → 1.3.1
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/{chunk-U3IQH5H6.js → chunk-GU7AMRM3.js} +186 -14
- package/dist/{http-EQBDM4C7.js → http-6V75VA23.js} +142 -20
- package/dist/index.d.ts +7 -1
- package/dist/index.js +163 -76
- package/dist/static/assets/index-DvqI1Lwz.js +10 -0
- package/dist/static/index.html +13 -13
- package/package.json +3 -3
- package/dist/static/assets/index-_hQ_P7Zz.js +0 -5
package/dist/index.js
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AGENTS_MD_RESOURCE_URI,
|
|
2
3
|
FABRIC_DIR,
|
|
3
4
|
appendEditIntentAuditEvents,
|
|
4
5
|
appendGetRulesAuditEvent,
|
|
5
6
|
appendLedgerEntry,
|
|
6
7
|
atomicWriteText,
|
|
8
|
+
contextCache,
|
|
7
9
|
readAgentsMeta,
|
|
8
10
|
readHumanLock,
|
|
9
11
|
resolveProjectRoot,
|
|
10
12
|
runDoctorAuditReport,
|
|
11
13
|
runDoctorReport,
|
|
12
14
|
sha256
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-GU7AMRM3.js";
|
|
14
16
|
|
|
15
17
|
// src/index.ts
|
|
16
|
-
import {
|
|
18
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
19
|
+
import { join as join3, resolve } from "path";
|
|
17
20
|
import { fileURLToPath } from "url";
|
|
18
21
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
19
22
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
23
|
|
|
21
24
|
// src/tools/append-intent.ts
|
|
22
25
|
import { aiLedgerEntrySchema } from "@fenglimg/fabric-shared";
|
|
26
|
+
import { z } from "zod";
|
|
23
27
|
|
|
24
28
|
// src/services/append-intent.ts
|
|
25
29
|
async function appendIntent(projectRoot, input) {
|
|
@@ -29,19 +33,22 @@ async function appendIntent(projectRoot, input) {
|
|
|
29
33
|
ts,
|
|
30
34
|
source: "ai"
|
|
31
35
|
});
|
|
36
|
+
let compliance;
|
|
32
37
|
try {
|
|
33
|
-
await appendEditIntentAuditEvents(projectRoot, {
|
|
38
|
+
const auditResult = await appendEditIntentAuditEvents(projectRoot, {
|
|
34
39
|
affected_paths: entry.affected_paths,
|
|
35
40
|
intent: entry.intent,
|
|
36
41
|
ledger_entry_id: entry.id,
|
|
37
42
|
ts
|
|
38
43
|
});
|
|
44
|
+
compliance = auditResult.compliance;
|
|
39
45
|
} catch {
|
|
40
46
|
}
|
|
41
47
|
return {
|
|
42
48
|
success: true,
|
|
43
49
|
timestamp: ts,
|
|
44
|
-
entry
|
|
50
|
+
entry,
|
|
51
|
+
compliance
|
|
45
52
|
};
|
|
46
53
|
}
|
|
47
54
|
|
|
@@ -53,31 +60,44 @@ var inputSchema = {
|
|
|
53
60
|
ts: true
|
|
54
61
|
})
|
|
55
62
|
};
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
}
|
|
63
|
+
var outputSchema = z.object({
|
|
64
|
+
success: z.boolean(),
|
|
65
|
+
timestamp: z.number(),
|
|
66
|
+
entry: z.record(z.unknown()),
|
|
67
|
+
compliance: z.object({
|
|
68
|
+
compliant: z.boolean(),
|
|
69
|
+
matched_get_rules_ts: z.string().nullable(),
|
|
70
|
+
window_ms: z.number()
|
|
71
|
+
}).optional()
|
|
72
|
+
});
|
|
66
73
|
function registerAppendIntent(server) {
|
|
67
|
-
server.
|
|
74
|
+
server.registerTool(
|
|
68
75
|
"fab_append_intent",
|
|
69
|
-
|
|
70
|
-
|
|
76
|
+
{
|
|
77
|
+
description: "Call after a completed task to append an intent ledger entry for Fabric.",
|
|
78
|
+
inputSchema,
|
|
79
|
+
outputSchema,
|
|
80
|
+
annotations: { readOnlyHint: false }
|
|
81
|
+
},
|
|
71
82
|
async ({ entry }) => {
|
|
72
83
|
const projectRoot = resolveProjectRoot();
|
|
73
84
|
const result = await appendIntent(projectRoot, { entry });
|
|
74
|
-
|
|
85
|
+
const structuredContent = {
|
|
86
|
+
success: result.success,
|
|
87
|
+
timestamp: result.timestamp,
|
|
88
|
+
entry: { ...result.entry },
|
|
89
|
+
compliance: result.compliance
|
|
90
|
+
};
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
93
|
+
structuredContent
|
|
94
|
+
};
|
|
75
95
|
}
|
|
76
96
|
);
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
// src/tools/get-rules.ts
|
|
80
|
-
import { z } from "zod";
|
|
100
|
+
import { z as z2 } from "zod";
|
|
81
101
|
|
|
82
102
|
// src/services/get-rules.ts
|
|
83
103
|
import { readFile } from "fs/promises";
|
|
@@ -107,17 +127,23 @@ async function getRules(projectRoot, input) {
|
|
|
107
127
|
return result;
|
|
108
128
|
}
|
|
109
129
|
async function loadGetRulesContext(projectRoot) {
|
|
110
|
-
const
|
|
111
|
-
|
|
130
|
+
const cached = contextCache.get("context", projectRoot);
|
|
131
|
+
if (cached !== void 0) {
|
|
132
|
+
return cached;
|
|
133
|
+
}
|
|
134
|
+
const meta = await readAgentsMeta(projectRoot);
|
|
135
|
+
const l0Content = await readFile(join(projectRoot, ".fabric", "bootstrap", "README.md"), "utf8");
|
|
112
136
|
const humanLockedNearby = (await readHumanLock(projectRoot)).map((entry) => ({
|
|
113
137
|
file: entry.file,
|
|
114
138
|
excerpt: JSON.stringify(entry)
|
|
115
139
|
}));
|
|
116
|
-
|
|
140
|
+
const context = {
|
|
117
141
|
meta,
|
|
118
142
|
l0Content,
|
|
119
143
|
humanLockedNearby
|
|
120
144
|
};
|
|
145
|
+
contextCache.set("context", projectRoot, context);
|
|
146
|
+
return context;
|
|
121
147
|
}
|
|
122
148
|
async function resolveRulesForPath(projectRoot, context, path, options = {}) {
|
|
123
149
|
const loadedRules = await loadRulesForPath(projectRoot, context.meta, path);
|
|
@@ -189,34 +215,43 @@ function dedupeEntriesByPath(entries) {
|
|
|
189
215
|
|
|
190
216
|
// src/tools/get-rules.ts
|
|
191
217
|
var inputSchema2 = {
|
|
192
|
-
path:
|
|
193
|
-
client_hash:
|
|
218
|
+
path: z2.string().describe("Target file path to query rules for"),
|
|
219
|
+
client_hash: z2.string().optional().describe("Revision hash from prior fab_get_rules response; enables stale detection")
|
|
194
220
|
};
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
221
|
+
var rulesEntrySchema = z2.object({ path: z2.string(), content: z2.string() });
|
|
222
|
+
var humanLockedSchema = z2.object({ file: z2.string(), excerpt: z2.string() });
|
|
223
|
+
var outputSchema2 = z2.object({
|
|
224
|
+
revision_hash: z2.string(),
|
|
225
|
+
stale: z2.boolean(),
|
|
226
|
+
rules: z2.object({
|
|
227
|
+
L0: z2.string(),
|
|
228
|
+
L1: z2.array(rulesEntrySchema),
|
|
229
|
+
L2: z2.array(rulesEntrySchema),
|
|
230
|
+
human_locked_nearby: z2.array(humanLockedSchema)
|
|
231
|
+
})
|
|
232
|
+
});
|
|
205
233
|
function registerGetRules(server) {
|
|
206
|
-
server.
|
|
234
|
+
server.registerTool(
|
|
207
235
|
"fab_get_rules",
|
|
208
|
-
|
|
209
|
-
|
|
236
|
+
{
|
|
237
|
+
description: "Call before modifying any file to retrieve Fabric rules for a target path.",
|
|
238
|
+
inputSchema: inputSchema2,
|
|
239
|
+
outputSchema: outputSchema2,
|
|
240
|
+
annotations: { readOnlyHint: true }
|
|
241
|
+
},
|
|
210
242
|
async ({ path, client_hash }) => {
|
|
211
243
|
const projectRoot = resolveProjectRoot();
|
|
212
244
|
const result = await getRules(projectRoot, { path, client_hash });
|
|
213
|
-
return
|
|
245
|
+
return {
|
|
246
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
247
|
+
structuredContent: result
|
|
248
|
+
};
|
|
214
249
|
}
|
|
215
250
|
);
|
|
216
251
|
}
|
|
217
252
|
|
|
218
253
|
// src/tools/plan-context.ts
|
|
219
|
-
import { z as
|
|
254
|
+
import { z as z3 } from "zod";
|
|
220
255
|
|
|
221
256
|
// src/services/plan-context.ts
|
|
222
257
|
async function planContext(projectRoot, input) {
|
|
@@ -249,41 +284,57 @@ function dedupePaths(paths) {
|
|
|
249
284
|
|
|
250
285
|
// src/tools/plan-context.ts
|
|
251
286
|
var inputSchema3 = {
|
|
252
|
-
paths:
|
|
253
|
-
client_hash:
|
|
287
|
+
paths: z3.array(z3.string()).min(2).describe("Candidate file paths to query rules for during planning or architecture review"),
|
|
288
|
+
client_hash: z3.string().optional().describe("Revision hash from a prior fab_plan_context response; enables stale detection")
|
|
254
289
|
};
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
290
|
+
var rulesEntrySchema2 = z3.object({ path: z3.string(), content: z3.string() });
|
|
291
|
+
var humanLockedSchema2 = z3.object({ file: z3.string(), excerpt: z3.string() });
|
|
292
|
+
var rulesPayloadSchema = z3.object({
|
|
293
|
+
L0: z3.string(),
|
|
294
|
+
L1: z3.array(rulesEntrySchema2),
|
|
295
|
+
L2: z3.array(rulesEntrySchema2),
|
|
296
|
+
human_locked_nearby: z3.array(humanLockedSchema2)
|
|
297
|
+
});
|
|
298
|
+
var outputSchema3 = z3.object({
|
|
299
|
+
revision_hash: z3.string(),
|
|
300
|
+
stale: z3.boolean(),
|
|
301
|
+
entries: z3.array(
|
|
302
|
+
z3.object({
|
|
303
|
+
path: z3.string(),
|
|
304
|
+
rules: rulesPayloadSchema
|
|
305
|
+
})
|
|
306
|
+
)
|
|
307
|
+
});
|
|
265
308
|
function registerPlanContext(server) {
|
|
266
|
-
server.
|
|
309
|
+
server.registerTool(
|
|
267
310
|
"fab_plan_context",
|
|
268
|
-
|
|
269
|
-
|
|
311
|
+
{
|
|
312
|
+
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.",
|
|
313
|
+
inputSchema: inputSchema3,
|
|
314
|
+
outputSchema: outputSchema3,
|
|
315
|
+
annotations: { readOnlyHint: true }
|
|
316
|
+
},
|
|
270
317
|
async ({ paths, client_hash }) => {
|
|
271
318
|
const projectRoot = resolveProjectRoot();
|
|
272
319
|
const result = await planContext(projectRoot, { paths, client_hash });
|
|
273
|
-
return
|
|
320
|
+
return {
|
|
321
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
322
|
+
structuredContent: result
|
|
323
|
+
};
|
|
274
324
|
}
|
|
275
325
|
);
|
|
276
326
|
}
|
|
277
327
|
|
|
278
328
|
// src/tools/update-registry.ts
|
|
279
|
-
import {
|
|
329
|
+
import { agentsLayerSchema, agentsTopologyTypeSchema } from "@fenglimg/fabric-shared";
|
|
330
|
+
import { z as z4 } from "zod";
|
|
280
331
|
|
|
281
332
|
// src/services/update-registry.ts
|
|
282
333
|
import { agentsMetaNodeSchema } from "@fenglimg/fabric-shared";
|
|
283
334
|
import { join as join2 } from "path";
|
|
284
335
|
async function updateRegistry(projectRoot, input) {
|
|
285
336
|
const metaPath = join2(projectRoot, FABRIC_DIR, "agents.meta.json");
|
|
286
|
-
const currentMeta = readAgentsMeta(projectRoot);
|
|
337
|
+
const currentMeta = await readAgentsMeta(projectRoot);
|
|
287
338
|
const nextMeta = applyRegistryOperation(currentMeta, input.op, input.node_id, input.data);
|
|
288
339
|
const newRevision = computeRevision(nextMeta);
|
|
289
340
|
await atomicWriteText(
|
|
@@ -298,6 +349,7 @@ async function updateRegistry(projectRoot, input) {
|
|
|
298
349
|
)}
|
|
299
350
|
`
|
|
300
351
|
);
|
|
352
|
+
contextCache.invalidate("meta_write", projectRoot);
|
|
301
353
|
return {
|
|
302
354
|
revision_hash: newRevision,
|
|
303
355
|
success: true
|
|
@@ -344,30 +396,40 @@ function applyRegistryOperation(meta, op, nodeId, data) {
|
|
|
344
396
|
}
|
|
345
397
|
|
|
346
398
|
// src/tools/update-registry.ts
|
|
399
|
+
var nodeInputSchema = z4.object({
|
|
400
|
+
file: z4.string().optional(),
|
|
401
|
+
scope_glob: z4.string().optional(),
|
|
402
|
+
deps: z4.array(z4.string()).optional(),
|
|
403
|
+
priority: z4.enum(["high", "medium", "low"]).optional(),
|
|
404
|
+
layer: agentsLayerSchema.optional(),
|
|
405
|
+
topology_type: agentsTopologyTypeSchema.optional(),
|
|
406
|
+
hash: z4.string().optional()
|
|
407
|
+
});
|
|
347
408
|
var inputSchema4 = {
|
|
348
|
-
op:
|
|
349
|
-
node_id:
|
|
350
|
-
data:
|
|
409
|
+
op: z4.enum(["add-node", "remove-node", "update-node"]),
|
|
410
|
+
node_id: z4.string(),
|
|
411
|
+
data: nodeInputSchema.optional()
|
|
351
412
|
};
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
type: "text",
|
|
357
|
-
text: JSON.stringify(payload)
|
|
358
|
-
}
|
|
359
|
-
]
|
|
360
|
-
};
|
|
361
|
-
}
|
|
413
|
+
var outputSchema4 = z4.object({
|
|
414
|
+
success: z4.boolean(),
|
|
415
|
+
revision_hash: z4.string()
|
|
416
|
+
});
|
|
362
417
|
function registerUpdateRegistry(server) {
|
|
363
|
-
server.
|
|
418
|
+
server.registerTool(
|
|
364
419
|
"fab_update_registry",
|
|
365
|
-
|
|
366
|
-
|
|
420
|
+
{
|
|
421
|
+
description: "Call to add, remove, or update Fabric registry nodes. Use instead of editing .fabric/agents.meta.json directly.",
|
|
422
|
+
inputSchema: inputSchema4,
|
|
423
|
+
outputSchema: outputSchema4,
|
|
424
|
+
annotations: { destructiveHint: true }
|
|
425
|
+
},
|
|
367
426
|
async ({ op, node_id, data }) => {
|
|
368
427
|
const projectRoot = resolveProjectRoot();
|
|
369
428
|
const result = await updateRegistry(projectRoot, { op, node_id, data });
|
|
370
|
-
return
|
|
429
|
+
return {
|
|
430
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
431
|
+
structuredContent: result
|
|
432
|
+
};
|
|
371
433
|
}
|
|
372
434
|
);
|
|
373
435
|
}
|
|
@@ -386,12 +448,33 @@ function formatError(error) {
|
|
|
386
448
|
function createFabricServer() {
|
|
387
449
|
const server = new McpServer({
|
|
388
450
|
name: "fabric-context-server",
|
|
389
|
-
version: "1.
|
|
451
|
+
version: "1.3.1"
|
|
390
452
|
});
|
|
391
453
|
registerGetRules(server);
|
|
392
454
|
registerPlanContext(server);
|
|
393
455
|
registerAppendIntent(server);
|
|
394
456
|
registerUpdateRegistry(server);
|
|
457
|
+
server.registerResource(
|
|
458
|
+
"bootstrap README",
|
|
459
|
+
AGENTS_MD_RESOURCE_URI,
|
|
460
|
+
{
|
|
461
|
+
description: "L0 fabric bootstrap file \u2014 global agent instructions for this project",
|
|
462
|
+
mimeType: "text/markdown"
|
|
463
|
+
},
|
|
464
|
+
async (_uri) => {
|
|
465
|
+
const projectRoot = process.env.FABRIC_PROJECT_ROOT ?? process.cwd();
|
|
466
|
+
const content = await readFile2(join3(projectRoot, ".fabric", "bootstrap", "README.md"), "utf8");
|
|
467
|
+
return {
|
|
468
|
+
contents: [
|
|
469
|
+
{
|
|
470
|
+
uri: AGENTS_MD_RESOURCE_URI,
|
|
471
|
+
mimeType: "text/markdown",
|
|
472
|
+
text: content
|
|
473
|
+
}
|
|
474
|
+
]
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
);
|
|
395
478
|
return server;
|
|
396
479
|
}
|
|
397
480
|
async function startStdioServer() {
|
|
@@ -400,11 +483,14 @@ async function startStdioServer() {
|
|
|
400
483
|
await server.connect(transport);
|
|
401
484
|
}
|
|
402
485
|
async function startHttpServer(options) {
|
|
403
|
-
const { createFabricHttpApp } = await import("./http-
|
|
486
|
+
const { createFabricHttpApp } = await import("./http-6V75VA23.js");
|
|
404
487
|
const { port, projectRoot, host = "127.0.0.1", authToken, dashboardDistPath, dev } = options;
|
|
405
488
|
const app = createFabricHttpApp({ projectRoot, host, authToken, dashboardDistPath, dev });
|
|
406
489
|
return await new Promise((resolveServer, rejectServer) => {
|
|
407
490
|
const server = app.listen(port, host);
|
|
491
|
+
server.once("close", () => {
|
|
492
|
+
void app.dispose();
|
|
493
|
+
});
|
|
408
494
|
server.once("listening", () => {
|
|
409
495
|
resolveServer(server);
|
|
410
496
|
});
|
|
@@ -423,6 +509,7 @@ if (isMainModule) {
|
|
|
423
509
|
});
|
|
424
510
|
}
|
|
425
511
|
export {
|
|
512
|
+
AGENTS_MD_RESOURCE_URI,
|
|
426
513
|
createFabricServer,
|
|
427
514
|
runDoctorAuditReport,
|
|
428
515
|
runDoctorReport,
|