@fragments-sdk/mcp 0.10.1 → 1.0.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/index.js CHANGED
@@ -1,223 +1,1123 @@
1
- import {
2
- AutoExtractionAdapter,
3
- BUILTIN_TOOLS,
4
- CORE_TOOLS,
5
- FragmentsJsonAdapter,
6
- INFRA_TOOLS,
7
- ToolRegistry,
8
- VIEWER_TOOLS,
9
- blockFromCompiledBlock,
10
- buildCapabilities,
11
- componentFromCompiledFragment,
12
- createMcpServer,
13
- createSandboxServer,
14
- executeWithMiddleware,
15
- loadConfigFile,
16
- startMcpServer,
17
- telemetryMiddleware,
18
- tokensFromCompiledTokenData,
19
- validateSnapshot
20
- } from "./chunk-KGFM5SCE.js";
21
- import {
22
- generateRulesFiles
23
- } from "./chunk-WDQPNHZ2.js";
24
- import "./chunk-7D4SUZUM.js";
1
+ // src/apps/resources.ts
2
+ var MCP_APP_RESOURCES = [];
3
+ function getResource(_uri) {
4
+ return null;
5
+ }
6
+ function listResources() {
7
+ return [];
8
+ }
25
9
 
26
- // src/adapters/custom-json.ts
27
- import { readFile } from "fs/promises";
28
- import { existsSync } from "fs";
29
- import { mcpSnapshotSchema } from "@fragments-sdk/core";
30
- var CustomJsonAdapter = class {
31
- constructor(filePath) {
32
- this.filePath = filePath;
33
- }
34
- filePath;
35
- name = "custom-json";
36
- discover() {
37
- return existsSync(this.filePath) ? [this.filePath] : [];
38
- }
39
- async load(_projectRoot = "") {
40
- if (!existsSync(this.filePath)) {
41
- throw new Error(`Custom data file not found: ${this.filePath}`);
42
- }
43
- const content = await readFile(this.filePath, "utf-8");
44
- const raw = JSON.parse(content);
45
- if (raw.schemaVersion === 1 && typeof raw.sourceType === "string" && raw.components && typeof raw.components === "object") {
46
- const snapshot2 = mcpSnapshotSchema.parse(raw);
47
- return {
48
- snapshot: snapshot2,
49
- components: snapshot2.components,
50
- blocks: snapshot2.blocks,
51
- tokens: snapshot2.tokens,
52
- graph: snapshot2.graph,
53
- performanceSummary: snapshot2.performanceSummary,
54
- packageMap: snapshot2.packageMap,
55
- defaultPackageName: snapshot2.defaultPackageName,
56
- capabilities: new Set(snapshot2.capabilities)
10
+ // src/tasks/store.ts
11
+ var nextTaskId = 1;
12
+ function createTaskId() {
13
+ const id = `task_${String(nextTaskId).padStart(6, "0")}`;
14
+ nextTaskId += 1;
15
+ return id;
16
+ }
17
+ var MemoryTaskStore = class {
18
+ tasks = /* @__PURE__ */ new Map();
19
+ async create(input) {
20
+ const now = Date.now();
21
+ const result = input.result ?? completedWorkflowResult(input.workflow?.kind);
22
+ const task = {
23
+ taskId: createTaskId(),
24
+ title: input.title,
25
+ status: result ? "completed" : "working",
26
+ createdAt: now,
27
+ updatedAt: now,
28
+ ttlMs: input.ttlMs ?? 15 * 60 * 1e3,
29
+ pollIntervalMs: input.pollIntervalMs ?? 1e3,
30
+ result,
31
+ progress: result ? { current: 1, total: 1, message: "Completed" } : { current: 0, total: 1, message: "Queued" }
32
+ };
33
+ this.tasks.set(task.taskId, task);
34
+ return task;
35
+ }
36
+ async get(taskId) {
37
+ return this.tasks.get(taskId) ?? null;
38
+ }
39
+ async update(taskId, patch) {
40
+ const existing = this.tasks.get(taskId);
41
+ if (!existing) return null;
42
+ const next = {
43
+ ...existing,
44
+ ...patch,
45
+ taskId,
46
+ updatedAt: Date.now()
47
+ };
48
+ this.tasks.set(taskId, next);
49
+ return next;
50
+ }
51
+ async cancel(taskId) {
52
+ return this.update(taskId, {
53
+ status: "cancelled",
54
+ progress: { message: "Cancellation requested" }
55
+ });
56
+ }
57
+ };
58
+ function completedWorkflowResult(kind) {
59
+ if (!kind) return void 0;
60
+ return {
61
+ content: [{ type: "text", text: `${kind} queued.` }],
62
+ structuredContent: {
63
+ kind,
64
+ status: "queued",
65
+ message: "Fragments accepted the workflow request. The hosted runtime attaches concrete job details."
66
+ }
67
+ };
68
+ }
69
+
70
+ // src/spec/generated/schema.ts
71
+ var LATEST_PROTOCOL_VERSION = "DRAFT-2026-v1";
72
+ var JSONRPC_VERSION = "2.0";
73
+
74
+ // src/tools/primitives.ts
75
+ var primitiveSchema = {
76
+ type: "object",
77
+ properties: {
78
+ id: { type: "string" },
79
+ name: { type: "string" },
80
+ primitiveName: { type: "string" },
81
+ filePath: { type: ["string", "null"] },
82
+ importPath: { type: ["string", "null"] },
83
+ packageName: { type: ["string", "null"] },
84
+ description: { type: "string" },
85
+ usageGuidance: { type: "string" },
86
+ props: { type: "object" },
87
+ examples: { type: "array" },
88
+ sourceRepoFullName: { type: ["string", "null"] }
89
+ },
90
+ required: ["id", "name", "primitiveName", "filePath", "importPath"],
91
+ additionalProperties: true
92
+ };
93
+ var primitiveTools = [
94
+ {
95
+ name: "design_system/list_primitives",
96
+ title: "List Primitives",
97
+ description: "List the design-system primitives curated in Fragments Cloud. Returns only reviewed primitives with their source file paths.",
98
+ inputSchema: {
99
+ type: "object",
100
+ properties: {},
101
+ additionalProperties: false,
102
+ maxProperties: 0
103
+ },
104
+ outputSchema: {
105
+ type: "object",
106
+ properties: {
107
+ primitiveCount: { type: "integer" },
108
+ primitives: { type: "array", items: primitiveSchema }
109
+ },
110
+ required: ["primitiveCount", "primitives"],
111
+ additionalProperties: false
112
+ },
113
+ annotations: {
114
+ readOnlyHint: true,
115
+ idempotentHint: true
116
+ },
117
+ async call(_args, context) {
118
+ const primitives = await context.provider.listPrimitives();
119
+ return primitiveResult(primitives);
120
+ }
121
+ }
122
+ ];
123
+ function primitiveResult(primitives) {
124
+ return {
125
+ content: [
126
+ {
127
+ type: "text",
128
+ text: primitives.length === 0 ? "No primitives have been selected in Fragments Cloud yet." : `Found ${primitives.length} primitives.`
129
+ }
130
+ ],
131
+ structuredContent: {
132
+ primitiveCount: primitives.length,
133
+ primitives: primitives.map(normalizePrimitive)
134
+ }
135
+ };
136
+ }
137
+ function normalizePrimitive(primitive) {
138
+ return {
139
+ id: primitive.id,
140
+ name: primitive.name,
141
+ primitiveName: primitive.primitiveName ?? primitive.name,
142
+ filePath: primitive.filePath ?? null,
143
+ importPath: primitive.importPath ?? null,
144
+ packageName: primitive.packageName ?? null,
145
+ description: primitive.description ?? "",
146
+ usageGuidance: primitive.usageGuidance ?? "",
147
+ props: primitive.props ?? {},
148
+ examples: primitive.examples ?? [],
149
+ sourceRepoFullName: primitive.sourceRepoFullName ?? null
150
+ };
151
+ }
152
+
153
+ // src/tools/conform.ts
154
+ var locationSchema = {
155
+ type: "object",
156
+ properties: {
157
+ line: { type: "integer" },
158
+ column: { type: "integer" },
159
+ endLine: { type: "integer" },
160
+ endColumn: { type: "integer" }
161
+ },
162
+ additionalProperties: false
163
+ };
164
+ var changeSchema = {
165
+ type: "object",
166
+ properties: {
167
+ kind: {
168
+ type: "string",
169
+ enum: ["swap-component", "rewrite-import", "rename-prop", "replace-token", "add-fallback"]
170
+ },
171
+ ruleId: { type: "string" },
172
+ code: { type: "string" },
173
+ severity: { type: "string", enum: ["error", "warning", "info"] },
174
+ message: { type: "string" },
175
+ before: { type: "string" },
176
+ after: { type: "string" },
177
+ canonical: { type: "string" },
178
+ confidence: { type: "string", enum: ["high", "medium", "low"] },
179
+ location: locationSchema
180
+ },
181
+ required: ["kind", "severity", "message", "confidence"],
182
+ additionalProperties: false
183
+ };
184
+ var suggestionSchema = {
185
+ type: "object",
186
+ properties: {
187
+ kind: {
188
+ type: "string",
189
+ enum: ["map-prop-value", "choose-among-alternates", "review-low-confidence"]
190
+ },
191
+ message: { type: "string" },
192
+ canonical: { type: "string" },
193
+ hint: { type: "string" },
194
+ confidence: { type: "string", enum: ["high", "medium", "low"] },
195
+ location: locationSchema
196
+ },
197
+ required: ["kind", "message", "confidence"],
198
+ additionalProperties: false
199
+ };
200
+ var unresolvedSchema = {
201
+ type: "object",
202
+ properties: {
203
+ element: { type: "string" },
204
+ canonical: { type: "string" },
205
+ reason: { type: "string" },
206
+ location: locationSchema
207
+ },
208
+ required: ["reason"],
209
+ additionalProperties: false
210
+ };
211
+ var conformTools = [
212
+ {
213
+ name: "design_system/conform",
214
+ title: "Conform to Design System",
215
+ description: "Rewrite a snippet of UI code so it matches THIS project's design system. Swaps raw HTML elements and components from other libraries (Material UI, shadcn/ui, Chakra, or custom) to the project's own components and import paths, replaces hardcoded colors/spacing/radii with the project's design tokens, and flags accessibility gaps. Call this whenever the user says 'fix this', 'make this match our design system', 'use our components here', right after pasting markup from elsewhere, or before committing UI you wrote. Input is the code itself \u2014 no repo access needed. Returns a conformed version plus a list of changes with rationale; ambiguous cross-library prop changes come back as suggestions for you to apply.",
216
+ inputSchema: {
217
+ type: "object",
218
+ properties: {
219
+ code: {
220
+ type: "string",
221
+ description: "The UI code to conform (JSX/TSX, HTML, or a CSS/SCSS block)."
222
+ },
223
+ filename: {
224
+ type: "string",
225
+ description: "Filename or extension hint for parser selection (e.g. 'Form.tsx', 'styles.scss'). Defaults to TSX."
226
+ },
227
+ apply: {
228
+ type: "string",
229
+ enum: ["deterministic", "none"],
230
+ description: "deterministic (default): return code with safe edits applied. none: findings only."
231
+ }
232
+ },
233
+ required: ["code"],
234
+ additionalProperties: false
235
+ },
236
+ outputSchema: {
237
+ type: "object",
238
+ properties: {
239
+ conformed: { type: "string" },
240
+ changed: { type: "boolean" },
241
+ summary: { type: "string" },
242
+ designSystem: {
243
+ type: "object",
244
+ properties: {
245
+ name: { type: "string" },
246
+ importsAdded: { type: "array", items: { type: "string" } }
247
+ },
248
+ required: ["importsAdded"],
249
+ additionalProperties: false
250
+ },
251
+ changes: { type: "array", items: changeSchema },
252
+ suggestions: { type: "array", items: suggestionSchema },
253
+ unresolved: { type: "array", items: unresolvedSchema }
254
+ },
255
+ required: ["conformed", "changed", "changes", "suggestions"],
256
+ additionalProperties: false
257
+ },
258
+ annotations: {
259
+ readOnlyHint: true,
260
+ idempotentHint: true,
261
+ // Output depends on the `code` argument, so it must not be served from a
262
+ // tenant-wide cache the way argument-free tools (list_primitives) are.
263
+ cacheScope: "none",
264
+ ttlMs: 0
265
+ },
266
+ async call(args, context) {
267
+ const input = {
268
+ code: typeof args.code === "string" ? args.code : "",
269
+ filename: typeof args.filename === "string" ? args.filename : void 0,
270
+ apply: args.apply === "none" ? "none" : "deterministic"
57
271
  };
272
+ const result = await context.provider.conform(input);
273
+ return conformResult(result);
58
274
  }
59
- if (!raw.components || typeof raw.components !== "object") {
60
- throw new Error(
61
- `Invalid design system data: "components" field is required and must be an object. File: ${this.filePath}`
62
- );
63
- }
64
- const packageMap = raw.packageMap ?? {};
65
- const defaultPackageName = raw.defaultPackageName;
66
- const metadata = raw.metadata;
67
- const components = Object.fromEntries(
68
- Object.entries(raw.components).map(
69
- ([key, fragment]) => [
70
- key,
71
- componentFromCompiledFragment({
72
- id: key,
73
- fragment,
74
- sourceType: "custom-json",
75
- packageName: packageMap[fragment.meta.name] ?? defaultPackageName,
76
- importPath: packageMap[fragment.meta.name] ?? defaultPackageName
77
- })
78
- ]
79
- )
80
- );
81
- const blocks = raw.blocks ? Object.fromEntries(
82
- Object.entries(raw.blocks).map(
83
- ([key, block]) => [key, blockFromCompiledBlock(key, block)]
84
- )
85
- ) : void 0;
86
- const tokens = raw.tokens ? tokensFromCompiledTokenData(raw.tokens) : void 0;
87
- const snapshot = validateSnapshot({
88
- schemaVersion: 1,
89
- sourceType: "custom-json",
90
- sourceLabel: this.filePath,
91
- capabilities: buildCapabilities({
92
- components,
93
- blocks,
94
- tokens,
95
- graph: raw.graph,
96
- performanceSummary: raw.performanceSummary
97
- }),
98
- metadata: {
99
- designSystemName: metadata?.designSystemName,
100
- packageName: metadata?.packageName ?? defaultPackageName,
101
- importPath: metadata?.importPath ?? defaultPackageName,
102
- revision: metadata?.revision,
103
- updatedAt: metadata?.updatedAt
275
+ }
276
+ ];
277
+ function conformResult(result) {
278
+ const summary = result.summary || defaultSummary(result);
279
+ return {
280
+ content: [{ type: "text", text: summary }],
281
+ structuredContent: {
282
+ conformed: result.conformed,
283
+ changed: result.changed,
284
+ summary,
285
+ ...result.designSystem ? {
286
+ designSystem: {
287
+ ...result.designSystem.name ? { name: result.designSystem.name } : {},
288
+ importsAdded: result.designSystem.importsAdded ?? []
289
+ }
290
+ } : {},
291
+ changes: result.changes,
292
+ suggestions: result.suggestions,
293
+ unresolved: result.unresolved
294
+ }
295
+ };
296
+ }
297
+ function defaultSummary(result) {
298
+ if (!result.changed && result.changes.length === 0) {
299
+ return "No conformance changes were applied.";
300
+ }
301
+ return `Applied ${result.changes.length} change(s); ${result.suggestions.length} suggestion(s) left for review.`;
302
+ }
303
+
304
+ // src/tools/prove-compliant-schema.ts
305
+ var locationSchema2 = {
306
+ type: "object",
307
+ properties: {
308
+ line: { type: "integer" },
309
+ column: { type: "integer" },
310
+ endLine: { type: "integer" },
311
+ endColumn: { type: "integer" }
312
+ },
313
+ additionalProperties: false
314
+ };
315
+ var residualSchema = {
316
+ type: "object",
317
+ properties: {
318
+ reason: { type: "string" },
319
+ message: { type: "string" },
320
+ canonical: { type: "string" },
321
+ element: { type: "string" },
322
+ hint: { type: "string" },
323
+ confidence: { type: "string" },
324
+ location: locationSchema2
325
+ },
326
+ additionalProperties: true
327
+ };
328
+ var proveCompliantOutputSchema = {
329
+ type: "object",
330
+ properties: {
331
+ provedCompliant: { type: "boolean" },
332
+ conformed: { type: "string" },
333
+ changed: { type: "boolean" },
334
+ passes: { type: "integer" },
335
+ maxPasses: { type: "integer" },
336
+ initialIssueCount: { type: "integer" },
337
+ finalIssueCount: { type: "integer" },
338
+ corrections: { type: "integer" },
339
+ summary: { type: "string" },
340
+ taskId: { type: "string" },
341
+ changes: { type: "array", items: { type: "object", additionalProperties: true } },
342
+ suggestions: { type: "array", items: residualSchema },
343
+ unresolved: { type: "array", items: residualSchema },
344
+ passHistory: { type: "array", items: { type: "object", additionalProperties: true } }
345
+ },
346
+ required: [
347
+ "provedCompliant",
348
+ "conformed",
349
+ "changed",
350
+ "passes",
351
+ "maxPasses",
352
+ "initialIssueCount",
353
+ "finalIssueCount",
354
+ "corrections",
355
+ "summary",
356
+ "changes",
357
+ "suggestions",
358
+ "unresolved",
359
+ "passHistory"
360
+ ],
361
+ additionalProperties: false
362
+ };
363
+
364
+ // src/tools/prove-compliant.ts
365
+ var TOOL_NAME = "design_system/prove_compliant";
366
+ var DEFAULT_MAX_PASSES = 4;
367
+ var MAX_PASSES = 8;
368
+ var DEFAULT_TTL_MS = 15 * 60 * 1e3;
369
+ var proveCompliantTools = [
370
+ {
371
+ name: TOOL_NAME,
372
+ title: "Prove Design-System Compliance",
373
+ description: "Run a closed validate-fix-validate loop over generated UI code until Fragments can prove it has zero design-system findings, or return the remaining issues. Uses deterministic fixes first, then MCP Sampling when the connected client supports it.",
374
+ inputSchema: {
375
+ type: "object",
376
+ properties: {
377
+ code: {
378
+ type: "string",
379
+ description: "The UI code to prove compliant."
380
+ },
381
+ filename: {
382
+ type: "string",
383
+ description: "Filename or extension hint. Defaults to TSX."
384
+ },
385
+ maxPasses: {
386
+ type: "integer",
387
+ minimum: 1,
388
+ maximum: MAX_PASSES,
389
+ description: "Maximum validation/fix passes. Defaults to 4."
390
+ },
391
+ allowSampling: {
392
+ type: "boolean",
393
+ description: "Allow MCP Sampling for residual issues. Defaults to true."
394
+ }
104
395
  },
105
- components,
106
- blocks,
107
- tokens,
108
- graph: raw.graph,
109
- performanceSummary: raw.performanceSummary,
110
- packageMap,
111
- defaultPackageName
396
+ required: ["code"],
397
+ additionalProperties: false
398
+ },
399
+ outputSchema: proveCompliantOutputSchema,
400
+ annotations: {
401
+ readOnlyHint: true,
402
+ idempotentHint: false,
403
+ cacheScope: "none",
404
+ ttlMs: 0
405
+ },
406
+ async call(args, context) {
407
+ return proveCompliant(args, context);
408
+ }
409
+ }
410
+ ];
411
+ async function proveCompliant(args, context) {
412
+ const restored = decodeState(context.requestState);
413
+ const input = restored ?? initialState(args);
414
+ const task = await ensureTask(context, input);
415
+ if (task) input.taskId = task.taskId;
416
+ const sampled = consumeSamplingResponse(input, context.inputResponses);
417
+ if (sampled) {
418
+ input.samplingAttempts += 1;
419
+ if (sampled.code) {
420
+ input.code = sampled.code;
421
+ }
422
+ const last = input.passHistory[input.passHistory.length - 1];
423
+ if (last) {
424
+ last.sampling = {
425
+ ...last.sampling ?? {},
426
+ used: Boolean(sampled.code),
427
+ model: sampled.model,
428
+ stopReason: sampled.stopReason,
429
+ reason: sampled.reason
430
+ };
431
+ }
432
+ }
433
+ let current = input.code;
434
+ let lastResult = null;
435
+ while (input.passHistory.length < input.maxPasses) {
436
+ const pass = input.passHistory.length + 1;
437
+ await updateTask(context, input.taskId, {
438
+ status: "working",
439
+ progress: {
440
+ current: pass,
441
+ total: input.maxPasses,
442
+ message: `Validating pass ${pass}`
443
+ }
444
+ });
445
+ const result = await context.provider.conform({
446
+ code: current,
447
+ filename: input.filename,
448
+ apply: "deterministic"
112
449
  });
450
+ lastResult = result;
451
+ const issues = issueCount(result);
452
+ input.passHistory.push({
453
+ pass,
454
+ issues,
455
+ deterministicChanges: result.changes.length,
456
+ suggestions: result.suggestions.length,
457
+ unresolved: result.unresolved.length,
458
+ changed: result.changed
459
+ });
460
+ input.corrections += result.changes.length;
461
+ if (issues === 0) {
462
+ const final2 = completeResult({
463
+ state: input,
464
+ result,
465
+ originalCode: args.code,
466
+ provedCompliant: true,
467
+ reason: `0 findings after ${pass} pass${pass === 1 ? "" : "es"}.`
468
+ });
469
+ return finish(context, input.taskId, final2);
470
+ }
471
+ if (result.changed && result.conformed !== current) {
472
+ current = result.conformed;
473
+ input.code = current;
474
+ continue;
475
+ }
476
+ const residual = {
477
+ suggestions: result.suggestions,
478
+ unresolved: result.unresolved
479
+ };
480
+ if (canUseSampling(input, context, residual)) {
481
+ return requestSampling({ state: input, context, current, residual });
482
+ }
483
+ break;
484
+ }
485
+ const fallback = lastResult ?? emptyConformResult(current);
486
+ const final = completeResult({
487
+ state: input,
488
+ result: fallback,
489
+ originalCode: args.code,
490
+ provedCompliant: false,
491
+ reason: incompleteReason(input, context, fallback)
492
+ });
493
+ return finish(context, input.taskId, final);
494
+ }
495
+ function initialState(args) {
496
+ return {
497
+ tool: TOOL_NAME,
498
+ code: typeof args.code === "string" ? args.code : "",
499
+ filename: typeof args.filename === "string" ? args.filename : void 0,
500
+ maxPasses: typeof args.maxPasses === "number" ? Math.min(MAX_PASSES, Math.max(1, Math.trunc(args.maxPasses))) : DEFAULT_MAX_PASSES,
501
+ allowSampling: args.allowSampling !== false,
502
+ passHistory: [],
503
+ corrections: 0,
504
+ samplingAttempts: 0
505
+ };
506
+ }
507
+ async function ensureTask(context, state) {
508
+ try {
509
+ if (state.taskId) return await context.tasks.get(state.taskId);
510
+ return await context.tasks.create({
511
+ title: "Prove UI compliance",
512
+ ttlMs: DEFAULT_TTL_MS,
513
+ pollIntervalMs: 500
514
+ });
515
+ } catch {
516
+ return null;
517
+ }
518
+ }
519
+ async function requestSampling(args) {
520
+ const requestKey = `prove_compliant_sampling_${args.state.passHistory.length}`;
521
+ args.state.requestKey = requestKey;
522
+ const last = args.state.passHistory[args.state.passHistory.length - 1];
523
+ if (last) last.sampling = { requested: true };
524
+ await updateTask(args.context, args.state.taskId, {
525
+ status: "input_required",
526
+ progress: {
527
+ current: args.state.passHistory.length,
528
+ total: args.state.maxPasses,
529
+ message: "Waiting for MCP Sampling to repair residual issues"
530
+ }
531
+ });
532
+ return {
533
+ resultType: "input_required",
534
+ inputRequests: {
535
+ [requestKey]: {
536
+ method: "sampling/createMessage",
537
+ params: {
538
+ messages: [
539
+ {
540
+ role: "user",
541
+ content: {
542
+ type: "text",
543
+ text: samplingPrompt(args.current, args.residual)
544
+ }
545
+ }
546
+ ],
547
+ systemPrompt: "You repair UI code for Fragments design-system governance. Return only JSON with a single string field named code.",
548
+ includeContext: "none",
549
+ maxTokens: 4e3,
550
+ temperature: 0.1,
551
+ modelPreferences: {
552
+ costPriority: 0.2,
553
+ speedPriority: 0.3,
554
+ intelligencePriority: 0.8
555
+ }
556
+ }
557
+ }
558
+ },
559
+ requestState: encodeState(args.state)
560
+ };
561
+ }
562
+ function canUseSampling(state, context, residual) {
563
+ if (!state.allowSampling) return false;
564
+ if (state.samplingAttempts >= state.maxPasses - 1) return false;
565
+ if (residual.suggestions.length === 0 && residual.unresolved.length === 0) return false;
566
+ const sampling = context.clientCapabilities?.sampling;
567
+ return Boolean(sampling && typeof sampling === "object");
568
+ }
569
+ function consumeSamplingResponse(state, responses) {
570
+ if (!state.requestKey || !responses) return null;
571
+ const response = responses[state.requestKey];
572
+ if (!response) return null;
573
+ const text = extractText(response.content);
574
+ const code = extractSampledCode(text);
575
+ state.requestKey = void 0;
576
+ if (!code) {
113
577
  return {
114
- snapshot,
115
- components: snapshot.components,
116
- blocks: snapshot.blocks,
117
- tokens: snapshot.tokens,
118
- graph: snapshot.graph,
119
- performanceSummary: snapshot.performanceSummary,
120
- packageMap: snapshot.packageMap,
121
- defaultPackageName: snapshot.defaultPackageName,
122
- capabilities: new Set(snapshot.capabilities)
578
+ attempted: true,
579
+ reason: "sampling response did not include code",
580
+ model: typeof response.model === "string" ? response.model : void 0,
581
+ stopReason: typeof response.stopReason === "string" ? response.stopReason : void 0
123
582
  };
124
583
  }
125
- };
584
+ return {
585
+ attempted: true,
586
+ code,
587
+ model: typeof response.model === "string" ? response.model : void 0,
588
+ stopReason: typeof response.stopReason === "string" ? response.stopReason : void 0
589
+ };
590
+ }
591
+ function completeResult(args) {
592
+ const initialIssueCount = args.state.passHistory[0]?.issues ?? 0;
593
+ const finalIssueCount = issueCount(args.result);
594
+ const changed = typeof args.originalCode === "string" && args.result.conformed !== args.originalCode;
595
+ const summary = args.provedCompliant ? `Proved compliant: ${args.reason}` : `Could not prove compliance: ${args.reason}`;
596
+ return {
597
+ content: [{ type: "text", text: summary }],
598
+ structuredContent: {
599
+ provedCompliant: args.provedCompliant,
600
+ conformed: args.result.conformed,
601
+ changed,
602
+ passes: args.state.passHistory.length,
603
+ maxPasses: args.state.maxPasses,
604
+ initialIssueCount,
605
+ finalIssueCount,
606
+ corrections: args.state.corrections,
607
+ summary,
608
+ taskId: args.state.taskId,
609
+ changes: args.result.changes,
610
+ suggestions: args.result.suggestions,
611
+ unresolved: args.result.unresolved,
612
+ passHistory: args.state.passHistory
613
+ }
614
+ };
615
+ }
616
+ async function finish(context, taskId, result) {
617
+ await updateTask(context, taskId, {
618
+ status: "completed",
619
+ result,
620
+ progress: { current: 1, total: 1, message: "Proof loop completed" }
621
+ });
622
+ return result;
623
+ }
624
+ async function updateTask(context, taskId, patch) {
625
+ if (!taskId) return null;
626
+ try {
627
+ return await context.tasks.update(taskId, patch);
628
+ } catch {
629
+ return null;
630
+ }
631
+ }
632
+ function issueCount(result) {
633
+ return result.changes.length + result.suggestions.length + result.unresolved.length;
634
+ }
635
+ function incompleteReason(state, context, result) {
636
+ if (state.passHistory.length >= state.maxPasses) {
637
+ return `stopped after ${state.maxPasses} passes with ${issueCount(result)} finding(s).`;
638
+ }
639
+ if (!state.allowSampling) return "sampling was disabled and residual issues remain.";
640
+ if (!context.clientCapabilities?.sampling) {
641
+ return "the MCP client did not declare sampling support and residual issues remain.";
642
+ }
643
+ return `${issueCount(result)} residual finding(s) remain after deterministic and sampled fixes.`;
644
+ }
645
+ function samplingPrompt(code, residual) {
646
+ return [
647
+ "Repair this UI code so it satisfies the remaining Fragments findings.",
648
+ "Preserve behavior, text, event handlers, and existing imports unless a finding requires a change.",
649
+ 'Return JSON only: {"code":"...full revised code..."}.',
650
+ "",
651
+ "Remaining findings:",
652
+ JSON.stringify(residual, null, 2),
653
+ "",
654
+ "Current code:",
655
+ "```tsx",
656
+ code,
657
+ "```"
658
+ ].join("\n");
659
+ }
660
+ function extractText(content) {
661
+ if (!content) return "";
662
+ if (Array.isArray(content)) return content.map(extractText).join("\n");
663
+ if (typeof content === "object") {
664
+ const record = content;
665
+ return typeof record.text === "string" ? record.text : "";
666
+ }
667
+ return typeof content === "string" ? content : "";
668
+ }
669
+ function extractSampledCode(text) {
670
+ const trimmed = text.trim();
671
+ if (!trimmed) return null;
672
+ try {
673
+ const parsed = JSON.parse(trimmed);
674
+ if (typeof parsed.code === "string" && parsed.code.trim()) return parsed.code;
675
+ } catch {
676
+ }
677
+ const fence = /```(?:[A-Za-z0-9_-]+)?\n([\s\S]*?)```/.exec(trimmed);
678
+ if (fence?.[1]?.trim()) return fence[1].trim();
679
+ return trimmed;
680
+ }
681
+ function encodeState(state) {
682
+ return JSON.stringify(state);
683
+ }
684
+ function decodeState(value) {
685
+ if (!value) return null;
686
+ try {
687
+ const parsed = JSON.parse(value);
688
+ return parsed?.tool === TOOL_NAME ? parsed : null;
689
+ } catch {
690
+ return null;
691
+ }
692
+ }
693
+ function emptyConformResult(code) {
694
+ return {
695
+ conformed: code,
696
+ changed: false,
697
+ summary: "No conform result was produced.",
698
+ changes: [],
699
+ suggestions: [],
700
+ unresolved: []
701
+ };
702
+ }
703
+
704
+ // src/tools/registry.ts
705
+ var MAX_SCHEMA_DEPTH = 16;
706
+ var MCP_TOOLS = [
707
+ ...primitiveTools,
708
+ ...conformTools,
709
+ ...proveCompliantTools
710
+ ];
711
+ function getTool(name) {
712
+ return MCP_TOOLS.find((tool) => tool.name === name) ?? null;
713
+ }
714
+ function listToolDescriptors() {
715
+ return MCP_TOOLS.map(({ call: _call, ...tool }) => ({
716
+ ...tool,
717
+ inputSchema: validateToolSchema(tool.name, tool.inputSchema),
718
+ ...tool.outputSchema ? { outputSchema: validateToolSchema(tool.name, tool.outputSchema) } : {},
719
+ annotations: {
720
+ cacheScope: "tenant",
721
+ ttlMs: 6e4,
722
+ ...tool.annotations ?? {}
723
+ }
724
+ }));
725
+ }
726
+ function validateToolSchema(toolName, schema) {
727
+ assertSchemaNode(toolName, schema, 0);
728
+ return schema;
729
+ }
730
+ function assertSchemaNode(toolName, value, depth) {
731
+ if (depth > MAX_SCHEMA_DEPTH) {
732
+ throw new Error(`Tool ${toolName} schema exceeds maximum depth`);
733
+ }
734
+ if (!value || typeof value !== "object") return;
735
+ if (Array.isArray(value)) {
736
+ for (const item of value) assertSchemaNode(toolName, item, depth + 1);
737
+ return;
738
+ }
739
+ const record = value;
740
+ const ref = record.$ref;
741
+ if (typeof ref === "string" && !ref.startsWith("#/")) {
742
+ throw new Error(`Tool ${toolName} schema contains external $ref`);
743
+ }
744
+ for (const child of Object.values(record)) {
745
+ assertSchemaNode(toolName, child, depth + 1);
746
+ }
747
+ }
126
748
 
127
- // src/orama-index.ts
128
- import { create, insertMultiple, search } from "@orama/orama";
129
- var SYNONYM_MAP = {
130
- "form": ["input", "field", "submit", "validation"],
131
- "input": ["form", "field", "text", "entry"],
132
- "button": ["action", "click", "submit", "trigger"],
133
- "action": ["button", "click", "trigger"],
134
- "submit": ["button", "form", "action", "send"],
135
- "alert": ["notification", "message", "warning", "error", "feedback"],
136
- "notification": ["alert", "message", "toast"],
137
- "feedback": ["form", "comment", "review", "rating"],
138
- "card": ["container", "panel", "box", "content"],
139
- "toggle": ["switch", "checkbox", "boolean", "on/off"],
140
- "switch": ["toggle", "checkbox", "boolean"],
141
- "badge": ["tag", "label", "status", "indicator"],
142
- "status": ["badge", "indicator", "state"],
143
- "login": ["auth", "signin", "authentication", "form"],
144
- "auth": ["login", "signin", "authentication"],
145
- "chat": ["message", "conversation", "ai"],
146
- "table": ["data", "grid", "list", "rows"],
147
- "textarea": ["text", "input", "multiline", "area", "comment"],
148
- "area": ["textarea", "multiline", "text"],
149
- "landing": ["page", "hero", "marketing", "section", "layout"],
150
- "hero": ["landing", "marketing", "banner", "headline", "section"],
151
- "marketing": ["landing", "hero", "pricing", "testimonial", "cta"],
152
- "cta": ["marketing", "banner", "action", "button"],
153
- "testimonial": ["marketing", "review", "quote", "feedback"],
154
- "layout": ["stack", "grid", "box", "container", "page"],
155
- "page": ["layout", "landing", "section", "container"],
156
- "section": ["hero", "feature", "testimonial", "cta", "faq"],
157
- "pricing": ["card", "plan", "tier", "marketing"],
158
- "plan": ["pricing", "card", "tier", "subscription"],
159
- "dashboard": ["metrics", "stats", "chart", "card", "grid"],
160
- "metrics": ["dashboard", "stats", "progress", "number"],
161
- "stats": ["metrics", "dashboard", "progress", "badge"],
162
- "chart": ["dashboard", "metrics", "data", "graph"]
749
+ // src/protocol/server.ts
750
+ var McpProtocolError = class extends Error {
751
+ code;
752
+ data;
753
+ constructor(code, message, data) {
754
+ super(message);
755
+ this.code = code;
756
+ this.data = data;
757
+ }
163
758
  };
164
- var USE_CASE_TOKEN_CATEGORIES = {
165
- "table": ["spacing", "borders", "surfaces", "text"],
166
- "data": ["spacing", "borders", "surfaces"],
167
- "grid": ["spacing", "layout"],
168
- "form": ["spacing", "borders", "radius", "focus"],
169
- "input": ["spacing", "borders", "radius", "focus"],
170
- "card": ["surfaces", "shadows", "radius", "borders", "spacing"],
171
- "button": ["colors", "radius", "spacing", "focus"],
172
- "layout": ["spacing", "layout", "surfaces"],
173
- "dashboard": ["spacing", "surfaces", "borders", "shadows"],
174
- "chat": ["spacing", "surfaces", "radius", "shadows"],
175
- "modal": ["shadows", "surfaces", "radius", "spacing"],
176
- "dialog": ["shadows", "surfaces", "radius", "spacing"],
177
- "navigation": ["spacing", "surfaces", "borders"],
178
- "sidebar": ["spacing", "surfaces", "borders"],
179
- "hero": ["spacing", "typography", "colors"],
180
- "landing": ["spacing", "typography", "colors"],
181
- "pricing": ["spacing", "surfaces", "borders", "radius"],
182
- "auth": ["spacing", "borders", "radius", "focus"],
183
- "login": ["spacing", "borders", "radius", "focus"],
184
- "dark": ["colors", "surfaces"],
185
- "theme": ["colors", "surfaces", "text"]
759
+ var FragmentsMcpServer = class {
760
+ provider;
761
+ tasks;
762
+ constructor(options) {
763
+ this.provider = options.provider;
764
+ this.tasks = options.tasks ?? new MemoryTaskStore();
765
+ }
766
+ async handleJsonRpc(request) {
767
+ try {
768
+ const result = await this.dispatch(request);
769
+ return success(request.id ?? null, result);
770
+ } catch (error) {
771
+ return failure(request.id ?? null, toProtocolError(error));
772
+ }
773
+ }
774
+ async dispatch(request) {
775
+ const params = request.params ?? {};
776
+ switch (request.method) {
777
+ case "server/discover":
778
+ return this.discover();
779
+ case "tools/list":
780
+ return { tools: listToolDescriptors() };
781
+ case "tools/call":
782
+ return this.callTool(params);
783
+ case "resources/list":
784
+ return { resources: listResources() };
785
+ case "resources/read":
786
+ return this.readResource(params);
787
+ case "tasks/get":
788
+ return this.getTask(params);
789
+ case "tasks/update":
790
+ return this.updateTask(params);
791
+ case "tasks/cancel":
792
+ return this.cancelTask(params);
793
+ default:
794
+ throw new McpProtocolError(-32601, `Unknown MCP method ${request.method}`);
795
+ }
796
+ }
797
+ discover() {
798
+ return {
799
+ protocolVersion: LATEST_PROTOCOL_VERSION,
800
+ serverInfo: {
801
+ name: "@fragments-sdk/mcp",
802
+ version: "0.11.0-rc"
803
+ },
804
+ capabilities: {
805
+ tools: { listChanged: false }
806
+ }
807
+ };
808
+ }
809
+ async callTool(params) {
810
+ const name = requireString(params.name, "name");
811
+ const tool = getTool(name);
812
+ if (!tool) {
813
+ throw new McpProtocolError(-32602, `Unknown tool ${name}`);
814
+ }
815
+ const context = {
816
+ provider: this.provider,
817
+ tasks: this.tasks,
818
+ requestMeta: readMeta(params),
819
+ clientCapabilities: readClientCapabilities(params),
820
+ inputResponses: readInputResponses(params),
821
+ requestState: readRequestState(params)
822
+ };
823
+ const args = readArgs(params);
824
+ validateArgs(tool.name, tool.inputSchema, args);
825
+ return tool.call(args, context);
826
+ }
827
+ async readResource(params) {
828
+ const uri = requireString(params.uri, "uri");
829
+ const resource = getResource(uri);
830
+ if (!resource) {
831
+ throw new McpProtocolError(-32602, `Unknown resource ${uri}`);
832
+ }
833
+ return resource.read({
834
+ provider: this.provider,
835
+ tasks: this.tasks,
836
+ requestMeta: readMeta(params)
837
+ });
838
+ }
839
+ async getTask(params) {
840
+ const taskId = requireString(params.taskId, "taskId");
841
+ const task = await this.tasks.get(taskId);
842
+ if (!task) {
843
+ throw new McpProtocolError(-32602, `Unknown task ${taskId}`);
844
+ }
845
+ return { task };
846
+ }
847
+ async updateTask(params) {
848
+ const taskId = requireString(params.taskId, "taskId");
849
+ const task = await this.tasks.update(taskId, {});
850
+ if (!task) {
851
+ throw new McpProtocolError(-32602, `Unknown task ${taskId}`);
852
+ }
853
+ return { task };
854
+ }
855
+ async cancelTask(params) {
856
+ const taskId = requireString(params.taskId, "taskId");
857
+ const task = await this.tasks.cancel(taskId);
858
+ if (!task) {
859
+ throw new McpProtocolError(-32602, `Unknown task ${taskId}`);
860
+ }
861
+ return { task };
862
+ }
186
863
  };
864
+ async function handleMcpJsonRpc(request, options) {
865
+ return new FragmentsMcpServer(options).handleJsonRpc(request);
866
+ }
867
+ async function handleMcpHttpRequest(request, options) {
868
+ let body;
869
+ try {
870
+ body = await request.json();
871
+ } catch {
872
+ return Response.json(failure(null, new McpProtocolError(-32700, "Invalid JSON")), {
873
+ status: 400
874
+ });
875
+ }
876
+ const response = await handleMcpJsonRpc(body, options);
877
+ return Response.json(response, {
878
+ status: "error" in response ? 400 : 200,
879
+ headers: {
880
+ "Cache-Control": "no-store",
881
+ "Mcp-Protocol-Version": LATEST_PROTOCOL_VERSION
882
+ }
883
+ });
884
+ }
885
+ function success(id, result) {
886
+ return { jsonrpc: "2.0", id, result };
887
+ }
888
+ function failure(id, error) {
889
+ return {
890
+ jsonrpc: "2.0",
891
+ id,
892
+ error: {
893
+ code: error.code,
894
+ message: error.message,
895
+ data: error.data
896
+ }
897
+ };
898
+ }
899
+ function toProtocolError(error) {
900
+ if (error instanceof McpProtocolError) return error;
901
+ return new McpProtocolError(
902
+ -32603,
903
+ error instanceof Error ? error.message : "Internal MCP error"
904
+ );
905
+ }
906
+ function requireString(value, key) {
907
+ if (typeof value === "string" && value.trim()) return value.trim();
908
+ throw new McpProtocolError(-32602, `Missing ${key}`);
909
+ }
910
+ function readArgs(params) {
911
+ const args = params.arguments ?? {};
912
+ if (!args || typeof args !== "object" || Array.isArray(args)) return {};
913
+ return args;
914
+ }
915
+ function readMeta(params) {
916
+ const meta = params._meta;
917
+ if (!meta || typeof meta !== "object" || Array.isArray(meta)) return void 0;
918
+ return meta;
919
+ }
920
+ function readClientCapabilities(params) {
921
+ const meta = readMeta(params);
922
+ const capabilities = meta?.["io.modelcontextprotocol/clientCapabilities"];
923
+ if (!capabilities || typeof capabilities !== "object" || Array.isArray(capabilities)) {
924
+ return void 0;
925
+ }
926
+ return capabilities;
927
+ }
928
+ function readInputResponses(params) {
929
+ const responses = params.inputResponses;
930
+ if (!responses || typeof responses !== "object" || Array.isArray(responses)) {
931
+ return void 0;
932
+ }
933
+ return responses;
934
+ }
935
+ function readRequestState(params) {
936
+ return typeof params.requestState === "string" ? params.requestState : void 0;
937
+ }
938
+ function validateArgs(toolName, schema, args) {
939
+ if (schema.type !== "object") return;
940
+ const properties = readProperties(schema.properties);
941
+ const required = Array.isArray(schema.required) ? schema.required.filter((item) => typeof item === "string") : [];
942
+ const argCount = Object.keys(args).filter(
943
+ (key) => args[key] !== void 0 && args[key] !== null
944
+ ).length;
945
+ if (typeof schema.minProperties === "number" && argCount < schema.minProperties) {
946
+ throw new McpProtocolError(
947
+ -32602,
948
+ `Invalid arguments for ${toolName}: expected at least ${schema.minProperties} argument(s)`
949
+ );
950
+ }
951
+ if (typeof schema.maxProperties === "number" && argCount > schema.maxProperties) {
952
+ throw new McpProtocolError(
953
+ -32602,
954
+ `Invalid arguments for ${toolName}: expected at most ${schema.maxProperties} argument(s)`
955
+ );
956
+ }
957
+ for (const key of required) {
958
+ if (!(key in args) || args[key] === void 0 || args[key] === null) {
959
+ throw new McpProtocolError(-32602, `Invalid arguments for ${toolName}: missing ${key}`);
960
+ }
961
+ if (properties[key]?.type === "string" && typeof args[key] === "string" && !args[key].trim()) {
962
+ throw new McpProtocolError(-32602, `Invalid arguments for ${toolName}: missing ${key}`);
963
+ }
964
+ }
965
+ if (schema.additionalProperties === false) {
966
+ for (const key of Object.keys(args)) {
967
+ if (!(key in properties)) {
968
+ throw new McpProtocolError(-32602, `Invalid arguments for ${toolName}: unknown ${key}`);
969
+ }
970
+ }
971
+ }
972
+ for (const [key, value] of Object.entries(args)) {
973
+ const property = properties[key];
974
+ if (!property || value === void 0 || value === null) continue;
975
+ validateValue(toolName, key, property, value);
976
+ }
977
+ }
978
+ function readProperties(value) {
979
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
980
+ const properties = {};
981
+ for (const [key, child] of Object.entries(value)) {
982
+ if (child && typeof child === "object" && !Array.isArray(child)) {
983
+ properties[key] = child;
984
+ }
985
+ }
986
+ return properties;
987
+ }
988
+ function validateValue(toolName, key, schema, value) {
989
+ if (Array.isArray(schema.enum) && !schema.enum.includes(value)) {
990
+ throw new McpProtocolError(
991
+ -32602,
992
+ `Invalid arguments for ${toolName}: ${key} must be one of ${schema.enum.join(", ")}`
993
+ );
994
+ }
995
+ const type = schema.type;
996
+ if (typeof type !== "string") return;
997
+ const valid = type === "integer" ? typeof value === "number" && Number.isInteger(value) : type === "number" ? typeof value === "number" && Number.isFinite(value) : type === "string" ? typeof value === "string" : type === "boolean" ? typeof value === "boolean" : type === "object" ? !!value && typeof value === "object" && !Array.isArray(value) : true;
998
+ if (!valid) {
999
+ throw new McpProtocolError(-32602, `Invalid arguments for ${toolName}: ${key} must be ${type}`);
1000
+ }
1001
+ if (typeof value === "number" && typeof schema.minimum === "number" && value < schema.minimum) {
1002
+ throw new McpProtocolError(
1003
+ -32602,
1004
+ `Invalid arguments for ${toolName}: ${key} must be >= ${schema.minimum}`
1005
+ );
1006
+ }
1007
+ if (typeof value === "number" && typeof schema.maximum === "number" && value > schema.maximum) {
1008
+ throw new McpProtocolError(
1009
+ -32602,
1010
+ `Invalid arguments for ${toolName}: ${key} must be <= ${schema.maximum}`
1011
+ );
1012
+ }
1013
+ }
187
1014
 
188
- // src/scoring.ts
189
- var MINIMUM_SCORE_THRESHOLD = 5;
190
- var BLOCK_BOOST_PER_OCCURRENCE = 5;
191
-
192
- // src/search-config.ts
193
- var DEFAULT_SEARCH_CONFIG = {
194
- synonyms: SYNONYM_MAP,
195
- useCaseTokenCategories: USE_CASE_TOKEN_CATEGORIES,
196
- minimumScoreThreshold: MINIMUM_SCORE_THRESHOLD,
197
- blockBoostPerOccurrence: BLOCK_BOOST_PER_OCCURRENCE,
198
- vectorSearchUrl: "https://combative-jay-834.convex.site/search",
199
- vectorSearchTimeoutMs: 3e3
1015
+ // src/testing/fixtures.ts
1016
+ var fixturePrimitives = [
1017
+ {
1018
+ id: "button",
1019
+ name: "Button",
1020
+ primitiveName: "Button",
1021
+ category: "Actions",
1022
+ status: "ready",
1023
+ description: "Primary action trigger.",
1024
+ usageGuidance: "Use for explicit user actions.",
1025
+ importPath: "@fixture/ui/button",
1026
+ packageName: "@fixture/ui",
1027
+ filePath: "src/components/Button.tsx",
1028
+ sourceRepoFullName: "fixture/ui",
1029
+ props: {
1030
+ variant: {
1031
+ type: '"primary" | "secondary"',
1032
+ required: false,
1033
+ description: "Visual emphasis."
1034
+ }
1035
+ }
1036
+ }
1037
+ ];
1038
+ var fixtureConformResult = {
1039
+ conformed: 'import { Button } from "@fixture/ui";\n\n<Button variant="primary" style={{ padding: "var(--space-4)" }}>Send</Button>',
1040
+ changed: true,
1041
+ summary: "Swapped <button> to Button (@fixture/ui), mapped #2563eb to --brand-600 and 16px to --space-4, flagged a missing accessible name.",
1042
+ designSystem: {
1043
+ name: "Fixture UI",
1044
+ importsAdded: ['import { Button } from "@fixture/ui";']
1045
+ },
1046
+ changes: [
1047
+ {
1048
+ kind: "swap-component",
1049
+ ruleId: "components/preferred-component",
1050
+ code: "FUI0410",
1051
+ severity: "warning",
1052
+ message: "Replaced native <button> with the design-system Button.",
1053
+ before: "<button>",
1054
+ after: '<Button variant="primary">',
1055
+ canonical: "Button",
1056
+ confidence: "high",
1057
+ location: { line: 1, column: 1 }
1058
+ },
1059
+ {
1060
+ kind: "replace-token",
1061
+ ruleId: "styles/no-raw-color",
1062
+ code: "FUI0601",
1063
+ severity: "error",
1064
+ message: "Replaced hardcoded color #2563eb with the matching design token.",
1065
+ before: "#2563eb",
1066
+ after: "var(--brand-600)",
1067
+ confidence: "high",
1068
+ location: { line: 1, column: 16 }
1069
+ },
1070
+ {
1071
+ kind: "replace-token",
1072
+ ruleId: "styles/no-raw-spacing",
1073
+ code: "FUI0602",
1074
+ severity: "warning",
1075
+ message: "Replaced hardcoded 16px with the matching spacing token.",
1076
+ before: "16px",
1077
+ after: "var(--space-4)",
1078
+ confidence: "high",
1079
+ location: { line: 1, column: 38 }
1080
+ }
1081
+ ],
1082
+ suggestions: [
1083
+ {
1084
+ kind: "review-low-confidence",
1085
+ confidence: "medium",
1086
+ message: 'Button has no accessible name beyond its text. Confirm "Send" is descriptive or add an aria-label.',
1087
+ canonical: "Button",
1088
+ location: { line: 1, column: 1 }
1089
+ }
1090
+ ],
1091
+ unresolved: []
200
1092
  };
201
-
202
- // src/index.ts
203
- import { BRAND } from "@fragments-sdk/core";
1093
+ function createFixtureProvider(args) {
1094
+ const primitives = args?.primitives ?? fixturePrimitives;
1095
+ const conformResult2 = args?.conform ?? fixtureConformResult;
1096
+ return {
1097
+ async listPrimitives() {
1098
+ return primitives;
1099
+ },
1100
+ async conform() {
1101
+ return conformResult2;
1102
+ }
1103
+ };
1104
+ }
204
1105
  export {
205
- AutoExtractionAdapter,
206
- BRAND,
207
- BUILTIN_TOOLS,
208
- CORE_TOOLS,
209
- CustomJsonAdapter,
210
- DEFAULT_SEARCH_CONFIG,
211
- FragmentsJsonAdapter,
212
- INFRA_TOOLS,
213
- ToolRegistry,
214
- VIEWER_TOOLS,
215
- createMcpServer,
216
- createSandboxServer,
217
- executeWithMiddleware,
218
- generateRulesFiles,
219
- loadConfigFile,
220
- startMcpServer,
221
- telemetryMiddleware
1106
+ FragmentsMcpServer,
1107
+ JSONRPC_VERSION,
1108
+ LATEST_PROTOCOL_VERSION,
1109
+ MCP_APP_RESOURCES,
1110
+ MCP_TOOLS,
1111
+ McpProtocolError,
1112
+ MemoryTaskStore,
1113
+ createFixtureProvider,
1114
+ fixtureConformResult,
1115
+ fixturePrimitives,
1116
+ getResource,
1117
+ getTool,
1118
+ handleMcpHttpRequest,
1119
+ handleMcpJsonRpc,
1120
+ listResources,
1121
+ listToolDescriptors
222
1122
  };
223
1123
  //# sourceMappingURL=index.js.map