@fragments-sdk/context 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ZMBYQK43.js → chunk-F3ZH5BUA.js} +0 -1
- package/dist/chunk-HAJWPNLU.js +310 -0
- package/dist/chunk-U4V5NX67.js +447 -0
- package/dist/cli-commands/index.d.ts +31 -0
- package/dist/cli-commands/index.js +8 -0
- package/dist/generate/index.d.ts +1 -0
- package/dist/graph/index.d.ts +66 -0
- package/dist/graph/index.js +388 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +17 -1
- package/dist/mcp-tools/index.d.ts +53 -0
- package/dist/mcp-tools/index.js +12 -0
- package/dist/search/index.js +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types-DOhSojcf.d.ts +119 -0
- package/package.json +17 -1
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
// src/graph/types.ts
|
|
2
|
+
var GRAPH_EDGE_TYPES = [
|
|
3
|
+
"imports",
|
|
4
|
+
"hook-depends",
|
|
5
|
+
"renders",
|
|
6
|
+
"composes",
|
|
7
|
+
"parent-of",
|
|
8
|
+
"alternative-to",
|
|
9
|
+
"sibling-of"
|
|
10
|
+
];
|
|
11
|
+
var EDGE_TYPE_WEIGHTS = {
|
|
12
|
+
"imports": 1,
|
|
13
|
+
"hook-depends": 0.75,
|
|
14
|
+
"renders": 0.5,
|
|
15
|
+
"composes": 0.5,
|
|
16
|
+
"parent-of": 1,
|
|
17
|
+
"alternative-to": 1,
|
|
18
|
+
"sibling-of": 0.75
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/graph/engine.ts
|
|
22
|
+
var ComponentGraphEngine = class {
|
|
23
|
+
nodes;
|
|
24
|
+
outgoing;
|
|
25
|
+
incoming;
|
|
26
|
+
edges;
|
|
27
|
+
blockIndex;
|
|
28
|
+
health;
|
|
29
|
+
constructor(graph, blocks) {
|
|
30
|
+
this.nodes = /* @__PURE__ */ new Map();
|
|
31
|
+
this.outgoing = /* @__PURE__ */ new Map();
|
|
32
|
+
this.incoming = /* @__PURE__ */ new Map();
|
|
33
|
+
this.edges = graph.edges;
|
|
34
|
+
this.health = graph.health;
|
|
35
|
+
this.blockIndex = /* @__PURE__ */ new Map();
|
|
36
|
+
for (const node of graph.nodes) {
|
|
37
|
+
this.nodes.set(node.name, node);
|
|
38
|
+
this.outgoing.set(node.name, []);
|
|
39
|
+
this.incoming.set(node.name, []);
|
|
40
|
+
}
|
|
41
|
+
for (const edge of graph.edges) {
|
|
42
|
+
const out = this.outgoing.get(edge.source);
|
|
43
|
+
if (out) out.push(edge);
|
|
44
|
+
else this.outgoing.set(edge.source, [edge]);
|
|
45
|
+
const inc = this.incoming.get(edge.target);
|
|
46
|
+
if (inc) inc.push(edge);
|
|
47
|
+
else this.incoming.set(edge.target, [edge]);
|
|
48
|
+
}
|
|
49
|
+
if (blocks) {
|
|
50
|
+
for (const [blockName, block] of Object.entries(blocks)) {
|
|
51
|
+
for (const comp of block.components) {
|
|
52
|
+
const existing = this.blockIndex.get(comp);
|
|
53
|
+
if (existing) existing.push(blockName);
|
|
54
|
+
else this.blockIndex.set(comp, [blockName]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// -------------------------------------------------------------------------
|
|
60
|
+
// Core queries
|
|
61
|
+
// -------------------------------------------------------------------------
|
|
62
|
+
/** Get outgoing edges from a component, optionally filtered by edge type */
|
|
63
|
+
dependencies(component, edgeTypes) {
|
|
64
|
+
const edges = this.outgoing.get(component) ?? [];
|
|
65
|
+
if (!edgeTypes || edgeTypes.length === 0) return edges;
|
|
66
|
+
return edges.filter((e) => edgeTypes.includes(e.type));
|
|
67
|
+
}
|
|
68
|
+
/** Get incoming edges to a component, optionally filtered by edge type */
|
|
69
|
+
dependents(component, edgeTypes) {
|
|
70
|
+
const edges = this.incoming.get(component) ?? [];
|
|
71
|
+
if (!edgeTypes || edgeTypes.length === 0) return edges;
|
|
72
|
+
return edges.filter((e) => edgeTypes.includes(e.type));
|
|
73
|
+
}
|
|
74
|
+
/** BFS transitive closure — what's affected if this component changes */
|
|
75
|
+
impact(component, maxDepth = 3) {
|
|
76
|
+
const affected = [];
|
|
77
|
+
const visited = /* @__PURE__ */ new Set([component]);
|
|
78
|
+
const queue = [
|
|
79
|
+
{ name: component, depth: 0, path: [component] }
|
|
80
|
+
];
|
|
81
|
+
while (queue.length > 0) {
|
|
82
|
+
const current = queue.shift();
|
|
83
|
+
if (current.depth >= maxDepth) continue;
|
|
84
|
+
const deps = this.incoming.get(current.name) ?? [];
|
|
85
|
+
for (const edge of deps) {
|
|
86
|
+
if (visited.has(edge.source)) continue;
|
|
87
|
+
visited.add(edge.source);
|
|
88
|
+
const newPath = [...current.path, edge.source];
|
|
89
|
+
affected.push({
|
|
90
|
+
component: edge.source,
|
|
91
|
+
depth: current.depth + 1,
|
|
92
|
+
path: newPath,
|
|
93
|
+
edgeType: edge.type
|
|
94
|
+
});
|
|
95
|
+
queue.push({ name: edge.source, depth: current.depth + 1, path: newPath });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const affectedComponents = /* @__PURE__ */ new Set([component, ...affected.map((a) => a.component)]);
|
|
99
|
+
const affectedBlocks = /* @__PURE__ */ new Set();
|
|
100
|
+
for (const comp of affectedComponents) {
|
|
101
|
+
const blocks = this.blockIndex.get(comp);
|
|
102
|
+
if (blocks) {
|
|
103
|
+
for (const b of blocks) affectedBlocks.add(b);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
component,
|
|
108
|
+
affected,
|
|
109
|
+
affectedBlocks: [...affectedBlocks],
|
|
110
|
+
totalAffected: affected.length
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** BFS shortest path between two components (undirected) */
|
|
114
|
+
path(from, to) {
|
|
115
|
+
if (from === to) {
|
|
116
|
+
return { found: true, path: [from], edges: [] };
|
|
117
|
+
}
|
|
118
|
+
const visited = /* @__PURE__ */ new Set([from]);
|
|
119
|
+
const queue = [
|
|
120
|
+
{ name: from, path: [from], edges: [] }
|
|
121
|
+
];
|
|
122
|
+
while (queue.length > 0) {
|
|
123
|
+
const current = queue.shift();
|
|
124
|
+
const allEdges = [
|
|
125
|
+
...this.outgoing.get(current.name) ?? [],
|
|
126
|
+
...this.incoming.get(current.name) ?? []
|
|
127
|
+
];
|
|
128
|
+
for (const edge of allEdges) {
|
|
129
|
+
const neighbor = edge.source === current.name ? edge.target : edge.source;
|
|
130
|
+
if (visited.has(neighbor)) continue;
|
|
131
|
+
visited.add(neighbor);
|
|
132
|
+
const newPath = [...current.path, neighbor];
|
|
133
|
+
const newEdges = [...current.edges, edge];
|
|
134
|
+
if (neighbor === to) {
|
|
135
|
+
return { found: true, path: newPath, edges: newEdges };
|
|
136
|
+
}
|
|
137
|
+
queue.push({ name: neighbor, path: newPath, edges: newEdges });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { found: false, path: [], edges: [] };
|
|
141
|
+
}
|
|
142
|
+
/** Connected components via BFS on undirected projection */
|
|
143
|
+
islands() {
|
|
144
|
+
const visited = /* @__PURE__ */ new Set();
|
|
145
|
+
const components = [];
|
|
146
|
+
for (const nodeName of this.nodes.keys()) {
|
|
147
|
+
if (visited.has(nodeName)) continue;
|
|
148
|
+
const island = [];
|
|
149
|
+
const queue = [nodeName];
|
|
150
|
+
visited.add(nodeName);
|
|
151
|
+
while (queue.length > 0) {
|
|
152
|
+
const current = queue.shift();
|
|
153
|
+
island.push(current);
|
|
154
|
+
const allEdges = [
|
|
155
|
+
...this.outgoing.get(current) ?? [],
|
|
156
|
+
...this.incoming.get(current) ?? []
|
|
157
|
+
];
|
|
158
|
+
for (const edge of allEdges) {
|
|
159
|
+
const neighbor = edge.source === current ? edge.target : edge.source;
|
|
160
|
+
if (!visited.has(neighbor) && this.nodes.has(neighbor)) {
|
|
161
|
+
visited.add(neighbor);
|
|
162
|
+
queue.push(neighbor);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
components.push(island.sort());
|
|
167
|
+
}
|
|
168
|
+
return components.sort((a, b) => b.length - a.length);
|
|
169
|
+
}
|
|
170
|
+
/** All components reachable within N hops (undirected) */
|
|
171
|
+
neighbors(component, maxHops = 1) {
|
|
172
|
+
const neighbors = [];
|
|
173
|
+
const visited = /* @__PURE__ */ new Set([component]);
|
|
174
|
+
const queue = [
|
|
175
|
+
{ name: component, hops: 0 }
|
|
176
|
+
];
|
|
177
|
+
while (queue.length > 0) {
|
|
178
|
+
const current = queue.shift();
|
|
179
|
+
if (current.hops >= maxHops) continue;
|
|
180
|
+
const allEdges = [
|
|
181
|
+
...this.outgoing.get(current.name) ?? [],
|
|
182
|
+
...this.incoming.get(current.name) ?? []
|
|
183
|
+
];
|
|
184
|
+
for (const edge of allEdges) {
|
|
185
|
+
const neighbor = edge.source === current.name ? edge.target : edge.source;
|
|
186
|
+
if (visited.has(neighbor)) continue;
|
|
187
|
+
visited.add(neighbor);
|
|
188
|
+
neighbors.push({
|
|
189
|
+
component: neighbor,
|
|
190
|
+
hops: current.hops + 1,
|
|
191
|
+
edgeType: edge.type
|
|
192
|
+
});
|
|
193
|
+
queue.push({ name: neighbor, hops: current.hops + 1 });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { component, neighbors };
|
|
197
|
+
}
|
|
198
|
+
// -------------------------------------------------------------------------
|
|
199
|
+
// Design-system queries
|
|
200
|
+
// -------------------------------------------------------------------------
|
|
201
|
+
/** Get the composition tree for a compound component */
|
|
202
|
+
composition(component) {
|
|
203
|
+
const node = this.nodes.get(component);
|
|
204
|
+
const subComponents = node?.subComponents ?? [];
|
|
205
|
+
const parentEdges = (this.outgoing.get(component) ?? []).filter((e) => e.type === "parent-of");
|
|
206
|
+
const requiredChildren = parentEdges.map((e) => e.target);
|
|
207
|
+
const childEdges = (this.incoming.get(component) ?? []).filter((e) => e.type === "parent-of");
|
|
208
|
+
const parent = childEdges.length > 0 ? childEdges[0].source : void 0;
|
|
209
|
+
const siblings = [];
|
|
210
|
+
if (parent) {
|
|
211
|
+
const parentOut = (this.outgoing.get(parent) ?? []).filter((e) => e.type === "parent-of");
|
|
212
|
+
for (const edge of parentOut) {
|
|
213
|
+
if (edge.target !== component) {
|
|
214
|
+
siblings.push(edge.target);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const siblingEdges = [
|
|
219
|
+
...(this.outgoing.get(component) ?? []).filter((e) => e.type === "sibling-of"),
|
|
220
|
+
...(this.incoming.get(component) ?? []).filter((e) => e.type === "sibling-of")
|
|
221
|
+
];
|
|
222
|
+
for (const edge of siblingEdges) {
|
|
223
|
+
const sib = edge.source === component ? edge.target : edge.source;
|
|
224
|
+
if (!siblings.includes(sib)) siblings.push(sib);
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
component,
|
|
228
|
+
compositionPattern: node?.compositionPattern,
|
|
229
|
+
subComponents,
|
|
230
|
+
requiredChildren,
|
|
231
|
+
parent,
|
|
232
|
+
siblings,
|
|
233
|
+
blocks: this.blockIndex.get(component) ?? []
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/** Get alternative components */
|
|
237
|
+
alternatives(component) {
|
|
238
|
+
const alts = [];
|
|
239
|
+
for (const edge of this.outgoing.get(component) ?? []) {
|
|
240
|
+
if (edge.type === "alternative-to") {
|
|
241
|
+
alts.push({ component: edge.target, note: edge.note });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
for (const edge of this.incoming.get(component) ?? []) {
|
|
245
|
+
if (edge.type === "alternative-to") {
|
|
246
|
+
alts.push({ component: edge.source, note: edge.note });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return alts;
|
|
250
|
+
}
|
|
251
|
+
/** Get blocks that use a component */
|
|
252
|
+
blocksUsing(component) {
|
|
253
|
+
return this.blockIndex.get(component) ?? [];
|
|
254
|
+
}
|
|
255
|
+
/** Extract an induced subgraph for a set of components */
|
|
256
|
+
subgraph(components) {
|
|
257
|
+
const componentSet = new Set(components);
|
|
258
|
+
const nodes = components.map((name) => this.nodes.get(name)).filter((n) => n !== void 0);
|
|
259
|
+
const edges = this.edges.filter(
|
|
260
|
+
(e) => componentSet.has(e.source) && componentSet.has(e.target)
|
|
261
|
+
);
|
|
262
|
+
return {
|
|
263
|
+
nodes,
|
|
264
|
+
edges,
|
|
265
|
+
health: computeHealthFromData(nodes, edges, this.blockIndex)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/** Return precomputed health metrics */
|
|
269
|
+
getHealth() {
|
|
270
|
+
return this.health;
|
|
271
|
+
}
|
|
272
|
+
/** Get a single node by name */
|
|
273
|
+
getNode(name) {
|
|
274
|
+
return this.nodes.get(name);
|
|
275
|
+
}
|
|
276
|
+
/** Check if a component exists in the graph */
|
|
277
|
+
hasNode(name) {
|
|
278
|
+
return this.nodes.has(name);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
function computeHealthFromData(nodes, edges, blockIndex) {
|
|
282
|
+
const nodeNames = new Set(nodes.map((n) => n.name));
|
|
283
|
+
const degreeMap = /* @__PURE__ */ new Map();
|
|
284
|
+
for (const name of nodeNames) {
|
|
285
|
+
degreeMap.set(name, 0);
|
|
286
|
+
}
|
|
287
|
+
for (const edge of edges) {
|
|
288
|
+
degreeMap.set(edge.source, (degreeMap.get(edge.source) ?? 0) + 1);
|
|
289
|
+
degreeMap.set(edge.target, (degreeMap.get(edge.target) ?? 0) + 1);
|
|
290
|
+
}
|
|
291
|
+
const orphans = [];
|
|
292
|
+
for (const [name, degree] of degreeMap) {
|
|
293
|
+
if (degree === 0) orphans.push(name);
|
|
294
|
+
}
|
|
295
|
+
const hubs = [...degreeMap.entries()].map(([name, degree]) => ({ name, degree })).sort((a, b) => b.degree - a.degree).slice(0, 10);
|
|
296
|
+
let inBlock = 0;
|
|
297
|
+
if (blockIndex) {
|
|
298
|
+
for (const name of nodeNames) {
|
|
299
|
+
if ((blockIndex.get(name) ?? []).length > 0) inBlock++;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const compositionCoverage = nodeNames.size > 0 ? Math.round(inBlock / nodeNames.size * 100) : 0;
|
|
303
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
304
|
+
for (const name of nodeNames) {
|
|
305
|
+
adjacency.set(name, /* @__PURE__ */ new Set());
|
|
306
|
+
}
|
|
307
|
+
for (const edge of edges) {
|
|
308
|
+
adjacency.get(edge.source)?.add(edge.target);
|
|
309
|
+
adjacency.get(edge.target)?.add(edge.source);
|
|
310
|
+
}
|
|
311
|
+
const visited = /* @__PURE__ */ new Set();
|
|
312
|
+
const connectedComponents = [];
|
|
313
|
+
for (const name of nodeNames) {
|
|
314
|
+
if (visited.has(name)) continue;
|
|
315
|
+
const island = [];
|
|
316
|
+
const queue = [name];
|
|
317
|
+
visited.add(name);
|
|
318
|
+
while (queue.length > 0) {
|
|
319
|
+
const current = queue.shift();
|
|
320
|
+
island.push(current);
|
|
321
|
+
for (const neighbor of adjacency.get(current) ?? []) {
|
|
322
|
+
if (!visited.has(neighbor)) {
|
|
323
|
+
visited.add(neighbor);
|
|
324
|
+
queue.push(neighbor);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
connectedComponents.push(island.sort());
|
|
329
|
+
}
|
|
330
|
+
connectedComponents.sort((a, b) => b.length - a.length);
|
|
331
|
+
const totalDegree = [...degreeMap.values()].reduce((sum, d) => sum + d, 0);
|
|
332
|
+
const averageDegree = nodeNames.size > 0 ? Math.round(totalDegree / nodeNames.size * 100) / 100 : 0;
|
|
333
|
+
return {
|
|
334
|
+
orphans: orphans.sort(),
|
|
335
|
+
hubs,
|
|
336
|
+
compositionCoverage,
|
|
337
|
+
connectedComponents,
|
|
338
|
+
averageDegree,
|
|
339
|
+
nodeCount: nodeNames.size,
|
|
340
|
+
edgeCount: edges.length
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// src/graph/serialization.ts
|
|
345
|
+
function serializeGraph(graph) {
|
|
346
|
+
return {
|
|
347
|
+
nodes: graph.nodes,
|
|
348
|
+
edges: graph.edges.map(serializeEdge),
|
|
349
|
+
health: graph.health
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function deserializeGraph(serialized) {
|
|
353
|
+
return {
|
|
354
|
+
nodes: serialized.nodes,
|
|
355
|
+
edges: serialized.edges.map(deserializeEdge),
|
|
356
|
+
health: serialized.health
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function serializeEdge(edge) {
|
|
360
|
+
const result = {
|
|
361
|
+
s: edge.source,
|
|
362
|
+
t: edge.target,
|
|
363
|
+
ty: edge.type,
|
|
364
|
+
w: edge.weight,
|
|
365
|
+
p: edge.provenance
|
|
366
|
+
};
|
|
367
|
+
if (edge.note) result.no = edge.note;
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
function deserializeEdge(edge) {
|
|
371
|
+
const result = {
|
|
372
|
+
source: edge.s,
|
|
373
|
+
target: edge.t,
|
|
374
|
+
type: edge.ty,
|
|
375
|
+
weight: edge.w,
|
|
376
|
+
provenance: edge.p
|
|
377
|
+
};
|
|
378
|
+
if (edge.no) result.note = edge.no;
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
export {
|
|
382
|
+
ComponentGraphEngine,
|
|
383
|
+
EDGE_TYPE_WEIGHTS,
|
|
384
|
+
GRAPH_EDGE_TYPES,
|
|
385
|
+
computeHealthFromData,
|
|
386
|
+
deserializeGraph,
|
|
387
|
+
serializeGraph
|
|
388
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -6,3 +6,6 @@ export { deduplicateChunks, reciprocalRankFusion } from './search/index.js';
|
|
|
6
6
|
export { F as FusedResult, R as RankedResult, a as ScoredChunk, S as SearchResult } from './types-B7duBj6U.js';
|
|
7
7
|
export { AST_SUPPORTED_LANGUAGES, ChangedFiles, FileEntry, GrammarMapping, INDEXABLE_EXTENSIONS, detectLanguage, getTreeSitterGrammar, hashContent, resolveChanges, shouldIndexFile } from './indexing/index.js';
|
|
8
8
|
export { ChunkMapping, CitationDocumentBlock, CitationDocumentOptions, DocumentMapping, RawCitation, ResolvedCitation, buildCitationDocuments, resolveCitation, resolveCitations } from './citations/index.js';
|
|
9
|
+
export { CLI_TOOL_EXTENSIONS, CliToolExtension, MCP_TOOL_DEFINITIONS, McpToolDefinition, McpToolParam, buildMcpTools, buildToolNames } from './mcp-tools/index.js';
|
|
10
|
+
export { CLI_COMMANDS, CLI_COMMAND_CATEGORIES, CliCategoryInfo, CliCommandCategory, CliCommandDef, CliOptionDef } from './cli-commands/index.js';
|
|
11
|
+
import './types-DOhSojcf.js';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CLI_TOOL_EXTENSIONS,
|
|
3
|
+
MCP_TOOL_DEFINITIONS,
|
|
4
|
+
buildMcpTools,
|
|
5
|
+
buildToolNames
|
|
6
|
+
} from "./chunk-HAJWPNLU.js";
|
|
7
|
+
import {
|
|
8
|
+
CLI_COMMANDS,
|
|
9
|
+
CLI_COMMAND_CATEGORIES
|
|
10
|
+
} from "./chunk-U4V5NX67.js";
|
|
1
11
|
import {
|
|
2
12
|
chunkByAST,
|
|
3
13
|
chunkByLines,
|
|
@@ -10,7 +20,7 @@ import {
|
|
|
10
20
|
import {
|
|
11
21
|
deduplicateChunks,
|
|
12
22
|
reciprocalRankFusion
|
|
13
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-F3ZH5BUA.js";
|
|
14
24
|
import {
|
|
15
25
|
hashContent,
|
|
16
26
|
resolveChanges
|
|
@@ -34,9 +44,15 @@ import {
|
|
|
34
44
|
} from "./chunk-3FEHRHFQ.js";
|
|
35
45
|
export {
|
|
36
46
|
AST_SUPPORTED_LANGUAGES,
|
|
47
|
+
CLI_COMMANDS,
|
|
48
|
+
CLI_COMMAND_CATEGORIES,
|
|
49
|
+
CLI_TOOL_EXTENSIONS,
|
|
37
50
|
INDEXABLE_EXTENSIONS,
|
|
51
|
+
MCP_TOOL_DEFINITIONS,
|
|
38
52
|
PLACEHOLDER_PATTERNS,
|
|
39
53
|
buildCitationDocuments,
|
|
54
|
+
buildMcpTools,
|
|
55
|
+
buildToolNames,
|
|
40
56
|
chunkByAST,
|
|
41
57
|
chunkByLines,
|
|
42
58
|
chunkFile,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared MCP tool definitions for Fragments.
|
|
3
|
+
*
|
|
4
|
+
* Both @fragments-sdk/mcp (standalone) and @fragments-sdk/cli (full-featured)
|
|
5
|
+
* import from here, eliminating duplication of tool names, descriptions, and
|
|
6
|
+
* input schemas.
|
|
7
|
+
*/
|
|
8
|
+
interface McpToolParam {
|
|
9
|
+
type: string;
|
|
10
|
+
description: string;
|
|
11
|
+
enum?: string[];
|
|
12
|
+
items?: {
|
|
13
|
+
type: string;
|
|
14
|
+
};
|
|
15
|
+
properties?: Record<string, McpToolParam>;
|
|
16
|
+
}
|
|
17
|
+
interface McpToolDefinition {
|
|
18
|
+
/** Short key used to build the prefixed tool name, e.g. "discover" */
|
|
19
|
+
key: string;
|
|
20
|
+
description: string;
|
|
21
|
+
params: Record<string, McpToolParam>;
|
|
22
|
+
required?: string[];
|
|
23
|
+
}
|
|
24
|
+
/** Extra params only present in the CLI server (Playwright-backed) */
|
|
25
|
+
interface CliToolExtension {
|
|
26
|
+
key: string;
|
|
27
|
+
/** Additional params merged into the base tool's inputSchema.properties */
|
|
28
|
+
params: Record<string, McpToolParam>;
|
|
29
|
+
/** Override the description (e.g. CLI render mentions baseline) */
|
|
30
|
+
description?: string;
|
|
31
|
+
}
|
|
32
|
+
declare const MCP_TOOL_DEFINITIONS: McpToolDefinition[];
|
|
33
|
+
declare const CLI_TOOL_EXTENSIONS: CliToolExtension[];
|
|
34
|
+
interface McpSdkTool {
|
|
35
|
+
name: string;
|
|
36
|
+
description: string;
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object';
|
|
39
|
+
properties: Record<string, unknown>;
|
|
40
|
+
required?: string[];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build a TOOL_NAMES map: `{ discover: "prefix_discover", ... }`
|
|
45
|
+
*/
|
|
46
|
+
declare function buildToolNames(prefix: string): Record<string, string>;
|
|
47
|
+
/**
|
|
48
|
+
* Build MCP SDK `Tool[]` from shared definitions, optionally merging CLI
|
|
49
|
+
* extensions.
|
|
50
|
+
*/
|
|
51
|
+
declare function buildMcpTools(prefix: string, extensions?: CliToolExtension[]): McpSdkTool[];
|
|
52
|
+
|
|
53
|
+
export { CLI_TOOL_EXTENSIONS, type CliToolExtension, MCP_TOOL_DEFINITIONS, type McpToolDefinition, type McpToolParam, buildMcpTools, buildToolNames };
|
package/dist/search/index.js
CHANGED
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { S as SerializedComponentGraph } from '../types-DOhSojcf.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Compiled fragment types — shared between CLI and MCP packages.
|
|
3
5
|
*
|
|
@@ -140,6 +142,8 @@ interface CompiledSegmentsFile {
|
|
|
140
142
|
segments: Record<string, CompiledSegment>;
|
|
141
143
|
blocks?: Record<string, CompiledBlock>;
|
|
142
144
|
tokens?: CompiledTokenData;
|
|
145
|
+
/** Component relationship graph for AI structural queries */
|
|
146
|
+
graph?: SerializedComponentGraph;
|
|
143
147
|
/** @deprecated Use blocks instead */
|
|
144
148
|
recipes?: Record<string, CompiledBlock>;
|
|
145
149
|
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Graph data model — types for the design-system-semantic relationship graph.
|
|
3
|
+
*
|
|
4
|
+
* These types describe nodes (components), edges (relationships), and health
|
|
5
|
+
* metrics that together give AI agents structural understanding of a design system.
|
|
6
|
+
*/
|
|
7
|
+
type GraphEdgeType = 'imports' | 'hook-depends' | 'renders' | 'composes' | 'parent-of' | 'alternative-to' | 'sibling-of';
|
|
8
|
+
declare const GRAPH_EDGE_TYPES: readonly GraphEdgeType[];
|
|
9
|
+
/** Default weight for each edge type */
|
|
10
|
+
declare const EDGE_TYPE_WEIGHTS: Record<GraphEdgeType, number>;
|
|
11
|
+
interface ComponentNode {
|
|
12
|
+
name: string;
|
|
13
|
+
category: string;
|
|
14
|
+
status: string;
|
|
15
|
+
compositionPattern?: 'compound' | 'simple' | 'controlled';
|
|
16
|
+
subComponents?: string[];
|
|
17
|
+
}
|
|
18
|
+
interface GraphEdge {
|
|
19
|
+
source: string;
|
|
20
|
+
target: string;
|
|
21
|
+
type: GraphEdgeType;
|
|
22
|
+
weight: number;
|
|
23
|
+
note?: string;
|
|
24
|
+
/** Where this edge was detected from */
|
|
25
|
+
provenance: string;
|
|
26
|
+
}
|
|
27
|
+
interface GraphHealth {
|
|
28
|
+
/** Components with zero edges */
|
|
29
|
+
orphans: string[];
|
|
30
|
+
/** Top components by total degree (in + out) */
|
|
31
|
+
hubs: Array<{
|
|
32
|
+
name: string;
|
|
33
|
+
degree: number;
|
|
34
|
+
}>;
|
|
35
|
+
/** Percentage of components appearing in at least one block */
|
|
36
|
+
compositionCoverage: number;
|
|
37
|
+
/** Disconnected groups (BFS on undirected projection) */
|
|
38
|
+
connectedComponents: string[][];
|
|
39
|
+
/** Average degree across all nodes */
|
|
40
|
+
averageDegree: number;
|
|
41
|
+
/** Total node and edge counts */
|
|
42
|
+
nodeCount: number;
|
|
43
|
+
edgeCount: number;
|
|
44
|
+
}
|
|
45
|
+
interface ComponentGraph {
|
|
46
|
+
nodes: ComponentNode[];
|
|
47
|
+
edges: GraphEdge[];
|
|
48
|
+
health: GraphHealth;
|
|
49
|
+
}
|
|
50
|
+
interface ImpactResult {
|
|
51
|
+
/** The component that was changed */
|
|
52
|
+
component: string;
|
|
53
|
+
/** Components affected at each depth level */
|
|
54
|
+
affected: Array<{
|
|
55
|
+
component: string;
|
|
56
|
+
depth: number;
|
|
57
|
+
path: string[];
|
|
58
|
+
edgeType: GraphEdgeType;
|
|
59
|
+
}>;
|
|
60
|
+
/** Blocks that use the changed component or any affected component */
|
|
61
|
+
affectedBlocks: string[];
|
|
62
|
+
/** Total count of affected components */
|
|
63
|
+
totalAffected: number;
|
|
64
|
+
}
|
|
65
|
+
interface PathResult {
|
|
66
|
+
/** Whether a path exists */
|
|
67
|
+
found: boolean;
|
|
68
|
+
/** Nodes along the shortest path (including source and target) */
|
|
69
|
+
path: string[];
|
|
70
|
+
/** Edges along the shortest path */
|
|
71
|
+
edges: GraphEdge[];
|
|
72
|
+
}
|
|
73
|
+
interface NeighborResult {
|
|
74
|
+
/** The center component */
|
|
75
|
+
component: string;
|
|
76
|
+
/** All components reachable within maxHops */
|
|
77
|
+
neighbors: Array<{
|
|
78
|
+
component: string;
|
|
79
|
+
hops: number;
|
|
80
|
+
edgeType: GraphEdgeType;
|
|
81
|
+
}>;
|
|
82
|
+
}
|
|
83
|
+
interface CompositionTree {
|
|
84
|
+
/** The root component */
|
|
85
|
+
component: string;
|
|
86
|
+
/** Composition pattern */
|
|
87
|
+
compositionPattern?: 'compound' | 'simple' | 'controlled';
|
|
88
|
+
/** Direct sub-components */
|
|
89
|
+
subComponents: string[];
|
|
90
|
+
/** Sub-components that must be present */
|
|
91
|
+
requiredChildren: string[];
|
|
92
|
+
/** Parent component (if this is a sub-component) */
|
|
93
|
+
parent?: string;
|
|
94
|
+
/** Sibling components at the same level */
|
|
95
|
+
siblings: string[];
|
|
96
|
+
/** Blocks that use this component */
|
|
97
|
+
blocks: string[];
|
|
98
|
+
}
|
|
99
|
+
interface SerializedEdge {
|
|
100
|
+
/** source */
|
|
101
|
+
s: string;
|
|
102
|
+
/** target */
|
|
103
|
+
t: string;
|
|
104
|
+
/** type */
|
|
105
|
+
ty: GraphEdgeType;
|
|
106
|
+
/** weight */
|
|
107
|
+
w: number;
|
|
108
|
+
/** note (optional) */
|
|
109
|
+
no?: string;
|
|
110
|
+
/** provenance */
|
|
111
|
+
p: string;
|
|
112
|
+
}
|
|
113
|
+
interface SerializedComponentGraph {
|
|
114
|
+
nodes: ComponentNode[];
|
|
115
|
+
edges: SerializedEdge[];
|
|
116
|
+
health: GraphHealth;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { type ComponentGraph as C, EDGE_TYPE_WEIGHTS as E, type GraphEdgeType as G, type ImpactResult as I, type NeighborResult as N, type PathResult as P, type SerializedComponentGraph as S, type GraphEdge as a, type CompositionTree as b, type GraphHealth as c, type ComponentNode as d, type SerializedEdge as e, GRAPH_EDGE_TYPES as f };
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragments-sdk/context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Code intelligence and RAG primitives for design system and codebase indexing",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/ConanMcN/fragments"
|
|
8
|
+
},
|
|
5
9
|
"type": "module",
|
|
6
10
|
"main": "./dist/index.js",
|
|
7
11
|
"module": "./dist/index.js",
|
|
@@ -38,6 +42,18 @@
|
|
|
38
42
|
"./citations": {
|
|
39
43
|
"types": "./dist/citations/index.d.ts",
|
|
40
44
|
"import": "./dist/citations/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./mcp-tools": {
|
|
47
|
+
"types": "./dist/mcp-tools/index.d.ts",
|
|
48
|
+
"import": "./dist/mcp-tools/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./cli-commands": {
|
|
51
|
+
"types": "./dist/cli-commands/index.d.ts",
|
|
52
|
+
"import": "./dist/cli-commands/index.js"
|
|
53
|
+
},
|
|
54
|
+
"./graph": {
|
|
55
|
+
"types": "./dist/graph/index.d.ts",
|
|
56
|
+
"import": "./dist/graph/index.js"
|
|
41
57
|
}
|
|
42
58
|
},
|
|
43
59
|
"publishConfig": {
|