@fragments-sdk/mcp 0.5.3 → 0.5.5
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/README.md +8 -13
- package/dist/bin.js +10 -5
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-WXUZ55XQ.js → chunk-IEJ7ZYTZ.js} +9 -6
- package/dist/chunk-IEJ7ZYTZ.js.map +1 -0
- package/dist/{chunk-QAXQVJOS.js → chunk-WEHZRM4L.js} +37 -16
- package/dist/chunk-WEHZRM4L.js.map +1 -0
- package/dist/{graph-6PMJ6XCF.js → graph-UWOAWP4T.js} +2 -2
- package/dist/server.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-QAXQVJOS.js.map +0 -1
- package/dist/chunk-WXUZ55XQ.js.map +0 -1
- /package/dist/{graph-6PMJ6XCF.js.map → graph-UWOAWP4T.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @fragments-sdk/mcp
|
|
2
2
|
|
|
3
|
-
Standalone MCP server for the Fragments design system. Gives AI coding assistants (Claude Code, Cursor, etc.)
|
|
3
|
+
Standalone MCP server for the Fragments design system. Gives AI coding assistants (Claude Code, Cursor, etc.) intelligent component discovery over components, blocks, and tokens — no Playwright or build tools required.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
@@ -78,24 +78,19 @@ Once the project root is known, the server walks up from it, scans `package.json
|
|
|
78
78
|
| `fragments_implement` | One-shot: components + blocks + tokens for a use case |
|
|
79
79
|
| `fragments_render` | Render a component screenshot (requires dev server) |
|
|
80
80
|
| `fragments_fix` | Generate token-compliance patches (requires dev server) |
|
|
81
|
+
| `fragments_graph` | Query the component relationship graph (dependencies, impact, composition, health) |
|
|
82
|
+
| `fragments_a11y` | Run an accessibility audit on a component (requires dev server) |
|
|
81
83
|
|
|
82
84
|
## How search works
|
|
83
85
|
|
|
84
|
-
Queries
|
|
86
|
+
Queries use **keyword search** with synonym expansion, weighted multi-field scoring (name, description, tags, usage, category, variants), and category-aware ranking — all running locally against your `fragments.json`. No external API calls are made.
|
|
87
|
+
|
|
88
|
+
**Premium:** Pass `--api-key` to enable semantic vector search (Voyage-Code-3 embeddings) fused with keyword results via Reciprocal Rank Fusion for deeper, meaning-based discovery.
|
|
85
89
|
|
|
86
90
|
## Options
|
|
87
91
|
|
|
88
92
|
```
|
|
89
93
|
-p, --project-root <path> Project root (default: cwd)
|
|
90
|
-
-u, --viewer-url <url> Dev server URL for render/fix tools
|
|
94
|
+
-u, --viewer-url <url> Dev server URL for render/fix/a11y tools
|
|
95
|
+
-k, --api-key <key> Premium API key for semantic vector search
|
|
91
96
|
```
|
|
92
|
-
|
|
93
|
-
## Convex backend
|
|
94
|
-
|
|
95
|
-
The `convex/` directory contains the hosted search backend:
|
|
96
|
-
|
|
97
|
-
- **schema.ts** — `entries` table with vector index (components, blocks, tokens)
|
|
98
|
-
- **search.ts** — HTTP action that embeds queries with Voyage-Code-3 and runs vector search
|
|
99
|
-
- **ingest.ts** — Mutation to upsert entries at publish time
|
|
100
|
-
|
|
101
|
-
Index entries: `pnpm --filter @fragments-sdk/mcp index` (requires `VOYAGE_API_KEY` and `CONVEX_URL`).
|
package/dist/bin.js
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startMcpServer
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-WEHZRM4L.js";
|
|
5
|
+
import "./chunk-IEJ7ZYTZ.js";
|
|
6
6
|
|
|
7
7
|
// src/bin.ts
|
|
8
8
|
var args = process.argv.slice(2);
|
|
9
9
|
var projectRoot = process.cwd();
|
|
10
10
|
var viewerUrl;
|
|
11
|
+
var apiKey;
|
|
11
12
|
for (let i = 0; i < args.length; i++) {
|
|
12
13
|
const arg = args[i];
|
|
13
14
|
if (arg === "--project-root" || arg === "-p") {
|
|
14
15
|
projectRoot = args[++i] ?? projectRoot;
|
|
15
16
|
} else if (arg === "--viewer-url" || arg === "-u") {
|
|
16
17
|
viewerUrl = args[++i];
|
|
18
|
+
} else if (arg === "--api-key" || arg === "-k") {
|
|
19
|
+
apiKey = args[++i];
|
|
17
20
|
} else if (arg === "--help" || arg === "-h") {
|
|
18
21
|
console.log(`
|
|
19
22
|
Usage: fragments-mcp [options]
|
|
20
23
|
|
|
21
24
|
Standalone MCP server for Fragments design system.
|
|
22
|
-
Provides component discovery with
|
|
25
|
+
Provides component discovery with keyword search, no CLI/Playwright needed.
|
|
23
26
|
|
|
24
27
|
Options:
|
|
25
28
|
-p, --project-root <path> Project root directory (default: cwd)
|
|
26
|
-
-u, --viewer-url <url> Viewer URL for render/fix tools (optional)
|
|
29
|
+
-u, --viewer-url <url> Viewer URL for render/fix/a11y tools (optional)
|
|
30
|
+
-k, --api-key <key> Premium API key for semantic vector search (optional)
|
|
27
31
|
-h, --help Show this help message
|
|
28
32
|
|
|
29
33
|
Setup (Claude Code / Cursor):
|
|
@@ -41,7 +45,8 @@ Setup (Claude Code / Cursor):
|
|
|
41
45
|
}
|
|
42
46
|
startMcpServer({
|
|
43
47
|
projectRoot,
|
|
44
|
-
viewerUrl
|
|
48
|
+
viewerUrl,
|
|
49
|
+
apiKey
|
|
45
50
|
}).catch((error) => {
|
|
46
51
|
console.error("Failed to start MCP server:", error);
|
|
47
52
|
process.exit(1);
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { startMcpServer } from './server.js';\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nlet projectRoot = process.cwd();\nlet viewerUrl: string | undefined;\n\nfor (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--project-root' || arg === '-p') {\n projectRoot = args[++i] ?? projectRoot;\n } else if (arg === '--viewer-url' || arg === '-u') {\n viewerUrl = args[++i];\n } else if (arg === '--help' || arg === '-h') {\n console.log(`\nUsage: fragments-mcp [options]\n\nStandalone MCP server for Fragments design system.\nProvides component discovery with
|
|
1
|
+
{"version":3,"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { startMcpServer } from './server.js';\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nlet projectRoot = process.cwd();\nlet viewerUrl: string | undefined;\nlet apiKey: string | undefined;\n\nfor (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--project-root' || arg === '-p') {\n projectRoot = args[++i] ?? projectRoot;\n } else if (arg === '--viewer-url' || arg === '-u') {\n viewerUrl = args[++i];\n } else if (arg === '--api-key' || arg === '-k') {\n apiKey = args[++i];\n } else if (arg === '--help' || arg === '-h') {\n console.log(`\nUsage: fragments-mcp [options]\n\nStandalone MCP server for Fragments design system.\nProvides component discovery with keyword search, no CLI/Playwright needed.\n\nOptions:\n -p, --project-root <path> Project root directory (default: cwd)\n -u, --viewer-url <url> Viewer URL for render/fix/a11y tools (optional)\n -k, --api-key <key> Premium API key for semantic vector search (optional)\n -h, --help Show this help message\n\nSetup (Claude Code / Cursor):\n {\n \"mcpServers\": {\n \"fragments\": {\n \"command\": \"npx\",\n \"args\": [\"@fragments-sdk/mcp\"]\n }\n }\n }\n`);\n process.exit(0);\n }\n}\n\n// Start server\nstartMcpServer({\n projectRoot,\n viewerUrl,\n apiKey,\n}).catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"mappings":";;;;;;;AAIA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAI,cAAc,QAAQ,IAAI;AAC9B,IAAI;AACJ,IAAI;AAEJ,SAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAM,MAAM,KAAK,CAAC;AAElB,MAAI,QAAQ,oBAAoB,QAAQ,MAAM;AAC5C,kBAAc,KAAK,EAAE,CAAC,KAAK;AAAA,EAC7B,WAAW,QAAQ,kBAAkB,QAAQ,MAAM;AACjD,gBAAY,KAAK,EAAE,CAAC;AAAA,EACtB,WAAW,QAAQ,eAAe,QAAQ,MAAM;AAC9C,aAAS,KAAK,EAAE,CAAC;AAAA,EACnB,WAAW,QAAQ,YAAY,QAAQ,MAAM;AAC3C,YAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAqBf;AACG,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAGA,eAAe;AAAA,EACb;AAAA,EACA;AAAA,EACA;AACF,CAAC,EAAE,MAAM,CAAC,UAAU;AAClB,UAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
|
@@ -201,7 +201,7 @@ var ComponentGraphEngine = class {
|
|
|
201
201
|
const node = this.nodes.get(component);
|
|
202
202
|
const subComponents = node?.subComponents ?? [];
|
|
203
203
|
const parentEdges = (this.outgoing.get(component) ?? []).filter((e) => e.type === "parent-of");
|
|
204
|
-
const
|
|
204
|
+
const children = parentEdges.map((e) => e.target);
|
|
205
205
|
const childEdges = (this.incoming.get(component) ?? []).filter((e) => e.type === "parent-of");
|
|
206
206
|
const parent = childEdges.length > 0 ? childEdges[0].source : void 0;
|
|
207
207
|
const siblings = [];
|
|
@@ -225,22 +225,25 @@ var ComponentGraphEngine = class {
|
|
|
225
225
|
component,
|
|
226
226
|
compositionPattern: node?.compositionPattern,
|
|
227
227
|
subComponents,
|
|
228
|
-
|
|
228
|
+
children,
|
|
229
229
|
parent,
|
|
230
230
|
siblings,
|
|
231
231
|
blocks: this.blockIndex.get(component) ?? []
|
|
232
232
|
};
|
|
233
233
|
}
|
|
234
|
-
/** Get alternative components */
|
|
234
|
+
/** Get alternative components (deduplicated for bidirectional edges) */
|
|
235
235
|
alternatives(component) {
|
|
236
|
+
const seen = /* @__PURE__ */ new Set();
|
|
236
237
|
const alts = [];
|
|
237
238
|
for (const edge of this.outgoing.get(component) ?? []) {
|
|
238
|
-
if (edge.type === "alternative-to") {
|
|
239
|
+
if (edge.type === "alternative-to" && !seen.has(edge.target)) {
|
|
240
|
+
seen.add(edge.target);
|
|
239
241
|
alts.push({ component: edge.target, note: edge.note });
|
|
240
242
|
}
|
|
241
243
|
}
|
|
242
244
|
for (const edge of this.incoming.get(component) ?? []) {
|
|
243
|
-
if (edge.type === "alternative-to") {
|
|
245
|
+
if (edge.type === "alternative-to" && !seen.has(edge.source)) {
|
|
246
|
+
seen.add(edge.source);
|
|
244
247
|
alts.push({ component: edge.source, note: edge.note });
|
|
245
248
|
}
|
|
246
249
|
}
|
|
@@ -383,4 +386,4 @@ export {
|
|
|
383
386
|
serializeGraph,
|
|
384
387
|
deserializeGraph
|
|
385
388
|
};
|
|
386
|
-
//# sourceMappingURL=chunk-
|
|
389
|
+
//# sourceMappingURL=chunk-IEJ7ZYTZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../context/dist/graph/index.js"],"sourcesContent":["// src/graph/types.ts\nvar GRAPH_EDGE_TYPES = [\n \"imports\",\n \"hook-depends\",\n \"renders\",\n \"composes\",\n \"parent-of\",\n \"alternative-to\",\n \"sibling-of\"\n];\nvar EDGE_TYPE_WEIGHTS = {\n \"imports\": 1,\n \"hook-depends\": 0.75,\n \"renders\": 0.5,\n \"composes\": 0.5,\n \"parent-of\": 1,\n \"alternative-to\": 1,\n \"sibling-of\": 0.75\n};\n\n// src/graph/engine.ts\nvar ComponentGraphEngine = class {\n nodes;\n outgoing;\n incoming;\n edges;\n blockIndex;\n health;\n constructor(graph, blocks) {\n this.nodes = /* @__PURE__ */ new Map();\n this.outgoing = /* @__PURE__ */ new Map();\n this.incoming = /* @__PURE__ */ new Map();\n this.edges = graph.edges;\n this.health = graph.health;\n this.blockIndex = /* @__PURE__ */ new Map();\n for (const node of graph.nodes) {\n this.nodes.set(node.name, node);\n this.outgoing.set(node.name, []);\n this.incoming.set(node.name, []);\n }\n for (const edge of graph.edges) {\n const out = this.outgoing.get(edge.source);\n if (out) out.push(edge);\n else this.outgoing.set(edge.source, [edge]);\n const inc = this.incoming.get(edge.target);\n if (inc) inc.push(edge);\n else this.incoming.set(edge.target, [edge]);\n }\n if (blocks) {\n for (const [blockName, block] of Object.entries(blocks)) {\n for (const comp of block.components) {\n const existing = this.blockIndex.get(comp);\n if (existing) existing.push(blockName);\n else this.blockIndex.set(comp, [blockName]);\n }\n }\n }\n }\n // -------------------------------------------------------------------------\n // Core queries\n // -------------------------------------------------------------------------\n /** Get outgoing edges from a component, optionally filtered by edge type */\n dependencies(component, edgeTypes) {\n const edges = this.outgoing.get(component) ?? [];\n if (!edgeTypes || edgeTypes.length === 0) return edges;\n return edges.filter((e) => edgeTypes.includes(e.type));\n }\n /** Get incoming edges to a component, optionally filtered by edge type */\n dependents(component, edgeTypes) {\n const edges = this.incoming.get(component) ?? [];\n if (!edgeTypes || edgeTypes.length === 0) return edges;\n return edges.filter((e) => edgeTypes.includes(e.type));\n }\n /** BFS transitive closure — what's affected if this component changes */\n impact(component, maxDepth = 3) {\n const affected = [];\n const visited = /* @__PURE__ */ new Set([component]);\n const queue = [\n { name: component, depth: 0, path: [component] }\n ];\n while (queue.length > 0) {\n const current = queue.shift();\n if (current.depth >= maxDepth) continue;\n const deps = this.incoming.get(current.name) ?? [];\n for (const edge of deps) {\n if (visited.has(edge.source)) continue;\n visited.add(edge.source);\n const newPath = [...current.path, edge.source];\n affected.push({\n component: edge.source,\n depth: current.depth + 1,\n path: newPath,\n edgeType: edge.type\n });\n queue.push({ name: edge.source, depth: current.depth + 1, path: newPath });\n }\n }\n const affectedComponents = /* @__PURE__ */ new Set([component, ...affected.map((a) => a.component)]);\n const affectedBlocks = /* @__PURE__ */ new Set();\n for (const comp of affectedComponents) {\n const blocks = this.blockIndex.get(comp);\n if (blocks) {\n for (const b of blocks) affectedBlocks.add(b);\n }\n }\n return {\n component,\n affected,\n affectedBlocks: [...affectedBlocks],\n totalAffected: affected.length\n };\n }\n /** BFS shortest path between two components (undirected) */\n path(from, to) {\n if (from === to) {\n return { found: true, path: [from], edges: [] };\n }\n const visited = /* @__PURE__ */ new Set([from]);\n const queue = [\n { name: from, path: [from], edges: [] }\n ];\n while (queue.length > 0) {\n const current = queue.shift();\n const allEdges = [\n ...this.outgoing.get(current.name) ?? [],\n ...this.incoming.get(current.name) ?? []\n ];\n for (const edge of allEdges) {\n const neighbor = edge.source === current.name ? edge.target : edge.source;\n if (visited.has(neighbor)) continue;\n visited.add(neighbor);\n const newPath = [...current.path, neighbor];\n const newEdges = [...current.edges, edge];\n if (neighbor === to) {\n return { found: true, path: newPath, edges: newEdges };\n }\n queue.push({ name: neighbor, path: newPath, edges: newEdges });\n }\n }\n return { found: false, path: [], edges: [] };\n }\n /** Connected components via BFS on undirected projection */\n islands() {\n const visited = /* @__PURE__ */ new Set();\n const components = [];\n for (const nodeName of this.nodes.keys()) {\n if (visited.has(nodeName)) continue;\n const island = [];\n const queue = [nodeName];\n visited.add(nodeName);\n while (queue.length > 0) {\n const current = queue.shift();\n island.push(current);\n const allEdges = [\n ...this.outgoing.get(current) ?? [],\n ...this.incoming.get(current) ?? []\n ];\n for (const edge of allEdges) {\n const neighbor = edge.source === current ? edge.target : edge.source;\n if (!visited.has(neighbor) && this.nodes.has(neighbor)) {\n visited.add(neighbor);\n queue.push(neighbor);\n }\n }\n }\n components.push(island.sort());\n }\n return components.sort((a, b) => b.length - a.length);\n }\n /** All components reachable within N hops (undirected) */\n neighbors(component, maxHops = 1) {\n const neighbors = [];\n const visited = /* @__PURE__ */ new Set([component]);\n const queue = [\n { name: component, hops: 0 }\n ];\n while (queue.length > 0) {\n const current = queue.shift();\n if (current.hops >= maxHops) continue;\n const allEdges = [\n ...this.outgoing.get(current.name) ?? [],\n ...this.incoming.get(current.name) ?? []\n ];\n for (const edge of allEdges) {\n const neighbor = edge.source === current.name ? edge.target : edge.source;\n if (visited.has(neighbor)) continue;\n visited.add(neighbor);\n neighbors.push({\n component: neighbor,\n hops: current.hops + 1,\n edgeType: edge.type\n });\n queue.push({ name: neighbor, hops: current.hops + 1 });\n }\n }\n return { component, neighbors };\n }\n // -------------------------------------------------------------------------\n // Design-system queries\n // -------------------------------------------------------------------------\n /** Get the composition tree for a compound component */\n composition(component) {\n const node = this.nodes.get(component);\n const subComponents = node?.subComponents ?? [];\n const parentEdges = (this.outgoing.get(component) ?? []).filter((e) => e.type === \"parent-of\");\n const children = parentEdges.map((e) => e.target);\n const childEdges = (this.incoming.get(component) ?? []).filter((e) => e.type === \"parent-of\");\n const parent = childEdges.length > 0 ? childEdges[0].source : void 0;\n const siblings = [];\n if (parent) {\n const parentOut = (this.outgoing.get(parent) ?? []).filter((e) => e.type === \"parent-of\");\n for (const edge of parentOut) {\n if (edge.target !== component) {\n siblings.push(edge.target);\n }\n }\n }\n const siblingEdges = [\n ...(this.outgoing.get(component) ?? []).filter((e) => e.type === \"sibling-of\"),\n ...(this.incoming.get(component) ?? []).filter((e) => e.type === \"sibling-of\")\n ];\n for (const edge of siblingEdges) {\n const sib = edge.source === component ? edge.target : edge.source;\n if (!siblings.includes(sib)) siblings.push(sib);\n }\n return {\n component,\n compositionPattern: node?.compositionPattern,\n subComponents,\n children,\n parent,\n siblings,\n blocks: this.blockIndex.get(component) ?? []\n };\n }\n /** Get alternative components (deduplicated for bidirectional edges) */\n alternatives(component) {\n const seen = /* @__PURE__ */ new Set();\n const alts = [];\n for (const edge of this.outgoing.get(component) ?? []) {\n if (edge.type === \"alternative-to\" && !seen.has(edge.target)) {\n seen.add(edge.target);\n alts.push({ component: edge.target, note: edge.note });\n }\n }\n for (const edge of this.incoming.get(component) ?? []) {\n if (edge.type === \"alternative-to\" && !seen.has(edge.source)) {\n seen.add(edge.source);\n alts.push({ component: edge.source, note: edge.note });\n }\n }\n return alts;\n }\n /** Get blocks that use a component */\n blocksUsing(component) {\n return this.blockIndex.get(component) ?? [];\n }\n /** Extract an induced subgraph for a set of components */\n subgraph(components) {\n const componentSet = new Set(components);\n const nodes = components.map((name) => this.nodes.get(name)).filter((n) => n !== void 0);\n const edges = this.edges.filter(\n (e) => componentSet.has(e.source) && componentSet.has(e.target)\n );\n return {\n nodes,\n edges,\n health: computeHealthFromData(nodes, edges, this.blockIndex)\n };\n }\n /** Return precomputed health metrics */\n getHealth() {\n return this.health;\n }\n /** Get a single node by name */\n getNode(name) {\n return this.nodes.get(name);\n }\n /** Check if a component exists in the graph */\n hasNode(name) {\n return this.nodes.has(name);\n }\n};\nfunction computeHealthFromData(nodes, edges, blockIndex) {\n const nodeNames = new Set(nodes.map((n) => n.name));\n const degreeMap = /* @__PURE__ */ new Map();\n for (const name of nodeNames) {\n degreeMap.set(name, 0);\n }\n for (const edge of edges) {\n degreeMap.set(edge.source, (degreeMap.get(edge.source) ?? 0) + 1);\n degreeMap.set(edge.target, (degreeMap.get(edge.target) ?? 0) + 1);\n }\n const orphans = [];\n for (const [name, degree] of degreeMap) {\n if (degree === 0) orphans.push(name);\n }\n const hubs = [...degreeMap.entries()].map(([name, degree]) => ({ name, degree })).sort((a, b) => b.degree - a.degree).slice(0, 10);\n let inBlock = 0;\n if (blockIndex) {\n for (const name of nodeNames) {\n if ((blockIndex.get(name) ?? []).length > 0) inBlock++;\n }\n }\n const compositionCoverage = nodeNames.size > 0 ? Math.round(inBlock / nodeNames.size * 100) : 0;\n const adjacency = /* @__PURE__ */ new Map();\n for (const name of nodeNames) {\n adjacency.set(name, /* @__PURE__ */ new Set());\n }\n for (const edge of edges) {\n adjacency.get(edge.source)?.add(edge.target);\n adjacency.get(edge.target)?.add(edge.source);\n }\n const visited = /* @__PURE__ */ new Set();\n const connectedComponents = [];\n for (const name of nodeNames) {\n if (visited.has(name)) continue;\n const island = [];\n const queue = [name];\n visited.add(name);\n while (queue.length > 0) {\n const current = queue.shift();\n island.push(current);\n for (const neighbor of adjacency.get(current) ?? []) {\n if (!visited.has(neighbor)) {\n visited.add(neighbor);\n queue.push(neighbor);\n }\n }\n }\n connectedComponents.push(island.sort());\n }\n connectedComponents.sort((a, b) => b.length - a.length);\n const totalDegree = [...degreeMap.values()].reduce((sum, d) => sum + d, 0);\n const averageDegree = nodeNames.size > 0 ? Math.round(totalDegree / nodeNames.size * 100) / 100 : 0;\n return {\n orphans: orphans.sort(),\n hubs,\n compositionCoverage,\n connectedComponents,\n averageDegree,\n nodeCount: nodeNames.size,\n edgeCount: edges.length\n };\n}\n\n// src/graph/serialization.ts\nfunction serializeGraph(graph) {\n return {\n nodes: graph.nodes,\n edges: graph.edges.map(serializeEdge),\n health: graph.health\n };\n}\nfunction deserializeGraph(serialized) {\n return {\n nodes: serialized.nodes,\n edges: serialized.edges.map(deserializeEdge),\n health: serialized.health\n };\n}\nfunction serializeEdge(edge) {\n const result = {\n s: edge.source,\n t: edge.target,\n ty: edge.type,\n w: edge.weight,\n p: edge.provenance\n };\n if (edge.note) result.no = edge.note;\n return result;\n}\nfunction deserializeEdge(edge) {\n const result = {\n source: edge.s,\n target: edge.t,\n type: edge.ty,\n weight: edge.w,\n provenance: edge.p\n };\n if (edge.no) result.note = edge.no;\n return result;\n}\nexport {\n ComponentGraphEngine,\n EDGE_TYPE_WEIGHTS,\n GRAPH_EDGE_TYPES,\n computeHealthFromData,\n deserializeGraph,\n serializeGraph\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ComponentGraphEngine,
|
|
3
3
|
deserializeGraph
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IEJ7ZYTZ.js";
|
|
5
5
|
|
|
6
6
|
// src/server.ts
|
|
7
7
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -745,8 +745,10 @@ var SYNONYM_MAP = {
|
|
|
745
745
|
"input": ["form", "field", "text", "entry"],
|
|
746
746
|
"button": ["action", "click", "submit", "trigger"],
|
|
747
747
|
"action": ["button", "click", "trigger"],
|
|
748
|
+
"submit": ["button", "form", "action", "send"],
|
|
748
749
|
"alert": ["notification", "message", "warning", "error", "feedback"],
|
|
749
750
|
"notification": ["alert", "message", "toast"],
|
|
751
|
+
"feedback": ["form", "comment", "review", "rating"],
|
|
750
752
|
"card": ["container", "panel", "box", "content"],
|
|
751
753
|
"toggle": ["switch", "checkbox", "boolean", "on/off"],
|
|
752
754
|
"switch": ["toggle", "checkbox", "boolean"],
|
|
@@ -755,15 +757,20 @@ var SYNONYM_MAP = {
|
|
|
755
757
|
"login": ["auth", "signin", "authentication", "form"],
|
|
756
758
|
"auth": ["login", "signin", "authentication"],
|
|
757
759
|
"chat": ["message", "conversation", "ai"],
|
|
758
|
-
"table": ["data", "grid", "list", "rows"]
|
|
760
|
+
"table": ["data", "grid", "list", "rows"],
|
|
761
|
+
"textarea": ["text", "input", "multiline", "area", "comment"],
|
|
762
|
+
"area": ["textarea", "multiline", "text"]
|
|
759
763
|
};
|
|
760
|
-
async function searchConvex(query, limit = 10, kind) {
|
|
764
|
+
async function searchConvex(query, apiKey, limit = 10, kind) {
|
|
761
765
|
try {
|
|
762
766
|
const controller = new AbortController();
|
|
763
767
|
const timeout = setTimeout(() => controller.abort(), CONVEX_TIMEOUT_MS);
|
|
764
768
|
const response = await fetch(CONVEX_SEARCH_URL, {
|
|
765
769
|
method: "POST",
|
|
766
|
-
headers: {
|
|
770
|
+
headers: {
|
|
771
|
+
"Content-Type": "application/json",
|
|
772
|
+
"Authorization": `Bearer ${apiKey}`
|
|
773
|
+
},
|
|
767
774
|
body: JSON.stringify({ query, limit, ...kind && { kind } }),
|
|
768
775
|
signal: controller.signal
|
|
769
776
|
});
|
|
@@ -896,7 +903,7 @@ function reciprocalRankFusion(resultSets, k = 60) {
|
|
|
896
903
|
});
|
|
897
904
|
return fused;
|
|
898
905
|
}
|
|
899
|
-
async function hybridSearch(query, data, limit = 10, kind) {
|
|
906
|
+
async function hybridSearch(query, data, limit = 10, kind, apiKey) {
|
|
900
907
|
const keywordResults = [];
|
|
901
908
|
if (!kind || kind === "component") {
|
|
902
909
|
keywordResults.push(...keywordScoreComponents(query, data.fragments));
|
|
@@ -911,14 +918,17 @@ async function hybridSearch(query, data, limit = 10, kind) {
|
|
|
911
918
|
keywordResults.forEach((r, i) => {
|
|
912
919
|
r.rank = i;
|
|
913
920
|
});
|
|
914
|
-
|
|
921
|
+
if (!apiKey) {
|
|
922
|
+
return keywordResults.slice(0, limit);
|
|
923
|
+
}
|
|
924
|
+
const vectorResults = await searchConvex(query, apiKey, limit, kind);
|
|
915
925
|
if (vectorResults.length === 0) {
|
|
916
926
|
return keywordResults.slice(0, limit);
|
|
917
927
|
}
|
|
918
928
|
const graphBoostResults = [];
|
|
919
929
|
if (data.graph) {
|
|
920
930
|
try {
|
|
921
|
-
const { ComponentGraphEngine: ComponentGraphEngine2, deserializeGraph: deserializeGraph2 } = await import("./graph-
|
|
931
|
+
const { ComponentGraphEngine: ComponentGraphEngine2, deserializeGraph: deserializeGraph2 } = await import("./graph-UWOAWP4T.js");
|
|
922
932
|
const graph = deserializeGraph2(data.graph);
|
|
923
933
|
const engine = new ComponentGraphEngine2(graph);
|
|
924
934
|
const topComponents = [...keywordResults, ...vectorResults].filter((r) => r.kind === "component").slice(0, 5);
|
|
@@ -1090,10 +1100,14 @@ function handleGraphTool(args, serializedGraph, blocks) {
|
|
|
1090
1100
|
switch (args.mode) {
|
|
1091
1101
|
case "health": {
|
|
1092
1102
|
const health = engine.getHealth();
|
|
1103
|
+
const blockCount = blocks ? Object.keys(blocks).length : 0;
|
|
1093
1104
|
return {
|
|
1094
1105
|
text: JSON.stringify({
|
|
1095
1106
|
mode: "health",
|
|
1096
1107
|
...health,
|
|
1108
|
+
...health.compositionCoverage === 0 && blockCount === 0 && {
|
|
1109
|
+
compositionNote: "No composition blocks defined yet \u2014 compositionCoverage will increase as blocks are added"
|
|
1110
|
+
},
|
|
1097
1111
|
summary: `${health.nodeCount} components, ${health.edgeCount} edges, ${health.connectedComponents.length} island(s), ${health.orphans.length} orphan(s), ${health.compositionCoverage}% in blocks`
|
|
1098
1112
|
}, null, 2)
|
|
1099
1113
|
};
|
|
@@ -1237,6 +1251,7 @@ function handleGraphTool(args, serializedGraph, blocks) {
|
|
|
1237
1251
|
|
|
1238
1252
|
// src/server.ts
|
|
1239
1253
|
var TOOL_NAMES = buildToolNames(BRAND.nameLower);
|
|
1254
|
+
var NO_VIEWER_MSG = "This tool requires a running dev server. Pass --viewer-url to the MCP server, or use the fragments-dev MCP config which connects to your local dev server.";
|
|
1240
1255
|
var TOOLS = buildMcpTools(BRAND.nameLower);
|
|
1241
1256
|
function createMcpServer(config) {
|
|
1242
1257
|
const server = new Server(
|
|
@@ -1387,7 +1402,7 @@ If you're a library author, run \`${BRAND.cliCommand} build\` first.`
|
|
|
1387
1402
|
blocks: allBlocks,
|
|
1388
1403
|
tokenData: data.tokens
|
|
1389
1404
|
};
|
|
1390
|
-
const searchResults = await hybridSearch(fullQuery, localData, 10, "component");
|
|
1405
|
+
const searchResults = await hybridSearch(fullQuery, localData, 10, "component", config.apiKey);
|
|
1391
1406
|
const scored = searchResults.map((result) => {
|
|
1392
1407
|
const fragment = allFragments.find(
|
|
1393
1408
|
(s) => s.meta.name.toLowerCase() === result.name.toLowerCase()
|
|
@@ -1511,7 +1526,10 @@ If you're a library author, run \`${BRAND.cliCommand} build\` first.`
|
|
|
1511
1526
|
description: s.meta.description,
|
|
1512
1527
|
status: s.meta.status ?? "stable",
|
|
1513
1528
|
variantCount: s.variants.length,
|
|
1514
|
-
tags: s.meta.tags ?? []
|
|
1529
|
+
tags: s.meta.tags ?? [],
|
|
1530
|
+
...includeCode && s.variants[0]?.code && {
|
|
1531
|
+
example: s.variants[0].code
|
|
1532
|
+
}
|
|
1515
1533
|
}));
|
|
1516
1534
|
return {
|
|
1517
1535
|
content: [{
|
|
@@ -1644,7 +1662,7 @@ If you're a library author, run \`${BRAND.cliCommand} build\` first.`
|
|
|
1644
1662
|
text: JSON.stringify({
|
|
1645
1663
|
total: 0,
|
|
1646
1664
|
blocks: [],
|
|
1647
|
-
hint: `No blocks found.
|
|
1665
|
+
hint: `No composition blocks found. Blocks are reusable patterns showing how components wire together (e.g., "Login Form", "Settings Page"). Create .block.ts files and run \`${BRAND.cliCommand} build\`.`
|
|
1648
1666
|
}, null, 2)
|
|
1649
1667
|
}]
|
|
1650
1668
|
};
|
|
@@ -1682,7 +1700,10 @@ If you're a library author, run \`${BRAND.cliCommand} build\` first.`
|
|
|
1682
1700
|
type: "text",
|
|
1683
1701
|
text: JSON.stringify({
|
|
1684
1702
|
total: filtered.length,
|
|
1685
|
-
blocks: filtered
|
|
1703
|
+
blocks: filtered,
|
|
1704
|
+
...filtered.length === 0 && allBlocks.length > 0 && {
|
|
1705
|
+
hint: "No blocks matching your query. Try broader search terms."
|
|
1706
|
+
}
|
|
1686
1707
|
}, null, 2)
|
|
1687
1708
|
}]
|
|
1688
1709
|
};
|
|
@@ -1764,7 +1785,7 @@ If you're a library author, run \`${BRAND.cliCommand} build\` first.`
|
|
|
1764
1785
|
blocks: allBlocks,
|
|
1765
1786
|
tokenData
|
|
1766
1787
|
};
|
|
1767
|
-
const searchResults = await hybridSearch(useCase, localData, 15);
|
|
1788
|
+
const searchResults = await hybridSearch(useCase, localData, 15, void 0, config.apiKey);
|
|
1768
1789
|
const componentResults = searchResults.filter((r) => r.kind === "component").slice(0, 3);
|
|
1769
1790
|
const blockResults = searchResults.filter((r) => r.kind === "block").slice(0, 2);
|
|
1770
1791
|
const tokenResults = searchResults.filter((r) => r.kind === "token").slice(0, 5);
|
|
@@ -1852,7 +1873,7 @@ If you're a library author, run \`${BRAND.cliCommand} build\` first.`
|
|
|
1852
1873
|
return {
|
|
1853
1874
|
content: [{
|
|
1854
1875
|
type: "text",
|
|
1855
|
-
text:
|
|
1876
|
+
text: NO_VIEWER_MSG
|
|
1856
1877
|
}],
|
|
1857
1878
|
isError: true
|
|
1858
1879
|
};
|
|
@@ -1968,7 +1989,7 @@ Suggestion: ${result.suggestion}` : ""}`
|
|
|
1968
1989
|
return {
|
|
1969
1990
|
content: [{
|
|
1970
1991
|
type: "text",
|
|
1971
|
-
text:
|
|
1992
|
+
text: NO_VIEWER_MSG
|
|
1972
1993
|
}],
|
|
1973
1994
|
isError: true
|
|
1974
1995
|
};
|
|
@@ -2028,7 +2049,7 @@ Suggestion: ${result.suggestion}` : ""}`
|
|
|
2028
2049
|
return {
|
|
2029
2050
|
content: [{
|
|
2030
2051
|
type: "text",
|
|
2031
|
-
text:
|
|
2052
|
+
text: NO_VIEWER_MSG
|
|
2032
2053
|
}],
|
|
2033
2054
|
isError: true
|
|
2034
2055
|
};
|
|
@@ -2129,4 +2150,4 @@ export {
|
|
|
2129
2150
|
createMcpServer,
|
|
2130
2151
|
startMcpServer
|
|
2131
2152
|
};
|
|
2132
|
-
//# sourceMappingURL=chunk-
|
|
2153
|
+
//# sourceMappingURL=chunk-WEHZRM4L.js.map
|