mcp-vector-search 0.8.0__py3-none-any.whl → 0.8.3__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.

@@ -1,7 +1,7 @@
1
1
  """MCP Vector Search - CLI-first semantic code search with MCP integration."""
2
2
 
3
- __version__ = "0.8.0"
4
- __build__ = "29"
3
+ __version__ = "0.8.3"
4
+ __build__ = "32"
5
5
  __author__ = "Robert Matsuoka"
6
6
  __email__ = "bobmatnyc@gmail.com"
7
7
 
@@ -330,6 +330,11 @@ async def _run_batch_indexing(
330
330
  console.print(
331
331
  f"[yellow]⚠ {failed_count} files failed to index[/yellow]"
332
332
  )
333
+ error_log_path = project_root / ".mcp-vector-search" / "indexing_errors.log"
334
+ if error_log_path.exists():
335
+ console.print(
336
+ f"[dim] → See details in: {error_log_path}[/dim]"
337
+ )
333
338
  else:
334
339
  # Non-progress mode (fallback to original behavior)
335
340
  indexed_count = await indexer.index_project(
@@ -11,7 +11,7 @@ from rich.panel import Panel
11
11
 
12
12
  from ...core.database import ChromaVectorDatabase
13
13
  from ...core.embeddings import create_embedding_function
14
- from ...core.project import load_project
14
+ from ...core.project import ProjectManager
15
15
 
16
16
  app = typer.Typer(
17
17
  help="Visualize code chunk relationships",
@@ -54,10 +54,16 @@ async def _export_chunks(output: Path, file_filter: str | None) -> None:
54
54
  """Export chunk relationship data."""
55
55
  try:
56
56
  # Load project
57
- project_manager, config = load_project(Path.cwd())
57
+ project_manager = ProjectManager(Path.cwd())
58
+
59
+ if not project_manager.is_initialized():
60
+ console.print("[red]Project not initialized. Run 'mcp-vector-search init' first.[/red]")
61
+ raise typer.Exit(1)
62
+
63
+ config = project_manager.load_config()
58
64
 
59
65
  # Get database
60
- embedding_function = create_embedding_function(config.embedding_model)
66
+ embedding_function, _ = create_embedding_function(config.embedding_model)
61
67
  database = ChromaVectorDatabase(
62
68
  persist_directory=config.index_path,
63
69
  embedding_function=embedding_function,
@@ -160,9 +166,30 @@ def serve(
160
166
  """
161
167
  import http.server
162
168
  import os
169
+ import socket
163
170
  import socketserver
164
171
  import webbrowser
165
172
 
173
+ # Find free port in range 8080-8099
174
+ def find_free_port(start_port: int = 8080, end_port: int = 8099) -> int:
175
+ """Find a free port in the given range."""
176
+ for test_port in range(start_port, end_port + 1):
177
+ try:
178
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
179
+ s.bind(("", test_port))
180
+ return test_port
181
+ except OSError:
182
+ continue
183
+ raise OSError(f"No free ports available in range {start_port}-{end_port}")
184
+
185
+ # Use specified port or find free one
186
+ if port == 8080: # Default port, try to find free one
187
+ try:
188
+ port = find_free_port(8080, 8099)
189
+ except OSError as e:
190
+ console.print(f"[red]✗ {e}[/red]")
191
+ raise typer.Exit(1)
192
+
166
193
  # Get visualization directory
167
194
  viz_dir = Path(__file__).parent.parent.parent / "visualization"
168
195
 
@@ -358,9 +385,8 @@ def _create_visualization_html(html_file: Path) -> None:
358
385
  <div id="controls">
359
386
  <h1>🔍 Code Graph</h1>
360
387
 
361
- <div class="control-group">
362
- <label>Load Graph Data:</label>
363
- <input type="file" id="fileInput" accept=".json">
388
+ <div class="control-group" id="loading">
389
+ <label>⏳ Loading graph data...</label>
364
390
  </div>
365
391
 
366
392
  <h3>Legend</h3>
@@ -402,34 +428,79 @@ def _create_visualization_html(html_file: Path) -> None:
402
428
  const g = svg.append("g");
403
429
  const tooltip = d3.select("#tooltip");
404
430
  let simulation;
431
+ let allNodes = [];
432
+ let allLinks = [];
433
+ let visibleNodes = new Set();
434
+ let collapsedNodes = new Set();
405
435
 
406
436
  function visualizeGraph(data) {
407
437
  g.selectAll("*").remove();
408
438
 
409
- simulation = d3.forceSimulation(data.nodes)
410
- .force("link", d3.forceLink(data.links).id(d => d.id).distance(100))
439
+ allNodes = data.nodes;
440
+ allLinks = data.links;
441
+
442
+ // Find root nodes (nodes without parents or depth 0/1)
443
+ const rootNodes = allNodes.filter(n =>
444
+ !n.parent_id || n.depth === 0 || n.depth === 1 || n.type === 'module'
445
+ );
446
+
447
+ // Start with only root nodes visible
448
+ visibleNodes = new Set(rootNodes.map(n => n.id));
449
+ collapsedNodes = new Set(rootNodes.map(n => n.id));
450
+
451
+ renderGraph();
452
+ }
453
+
454
+ function renderGraph() {
455
+ const visibleNodesList = allNodes.filter(n => visibleNodes.has(n.id));
456
+ const visibleLinks = allLinks.filter(l =>
457
+ visibleNodes.has(l.source.id || l.source) &&
458
+ visibleNodes.has(l.target.id || l.target)
459
+ );
460
+
461
+ simulation = d3.forceSimulation(visibleNodesList)
462
+ .force("link", d3.forceLink(visibleLinks).id(d => d.id).distance(100))
411
463
  .force("charge", d3.forceManyBody().strength(-400))
412
464
  .force("center", d3.forceCenter(width / 2, height / 2))
413
465
  .force("collision", d3.forceCollide().radius(40));
414
466
 
467
+ g.selectAll("*").remove();
468
+
415
469
  const link = g.append("g")
416
470
  .selectAll("line")
417
- .data(data.links)
471
+ .data(visibleLinks)
418
472
  .join("line")
419
473
  .attr("class", "link");
420
474
 
421
475
  const node = g.append("g")
422
476
  .selectAll("g")
423
- .data(data.nodes)
477
+ .data(visibleNodesList)
424
478
  .join("g")
425
479
  .attr("class", d => `node ${d.type}`)
426
480
  .call(drag(simulation))
481
+ .on("click", toggleNode)
427
482
  .on("mouseover", showTooltip)
428
483
  .on("mouseout", hideTooltip);
429
484
 
485
+ // Add circles with expand indicator
430
486
  node.append("circle")
431
- .attr("r", d => d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12);
432
-
487
+ .attr("r", d => d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12)
488
+ .attr("stroke", d => hasChildren(d) ? "#ffffff" : "none")
489
+ .attr("stroke-width", d => hasChildren(d) ? 2 : 0);
490
+
491
+ // Add expand/collapse indicator
492
+ node.filter(d => hasChildren(d))
493
+ .append("text")
494
+ .attr("class", "expand-indicator")
495
+ .attr("text-anchor", "middle")
496
+ .attr("dy", 5)
497
+ .style("font-size", "16px")
498
+ .style("font-weight", "bold")
499
+ .style("fill", "#ffffff")
500
+ .style("pointer-events", "none")
501
+ .text(d => collapsedNodes.has(d.id) ? "+" : "−");
502
+
503
+ // Add labels
433
504
  node.append("text")
434
505
  .text(d => d.name)
435
506
  .attr("dy", 30);
@@ -444,7 +515,61 @@ def _create_visualization_html(html_file: Path) -> None:
444
515
  node.attr("transform", d => `translate(${d.x},${d.y})`);
445
516
  });
446
517
 
447
- updateStats(data);
518
+ updateStats({nodes: visibleNodesList, links: visibleLinks, metadata: {total_files: allNodes.length}});
519
+ }
520
+
521
+ function hasChildren(node) {
522
+ return allLinks.some(l => (l.source.id || l.source) === node.id);
523
+ }
524
+
525
+ function toggleNode(event, d) {
526
+ event.stopPropagation();
527
+
528
+ if (!hasChildren(d)) return;
529
+
530
+ if (collapsedNodes.has(d.id)) {
531
+ // Expand: show children
532
+ expandNode(d);
533
+ } else {
534
+ // Collapse: hide children
535
+ collapseNode(d);
536
+ }
537
+
538
+ renderGraph();
539
+ }
540
+
541
+ function expandNode(node) {
542
+ collapsedNodes.delete(node.id);
543
+
544
+ // Find direct children
545
+ const children = allLinks
546
+ .filter(l => (l.source.id || l.source) === node.id)
547
+ .map(l => allNodes.find(n => n.id === (l.target.id || l.target)))
548
+ .filter(n => n);
549
+
550
+ children.forEach(child => {
551
+ visibleNodes.add(child.id);
552
+ collapsedNodes.add(child.id); // Children start collapsed
553
+ });
554
+ }
555
+
556
+ function collapseNode(node) {
557
+ collapsedNodes.add(node.id);
558
+
559
+ // Hide all descendants recursively
560
+ function hideDescendants(parentId) {
561
+ const children = allLinks
562
+ .filter(l => (l.source.id || l.source) === parentId)
563
+ .map(l => l.target.id || l.target);
564
+
565
+ children.forEach(childId => {
566
+ visibleNodes.delete(childId);
567
+ collapsedNodes.delete(childId);
568
+ hideDescendants(childId);
569
+ });
570
+ }
571
+
572
+ hideDescendants(node.id);
448
573
  }
449
574
 
450
575
  function showTooltip(event, d) {
@@ -498,23 +623,29 @@ def _create_visualization_html(html_file: Path) -> None:
498
623
  `);
499
624
  }
500
625
 
501
- document.getElementById("fileInput").addEventListener("change", (event) => {
502
- const file = event.target.files[0];
503
- if (file) {
504
- const reader = new FileReader();
505
- reader.onload = (e) => {
506
- const data = JSON.parse(e.target.result);
626
+ // Auto-load graph data on page load
627
+ window.addEventListener('DOMContentLoaded', () => {
628
+ const loadingEl = document.getElementById('loading');
629
+
630
+ fetch("chunk-graph.json")
631
+ .then(response => {
632
+ if (!response.ok) {
633
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
634
+ }
635
+ return response.json();
636
+ })
637
+ .then(data => {
638
+ loadingEl.innerHTML = '<label style="color: #238636;">✓ Graph loaded successfully</label>';
639
+ setTimeout(() => loadingEl.style.display = 'none', 2000);
507
640
  visualizeGraph(data);
508
- };
509
- reader.readAsText(file);
510
- }
641
+ })
642
+ .catch(err => {
643
+ loadingEl.innerHTML = `<label style="color: #f85149;">✗ Failed to load graph data</label><br>` +
644
+ `<small style="color: #8b949e;">${err.message}</small><br>` +
645
+ `<small style="color: #8b949e;">Run: mcp-vector-search visualize export</small>`;
646
+ console.error("Failed to load graph:", err);
647
+ });
511
648
  });
512
-
513
- // Try to load default data
514
- fetch("chunk-graph.json")
515
- .then(response => response.json())
516
- .then(data => visualizeGraph(data))
517
- .catch(err => console.log("No default graph found. Please load a JSON file."));
518
649
  </script>
519
650
  </body>
520
651
  </html>'''
@@ -727,9 +727,20 @@ class SemanticIndexer:
727
727
  metadata[str(file_path)] = os.path.getmtime(file_path)
728
728
 
729
729
  except Exception as e:
730
- logger.error(f"Failed to index file {file_path}: {e}")
730
+ error_msg = f"Failed to index file {file_path}: {type(e).__name__}: {str(e)}"
731
+ logger.error(error_msg)
731
732
  success = False
732
733
 
734
+ # Save error to error log file
735
+ try:
736
+ error_log_path = self.project_root / ".mcp-vector-search" / "indexing_errors.log"
737
+ with open(error_log_path, "a", encoding="utf-8") as f:
738
+ from datetime import datetime
739
+ timestamp = datetime.now().isoformat()
740
+ f.write(f"[{timestamp}] {error_msg}\n")
741
+ except Exception as log_err:
742
+ logger.debug(f"Failed to write error log: {log_err}")
743
+
733
744
  # Yield progress update
734
745
  yield (file_path, chunks_added, success)
735
746
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-vector-search
3
- Version: 0.8.0
3
+ Version: 0.8.3
4
4
  Summary: CLI-first semantic code search with MCP integration
5
5
  Project-URL: Homepage, https://github.com/bobmatnyc/mcp-vector-search
6
6
  Project-URL: Documentation, https://mcp-vector-search.readthedocs.io
@@ -1,4 +1,4 @@
1
- mcp_vector_search/__init__.py,sha256=j0J6-76f4J8zJJka6ztBM3ah039ges62kwsejscnarc,299
1
+ mcp_vector_search/__init__.py,sha256=O0yFOAUi3iVdWNh8T90tgKHdwJTCaw-s0DKDUi97H6Q,299
2
2
  mcp_vector_search/py.typed,sha256=lCKeV9Qcn9sGtbRsgg-LJO2ZwWRuknnnlmomq3bJFH0,43
3
3
  mcp_vector_search/cli/__init__.py,sha256=TNB7CaOASz8u3yHWLbNmo8-GtHF0qwUjVKWAuNphKgo,40
4
4
  mcp_vector_search/cli/didyoumean.py,sha256=F_ss-EX4F9RgnMsEhdTwLpyNCah9SqnBZc2tBtzASck,15918
@@ -12,14 +12,14 @@ mcp_vector_search/cli/commands/__init__.py,sha256=vQls-YKZ54YEwmf7g1dL0T2SS9D4pd
12
12
  mcp_vector_search/cli/commands/auto_index.py,sha256=imVVbxWRlA128NPdK9BetNNl3ELrsdq-hqcsLqyAmoM,12712
13
13
  mcp_vector_search/cli/commands/config.py,sha256=mKE8gUgAOqCM__4yzEEu9HJPbx9X15lN264zkDJBRxg,12399
14
14
  mcp_vector_search/cli/commands/demo.py,sha256=MVfEkYmA2abRFwAbk-lpa6P14_SLJBHZAuHb9d6d02U,10630
15
- mcp_vector_search/cli/commands/index.py,sha256=K_5gmmgclfkyXDvucBPdnvbYzyfa53eVbPdkuWiqZUk,22106
15
+ mcp_vector_search/cli/commands/index.py,sha256=Amo8DOcp1WZrLcPqIWH8nrZU-mfDkjZIbumytFAx2Bw,22377
16
16
  mcp_vector_search/cli/commands/init.py,sha256=2kdjtIPPeutKUXs65-6W1VQPF_BQrbV6_U3TCE7U5mw,23242
17
17
  mcp_vector_search/cli/commands/install.py,sha256=phk7Eb7UOU5IsRfJyaDPdOfdUWli9gyA4cHjhgXcNEI,24609
18
18
  mcp_vector_search/cli/commands/mcp.py,sha256=Mk4g43R9yRiJVMxsDFUsZldKqY0yi2coQmhAqIMPklo,38958
19
19
  mcp_vector_search/cli/commands/reset.py,sha256=bsIT6zjDf6gsvIkVaRaUClYzlTyNe--8t0NWkBY0ldU,13724
20
20
  mcp_vector_search/cli/commands/search.py,sha256=yyou7wO9qZ_w2oiKdyOrk2WUxvkFpc-Up8hpflxYlyw,24802
21
21
  mcp_vector_search/cli/commands/status.py,sha256=sa_0QHioCmPF5A7obqV2ls-9kmX_JYo7nq3XUe1dmrg,19630
22
- mcp_vector_search/cli/commands/visualize.py,sha256=vlTYgcepIFWFAe8LAXvZiV5OSLM2JzinYR-k0D0-5K4,16349
22
+ mcp_vector_search/cli/commands/visualize.py,sha256=tipe_QLjkZboqEz8SfIx5mjYrAenqrKsQPnXkgG7GBg,21398
23
23
  mcp_vector_search/cli/commands/watch.py,sha256=2pyWRoo4fIppFnyQ4sW4IBLHmpb_IwnTjRnzHkVBPcQ,8927
24
24
  mcp_vector_search/config/__init__.py,sha256=r_qAQkU5gc0EQ2pv8EQARACe4klhrR_WRJqCb9lfGc0,54
25
25
  mcp_vector_search/config/constants.py,sha256=afXR6SvLLd8QYY4MG4s1vq-hCJiQsE5PhnE-XG9lvb4,1092
@@ -33,7 +33,7 @@ mcp_vector_search/core/embeddings.py,sha256=wSMUNxZcuGPMxxQ1AbKqA1a3-0c6AiOqmuuI
33
33
  mcp_vector_search/core/exceptions.py,sha256=3bCjT8wmrLz_0e_Tayr90049zNTKYFWZa19kl0saKz8,1597
34
34
  mcp_vector_search/core/factory.py,sha256=tM6Ft-V9buF7nn9xbRMU1ngji-BJOKt6BhtfQhFLmF4,10384
35
35
  mcp_vector_search/core/git_hooks.py,sha256=xOfPpzgKoNTwM-vbhAihUucgudBQk45bCAVR5zJOFlQ,10878
36
- mcp_vector_search/core/indexer.py,sha256=NdIYVtD5D21ej9_RRypKq-UKjpGXTXiDXskhzdYHUCQ,28440
36
+ mcp_vector_search/core/indexer.py,sha256=IpCzP50wLOttWuUI-NE0qwYq-LlbDo5lrGfVMFMzwAM,29089
37
37
  mcp_vector_search/core/models.py,sha256=h54wTwwXR5qU-YOVi8q8NEFmpnQfC4S0ER2mMJqn4bk,8512
38
38
  mcp_vector_search/core/project.py,sha256=l81uc5B4CB8VXDbcHzF-_CagxIERDh23tH0iNqTePTs,10403
39
39
  mcp_vector_search/core/scheduler.py,sha256=PBSlu-ieDYCXOMGYY7QKv9UReFEDPHNmwnUv_xb4vxg,11761
@@ -57,8 +57,8 @@ mcp_vector_search/utils/__init__.py,sha256=Eq6lY-oPMfCt-GpPUbg9QbmTHuQVmTaVDBMU2
57
57
  mcp_vector_search/utils/gitignore.py,sha256=GiHQu9kv9PRLsWuNS8kbpXsTaBdhlsSHTu1NrZ8Ug5Y,8162
58
58
  mcp_vector_search/utils/timing.py,sha256=THC7mfbTYnUpnnDcblgQacYMzbEkfFoIShx6plmhCgg,11285
59
59
  mcp_vector_search/utils/version.py,sha256=d7fS-CLemxb8UzZ9j18zH0Y0Ud097ljKKYYOPulnGPE,1138
60
- mcp_vector_search-0.8.0.dist-info/METADATA,sha256=8ZdCNZR0sEfaPSKZLINETw7M_4zLHU6dO9LiieUh4uA,19120
61
- mcp_vector_search-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
- mcp_vector_search-0.8.0.dist-info/entry_points.txt,sha256=y3Ygtc_JiBchNEIL-tPABo7EbzBExGAxwGdkkeP5D2I,86
63
- mcp_vector_search-0.8.0.dist-info/licenses/LICENSE,sha256=FqZUgGJH_tZKZLQsMCpXaLawRyLmyFKRVfMwYyEcyTs,1072
64
- mcp_vector_search-0.8.0.dist-info/RECORD,,
60
+ mcp_vector_search-0.8.3.dist-info/METADATA,sha256=Yk6nZLkTTIZYpXdH67gkobj9rnlUoPCyjn4yo9-0IXA,19120
61
+ mcp_vector_search-0.8.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
+ mcp_vector_search-0.8.3.dist-info/entry_points.txt,sha256=y3Ygtc_JiBchNEIL-tPABo7EbzBExGAxwGdkkeP5D2I,86
63
+ mcp_vector_search-0.8.3.dist-info/licenses/LICENSE,sha256=FqZUgGJH_tZKZLQsMCpXaLawRyLmyFKRVfMwYyEcyTs,1072
64
+ mcp_vector_search-0.8.3.dist-info/RECORD,,