mcp-vector-search 0.8.6__tar.gz → 0.9.0__tar.gz
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-0.8.6 → mcp_vector_search-0.9.0}/PKG-INFO +1 -1
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/__init__.py +2 -2
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/index.py +1 -1
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/visualize.py +215 -36
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/database.py +113 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/indexer.py +17 -1
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/models.py +8 -0
- mcp_vector_search-0.9.0/src/mcp_vector_search/utils/monorepo.py +277 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.changesets/20251009-204754-feat-add-comprehensive-changeset-and-documentation.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.changesets/20251009-205435-fix-update-readme-version-badge-to-0-7-1.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.changesets/20251009-205439-feat-add-comprehensive-changeset-support-system.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.changesets/EXAMPLE.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.changesets/IMPLEMENTATION_SUMMARY.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.changesets/README.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.changesets/template.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.editorconfig +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.github/workflows/ci.yml +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.gitignore +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/.pre-commit-config.yaml +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/CLAUDE.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/LICENSE +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/Makefile +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/PERFORMANCE_OPTIMIZATION_SUMMARY.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/README.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/CHANGELOG.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/CLI_FEATURES.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/DEPLOY.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/DEVELOPMENT.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/FEATURES.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/IMPROVEMENTS_SUMMARY.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/MCP_FILE_WATCHING.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/RELEASES.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/STRUCTURE.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/VERSIONING.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/VERSIONING_WORKFLOW.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/_archive/CLAUDE_20251009_pre_mpm_init.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/_archive/CLAUDE_MPM_INIT_SUMMARY_20251009.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/_archive/MPM_INIT_EXECUTIVE_SUMMARY.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/analysis/SEARCH_ANALYSIS_REPORT.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/analysis/SEARCH_IMPROVEMENT_PLAN.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/architecture/REINDEXING_WORKFLOW.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/debugging/SEARCH_BUG_ANALYSIS.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/developer/API.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/developer/CONTRIBUTING.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/developer/DEVELOPER.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/developer/LINTING.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/developer/REFACTORING_ANALYSIS.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/developer/TESTING.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/developer/TESTING_STRATEGY.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/developer/TEST_SUITE_SUMMARY.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/mcp-integration.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/optimizations/database-stats-chunked-processing.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/performance/CONNECTION_POOLING.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/performance/SEARCH_TIMING_ANALYSIS.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/prd/mcp_vector_search_prd_updated.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/reference/ENGINEER_TASK.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/reference/INSTALL.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/reference/INSTALL_COMMAND_ENHANCEMENTS.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/reference/MCP_SETUP.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/reference/PROJECT_ORGANIZATION.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/docs/technical/SIMILARITY_CALCULATION_FIX.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/examples/connection_pooling_example.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/examples/semi_automatic_reindexing_demo.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/mcp-vector-search-wrapper +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/pyproject.toml +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/pytest.ini +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/README.md +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/analyze_search_bottlenecks.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/build.sh +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/changeset.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/comprehensive_build.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/deploy-test.sh +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/dev-build.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/dev-setup.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/dev-test.sh +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/fix_linting.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/mcp-dev +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/monitor_search_performance.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/publish.sh +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/quick_search_timing.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/run_search_timing_tests.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/run_tests.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/search_performance_monitor.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/search_quality_analyzer.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/setup/mcp-vector-search.sh +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/setup/setup-alias.sh +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/setup-dev-mcp.sh +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/update_docs.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/version_manager.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/scripts/workflow.sh +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/__init__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/__init__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/auto_index.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/config.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/demo.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/init.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/install.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/mcp.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/reset.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/search.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/status.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/watch.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/didyoumean.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/export.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/history.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/interactive.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/main.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/output.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/suggestions.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/config/__init__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/config/constants.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/config/defaults.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/config/settings.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/__init__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/auto_indexer.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/connection_pool.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/embeddings.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/exceptions.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/factory.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/git_hooks.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/project.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/scheduler.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/search.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/core/watcher.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/mcp/__init__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/mcp/__main__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/mcp/server.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/__init__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/base.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/dart.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/html.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/javascript.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/php.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/python.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/registry.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/ruby.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/text.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/parsers/utils.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/py.typed +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/utils/__init__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/utils/gitignore.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/utils/timing.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/utils/version.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/tests/__init__.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/tests/conftest.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/tests/sample_code/ast_test_javascript.js +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/tests/sample_code/ast_test_python.py +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/tests/sample_code/ast_test_typescript.ts +0 -0
- {mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-vector-search
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
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
|
{mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/index.py
RENAMED
|
@@ -330,7 +330,7 @@ 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"
|
|
333
|
+
error_log_path = indexer.project_root / ".mcp-vector-search" / "indexing_errors.log"
|
|
334
334
|
if error_log_path.exists():
|
|
335
335
|
console.print(
|
|
336
336
|
f"[dim] → See details in: {error_log_path}[/dim]"
|
{mcp_vector_search-0.8.6 → mcp_vector_search-0.9.0}/src/mcp_vector_search/cli/commands/visualize.py
RENAMED
|
@@ -72,48 +72,116 @@ async def _export_chunks(output: Path, file_filter: str | None) -> None:
|
|
|
72
72
|
|
|
73
73
|
# Get all chunks with metadata
|
|
74
74
|
console.print("[cyan]Fetching chunks from database...[/cyan]")
|
|
75
|
+
chunks = await database.get_all_chunks()
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
stats = await database.get_stats()
|
|
78
|
-
|
|
79
|
-
if stats.total_chunks == 0:
|
|
77
|
+
if len(chunks) == 0:
|
|
80
78
|
console.print("[yellow]No chunks found in index. Run 'mcp-vector-search index' first.[/yellow]")
|
|
81
79
|
raise typer.Exit(1)
|
|
82
80
|
|
|
81
|
+
console.print(f"[green]✓[/green] Retrieved {len(chunks)} chunks")
|
|
82
|
+
|
|
83
|
+
# Apply file filter if specified
|
|
84
|
+
if file_filter:
|
|
85
|
+
from fnmatch import fnmatch
|
|
86
|
+
chunks = [c for c in chunks if fnmatch(str(c.file_path), file_filter)]
|
|
87
|
+
console.print(f"[cyan]Filtered to {len(chunks)} chunks matching '{file_filter}'[/cyan]")
|
|
88
|
+
|
|
89
|
+
# Collect subprojects for monorepo support
|
|
90
|
+
subprojects = {}
|
|
91
|
+
for chunk in chunks:
|
|
92
|
+
if chunk.subproject_name and chunk.subproject_name not in subprojects:
|
|
93
|
+
subprojects[chunk.subproject_name] = {
|
|
94
|
+
"name": chunk.subproject_name,
|
|
95
|
+
"path": chunk.subproject_path,
|
|
96
|
+
"color": _get_subproject_color(chunk.subproject_name, len(subprojects)),
|
|
97
|
+
}
|
|
98
|
+
|
|
83
99
|
# Build graph data structure
|
|
84
100
|
nodes = []
|
|
85
101
|
links = []
|
|
102
|
+
chunk_id_map = {} # Map chunk IDs to array indices
|
|
103
|
+
|
|
104
|
+
# Add subproject root nodes for monorepos
|
|
105
|
+
if subprojects:
|
|
106
|
+
console.print(f"[cyan]Detected monorepo with {len(subprojects)} subprojects[/cyan]")
|
|
107
|
+
for sp_name, sp_data in subprojects.items():
|
|
108
|
+
node = {
|
|
109
|
+
"id": f"subproject_{sp_name}",
|
|
110
|
+
"name": sp_name,
|
|
111
|
+
"type": "subproject",
|
|
112
|
+
"file_path": sp_data["path"] or "",
|
|
113
|
+
"start_line": 0,
|
|
114
|
+
"end_line": 0,
|
|
115
|
+
"complexity": 0,
|
|
116
|
+
"color": sp_data["color"],
|
|
117
|
+
"depth": 0,
|
|
118
|
+
}
|
|
119
|
+
nodes.append(node)
|
|
120
|
+
|
|
121
|
+
# Add chunk nodes
|
|
122
|
+
for chunk in chunks:
|
|
123
|
+
node = {
|
|
124
|
+
"id": chunk.chunk_id or chunk.id,
|
|
125
|
+
"name": chunk.function_name or chunk.class_name or f"L{chunk.start_line}",
|
|
126
|
+
"type": chunk.chunk_type,
|
|
127
|
+
"file_path": str(chunk.file_path),
|
|
128
|
+
"start_line": chunk.start_line,
|
|
129
|
+
"end_line": chunk.end_line,
|
|
130
|
+
"complexity": chunk.complexity_score,
|
|
131
|
+
"parent_id": chunk.parent_chunk_id,
|
|
132
|
+
"depth": chunk.chunk_depth,
|
|
133
|
+
}
|
|
86
134
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
135
|
+
# Add subproject info for monorepos
|
|
136
|
+
if chunk.subproject_name:
|
|
137
|
+
node["subproject"] = chunk.subproject_name
|
|
138
|
+
node["color"] = subprojects[chunk.subproject_name]["color"]
|
|
90
139
|
|
|
91
|
-
|
|
92
|
-
|
|
140
|
+
nodes.append(node)
|
|
141
|
+
chunk_id_map[node["id"]] = len(nodes) - 1
|
|
142
|
+
|
|
143
|
+
# Build hierarchical links from parent-child relationships
|
|
144
|
+
for chunk in chunks:
|
|
145
|
+
chunk_id = chunk.chunk_id or chunk.id
|
|
146
|
+
|
|
147
|
+
# Link to subproject root if in monorepo
|
|
148
|
+
if chunk.subproject_name and not chunk.parent_chunk_id:
|
|
149
|
+
links.append({
|
|
150
|
+
"source": f"subproject_{chunk.subproject_name}",
|
|
151
|
+
"target": chunk_id,
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
# Link to parent chunk
|
|
155
|
+
if chunk.parent_chunk_id and chunk.parent_chunk_id in chunk_id_map:
|
|
156
|
+
links.append({
|
|
157
|
+
"source": chunk.parent_chunk_id,
|
|
158
|
+
"target": chunk_id,
|
|
159
|
+
})
|
|
93
160
|
|
|
94
|
-
#
|
|
161
|
+
# Parse inter-project dependencies for monorepos
|
|
162
|
+
if subprojects:
|
|
163
|
+
console.print("[cyan]Parsing inter-project dependencies...[/cyan]")
|
|
164
|
+
dep_links = _parse_project_dependencies(
|
|
165
|
+
project_manager.project_root,
|
|
166
|
+
subprojects
|
|
167
|
+
)
|
|
168
|
+
links.extend(dep_links)
|
|
169
|
+
if dep_links:
|
|
170
|
+
console.print(f"[green]✓[/green] Found {len(dep_links)} inter-project dependencies")
|
|
171
|
+
|
|
172
|
+
# Get stats
|
|
173
|
+
stats = await database.get_stats()
|
|
174
|
+
|
|
175
|
+
# Build final graph data
|
|
95
176
|
graph_data = {
|
|
96
|
-
"nodes":
|
|
97
|
-
|
|
98
|
-
"id": f"chunk_{i}",
|
|
99
|
-
"name": f"Chunk {i}",
|
|
100
|
-
"type": "code",
|
|
101
|
-
"file_path": "example.py",
|
|
102
|
-
"start_line": i * 10,
|
|
103
|
-
"end_line": (i + 1) * 10,
|
|
104
|
-
"complexity": 1.0 + (i % 5),
|
|
105
|
-
}
|
|
106
|
-
for i in range(min(stats.total_chunks, 50)) # Limit to 50 for demo
|
|
107
|
-
],
|
|
108
|
-
"links": [
|
|
109
|
-
{"source": f"chunk_{i}", "target": f"chunk_{i+1}"}
|
|
110
|
-
for i in range(min(stats.total_chunks - 1, 49))
|
|
111
|
-
],
|
|
177
|
+
"nodes": nodes,
|
|
178
|
+
"links": links,
|
|
112
179
|
"metadata": {
|
|
113
|
-
"total_chunks":
|
|
180
|
+
"total_chunks": len(chunks),
|
|
114
181
|
"total_files": stats.total_files,
|
|
115
182
|
"languages": stats.languages,
|
|
116
|
-
"
|
|
183
|
+
"is_monorepo": len(subprojects) > 0,
|
|
184
|
+
"subprojects": list(subprojects.keys()) if subprojects else [],
|
|
117
185
|
},
|
|
118
186
|
}
|
|
119
187
|
|
|
@@ -129,7 +197,8 @@ async def _export_chunks(output: Path, file_filter: str | None) -> None:
|
|
|
129
197
|
Panel.fit(
|
|
130
198
|
f"[green]✓[/green] Exported graph data to [cyan]{output}[/cyan]\n\n"
|
|
131
199
|
f"Nodes: {len(graph_data['nodes'])}\n"
|
|
132
|
-
f"Links: {len(graph_data['links'])}\n
|
|
200
|
+
f"Links: {len(graph_data['links'])}\n"
|
|
201
|
+
f"{'Subprojects: ' + str(len(subprojects)) if subprojects else ''}\n\n"
|
|
133
202
|
f"[dim]Next: Run 'mcp-vector-search visualize serve' to view[/dim]",
|
|
134
203
|
title="Export Complete",
|
|
135
204
|
border_style="green",
|
|
@@ -142,6 +211,69 @@ async def _export_chunks(output: Path, file_filter: str | None) -> None:
|
|
|
142
211
|
raise typer.Exit(1)
|
|
143
212
|
|
|
144
213
|
|
|
214
|
+
def _get_subproject_color(subproject_name: str, index: int) -> str:
|
|
215
|
+
"""Get a consistent color for a subproject."""
|
|
216
|
+
# Color palette for subprojects (GitHub-style colors)
|
|
217
|
+
colors = [
|
|
218
|
+
"#238636", # Green
|
|
219
|
+
"#1f6feb", # Blue
|
|
220
|
+
"#d29922", # Yellow
|
|
221
|
+
"#8957e5", # Purple
|
|
222
|
+
"#da3633", # Red
|
|
223
|
+
"#bf8700", # Orange
|
|
224
|
+
"#1a7f37", # Dark green
|
|
225
|
+
"#0969da", # Dark blue
|
|
226
|
+
]
|
|
227
|
+
return colors[index % len(colors)]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _parse_project_dependencies(project_root: Path, subprojects: dict) -> list[dict]:
|
|
231
|
+
"""Parse package.json files to find inter-project dependencies.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
project_root: Root directory of the monorepo
|
|
235
|
+
subprojects: Dictionary of subproject information
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
List of dependency links between subprojects
|
|
239
|
+
"""
|
|
240
|
+
dependency_links = []
|
|
241
|
+
|
|
242
|
+
for sp_name, sp_data in subprojects.items():
|
|
243
|
+
package_json = project_root / sp_data["path"] / "package.json"
|
|
244
|
+
|
|
245
|
+
if not package_json.exists():
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
with open(package_json) as f:
|
|
250
|
+
package_data = json.load(f)
|
|
251
|
+
|
|
252
|
+
# Check all dependency types
|
|
253
|
+
all_deps = {}
|
|
254
|
+
for dep_type in ["dependencies", "devDependencies", "peerDependencies"]:
|
|
255
|
+
if dep_type in package_data:
|
|
256
|
+
all_deps.update(package_data[dep_type])
|
|
257
|
+
|
|
258
|
+
# Find dependencies on other subprojects
|
|
259
|
+
for dep_name in all_deps.keys():
|
|
260
|
+
# Check if this dependency is another subproject
|
|
261
|
+
for other_sp_name in subprojects.keys():
|
|
262
|
+
if other_sp_name != sp_name and dep_name == other_sp_name:
|
|
263
|
+
# Found inter-project dependency
|
|
264
|
+
dependency_links.append({
|
|
265
|
+
"source": f"subproject_{sp_name}",
|
|
266
|
+
"target": f"subproject_{other_sp_name}",
|
|
267
|
+
"type": "dependency",
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
except Exception as e:
|
|
271
|
+
logger.debug(f"Failed to parse {package_json}: {e}")
|
|
272
|
+
continue
|
|
273
|
+
|
|
274
|
+
return dependency_links
|
|
275
|
+
|
|
276
|
+
|
|
145
277
|
@app.command()
|
|
146
278
|
def serve(
|
|
147
279
|
port: int = typer.Option(8080, "--port", "-p", help="Port for visualization server"),
|
|
@@ -344,6 +476,7 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
344
476
|
.node.function circle { fill: #d29922; }
|
|
345
477
|
.node.method circle { fill: #8957e5; }
|
|
346
478
|
.node.code circle { fill: #6e7681; }
|
|
479
|
+
.node.subproject circle { fill: #da3633; stroke-width: 3px; }
|
|
347
480
|
|
|
348
481
|
.node text {
|
|
349
482
|
font-size: 11px;
|
|
@@ -359,6 +492,13 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
359
492
|
stroke-width: 1.5px;
|
|
360
493
|
}
|
|
361
494
|
|
|
495
|
+
.link.dependency {
|
|
496
|
+
stroke: #d29922;
|
|
497
|
+
stroke-opacity: 0.8;
|
|
498
|
+
stroke-width: 2px;
|
|
499
|
+
stroke-dasharray: 5,5;
|
|
500
|
+
}
|
|
501
|
+
|
|
362
502
|
.tooltip {
|
|
363
503
|
position: absolute;
|
|
364
504
|
padding: 12px;
|
|
@@ -391,6 +531,9 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
391
531
|
|
|
392
532
|
<h3>Legend</h3>
|
|
393
533
|
<div class="legend">
|
|
534
|
+
<div class="legend-item">
|
|
535
|
+
<span class="legend-color" style="background: #da3633;"></span> Subproject
|
|
536
|
+
</div>
|
|
394
537
|
<div class="legend-item">
|
|
395
538
|
<span class="legend-color" style="background: #238636;"></span> Module
|
|
396
539
|
</div>
|
|
@@ -408,6 +551,11 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
408
551
|
</div>
|
|
409
552
|
</div>
|
|
410
553
|
|
|
554
|
+
<div id="subprojects-legend" style="display: none;">
|
|
555
|
+
<h3>Subprojects</h3>
|
|
556
|
+
<div class="legend" id="subprojects-list"></div>
|
|
557
|
+
</div>
|
|
558
|
+
|
|
411
559
|
<div class="stats" id="stats"></div>
|
|
412
560
|
</div>
|
|
413
561
|
|
|
@@ -439,10 +587,17 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
439
587
|
allNodes = data.nodes;
|
|
440
588
|
allLinks = data.links;
|
|
441
589
|
|
|
442
|
-
// Find root nodes
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
590
|
+
// Find root nodes
|
|
591
|
+
let rootNodes;
|
|
592
|
+
if (data.metadata && data.metadata.is_monorepo) {
|
|
593
|
+
// In monorepos, subproject nodes are roots
|
|
594
|
+
rootNodes = allNodes.filter(n => n.type === 'subproject');
|
|
595
|
+
} else {
|
|
596
|
+
// Regular projects: nodes without parents or depth 0/1
|
|
597
|
+
rootNodes = allNodes.filter(n =>
|
|
598
|
+
!n.parent_id || n.depth === 0 || n.depth === 1 || n.type === 'module'
|
|
599
|
+
);
|
|
600
|
+
}
|
|
446
601
|
|
|
447
602
|
// Start with only root nodes visible
|
|
448
603
|
visibleNodes = new Set(rootNodes.map(n => n.id));
|
|
@@ -470,7 +625,7 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
470
625
|
.selectAll("line")
|
|
471
626
|
.data(visibleLinks)
|
|
472
627
|
.join("line")
|
|
473
|
-
.attr("class", "link");
|
|
628
|
+
.attr("class", d => d.type === "dependency" ? "link dependency" : "link");
|
|
474
629
|
|
|
475
630
|
const node = g.append("g")
|
|
476
631
|
.selectAll("g")
|
|
@@ -484,9 +639,13 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
484
639
|
|
|
485
640
|
// Add circles with expand indicator
|
|
486
641
|
node.append("circle")
|
|
487
|
-
.attr("r", d =>
|
|
642
|
+
.attr("r", d => {
|
|
643
|
+
if (d.type === 'subproject') return 20;
|
|
644
|
+
return d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12;
|
|
645
|
+
})
|
|
488
646
|
.attr("stroke", d => hasChildren(d) ? "#ffffff" : "none")
|
|
489
|
-
.attr("stroke-width", d => hasChildren(d) ? 2 : 0)
|
|
647
|
+
.attr("stroke-width", d => hasChildren(d) ? 2 : 0)
|
|
648
|
+
.style("fill", d => d.color || null); // Use custom color if available
|
|
490
649
|
|
|
491
650
|
// Add expand/collapse indicator
|
|
492
651
|
node.filter(d => hasChildren(d))
|
|
@@ -620,7 +779,27 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
620
779
|
<div>Nodes: ${data.nodes.length}</div>
|
|
621
780
|
<div>Links: ${data.links.length}</div>
|
|
622
781
|
${data.metadata ? `<div>Files: ${data.metadata.total_files || 'N/A'}</div>` : ''}
|
|
782
|
+
${data.metadata && data.metadata.is_monorepo ? `<div>Monorepo: ${data.metadata.subprojects.length} subprojects</div>` : ''}
|
|
623
783
|
`);
|
|
784
|
+
|
|
785
|
+
// Show subproject legend if monorepo
|
|
786
|
+
if (data.metadata && data.metadata.is_monorepo && data.metadata.subprojects.length > 0) {
|
|
787
|
+
const subprojectsLegend = d3.select("#subprojects-legend");
|
|
788
|
+
const subprojectsList = d3.select("#subprojects-list");
|
|
789
|
+
|
|
790
|
+
subprojectsLegend.style("display", "block");
|
|
791
|
+
|
|
792
|
+
// Get subproject nodes with colors
|
|
793
|
+
const subprojectNodes = allNodes.filter(n => n.type === 'subproject');
|
|
794
|
+
|
|
795
|
+
subprojectsList.html(
|
|
796
|
+
subprojectNodes.map(sp =>
|
|
797
|
+
`<div class="legend-item">
|
|
798
|
+
<span class="legend-color" style="background: ${sp.color};"></span> ${sp.name}
|
|
799
|
+
</div>`
|
|
800
|
+
).join('')
|
|
801
|
+
);
|
|
802
|
+
}
|
|
624
803
|
}
|
|
625
804
|
|
|
626
805
|
// Auto-load graph data on page load
|
|
@@ -98,6 +98,15 @@ class VectorDatabase(ABC):
|
|
|
98
98
|
"""Reset the database (delete all data)."""
|
|
99
99
|
...
|
|
100
100
|
|
|
101
|
+
@abstractmethod
|
|
102
|
+
async def get_all_chunks(self) -> list[CodeChunk]:
|
|
103
|
+
"""Get all chunks from the database.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
List of all code chunks with metadata
|
|
107
|
+
"""
|
|
108
|
+
...
|
|
109
|
+
|
|
101
110
|
@abstractmethod
|
|
102
111
|
async def health_check(self) -> bool:
|
|
103
112
|
"""Check database health and integrity.
|
|
@@ -467,6 +476,59 @@ class ChromaVectorDatabase(VectorDatabase):
|
|
|
467
476
|
logger.error(f"Failed to reset database: {e}")
|
|
468
477
|
raise DatabaseError(f"Failed to reset database: {e}") from e
|
|
469
478
|
|
|
479
|
+
async def get_all_chunks(self) -> list[CodeChunk]:
|
|
480
|
+
"""Get all chunks from the database.
|
|
481
|
+
|
|
482
|
+
Returns:
|
|
483
|
+
List of all code chunks with metadata
|
|
484
|
+
"""
|
|
485
|
+
if not self._collection:
|
|
486
|
+
raise DatabaseNotInitializedError("Database not initialized")
|
|
487
|
+
|
|
488
|
+
try:
|
|
489
|
+
# Get all documents from collection
|
|
490
|
+
results = self._collection.get(
|
|
491
|
+
include=["metadatas", "documents"]
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
chunks = []
|
|
495
|
+
if results and results.get("ids"):
|
|
496
|
+
for i, chunk_id in enumerate(results["ids"]):
|
|
497
|
+
metadata = results["metadatas"][i]
|
|
498
|
+
content = results["documents"][i]
|
|
499
|
+
|
|
500
|
+
chunk = CodeChunk(
|
|
501
|
+
content=content,
|
|
502
|
+
file_path=Path(metadata["file_path"]),
|
|
503
|
+
start_line=metadata["start_line"],
|
|
504
|
+
end_line=metadata["end_line"],
|
|
505
|
+
language=metadata["language"],
|
|
506
|
+
chunk_type=metadata.get("chunk_type", "code"),
|
|
507
|
+
function_name=metadata.get("function_name"),
|
|
508
|
+
class_name=metadata.get("class_name"),
|
|
509
|
+
docstring=metadata.get("docstring"),
|
|
510
|
+
imports=metadata.get("imports", []),
|
|
511
|
+
complexity_score=metadata.get("complexity_score", 0.0),
|
|
512
|
+
chunk_id=metadata.get("chunk_id"),
|
|
513
|
+
parent_chunk_id=metadata.get("parent_chunk_id"),
|
|
514
|
+
child_chunk_ids=metadata.get("child_chunk_ids", []),
|
|
515
|
+
chunk_depth=metadata.get("chunk_depth", 0),
|
|
516
|
+
decorators=metadata.get("decorators", []),
|
|
517
|
+
parameters=metadata.get("parameters", []),
|
|
518
|
+
return_type=metadata.get("return_type"),
|
|
519
|
+
type_annotations=metadata.get("type_annotations", {}),
|
|
520
|
+
subproject_name=metadata.get("subproject_name"),
|
|
521
|
+
subproject_path=metadata.get("subproject_path"),
|
|
522
|
+
)
|
|
523
|
+
chunks.append(chunk)
|
|
524
|
+
|
|
525
|
+
logger.debug(f"Retrieved {len(chunks)} chunks from database")
|
|
526
|
+
return chunks
|
|
527
|
+
|
|
528
|
+
except Exception as e:
|
|
529
|
+
logger.error(f"Failed to get all chunks: {e}")
|
|
530
|
+
raise DatabaseError(f"Failed to get all chunks: {e}") from e
|
|
531
|
+
|
|
470
532
|
def _create_searchable_text(self, chunk: CodeChunk) -> str:
|
|
471
533
|
"""Create optimized searchable text from code chunk."""
|
|
472
534
|
parts = [chunk.content]
|
|
@@ -914,6 +976,57 @@ class PooledChromaVectorDatabase(VectorDatabase):
|
|
|
914
976
|
logger.error(f"Failed to reset database: {e}")
|
|
915
977
|
raise DatabaseError(f"Failed to reset database: {e}") from e
|
|
916
978
|
|
|
979
|
+
async def get_all_chunks(self) -> list[CodeChunk]:
|
|
980
|
+
"""Get all chunks from the database using pooled connection.
|
|
981
|
+
|
|
982
|
+
Returns:
|
|
983
|
+
List of all code chunks with metadata
|
|
984
|
+
"""
|
|
985
|
+
try:
|
|
986
|
+
async with self._pool.get_connection() as conn:
|
|
987
|
+
# Get all documents from collection
|
|
988
|
+
results = conn.collection.get(
|
|
989
|
+
include=["metadatas", "documents"]
|
|
990
|
+
)
|
|
991
|
+
|
|
992
|
+
chunks = []
|
|
993
|
+
if results and results.get("ids"):
|
|
994
|
+
for i, chunk_id in enumerate(results["ids"]):
|
|
995
|
+
metadata = results["metadatas"][i]
|
|
996
|
+
content = results["documents"][i]
|
|
997
|
+
|
|
998
|
+
chunk = CodeChunk(
|
|
999
|
+
content=content,
|
|
1000
|
+
file_path=Path(metadata["file_path"]),
|
|
1001
|
+
start_line=metadata["start_line"],
|
|
1002
|
+
end_line=metadata["end_line"],
|
|
1003
|
+
language=metadata["language"],
|
|
1004
|
+
chunk_type=metadata.get("chunk_type", "code"),
|
|
1005
|
+
function_name=metadata.get("function_name"),
|
|
1006
|
+
class_name=metadata.get("class_name"),
|
|
1007
|
+
docstring=metadata.get("docstring"),
|
|
1008
|
+
imports=metadata.get("imports", []),
|
|
1009
|
+
complexity_score=metadata.get("complexity_score", 0.0),
|
|
1010
|
+
chunk_id=metadata.get("chunk_id"),
|
|
1011
|
+
parent_chunk_id=metadata.get("parent_chunk_id"),
|
|
1012
|
+
child_chunk_ids=metadata.get("child_chunk_ids", []),
|
|
1013
|
+
chunk_depth=metadata.get("chunk_depth", 0),
|
|
1014
|
+
decorators=metadata.get("decorators", []),
|
|
1015
|
+
parameters=metadata.get("parameters", []),
|
|
1016
|
+
return_type=metadata.get("return_type"),
|
|
1017
|
+
type_annotations=metadata.get("type_annotations", {}),
|
|
1018
|
+
subproject_name=metadata.get("subproject_name"),
|
|
1019
|
+
subproject_path=metadata.get("subproject_path"),
|
|
1020
|
+
)
|
|
1021
|
+
chunks.append(chunk)
|
|
1022
|
+
|
|
1023
|
+
logger.debug(f"Retrieved {len(chunks)} chunks from database")
|
|
1024
|
+
return chunks
|
|
1025
|
+
|
|
1026
|
+
except Exception as e:
|
|
1027
|
+
logger.error(f"Failed to get all chunks: {e}")
|
|
1028
|
+
raise DatabaseError(f"Failed to get all chunks: {e}") from e
|
|
1029
|
+
|
|
917
1030
|
def _build_where_clause(self, filters: dict[str, Any]) -> dict[str, Any] | None:
|
|
918
1031
|
"""Build ChromaDB where clause from filters."""
|
|
919
1032
|
if not filters:
|
|
@@ -13,6 +13,7 @@ from .. import __version__
|
|
|
13
13
|
from ..config.defaults import DEFAULT_IGNORE_PATTERNS
|
|
14
14
|
from ..parsers.registry import get_parser_registry
|
|
15
15
|
from ..utils.gitignore import create_gitignore_parser
|
|
16
|
+
from ..utils.monorepo import MonorepoDetector
|
|
16
17
|
from .database import VectorDatabase
|
|
17
18
|
from .exceptions import ParsingError
|
|
18
19
|
from .models import CodeChunk
|
|
@@ -72,6 +73,14 @@ class SemanticIndexer:
|
|
|
72
73
|
logger.warning(f"Failed to load gitignore patterns: {e}")
|
|
73
74
|
self.gitignore_parser = None
|
|
74
75
|
|
|
76
|
+
# Initialize monorepo detector
|
|
77
|
+
self.monorepo_detector = MonorepoDetector(project_root)
|
|
78
|
+
if self.monorepo_detector.is_monorepo():
|
|
79
|
+
subprojects = self.monorepo_detector.detect_subprojects()
|
|
80
|
+
logger.info(f"Detected monorepo with {len(subprojects)} subprojects")
|
|
81
|
+
for sp in subprojects:
|
|
82
|
+
logger.debug(f" - {sp.name} ({sp.relative_path})")
|
|
83
|
+
|
|
75
84
|
async def index_project(
|
|
76
85
|
self,
|
|
77
86
|
force_reindex: bool = False,
|
|
@@ -519,7 +528,7 @@ class SemanticIndexer:
|
|
|
519
528
|
file_path: Path to the file to parse
|
|
520
529
|
|
|
521
530
|
Returns:
|
|
522
|
-
List of code chunks
|
|
531
|
+
List of code chunks with subproject information
|
|
523
532
|
"""
|
|
524
533
|
try:
|
|
525
534
|
# Get appropriate parser
|
|
@@ -531,6 +540,13 @@ class SemanticIndexer:
|
|
|
531
540
|
# Filter out empty chunks
|
|
532
541
|
valid_chunks = [chunk for chunk in chunks if chunk.content.strip()]
|
|
533
542
|
|
|
543
|
+
# Assign subproject information for monorepos
|
|
544
|
+
subproject = self.monorepo_detector.get_subproject_for_file(file_path)
|
|
545
|
+
if subproject:
|
|
546
|
+
for chunk in valid_chunks:
|
|
547
|
+
chunk.subproject_name = subproject.name
|
|
548
|
+
chunk.subproject_path = subproject.relative_path
|
|
549
|
+
|
|
534
550
|
return valid_chunks
|
|
535
551
|
|
|
536
552
|
except Exception as e:
|
|
@@ -37,6 +37,10 @@ class CodeChunk:
|
|
|
37
37
|
return_type: str | None = None
|
|
38
38
|
type_annotations: dict[str, str] = None
|
|
39
39
|
|
|
40
|
+
# Enhancement 5: Monorepo support
|
|
41
|
+
subproject_name: str | None = None # "ewtn-plus-foundation"
|
|
42
|
+
subproject_path: str | None = None # Relative path from root
|
|
43
|
+
|
|
40
44
|
def __post_init__(self) -> None:
|
|
41
45
|
"""Initialize default values and generate chunk ID."""
|
|
42
46
|
if self.imports is None:
|
|
@@ -93,6 +97,8 @@ class CodeChunk:
|
|
|
93
97
|
"parameters": self.parameters,
|
|
94
98
|
"return_type": self.return_type,
|
|
95
99
|
"type_annotations": self.type_annotations,
|
|
100
|
+
"subproject_name": self.subproject_name,
|
|
101
|
+
"subproject_path": self.subproject_path,
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
@classmethod
|
|
@@ -118,6 +124,8 @@ class CodeChunk:
|
|
|
118
124
|
parameters=data.get("parameters", []),
|
|
119
125
|
return_type=data.get("return_type"),
|
|
120
126
|
type_annotations=data.get("type_annotations", {}),
|
|
127
|
+
subproject_name=data.get("subproject_name"),
|
|
128
|
+
subproject_path=data.get("subproject_path"),
|
|
121
129
|
)
|
|
122
130
|
|
|
123
131
|
|