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.
- mcp_vector_search/__init__.py +2 -2
- mcp_vector_search/cli/commands/index.py +5 -0
- mcp_vector_search/cli/commands/visualize.py +159 -28
- mcp_vector_search/core/indexer.py +12 -1
- {mcp_vector_search-0.8.0.dist-info → mcp_vector_search-0.8.3.dist-info}/METADATA +1 -1
- {mcp_vector_search-0.8.0.dist-info → mcp_vector_search-0.8.3.dist-info}/RECORD +9 -9
- {mcp_vector_search-0.8.0.dist-info → mcp_vector_search-0.8.3.dist-info}/WHEEL +0 -0
- {mcp_vector_search-0.8.0.dist-info → mcp_vector_search-0.8.3.dist-info}/entry_points.txt +0 -0
- {mcp_vector_search-0.8.0.dist-info → mcp_vector_search-0.8.3.dist-info}/licenses/LICENSE +0 -0
mcp_vector_search/__init__.py
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
-
|
|
410
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
61
|
-
mcp_vector_search-0.8.
|
|
62
|
-
mcp_vector_search-0.8.
|
|
63
|
-
mcp_vector_search-0.8.
|
|
64
|
-
mcp_vector_search-0.8.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|