mcp-vector-search 0.9.3__tar.gz → 0.12.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.9.3 → mcp_vector_search-0.12.0}/.gitignore +12 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/PKG-INFO +1 -1
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/CHANGELOG.md +46 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/pyproject.toml +3 -7
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/__init__.py +2 -2
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/index.py +31 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/visualize.py +358 -20
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/database.py +55 -20
- mcp_vector_search-0.12.0/src/mcp_vector_search/core/directory_index.py +303 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/indexer.py +67 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/models.py +58 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/utils/gitignore.py +14 -4
- mcp_vector_search-0.12.0/src/mcp_vector_search/visualization/index.html +658 -0
- mcp_vector_search-0.9.3/.changesets/20251009-204754-feat-add-comprehensive-changeset-and-documentation.md +0 -29
- mcp_vector_search-0.9.3/.changesets/20251009-205435-fix-update-readme-version-badge-to-0-7-1.md +0 -27
- mcp_vector_search-0.9.3/.changesets/20251009-205439-feat-add-comprehensive-changeset-support-system.md +0 -27
- mcp_vector_search-0.9.3/.changesets/EXAMPLE.md +0 -272
- mcp_vector_search-0.9.3/.changesets/IMPLEMENTATION_SUMMARY.md +0 -317
- mcp_vector_search-0.9.3/.changesets/README.md +0 -172
- mcp_vector_search-0.9.3/.changesets/template.md +0 -27
- mcp_vector_search-0.9.3/.editorconfig +0 -53
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/.github/workflows/ci.yml +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/.pre-commit-config.yaml +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/CLAUDE.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/LICENSE +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/Makefile +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/PERFORMANCE_OPTIMIZATION_SUMMARY.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/README.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/CLI_FEATURES.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/DEPLOY.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/DEVELOPMENT.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/FEATURES.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/IMPROVEMENTS_SUMMARY.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/MCP_FILE_WATCHING.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/RELEASES.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/STRUCTURE.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/VERSIONING.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/VERSIONING_WORKFLOW.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/_archive/CLAUDE_20251009_pre_mpm_init.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/_archive/CLAUDE_MPM_INIT_SUMMARY_20251009.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/_archive/MPM_INIT_EXECUTIVE_SUMMARY.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/analysis/SEARCH_ANALYSIS_REPORT.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/analysis/SEARCH_IMPROVEMENT_PLAN.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/architecture/REINDEXING_WORKFLOW.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/debugging/SEARCH_BUG_ANALYSIS.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/developer/API.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/developer/CONTRIBUTING.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/developer/DEVELOPER.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/developer/LINTING.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/developer/REFACTORING_ANALYSIS.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/developer/TESTING.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/developer/TESTING_STRATEGY.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/developer/TEST_SUITE_SUMMARY.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/mcp-integration.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/optimizations/database-stats-chunked-processing.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/performance/CONNECTION_POOLING.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/performance/SEARCH_TIMING_ANALYSIS.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/prd/mcp_vector_search_prd_updated.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/reference/ENGINEER_TASK.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/reference/INSTALL.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/reference/INSTALL_COMMAND_ENHANCEMENTS.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/reference/MCP_SETUP.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/reference/PROJECT_ORGANIZATION.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/docs/technical/SIMILARITY_CALCULATION_FIX.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/examples/connection_pooling_example.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/examples/semi_automatic_reindexing_demo.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/mcp-vector-search-wrapper +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/pytest.ini +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/README.md +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/analyze_search_bottlenecks.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/build.sh +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/changeset.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/comprehensive_build.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/deploy-test.sh +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/dev-build.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/dev-setup.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/dev-test.sh +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/fix_linting.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/mcp-dev +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/monitor_search_performance.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/publish.sh +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/quick_search_timing.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/run_search_timing_tests.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/run_tests.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/search_performance_monitor.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/search_quality_analyzer.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/setup/mcp-vector-search.sh +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/setup/setup-alias.sh +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/setup-dev-mcp.sh +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/update_docs.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/version_manager.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/scripts/workflow.sh +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/__init__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/__init__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/auto_index.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/config.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/demo.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/init.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/install.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/mcp.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/reset.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/search.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/status.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/watch.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/didyoumean.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/export.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/history.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/interactive.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/main.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/output.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/suggestions.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/config/__init__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/config/constants.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/config/defaults.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/config/settings.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/__init__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/auto_indexer.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/connection_pool.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/embeddings.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/exceptions.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/factory.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/git_hooks.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/project.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/scheduler.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/search.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/core/watcher.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/mcp/__init__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/mcp/__main__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/mcp/server.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/__init__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/base.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/dart.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/html.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/javascript.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/php.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/python.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/registry.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/ruby.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/text.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/parsers/utils.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/py.typed +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/utils/__init__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/utils/monorepo.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/utils/timing.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/utils/version.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/tests/__init__.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/tests/conftest.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/tests/sample_code/ast_test_javascript.js +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/tests/sample_code/ast_test_python.py +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/tests/sample_code/ast_test_typescript.ts +0 -0
- {mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/uv.lock +0 -0
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
# All dotfiles and dot-directories (catch-all)
|
|
2
|
+
.*
|
|
3
|
+
!.gitignore
|
|
4
|
+
!.github/
|
|
5
|
+
!.pre-commit-config.yaml
|
|
6
|
+
|
|
7
|
+
# Explicitly exclude common dotfiles/directories
|
|
8
|
+
.claude/
|
|
9
|
+
.changesets/
|
|
10
|
+
|
|
1
11
|
# MCP Vector Search specific
|
|
2
12
|
.mcp-vector-search/
|
|
3
13
|
*.db
|
|
@@ -179,6 +189,8 @@ test_*.py
|
|
|
179
189
|
*_test.py
|
|
180
190
|
debug_*.py
|
|
181
191
|
test_js_project/
|
|
192
|
+
test-screenshots/
|
|
193
|
+
chunk-graph.json
|
|
182
194
|
|
|
183
195
|
# UV specific
|
|
184
196
|
.uv/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-vector-search
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.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
|
|
@@ -56,6 +56,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
56
56
|
- Created parser utilities module to reduce code duplication (potential -800 to -1000 LOC)
|
|
57
57
|
- Proper LRU cache implementation with statistics and configurable size
|
|
58
58
|
|
|
59
|
+
## [0.12.0] - 2025-10-25
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
- **Hierarchical Graph Visualization**: Complete directory, file, and chunk-based visualization system
|
|
63
|
+
- Interactive D3.js force-directed graph with expand/collapse functionality
|
|
64
|
+
- Directory nodes expand to show all files and subdirectories
|
|
65
|
+
- File nodes expand to show individual code chunks with metadata
|
|
66
|
+
- Visual hierarchy with optimized 35px folder/file icons
|
|
67
|
+
- Cache-busting URL parameters and meta tags for fresh data loading
|
|
68
|
+
|
|
69
|
+
### Enhanced
|
|
70
|
+
- **Graph Link Visibility**: Improved visual clarity of relationships
|
|
71
|
+
- Enhanced link colors with better opacity (0.4 for directories, 0.3 for files)
|
|
72
|
+
- Dynamic link distances based on node types (150px directories, 80px files/chunks)
|
|
73
|
+
- Optimized collision detection with dynamic radius calculations
|
|
74
|
+
- Better auto-spacing with enhanced force simulation parameters
|
|
75
|
+
|
|
76
|
+
- **Expand/Collapse Functionality**: Robust node interaction system
|
|
77
|
+
- Working directory expansion showing all child files and subdirectories
|
|
78
|
+
- File expansion revealing all contained code chunks
|
|
79
|
+
- Preserves original link structure before D3 modifications
|
|
80
|
+
- Proper state management for expanded/collapsed nodes
|
|
81
|
+
- Visual feedback with node color changes
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
- **Parent Directory Linking**: Corrected absolute to relative path conversion
|
|
85
|
+
- Fixed lookup of parent directory IDs during graph generation
|
|
86
|
+
- Proper handling of nested directory structures
|
|
87
|
+
- Consistent path normalization across all node types
|
|
88
|
+
|
|
89
|
+
- **Stale Data Prevention**: Enhanced data freshness mechanisms
|
|
90
|
+
- Added `Cache-Control: no-cache, no-store, must-revalidate` meta tags
|
|
91
|
+
- Implemented timestamp-based cache-busting for JSON files
|
|
92
|
+
- Ensured visualization directory contains latest graph data
|
|
93
|
+
- Prevents browser caching of outdated graph structures
|
|
94
|
+
|
|
95
|
+
### Files Modified
|
|
96
|
+
- `src/mcp_vector_search/visualization/index.html` - UI improvements, expand/collapse fixes, cache prevention
|
|
97
|
+
- `src/mcp_vector_search/cli/commands/visualize.py` - Parent directory path normalization and linking fixes
|
|
98
|
+
|
|
99
|
+
### Technical Details
|
|
100
|
+
- Zero new dependencies (uses existing D3.js v7)
|
|
101
|
+
- Enhanced force simulation with configurable parameters
|
|
102
|
+
- Improved node interaction state management
|
|
103
|
+
- Better visual design with optimized spacing and colors
|
|
104
|
+
|
|
59
105
|
## [0.5.0] - 2025-10-02
|
|
60
106
|
|
|
61
107
|
### Added
|
|
@@ -47,6 +47,8 @@ dev = [
|
|
|
47
47
|
"pytest-benchmark>=4.0.0",
|
|
48
48
|
"pytest-cov>=4.1.0",
|
|
49
49
|
"pytest-mock>=3.11.0",
|
|
50
|
+
"pytest-xdist>=3.3.0",
|
|
51
|
+
"pytest-watch>=4.2.0",
|
|
50
52
|
"hypothesis>=6.88.0",
|
|
51
53
|
"black>=23.0.0",
|
|
52
54
|
"ruff>=0.1.0",
|
|
@@ -80,13 +82,7 @@ path = "src/mcp_vector_search/__init__.py"
|
|
|
80
82
|
packages = ["src/mcp_vector_search"]
|
|
81
83
|
|
|
82
84
|
# UV-specific configuration
|
|
83
|
-
[
|
|
84
|
-
dev-dependencies = [
|
|
85
|
-
"pytest-xdist>=3.3.0",
|
|
86
|
-
"pytest-watch>=4.2.0",
|
|
87
|
-
]
|
|
88
|
-
|
|
89
|
-
# UV sources configuration removed - using standard dependencies
|
|
85
|
+
# Note: dev-dependencies moved to [dependency-groups] section above
|
|
90
86
|
|
|
91
87
|
# Development tools configuration
|
|
92
88
|
[tool.black]
|
{mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/index.py
RENAMED
|
@@ -67,6 +67,13 @@ def main(
|
|
|
67
67
|
max=128,
|
|
68
68
|
rich_help_panel="⚡ Performance",
|
|
69
69
|
),
|
|
70
|
+
debug: bool = typer.Option(
|
|
71
|
+
False,
|
|
72
|
+
"--debug",
|
|
73
|
+
"-d",
|
|
74
|
+
help="Enable debug output (shows hierarchy building details)",
|
|
75
|
+
rich_help_panel="🔍 Debugging",
|
|
76
|
+
),
|
|
70
77
|
) -> None:
|
|
71
78
|
"""📑 Index your codebase for semantic search.
|
|
72
79
|
|
|
@@ -114,6 +121,7 @@ def main(
|
|
|
114
121
|
force_reindex=force,
|
|
115
122
|
batch_size=batch_size,
|
|
116
123
|
show_progress=True,
|
|
124
|
+
debug=debug,
|
|
117
125
|
)
|
|
118
126
|
)
|
|
119
127
|
|
|
@@ -134,6 +142,7 @@ async def run_indexing(
|
|
|
134
142
|
force_reindex: bool = False,
|
|
135
143
|
batch_size: int = 32,
|
|
136
144
|
show_progress: bool = True,
|
|
145
|
+
debug: bool = False,
|
|
137
146
|
) -> None:
|
|
138
147
|
"""Run the indexing process."""
|
|
139
148
|
# Load project configuration
|
|
@@ -179,6 +188,7 @@ async def run_indexing(
|
|
|
179
188
|
database=database,
|
|
180
189
|
project_root=project_root,
|
|
181
190
|
file_extensions=file_extensions,
|
|
191
|
+
debug=debug,
|
|
182
192
|
)
|
|
183
193
|
|
|
184
194
|
try:
|
|
@@ -324,6 +334,27 @@ async def _run_batch_indexing(
|
|
|
324
334
|
)
|
|
325
335
|
)
|
|
326
336
|
|
|
337
|
+
# Rebuild directory index after indexing completes
|
|
338
|
+
try:
|
|
339
|
+
import os
|
|
340
|
+
chunk_stats = {}
|
|
341
|
+
for file_path in files_to_index:
|
|
342
|
+
try:
|
|
343
|
+
mtime = os.path.getmtime(file_path)
|
|
344
|
+
chunk_stats[str(file_path)] = {
|
|
345
|
+
'modified': mtime,
|
|
346
|
+
'chunks': 1, # Placeholder - real counts are in database
|
|
347
|
+
}
|
|
348
|
+
except OSError:
|
|
349
|
+
pass
|
|
350
|
+
|
|
351
|
+
indexer.directory_index.rebuild_from_files(
|
|
352
|
+
files_to_index, indexer.project_root, chunk_stats=chunk_stats
|
|
353
|
+
)
|
|
354
|
+
indexer.directory_index.save()
|
|
355
|
+
except Exception as e:
|
|
356
|
+
logger.error(f"Failed to update directory index: {e}")
|
|
357
|
+
|
|
327
358
|
# Final progress summary
|
|
328
359
|
console.print()
|
|
329
360
|
if failed_count > 0:
|
{mcp_vector_search-0.9.3 → mcp_vector_search-0.12.0}/src/mcp_vector_search/cli/commands/visualize.py
RENAMED
|
@@ -100,6 +100,8 @@ async def _export_chunks(output: Path, file_filter: str | None) -> None:
|
|
|
100
100
|
nodes = []
|
|
101
101
|
links = []
|
|
102
102
|
chunk_id_map = {} # Map chunk IDs to array indices
|
|
103
|
+
file_nodes = {} # Track file nodes by path
|
|
104
|
+
dir_nodes = {} # Track directory nodes by path
|
|
103
105
|
|
|
104
106
|
# Add subproject root nodes for monorepos
|
|
105
107
|
if subprojects:
|
|
@@ -118,6 +120,80 @@ async def _export_chunks(output: Path, file_filter: str | None) -> None:
|
|
|
118
120
|
}
|
|
119
121
|
nodes.append(node)
|
|
120
122
|
|
|
123
|
+
# Load directory index for enhanced directory metadata
|
|
124
|
+
console.print("[cyan]Loading directory index...[/cyan]")
|
|
125
|
+
from ...core.directory_index import DirectoryIndex
|
|
126
|
+
dir_index_path = project_manager.project_root / ".mcp-vector-search" / "directory_index.json"
|
|
127
|
+
dir_index = DirectoryIndex(dir_index_path)
|
|
128
|
+
dir_index.load()
|
|
129
|
+
|
|
130
|
+
# Create directory nodes from directory index
|
|
131
|
+
console.print(f"[green]✓[/green] Loaded {len(dir_index.directories)} directories")
|
|
132
|
+
for dir_path_str, directory in dir_index.directories.items():
|
|
133
|
+
dir_id = f"dir_{hash(dir_path_str) & 0xffffffff:08x}"
|
|
134
|
+
dir_nodes[dir_path_str] = {
|
|
135
|
+
"id": dir_id,
|
|
136
|
+
"name": directory.name,
|
|
137
|
+
"type": "directory",
|
|
138
|
+
"file_path": dir_path_str,
|
|
139
|
+
"start_line": 0,
|
|
140
|
+
"end_line": 0,
|
|
141
|
+
"complexity": 0,
|
|
142
|
+
"depth": directory.depth,
|
|
143
|
+
"dir_path": dir_path_str,
|
|
144
|
+
"file_count": directory.file_count,
|
|
145
|
+
"subdirectory_count": directory.subdirectory_count,
|
|
146
|
+
"total_chunks": directory.total_chunks,
|
|
147
|
+
"languages": directory.languages or {},
|
|
148
|
+
"is_package": directory.is_package,
|
|
149
|
+
"last_modified": directory.last_modified,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# Create file nodes from chunks
|
|
153
|
+
for chunk in chunks:
|
|
154
|
+
file_path_str = str(chunk.file_path)
|
|
155
|
+
file_path = Path(file_path_str)
|
|
156
|
+
|
|
157
|
+
# Create file node with parent directory reference
|
|
158
|
+
if file_path_str not in file_nodes:
|
|
159
|
+
file_id = f"file_{hash(file_path_str) & 0xffffffff:08x}"
|
|
160
|
+
|
|
161
|
+
# Convert absolute path to relative path for parent directory lookup
|
|
162
|
+
try:
|
|
163
|
+
relative_file_path = file_path.relative_to(project_manager.project_root)
|
|
164
|
+
parent_dir = relative_file_path.parent
|
|
165
|
+
# Use relative path for parent directory (matches directory_index)
|
|
166
|
+
parent_dir_str = str(parent_dir) if parent_dir != Path(".") else None
|
|
167
|
+
except ValueError:
|
|
168
|
+
# File is outside project root
|
|
169
|
+
parent_dir_str = None
|
|
170
|
+
|
|
171
|
+
# Look up parent directory ID from dir_nodes (must match exactly)
|
|
172
|
+
parent_dir_id = None
|
|
173
|
+
if parent_dir_str and parent_dir_str in dir_nodes:
|
|
174
|
+
parent_dir_id = dir_nodes[parent_dir_str]["id"]
|
|
175
|
+
|
|
176
|
+
file_nodes[file_path_str] = {
|
|
177
|
+
"id": file_id,
|
|
178
|
+
"name": file_path.name,
|
|
179
|
+
"type": "file",
|
|
180
|
+
"file_path": file_path_str,
|
|
181
|
+
"start_line": 0,
|
|
182
|
+
"end_line": 0,
|
|
183
|
+
"complexity": 0,
|
|
184
|
+
"depth": len(file_path.parts) - 1,
|
|
185
|
+
"parent_dir_id": parent_dir_id,
|
|
186
|
+
"parent_dir_path": parent_dir_str,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
# Add directory nodes to graph
|
|
190
|
+
for dir_node in dir_nodes.values():
|
|
191
|
+
nodes.append(dir_node)
|
|
192
|
+
|
|
193
|
+
# Add file nodes to graph
|
|
194
|
+
for file_node in file_nodes.values():
|
|
195
|
+
nodes.append(file_node)
|
|
196
|
+
|
|
121
197
|
# Add chunk nodes
|
|
122
198
|
for chunk in chunks:
|
|
123
199
|
node = {
|
|
@@ -130,6 +206,9 @@ async def _export_chunks(output: Path, file_filter: str | None) -> None:
|
|
|
130
206
|
"complexity": chunk.complexity_score,
|
|
131
207
|
"parent_id": chunk.parent_chunk_id,
|
|
132
208
|
"depth": chunk.chunk_depth,
|
|
209
|
+
"content": chunk.content, # Add content for code viewer
|
|
210
|
+
"docstring": chunk.docstring,
|
|
211
|
+
"language": chunk.language,
|
|
133
212
|
}
|
|
134
213
|
|
|
135
214
|
# Add subproject info for monorepos
|
|
@@ -140,9 +219,52 @@ async def _export_chunks(output: Path, file_filter: str | None) -> None:
|
|
|
140
219
|
nodes.append(node)
|
|
141
220
|
chunk_id_map[node["id"]] = len(nodes) - 1
|
|
142
221
|
|
|
222
|
+
# Link directories to their parent directories (hierarchical structure)
|
|
223
|
+
for dir_path_str, dir_info in dir_index.directories.items():
|
|
224
|
+
if dir_info.parent_path:
|
|
225
|
+
parent_path_str = str(dir_info.parent_path)
|
|
226
|
+
if parent_path_str in dir_nodes:
|
|
227
|
+
parent_dir_id = f"dir_{hash(parent_path_str) & 0xffffffff:08x}"
|
|
228
|
+
child_dir_id = f"dir_{hash(dir_path_str) & 0xffffffff:08x}"
|
|
229
|
+
links.append({
|
|
230
|
+
"source": parent_dir_id,
|
|
231
|
+
"target": child_dir_id,
|
|
232
|
+
"type": "dir_hierarchy",
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
# Link directories to subprojects in monorepos (simple flat structure)
|
|
236
|
+
if subprojects:
|
|
237
|
+
for dir_path_str, dir_node in dir_nodes.items():
|
|
238
|
+
for sp_name, sp_data in subprojects.items():
|
|
239
|
+
if dir_path_str.startswith(sp_data.get("path", "")):
|
|
240
|
+
links.append({
|
|
241
|
+
"source": f"subproject_{sp_name}",
|
|
242
|
+
"target": dir_node["id"],
|
|
243
|
+
"type": "dir_containment",
|
|
244
|
+
})
|
|
245
|
+
break
|
|
246
|
+
|
|
247
|
+
# Link files to their parent directories
|
|
248
|
+
for file_path_str, file_node in file_nodes.items():
|
|
249
|
+
if file_node.get("parent_dir_id"):
|
|
250
|
+
links.append({
|
|
251
|
+
"source": file_node["parent_dir_id"],
|
|
252
|
+
"target": file_node["id"],
|
|
253
|
+
"type": "dir_containment",
|
|
254
|
+
})
|
|
255
|
+
|
|
143
256
|
# Build hierarchical links from parent-child relationships
|
|
144
257
|
for chunk in chunks:
|
|
145
258
|
chunk_id = chunk.chunk_id or chunk.id
|
|
259
|
+
file_path = str(chunk.file_path)
|
|
260
|
+
|
|
261
|
+
# Link chunk to its file node if it has no parent (top-level chunks)
|
|
262
|
+
if not chunk.parent_chunk_id and file_path in file_nodes:
|
|
263
|
+
links.append({
|
|
264
|
+
"source": file_nodes[file_path]["id"],
|
|
265
|
+
"target": chunk_id,
|
|
266
|
+
"type": "file_containment",
|
|
267
|
+
})
|
|
146
268
|
|
|
147
269
|
# Link to subproject root if in monorepo
|
|
148
270
|
if chunk.subproject_name and not chunk.parent_chunk_id:
|
|
@@ -476,8 +598,30 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
476
598
|
.node.function circle { fill: #d29922; }
|
|
477
599
|
.node.method circle { fill: #8957e5; }
|
|
478
600
|
.node.code circle { fill: #6e7681; }
|
|
601
|
+
.node.file circle {
|
|
602
|
+
fill: none;
|
|
603
|
+
stroke: #58a6ff;
|
|
604
|
+
stroke-width: 2px;
|
|
605
|
+
stroke-dasharray: 5,3;
|
|
606
|
+
opacity: 0.6;
|
|
607
|
+
}
|
|
608
|
+
.node.directory circle {
|
|
609
|
+
fill: none;
|
|
610
|
+
stroke: #79c0ff;
|
|
611
|
+
stroke-width: 2px;
|
|
612
|
+
stroke-dasharray: 3,3;
|
|
613
|
+
opacity: 0.5;
|
|
614
|
+
}
|
|
479
615
|
.node.subproject circle { fill: #da3633; stroke-width: 3px; }
|
|
480
616
|
|
|
617
|
+
/* Non-code document nodes - squares */
|
|
618
|
+
.node.docstring rect { fill: #8b949e; }
|
|
619
|
+
.node.comment rect { fill: #6e7681; }
|
|
620
|
+
.node rect {
|
|
621
|
+
stroke: #c9d1d9;
|
|
622
|
+
stroke-width: 1.5px;
|
|
623
|
+
}
|
|
624
|
+
|
|
481
625
|
.node text {
|
|
482
626
|
font-size: 11px;
|
|
483
627
|
fill: #c9d1d9;
|
|
@@ -519,6 +663,79 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
519
663
|
font-size: 12px;
|
|
520
664
|
color: #8b949e;
|
|
521
665
|
}
|
|
666
|
+
|
|
667
|
+
#code-viewer {
|
|
668
|
+
position: absolute;
|
|
669
|
+
top: 20px;
|
|
670
|
+
right: 20px;
|
|
671
|
+
width: 500px;
|
|
672
|
+
max-height: 80vh;
|
|
673
|
+
background: rgba(13, 17, 23, 0.95);
|
|
674
|
+
border: 1px solid #30363d;
|
|
675
|
+
border-radius: 6px;
|
|
676
|
+
padding: 16px;
|
|
677
|
+
overflow-y: auto;
|
|
678
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
679
|
+
display: none;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
#code-viewer.visible {
|
|
683
|
+
display: block;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
#code-viewer .header {
|
|
687
|
+
margin-bottom: 12px;
|
|
688
|
+
padding-bottom: 12px;
|
|
689
|
+
border-bottom: 1px solid #30363d;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
#code-viewer .title {
|
|
693
|
+
font-size: 14px;
|
|
694
|
+
font-weight: bold;
|
|
695
|
+
color: #58a6ff;
|
|
696
|
+
margin-bottom: 4px;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
#code-viewer .meta {
|
|
700
|
+
font-size: 11px;
|
|
701
|
+
color: #8b949e;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
#code-viewer .close-btn {
|
|
705
|
+
float: right;
|
|
706
|
+
cursor: pointer;
|
|
707
|
+
color: #8b949e;
|
|
708
|
+
font-size: 20px;
|
|
709
|
+
line-height: 1;
|
|
710
|
+
margin-top: -4px;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
#code-viewer .close-btn:hover {
|
|
714
|
+
color: #c9d1d9;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
#code-viewer pre {
|
|
718
|
+
margin: 0;
|
|
719
|
+
padding: 12px;
|
|
720
|
+
background: #0d1117;
|
|
721
|
+
border: 1px solid #30363d;
|
|
722
|
+
border-radius: 6px;
|
|
723
|
+
overflow-x: auto;
|
|
724
|
+
font-size: 11px;
|
|
725
|
+
line-height: 1.5;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
#code-viewer code {
|
|
729
|
+
color: #c9d1d9;
|
|
730
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.node.highlighted circle,
|
|
734
|
+
.node.highlighted rect {
|
|
735
|
+
stroke: #f0e68c;
|
|
736
|
+
stroke-width: 3px;
|
|
737
|
+
filter: drop-shadow(0 0 8px #f0e68c);
|
|
738
|
+
}
|
|
522
739
|
</style>
|
|
523
740
|
</head>
|
|
524
741
|
<body>
|
|
@@ -534,6 +751,12 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
534
751
|
<div class="legend-item">
|
|
535
752
|
<span class="legend-color" style="background: #da3633;"></span> Subproject
|
|
536
753
|
</div>
|
|
754
|
+
<div class="legend-item">
|
|
755
|
+
<span class="legend-color" style="border: 2px dashed #79c0ff; border-radius: 50%; background: transparent;"></span> Directory
|
|
756
|
+
</div>
|
|
757
|
+
<div class="legend-item">
|
|
758
|
+
<span class="legend-color" style="border: 2px dashed #58a6ff; border-radius: 50%; background: transparent;"></span> File
|
|
759
|
+
</div>
|
|
537
760
|
<div class="legend-item">
|
|
538
761
|
<span class="legend-color" style="background: #238636;"></span> Module
|
|
539
762
|
</div>
|
|
@@ -549,6 +772,12 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
549
772
|
<div class="legend-item">
|
|
550
773
|
<span class="legend-color" style="background: #6e7681;"></span> Code
|
|
551
774
|
</div>
|
|
775
|
+
<div class="legend-item">
|
|
776
|
+
<span class="legend-color" style="background: #8b949e; border-radius: 2px;"></span> Docstring ▢
|
|
777
|
+
</div>
|
|
778
|
+
<div class="legend-item">
|
|
779
|
+
<span class="legend-color" style="background: #6e7681; border-radius: 2px;"></span> Comment ▢
|
|
780
|
+
</div>
|
|
552
781
|
</div>
|
|
553
782
|
|
|
554
783
|
<div id="subprojects-legend" style="display: none;">
|
|
@@ -562,6 +791,15 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
562
791
|
<svg id="graph"></svg>
|
|
563
792
|
<div id="tooltip" class="tooltip"></div>
|
|
564
793
|
|
|
794
|
+
<div id="code-viewer">
|
|
795
|
+
<div class="header">
|
|
796
|
+
<span class="close-btn" onclick="closeCodeViewer()">×</span>
|
|
797
|
+
<div class="title" id="viewer-title"></div>
|
|
798
|
+
<div class="meta" id="viewer-meta"></div>
|
|
799
|
+
</div>
|
|
800
|
+
<pre><code id="viewer-code"></code></pre>
|
|
801
|
+
</div>
|
|
802
|
+
|
|
565
803
|
<script>
|
|
566
804
|
const width = window.innerWidth;
|
|
567
805
|
const height = window.innerHeight;
|
|
@@ -580,6 +818,7 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
580
818
|
let allLinks = [];
|
|
581
819
|
let visibleNodes = new Set();
|
|
582
820
|
let collapsedNodes = new Set();
|
|
821
|
+
let highlightedNode = null;
|
|
583
822
|
|
|
584
823
|
function visualizeGraph(data) {
|
|
585
824
|
g.selectAll("*").remove();
|
|
@@ -587,19 +826,37 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
587
826
|
allNodes = data.nodes;
|
|
588
827
|
allLinks = data.links;
|
|
589
828
|
|
|
590
|
-
// Find root nodes
|
|
829
|
+
// Find root nodes - start with only top-level nodes
|
|
591
830
|
let rootNodes;
|
|
592
831
|
if (data.metadata && data.metadata.is_monorepo) {
|
|
593
832
|
// In monorepos, subproject nodes are roots
|
|
594
833
|
rootNodes = allNodes.filter(n => n.type === 'subproject');
|
|
595
834
|
} else {
|
|
596
|
-
// Regular projects:
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
835
|
+
// Regular projects: show root-level directories AND files
|
|
836
|
+
const dirNodes = allNodes.filter(n => n.type === 'directory');
|
|
837
|
+
const fileNodes = allNodes.filter(n => n.type === 'file');
|
|
838
|
+
|
|
839
|
+
// Find minimum depth for directories and files
|
|
840
|
+
const minDirDepth = dirNodes.length > 0
|
|
841
|
+
? Math.min(...dirNodes.map(n => n.depth))
|
|
842
|
+
: Infinity;
|
|
843
|
+
const minFileDepth = fileNodes.length > 0
|
|
844
|
+
? Math.min(...fileNodes.map(n => n.depth))
|
|
845
|
+
: Infinity;
|
|
846
|
+
|
|
847
|
+
// Include both root-level directories and root-level files
|
|
848
|
+
rootNodes = [
|
|
849
|
+
...dirNodes.filter(n => n.depth === minDirDepth),
|
|
850
|
+
...fileNodes.filter(n => n.depth === minFileDepth)
|
|
851
|
+
];
|
|
852
|
+
|
|
853
|
+
// Fallback to all files if nothing found
|
|
854
|
+
if (rootNodes.length === 0) {
|
|
855
|
+
rootNodes = fileNodes;
|
|
856
|
+
}
|
|
600
857
|
}
|
|
601
858
|
|
|
602
|
-
// Start with only root nodes visible
|
|
859
|
+
// Start with only root nodes visible, all collapsed
|
|
603
860
|
visibleNodes = new Set(rootNodes.map(n => n.id));
|
|
604
861
|
collapsedNodes = new Set(rootNodes.map(n => n.id));
|
|
605
862
|
|
|
@@ -631,22 +888,59 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
631
888
|
.selectAll("g")
|
|
632
889
|
.data(visibleNodesList)
|
|
633
890
|
.join("g")
|
|
634
|
-
.attr("class", d =>
|
|
891
|
+
.attr("class", d => {
|
|
892
|
+
let classes = `node ${d.type}`;
|
|
893
|
+
if (highlightedNode && d.id === highlightedNode.id) {
|
|
894
|
+
classes += ' highlighted';
|
|
895
|
+
}
|
|
896
|
+
return classes;
|
|
897
|
+
})
|
|
635
898
|
.call(drag(simulation))
|
|
636
|
-
.on("click",
|
|
899
|
+
.on("click", handleNodeClick)
|
|
637
900
|
.on("mouseover", showTooltip)
|
|
638
901
|
.on("mouseout", hideTooltip);
|
|
639
902
|
|
|
640
|
-
// Add circles
|
|
641
|
-
|
|
903
|
+
// Add shapes based on node type (circles for code, squares for docs)
|
|
904
|
+
const isDocNode = d => ['docstring', 'comment'].includes(d.type);
|
|
905
|
+
|
|
906
|
+
// Add circles for code nodes
|
|
907
|
+
node.filter(d => !isDocNode(d))
|
|
908
|
+
.append("circle")
|
|
642
909
|
.attr("r", d => {
|
|
643
910
|
if (d.type === 'subproject') return 20;
|
|
911
|
+
if (d.type === 'directory') return 40; // Largest for directory containers
|
|
912
|
+
if (d.type === 'file') return 30; // Larger transparent circle for files
|
|
644
913
|
return d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12;
|
|
645
914
|
})
|
|
646
915
|
.attr("stroke", d => hasChildren(d) ? "#ffffff" : "none")
|
|
647
916
|
.attr("stroke-width", d => hasChildren(d) ? 2 : 0)
|
|
648
917
|
.style("fill", d => d.color || null); // Use custom color if available
|
|
649
918
|
|
|
919
|
+
// Add rectangles for document nodes
|
|
920
|
+
node.filter(d => isDocNode(d))
|
|
921
|
+
.append("rect")
|
|
922
|
+
.attr("width", d => {
|
|
923
|
+
const size = d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12;
|
|
924
|
+
return size * 2;
|
|
925
|
+
})
|
|
926
|
+
.attr("height", d => {
|
|
927
|
+
const size = d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12;
|
|
928
|
+
return size * 2;
|
|
929
|
+
})
|
|
930
|
+
.attr("x", d => {
|
|
931
|
+
const size = d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12;
|
|
932
|
+
return -size;
|
|
933
|
+
})
|
|
934
|
+
.attr("y", d => {
|
|
935
|
+
const size = d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12;
|
|
936
|
+
return -size;
|
|
937
|
+
})
|
|
938
|
+
.attr("rx", 2) // Rounded corners
|
|
939
|
+
.attr("ry", 2)
|
|
940
|
+
.attr("stroke", d => hasChildren(d) ? "#ffffff" : "none")
|
|
941
|
+
.attr("stroke-width", d => hasChildren(d) ? 2 : 0)
|
|
942
|
+
.style("fill", d => d.color || null);
|
|
943
|
+
|
|
650
944
|
// Add expand/collapse indicator
|
|
651
945
|
node.filter(d => hasChildren(d))
|
|
652
946
|
.append("text")
|
|
@@ -681,20 +975,21 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
681
975
|
return allLinks.some(l => (l.source.id || l.source) === node.id);
|
|
682
976
|
}
|
|
683
977
|
|
|
684
|
-
function
|
|
978
|
+
function handleNodeClick(event, d) {
|
|
685
979
|
event.stopPropagation();
|
|
686
980
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
981
|
+
// If node has children, toggle expansion
|
|
982
|
+
if (hasChildren(d)) {
|
|
983
|
+
if (collapsedNodes.has(d.id)) {
|
|
984
|
+
expandNode(d);
|
|
985
|
+
} else {
|
|
986
|
+
collapseNode(d);
|
|
987
|
+
}
|
|
988
|
+
renderGraph();
|
|
692
989
|
} else {
|
|
693
|
-
//
|
|
694
|
-
|
|
990
|
+
// Leaf node - show code viewer
|
|
991
|
+
showCodeViewer(d);
|
|
695
992
|
}
|
|
696
|
-
|
|
697
|
-
renderGraph();
|
|
698
993
|
}
|
|
699
994
|
|
|
700
995
|
function expandNode(node) {
|
|
@@ -802,6 +1097,49 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
802
1097
|
}
|
|
803
1098
|
}
|
|
804
1099
|
|
|
1100
|
+
function showCodeViewer(node) {
|
|
1101
|
+
// Highlight the node
|
|
1102
|
+
highlightedNode = node;
|
|
1103
|
+
renderGraph();
|
|
1104
|
+
|
|
1105
|
+
// Populate code viewer
|
|
1106
|
+
const viewer = document.getElementById('code-viewer');
|
|
1107
|
+
const title = document.getElementById('viewer-title');
|
|
1108
|
+
const meta = document.getElementById('viewer-meta');
|
|
1109
|
+
const code = document.getElementById('viewer-code');
|
|
1110
|
+
|
|
1111
|
+
title.textContent = node.name;
|
|
1112
|
+
|
|
1113
|
+
let metaText = `${node.type} • ${node.file_path}`;
|
|
1114
|
+
if (node.start_line) {
|
|
1115
|
+
metaText += ` • Lines ${node.start_line}-${node.end_line}`;
|
|
1116
|
+
}
|
|
1117
|
+
if (node.language) {
|
|
1118
|
+
metaText += ` • ${node.language}`;
|
|
1119
|
+
}
|
|
1120
|
+
meta.textContent = metaText;
|
|
1121
|
+
|
|
1122
|
+
// Show content if available
|
|
1123
|
+
if (node.content) {
|
|
1124
|
+
code.textContent = node.content;
|
|
1125
|
+
} else if (node.docstring) {
|
|
1126
|
+
code.textContent = `// Docstring:\n${node.docstring}`;
|
|
1127
|
+
} else {
|
|
1128
|
+
code.textContent = '// No content available';
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
viewer.classList.add('visible');
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
function closeCodeViewer() {
|
|
1135
|
+
const viewer = document.getElementById('code-viewer');
|
|
1136
|
+
viewer.classList.remove('visible');
|
|
1137
|
+
|
|
1138
|
+
// Remove highlight
|
|
1139
|
+
highlightedNode = null;
|
|
1140
|
+
renderGraph();
|
|
1141
|
+
}
|
|
1142
|
+
|
|
805
1143
|
// Auto-load graph data on page load
|
|
806
1144
|
window.addEventListener('DOMContentLoaded', () => {
|
|
807
1145
|
const loadingEl = document.getElementById('loading');
|