mcp-vector-search 0.9.3__py3-none-any.whl → 0.12.1__py3-none-any.whl

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.

Potentially problematic release.


This version of mcp-vector-search might be problematic. Click here for more details.

@@ -0,0 +1,658 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
6
+ <meta http-equiv="Pragma" content="no-cache">
7
+ <meta http-equiv="Expires" content="0">
8
+ <title>Code Chunk Relationship Graph</title>
9
+ <script src="https://d3js.org/d3.v7.min.js"></script>
10
+ <style>
11
+ body {
12
+ margin: 0;
13
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
14
+ background: #0d1117;
15
+ color: #c9d1d9;
16
+ overflow: hidden;
17
+ }
18
+
19
+ #controls {
20
+ position: absolute;
21
+ top: 20px;
22
+ left: 20px;
23
+ background: rgba(13, 17, 23, 0.95);
24
+ border: 1px solid #30363d;
25
+ border-radius: 6px;
26
+ padding: 16px;
27
+ min-width: 250px;
28
+ max-height: 80vh;
29
+ overflow-y: auto;
30
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
31
+ }
32
+
33
+ h1 { margin: 0 0 16px 0; font-size: 18px; }
34
+ h3 { margin: 16px 0 8px 0; font-size: 14px; color: #8b949e; }
35
+
36
+ .control-group {
37
+ margin-bottom: 12px;
38
+ }
39
+
40
+ label {
41
+ display: block;
42
+ margin-bottom: 4px;
43
+ font-size: 12px;
44
+ color: #8b949e;
45
+ }
46
+
47
+ input[type="file"] {
48
+ width: 100%;
49
+ padding: 6px;
50
+ background: #161b22;
51
+ border: 1px solid #30363d;
52
+ border-radius: 6px;
53
+ color: #c9d1d9;
54
+ font-size: 12px;
55
+ }
56
+
57
+ .legend {
58
+ font-size: 12px;
59
+ }
60
+
61
+ .legend-item {
62
+ margin: 4px 0;
63
+ display: flex;
64
+ align-items: center;
65
+ }
66
+
67
+ .legend-color {
68
+ width: 12px;
69
+ height: 12px;
70
+ border-radius: 50%;
71
+ margin-right: 8px;
72
+ }
73
+
74
+ #graph {
75
+ width: 100vw;
76
+ height: 100vh;
77
+ }
78
+
79
+ .node circle {
80
+ cursor: pointer;
81
+ stroke: #c9d1d9;
82
+ stroke-width: 1.5px;
83
+ }
84
+
85
+ .node.directory circle { fill: #ffa657; }
86
+ .node.file circle { fill: #58a6ff; }
87
+ .node.module circle { fill: #238636; }
88
+ .node.class circle { fill: #1f6feb; }
89
+ .node.function circle { fill: #d29922; }
90
+ .node.method circle { fill: #8957e5; }
91
+ .node.imports circle { fill: #6e7681; }
92
+ .node.text circle { fill: #6e7681; }
93
+ .node.code circle { fill: #6e7681; }
94
+ .node.subproject circle { fill: #da3633; stroke-width: 3px; }
95
+
96
+ .node-icon {
97
+ font-size: 35px !important;
98
+ text-anchor: middle;
99
+ pointer-events: none;
100
+ user-select: none;
101
+ fill: #0d1117;
102
+ font-weight: bold;
103
+ }
104
+
105
+ .node text {
106
+ font-size: 11px;
107
+ fill: #c9d1d9;
108
+ text-anchor: middle;
109
+ pointer-events: none;
110
+ user-select: none;
111
+ }
112
+
113
+ .link {
114
+ stroke: #58a6ff;
115
+ stroke-opacity: 0.4;
116
+ stroke-width: 2px;
117
+ }
118
+
119
+ .link.dependency {
120
+ stroke: #d29922;
121
+ stroke-opacity: 0.8;
122
+ stroke-width: 2px;
123
+ stroke-dasharray: 5,5;
124
+ }
125
+
126
+ .tooltip {
127
+ position: absolute;
128
+ padding: 12px;
129
+ background: rgba(13, 17, 23, 0.95);
130
+ border: 1px solid #30363d;
131
+ border-radius: 6px;
132
+ pointer-events: none;
133
+ display: none;
134
+ font-size: 12px;
135
+ max-width: 300px;
136
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
137
+ }
138
+
139
+ .stats {
140
+ margin-top: 16px;
141
+ padding-top: 16px;
142
+ border-top: 1px solid #30363d;
143
+ font-size: 12px;
144
+ color: #8b949e;
145
+ }
146
+
147
+ #code-viewer {
148
+ position: absolute;
149
+ top: 20px;
150
+ right: 20px;
151
+ width: 500px;
152
+ max-height: 80vh;
153
+ background: rgba(13, 17, 23, 0.95);
154
+ border: 1px solid #30363d;
155
+ border-radius: 6px;
156
+ padding: 16px;
157
+ overflow-y: auto;
158
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
159
+ display: none;
160
+ }
161
+
162
+ #code-viewer.visible {
163
+ display: block;
164
+ }
165
+
166
+ #code-viewer .header {
167
+ margin-bottom: 12px;
168
+ padding-bottom: 12px;
169
+ border-bottom: 1px solid #30363d;
170
+ }
171
+
172
+ #code-viewer .title {
173
+ font-size: 14px;
174
+ font-weight: bold;
175
+ color: #58a6ff;
176
+ margin-bottom: 4px;
177
+ }
178
+
179
+ #code-viewer .meta {
180
+ font-size: 11px;
181
+ color: #8b949e;
182
+ }
183
+
184
+ #code-viewer .close-btn {
185
+ float: right;
186
+ cursor: pointer;
187
+ color: #8b949e;
188
+ font-size: 20px;
189
+ line-height: 1;
190
+ margin-top: -4px;
191
+ }
192
+
193
+ #code-viewer .close-btn:hover {
194
+ color: #c9d1d9;
195
+ }
196
+
197
+ #code-viewer pre {
198
+ margin: 0;
199
+ padding: 12px;
200
+ background: #0d1117;
201
+ border: 1px solid #30363d;
202
+ border-radius: 6px;
203
+ overflow-x: auto;
204
+ font-size: 11px;
205
+ line-height: 1.5;
206
+ }
207
+
208
+ #code-viewer code {
209
+ color: #c9d1d9;
210
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
211
+ }
212
+
213
+ .node.highlighted circle {
214
+ stroke: #f0e68c;
215
+ stroke-width: 3px;
216
+ filter: drop-shadow(0 0 8px #f0e68c);
217
+ }
218
+ </style>
219
+ </head>
220
+ <body>
221
+ <div id="controls">
222
+ <h1>🔍 Code Graph</h1>
223
+
224
+ <div class="control-group" id="loading">
225
+ <label>⏳ Loading graph data...</label>
226
+ </div>
227
+
228
+ <h3>Legend</h3>
229
+ <div class="legend">
230
+ <div class="legend-item">
231
+ 📁 <span class="legend-color" style="background: #ffa657;"></span> Directory
232
+ </div>
233
+ <div class="legend-item">
234
+ 📄 <span class="legend-color" style="background: #58a6ff;"></span> File
235
+ </div>
236
+ <div class="legend-item">
237
+ C <span class="legend-color" style="background: #1f6feb;"></span> Class
238
+ </div>
239
+ <div class="legend-item">
240
+ ƒ <span class="legend-color" style="background: #d29922;"></span> Function
241
+ </div>
242
+ <div class="legend-item">
243
+ m <span class="legend-color" style="background: #8957e5;"></span> Method
244
+ </div>
245
+ <div class="legend-item">
246
+ M <span class="legend-color" style="background: #238636;"></span> Module
247
+ </div>
248
+ <div class="legend-item">
249
+ • <span class="legend-color" style="background: #6e7681;"></span> Text/Other
250
+ </div>
251
+ </div>
252
+
253
+ <div id="subprojects-legend" style="display: none;">
254
+ <h3>Subprojects</h3>
255
+ <div class="legend" id="subprojects-list"></div>
256
+ </div>
257
+
258
+ <div class="stats" id="stats"></div>
259
+ </div>
260
+
261
+ <svg id="graph"></svg>
262
+ <div id="tooltip" class="tooltip"></div>
263
+
264
+ <div id="code-viewer">
265
+ <div class="header">
266
+ <span class="close-btn" onclick="closeCodeViewer()">×</span>
267
+ <div class="title" id="viewer-title"></div>
268
+ <div class="meta" id="viewer-meta"></div>
269
+ </div>
270
+ <pre><code id="viewer-code"></code></pre>
271
+ </div>
272
+
273
+ <script>
274
+ const width = window.innerWidth;
275
+ const height = window.innerHeight;
276
+
277
+ const svg = d3.select("#graph")
278
+ .attr("width", width)
279
+ .attr("height", height)
280
+ .call(d3.zoom().on("zoom", (event) => {
281
+ g.attr("transform", event.transform);
282
+ }));
283
+
284
+ const g = svg.append("g");
285
+ const tooltip = d3.select("#tooltip");
286
+ let simulation;
287
+ let allNodes = [];
288
+ let allLinks = [];
289
+ let allLinksOriginal = []; // Keep original link structure before D3 modifies it
290
+ let visibleNodes = new Set();
291
+ let collapsedNodes = new Set();
292
+ let highlightedNode = null;
293
+
294
+ function visualizeGraph(data) {
295
+ g.selectAll("*").remove();
296
+
297
+ allNodes = data.nodes;
298
+ allLinks = data.links;
299
+ // Deep copy links before D3 modifies them
300
+ allLinksOriginal = JSON.parse(JSON.stringify(data.links));
301
+
302
+ // Find root nodes - start with only top-level nodes
303
+ let rootNodes;
304
+ if (data.metadata && data.metadata.is_monorepo) {
305
+ // In monorepos, subproject nodes are roots
306
+ rootNodes = allNodes.filter(n => n.type === 'subproject');
307
+ } else {
308
+ // Regular projects: prefer directories, fallback to files
309
+ const dirNodes = allNodes.filter(n => n.type === 'directory');
310
+ const fileNodes = allNodes.filter(n => n.type === 'file');
311
+
312
+ if (dirNodes.length > 0) {
313
+ // Show root-level directories (minimum depth)
314
+ const minDirDepth = Math.min(...dirNodes.map(n => n.depth || 0));
315
+ rootNodes = dirNodes.filter(n => (n.depth || 0) === minDirDepth);
316
+ } else if (fileNodes.length > 0) {
317
+ // No directories, show root-level files
318
+ const minFileDepth = Math.min(...fileNodes.map(n => n.depth || 0));
319
+ rootNodes = fileNodes.filter(n => (n.depth || 0) === minFileDepth);
320
+ } else {
321
+ // No directories or files, show all nodes
322
+ rootNodes = allNodes;
323
+ }
324
+ }
325
+
326
+ // Start with only root nodes visible, all collapsed
327
+ visibleNodes = new Set(rootNodes.map(n => n.id));
328
+ collapsedNodes = new Set(rootNodes.map(n => n.id));
329
+
330
+ renderGraph();
331
+ }
332
+
333
+ function renderGraph() {
334
+ const visibleNodesList = allNodes.filter(n => visibleNodes.has(n.id));
335
+ const visibleLinks = allLinks.filter(l =>
336
+ visibleNodes.has(l.source.id || l.source) &&
337
+ visibleNodes.has(l.target.id || l.target)
338
+ );
339
+
340
+ // Dynamic collision radius based on node type
341
+ const getNodeRadius = (d) => {
342
+ if (d.type === 'directory') return 35;
343
+ if (d.type === 'file') return 32;
344
+ if (d.type === 'subproject') return 38;
345
+ return d.complexity ? Math.min(20 + d.complexity * 2, 35) : 25;
346
+ };
347
+
348
+ // Dynamic link distance based on node types
349
+ const getLinkDistance = (link) => {
350
+ const source = typeof link.source === 'object' ? link.source : visibleNodesList.find(n => n.id === link.source);
351
+ const target = typeof link.target === 'object' ? link.target : visibleNodesList.find(n => n.id === link.target);
352
+
353
+ if (!source || !target) return 150;
354
+
355
+ // Longer distances for directory relationships
356
+ if (source.type === 'directory' || target.type === 'directory') return 200;
357
+ if (source.type === 'file' || target.type === 'file') return 150;
358
+ return 100;
359
+ };
360
+
361
+ simulation = d3.forceSimulation(visibleNodesList)
362
+ .force("link", d3.forceLink(visibleLinks)
363
+ .id(d => d.id)
364
+ .distance(getLinkDistance)
365
+ .strength(0.5))
366
+ .force("charge", d3.forceManyBody()
367
+ .strength(d => {
368
+ // Stronger repulsion for directories and files
369
+ if (d.type === 'directory') return -800;
370
+ if (d.type === 'file') return -600;
371
+ return -400;
372
+ })
373
+ .distanceMax(500))
374
+ .force("center", d3.forceCenter(width / 2, height / 2))
375
+ .force("collision", d3.forceCollide()
376
+ .radius(getNodeRadius)
377
+ .strength(0.9))
378
+ .force("x", d3.forceX(width / 2).strength(0.05))
379
+ .force("y", d3.forceY(height / 2).strength(0.05))
380
+ .alphaDecay(0.02)
381
+ .velocityDecay(0.3);
382
+
383
+ g.selectAll("*").remove();
384
+
385
+ const link = g.append("g")
386
+ .selectAll("line")
387
+ .data(visibleLinks)
388
+ .join("line")
389
+ .attr("class", d => d.type === "dependency" ? "link dependency" : "link");
390
+
391
+ const node = g.append("g")
392
+ .selectAll("g")
393
+ .data(visibleNodesList)
394
+ .join("g")
395
+ .attr("class", d => {
396
+ let classes = `node ${d.type}`;
397
+ if (highlightedNode && d.id === highlightedNode.id) {
398
+ classes += ' highlighted';
399
+ }
400
+ return classes;
401
+ })
402
+ .call(drag(simulation))
403
+ .on("click", handleNodeClick)
404
+ .on("mouseover", showTooltip)
405
+ .on("mouseout", hideTooltip);
406
+
407
+ // Add circles
408
+ node.append("circle")
409
+ .attr("r", d => {
410
+ if (d.type === 'directory') return 25;
411
+ if (d.type === 'file') return 22;
412
+ if (d.type === 'subproject') return 28;
413
+ return d.complexity ? Math.min(12 + d.complexity * 2, 25) : 15;
414
+ })
415
+ .style("fill", d => d.color || null);
416
+
417
+ // Add icons based on node type
418
+ node.append("text")
419
+ .attr("class", "node-icon")
420
+ .attr("dy", 15)
421
+ .text(d => {
422
+ if (d.type === 'directory') return '📁';
423
+ if (d.type === 'file') return '📄';
424
+ if (d.type === 'class') return 'C';
425
+ if (d.type === 'function') return 'ƒ';
426
+ if (d.type === 'method') return 'm';
427
+ if (d.type === 'module') return 'M';
428
+ if (d.type === 'imports') return '⇄';
429
+ return '•';
430
+ });
431
+
432
+ // Add expand/collapse indicator for nodes with children
433
+ node.filter(d => hasChildren(d))
434
+ .append("text")
435
+ .attr("class", "expand-indicator")
436
+ .attr("text-anchor", "middle")
437
+ .attr("dy", -20)
438
+ .style("font-size", "14px")
439
+ .style("font-weight", "bold")
440
+ .style("fill", "#58a6ff")
441
+ .style("pointer-events", "none")
442
+ .text(d => collapsedNodes.has(d.id) ? "+" : "−");
443
+
444
+ // Add labels
445
+ node.append("text")
446
+ .text(d => d.name)
447
+ .attr("dy", 30);
448
+
449
+ simulation.on("tick", () => {
450
+ link
451
+ .attr("x1", d => d.source.x)
452
+ .attr("y1", d => d.source.y)
453
+ .attr("x2", d => d.target.x)
454
+ .attr("y2", d => d.target.y);
455
+
456
+ node.attr("transform", d => `translate(${d.x},${d.y})`);
457
+ });
458
+
459
+ updateStats({nodes: visibleNodesList, links: visibleLinks, metadata: {total_files: allNodes.length}});
460
+ }
461
+
462
+ function hasChildren(node) {
463
+ // Use original links (not modified by D3)
464
+ return allLinksOriginal.some(l => l.source === node.id);
465
+ }
466
+
467
+ function handleNodeClick(event, d) {
468
+ event.stopPropagation();
469
+
470
+ // If node has children, toggle expansion
471
+ if (hasChildren(d)) {
472
+ if (collapsedNodes.has(d.id)) {
473
+ expandNode(d);
474
+ } else {
475
+ collapseNode(d);
476
+ }
477
+ renderGraph();
478
+ } else {
479
+ // Leaf node - show code viewer
480
+ showCodeViewer(d);
481
+ }
482
+ }
483
+
484
+ function expandNode(node) {
485
+ collapsedNodes.delete(node.id);
486
+
487
+ // Find direct children using original links (not modified by D3)
488
+ const children = allLinksOriginal
489
+ .filter(l => l.source === node.id)
490
+ .map(l => allNodes.find(n => n.id === l.target))
491
+ .filter(n => n);
492
+
493
+ children.forEach(child => {
494
+ visibleNodes.add(child.id);
495
+ collapsedNodes.add(child.id); // Children start collapsed
496
+ });
497
+ }
498
+
499
+ function collapseNode(node) {
500
+ collapsedNodes.add(node.id);
501
+
502
+ // Hide all descendants recursively using original links
503
+ function hideDescendants(parentId) {
504
+ const children = allLinksOriginal
505
+ .filter(l => l.source === parentId)
506
+ .map(l => l.target);
507
+
508
+ children.forEach(childId => {
509
+ visibleNodes.delete(childId);
510
+ collapsedNodes.delete(childId);
511
+ hideDescendants(childId);
512
+ });
513
+ }
514
+
515
+ hideDescendants(node.id);
516
+ }
517
+
518
+ function showTooltip(event, d) {
519
+ tooltip
520
+ .style("display", "block")
521
+ .style("left", (event.pageX + 10) + "px")
522
+ .style("top", (event.pageY + 10) + "px")
523
+ .html(`
524
+ <div><strong>${d.name}</strong></div>
525
+ <div>Type: ${d.type}</div>
526
+ ${d.complexity ? `<div>Complexity: ${d.complexity.toFixed(1)}</div>` : ''}
527
+ ${d.start_line ? `<div>Lines: ${d.start_line}-${d.end_line}</div>` : ''}
528
+ <div>File: ${d.file_path}</div>
529
+ `);
530
+ }
531
+
532
+ function hideTooltip() {
533
+ tooltip.style("display", "none");
534
+ }
535
+
536
+ function drag(simulation) {
537
+ function dragstarted(event) {
538
+ if (!event.active) simulation.alphaTarget(0.3).restart();
539
+ event.subject.fx = event.subject.x;
540
+ event.subject.fy = event.subject.y;
541
+ }
542
+
543
+ function dragged(event) {
544
+ event.subject.fx = event.x;
545
+ event.subject.fy = event.y;
546
+ }
547
+
548
+ function dragended(event) {
549
+ if (!event.active) simulation.alphaTarget(0);
550
+ event.subject.fx = null;
551
+ event.subject.fy = null;
552
+ }
553
+
554
+ return d3.drag()
555
+ .on("start", dragstarted)
556
+ .on("drag", dragged)
557
+ .on("end", dragended);
558
+ }
559
+
560
+ function updateStats(data) {
561
+ const stats = d3.select("#stats");
562
+ stats.html(`
563
+ <div>Nodes: ${data.nodes.length}</div>
564
+ <div>Links: ${data.links.length}</div>
565
+ ${data.metadata ? `<div>Files: ${data.metadata.total_files || 'N/A'}</div>` : ''}
566
+ ${data.metadata && data.metadata.is_monorepo ? `<div>Monorepo: ${data.metadata.subprojects.length} subprojects</div>` : ''}
567
+ `);
568
+
569
+ // Show subproject legend if monorepo
570
+ if (data.metadata && data.metadata.is_monorepo && data.metadata.subprojects.length > 0) {
571
+ const subprojectsLegend = d3.select("#subprojects-legend");
572
+ const subprojectsList = d3.select("#subprojects-list");
573
+
574
+ subprojectsLegend.style("display", "block");
575
+
576
+ // Get subproject nodes with colors
577
+ const subprojectNodes = allNodes.filter(n => n.type === 'subproject');
578
+
579
+ subprojectsList.html(
580
+ subprojectNodes.map(sp =>
581
+ `<div class="legend-item">
582
+ <span class="legend-color" style="background: ${sp.color};"></span> ${sp.name}
583
+ </div>`
584
+ ).join('')
585
+ );
586
+ }
587
+ }
588
+
589
+ function showCodeViewer(node) {
590
+ // Highlight the node
591
+ highlightedNode = node;
592
+ renderGraph();
593
+
594
+ // Populate code viewer
595
+ const viewer = document.getElementById('code-viewer');
596
+ const title = document.getElementById('viewer-title');
597
+ const meta = document.getElementById('viewer-meta');
598
+ const code = document.getElementById('viewer-code');
599
+
600
+ title.textContent = node.name;
601
+
602
+ let metaText = `${node.type} • ${node.file_path}`;
603
+ if (node.start_line) {
604
+ metaText += ` • Lines ${node.start_line}-${node.end_line}`;
605
+ }
606
+ if (node.language) {
607
+ metaText += ` • ${node.language}`;
608
+ }
609
+ meta.textContent = metaText;
610
+
611
+ // Show content if available
612
+ if (node.content) {
613
+ code.textContent = node.content;
614
+ } else if (node.docstring) {
615
+ code.textContent = `// Docstring:
616
+ ${node.docstring}`;
617
+ } else {
618
+ code.textContent = '// No content available';
619
+ }
620
+
621
+ viewer.classList.add('visible');
622
+ }
623
+
624
+ function closeCodeViewer() {
625
+ const viewer = document.getElementById('code-viewer');
626
+ viewer.classList.remove('visible');
627
+
628
+ // Remove highlight
629
+ highlightedNode = null;
630
+ renderGraph();
631
+ }
632
+
633
+ // Auto-load graph data on page load
634
+ window.addEventListener('DOMContentLoaded', () => {
635
+ const loadingEl = document.getElementById('loading');
636
+
637
+ fetch(`chunk-graph.json?t=${Date.now()}`)
638
+ .then(response => {
639
+ if (!response.ok) {
640
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
641
+ }
642
+ return response.json();
643
+ })
644
+ .then(data => {
645
+ loadingEl.innerHTML = '<label style="color: #238636;">✓ Graph loaded successfully</label>';
646
+ setTimeout(() => loadingEl.style.display = 'none', 2000);
647
+ visualizeGraph(data);
648
+ })
649
+ .catch(err => {
650
+ loadingEl.innerHTML = `<label style="color: #f85149;">✗ Failed to load graph data</label><br>` +
651
+ `<small style="color: #8b949e;">${err.message}</small><br>` +
652
+ `<small style="color: #8b949e;">Run: mcp-vector-search visualize export</small>`;
653
+ console.error("Failed to load graph:", err);
654
+ });
655
+ });
656
+ </script>
657
+ </body>
658
+ </html>