synapps-mcp 1.2.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.
- synapps_mcp-1.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +73 -0
- synapps_mcp-1.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +44 -0
- synapps_mcp-1.2.0/.github/PULL_REQUEST_TEMPLATE.md +19 -0
- synapps_mcp-1.2.0/.github/workflows/ci.yml +30 -0
- synapps_mcp-1.2.0/.github/workflows/publish.yml +63 -0
- synapps_mcp-1.2.0/.gitignore +16 -0
- synapps_mcp-1.2.0/.synapps/config.json +9 -0
- synapps_mcp-1.2.0/.synignore +11 -0
- synapps_mcp-1.2.0/CHANGELOG.md +63 -0
- synapps_mcp-1.2.0/CLAUDE.md +246 -0
- synapps_mcp-1.2.0/CONTRIBUTING.md +62 -0
- synapps_mcp-1.2.0/LICENSE +21 -0
- synapps_mcp-1.2.0/NOTICES +15 -0
- synapps_mcp-1.2.0/PKG-INFO +108 -0
- synapps_mcp-1.2.0/PYPI_README.md +60 -0
- synapps_mcp-1.2.0/README.md +449 -0
- synapps_mcp-1.2.0/docker-compose.yml +13 -0
- synapps_mcp-1.2.0/docs/DISTRIBUTION-AND-ONBOARDING.md +124 -0
- synapps_mcp-1.2.0/docs/HTTP-ENDPOINT-STRATEGY.md +161 -0
- synapps_mcp-1.2.0/docs/LANGUAGE-PLUGIN-GUIDE.md +1064 -0
- synapps_mcp-1.2.0/docs/TODO-mcp-tools-consolidation.md +28 -0
- synapps_mcp-1.2.0/docs/demo/README.md +47 -0
- synapps_mcp-1.2.0/docs/demo/demo-self.tape +59 -0
- synapps_mcp-1.2.0/docs/demo/demo.tape +53 -0
- synapps_mcp-1.2.0/pyproject.toml +65 -0
- synapps_mcp-1.2.0/pytest.ini +7 -0
- synapps_mcp-1.2.0/src/solidlsp/.gitignore +1 -0
- synapps_mcp-1.2.0/src/solidlsp/LICENSE +21 -0
- synapps_mcp-1.2.0/src/solidlsp/__init__.py +2 -0
- synapps_mcp-1.2.0/src/solidlsp/language_servers/common.py +164 -0
- synapps_mcp-1.2.0/src/solidlsp/language_servers/csharp_language_server.py +745 -0
- synapps_mcp-1.2.0/src/solidlsp/language_servers/eclipse_jdtls.py +291 -0
- synapps_mcp-1.2.0/src/solidlsp/language_servers/omnisharp/initialize_params.json +631 -0
- synapps_mcp-1.2.0/src/solidlsp/language_servers/omnisharp/runtime_dependencies.json +441 -0
- synapps_mcp-1.2.0/src/solidlsp/language_servers/omnisharp/workspace_did_change_configuration.json +111 -0
- synapps_mcp-1.2.0/src/solidlsp/language_servers/pyright_server.py +203 -0
- synapps_mcp-1.2.0/src/solidlsp/language_servers/typescript_language_server.py +312 -0
- synapps_mcp-1.2.0/src/solidlsp/ls.py +2238 -0
- synapps_mcp-1.2.0/src/solidlsp/ls_config.py +514 -0
- synapps_mcp-1.2.0/src/solidlsp/ls_exceptions.py +74 -0
- synapps_mcp-1.2.0/src/solidlsp/ls_process.py +574 -0
- synapps_mcp-1.2.0/src/solidlsp/ls_request.py +383 -0
- synapps_mcp-1.2.0/src/solidlsp/ls_types.py +453 -0
- synapps_mcp-1.2.0/src/solidlsp/ls_utils.py +425 -0
- synapps_mcp-1.2.0/src/solidlsp/lsp_protocol_handler/lsp_constants.py +69 -0
- synapps_mcp-1.2.0/src/solidlsp/lsp_protocol_handler/lsp_requests.py +561 -0
- synapps_mcp-1.2.0/src/solidlsp/lsp_protocol_handler/lsp_types.py +5964 -0
- synapps_mcp-1.2.0/src/solidlsp/lsp_protocol_handler/server.py +158 -0
- synapps_mcp-1.2.0/src/solidlsp/settings.py +73 -0
- synapps_mcp-1.2.0/src/solidlsp/util/cache.py +23 -0
- synapps_mcp-1.2.0/src/solidlsp/util/metals_db_utils.py +280 -0
- synapps_mcp-1.2.0/src/solidlsp/util/subprocess_util.py +22 -0
- synapps_mcp-1.2.0/src/solidlsp/util/zip.py +128 -0
- synapps_mcp-1.2.0/src/synapps/__init__.py +8 -0
- synapps_mcp-1.2.0/src/synapps/cli/__init__.py +1 -0
- synapps_mcp-1.2.0/src/synapps/cli/app.py +597 -0
- synapps_mcp-1.2.0/src/synapps/cli/banner.py +28 -0
- synapps_mcp-1.2.0/src/synapps/cli/tree.py +105 -0
- synapps_mcp-1.2.0/src/synapps/config.py +40 -0
- synapps_mcp-1.2.0/src/synapps/container/__init__.py +3 -0
- synapps_mcp-1.2.0/src/synapps/container/manager.py +196 -0
- synapps_mcp-1.2.0/src/synapps/doctor/__init__.py +6 -0
- synapps_mcp-1.2.0/src/synapps/doctor/base.py +28 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/__init__.py +1 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/csharp_ls.py +62 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/docker_daemon.py +41 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/dotnet.py +59 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/java.py +54 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/jdtls.py +59 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/memgraph_bolt.py +63 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/node.py +53 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/pylsp.py +49 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/python3.py +60 -0
- synapps_mcp-1.2.0/src/synapps/doctor/checks/typescript_ls.py +47 -0
- synapps_mcp-1.2.0/src/synapps/doctor/service.py +39 -0
- synapps_mcp-1.2.0/src/synapps/graph/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/graph/analysis.py +187 -0
- synapps_mcp-1.2.0/src/synapps/graph/connection.py +94 -0
- synapps_mcp-1.2.0/src/synapps/graph/edges.py +303 -0
- synapps_mcp-1.2.0/src/synapps/graph/lookups.py +606 -0
- synapps_mcp-1.2.0/src/synapps/graph/nodes.py +239 -0
- synapps_mcp-1.2.0/src/synapps/graph/schema.py +31 -0
- synapps_mcp-1.2.0/src/synapps/graph/traversal.py +158 -0
- synapps_mcp-1.2.0/src/synapps/indexer/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/indexer/assignment_ref.py +12 -0
- synapps_mcp-1.2.0/src/synapps/indexer/call_indexer.py +107 -0
- synapps_mcp-1.2.0/src/synapps/indexer/csharp/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/indexer/csharp/csharp_attribute_extractor.py +118 -0
- synapps_mcp-1.2.0/src/synapps/indexer/csharp/csharp_base_type_extractor.py +81 -0
- synapps_mcp-1.2.0/src/synapps/indexer/csharp/csharp_call_extractor.py +82 -0
- synapps_mcp-1.2.0/src/synapps/indexer/csharp/csharp_http_extractor.py +404 -0
- synapps_mcp-1.2.0/src/synapps/indexer/csharp/csharp_import_extractor.py +44 -0
- synapps_mcp-1.2.0/src/synapps/indexer/csharp/csharp_type_ref_extractor.py +150 -0
- synapps_mcp-1.2.0/src/synapps/indexer/git.py +78 -0
- synapps_mcp-1.2.0/src/synapps/indexer/http/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/indexer/http/constants_resolver.py +225 -0
- synapps_mcp-1.2.0/src/synapps/indexer/http/interface.py +48 -0
- synapps_mcp-1.2.0/src/synapps/indexer/http/matcher.py +95 -0
- synapps_mcp-1.2.0/src/synapps/indexer/http/route_utils.py +54 -0
- synapps_mcp-1.2.0/src/synapps/indexer/http_phase.py +135 -0
- synapps_mcp-1.2.0/src/synapps/indexer/indexer.py +762 -0
- synapps_mcp-1.2.0/src/synapps/indexer/java/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/indexer/java/java_attribute_extractor.py +107 -0
- synapps_mcp-1.2.0/src/synapps/indexer/java/java_base_type_extractor.py +131 -0
- synapps_mcp-1.2.0/src/synapps/indexer/java/java_call_extractor.py +114 -0
- synapps_mcp-1.2.0/src/synapps/indexer/java/java_http_extractor.py +529 -0
- synapps_mcp-1.2.0/src/synapps/indexer/java/java_import_extractor.py +58 -0
- synapps_mcp-1.2.0/src/synapps/indexer/java/java_type_ref_extractor.py +167 -0
- synapps_mcp-1.2.0/src/synapps/indexer/method_implements_indexer.py +63 -0
- synapps_mcp-1.2.0/src/synapps/indexer/overrides_indexer.py +34 -0
- synapps_mcp-1.2.0/src/synapps/indexer/python/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/indexer/python/python_assignment_extractor.py +211 -0
- synapps_mcp-1.2.0/src/synapps/indexer/python/python_attribute_extractor.py +140 -0
- synapps_mcp-1.2.0/src/synapps/indexer/python/python_base_type_extractor.py +62 -0
- synapps_mcp-1.2.0/src/synapps/indexer/python/python_call_extractor.py +124 -0
- synapps_mcp-1.2.0/src/synapps/indexer/python/python_http_extractor.py +614 -0
- synapps_mcp-1.2.0/src/synapps/indexer/python/python_import_extractor.py +150 -0
- synapps_mcp-1.2.0/src/synapps/indexer/python/python_type_ref_extractor.py +219 -0
- synapps_mcp-1.2.0/src/synapps/indexer/symbol_resolver.py +501 -0
- synapps_mcp-1.2.0/src/synapps/indexer/sync.py +181 -0
- synapps_mcp-1.2.0/src/synapps/indexer/tree_sitter_util.py +40 -0
- synapps_mcp-1.2.0/src/synapps/indexer/type_ref.py +12 -0
- synapps_mcp-1.2.0/src/synapps/indexer/typescript/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/indexer/typescript/typescript_attribute_extractor.py +313 -0
- synapps_mcp-1.2.0/src/synapps/indexer/typescript/typescript_base_type_extractor.py +135 -0
- synapps_mcp-1.2.0/src/synapps/indexer/typescript/typescript_call_extractor.py +149 -0
- synapps_mcp-1.2.0/src/synapps/indexer/typescript/typescript_http_extractor.py +358 -0
- synapps_mcp-1.2.0/src/synapps/indexer/typescript/typescript_import_extractor.py +170 -0
- synapps_mcp-1.2.0/src/synapps/indexer/typescript/typescript_type_ref_extractor.py +253 -0
- synapps_mcp-1.2.0/src/synapps/lsp/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/lsp/csharp.py +121 -0
- synapps_mcp-1.2.0/src/synapps/lsp/interface.py +89 -0
- synapps_mcp-1.2.0/src/synapps/lsp/java.py +267 -0
- synapps_mcp-1.2.0/src/synapps/lsp/python.py +195 -0
- synapps_mcp-1.2.0/src/synapps/lsp/typescript.py +227 -0
- synapps_mcp-1.2.0/src/synapps/lsp/util.py +22 -0
- synapps_mcp-1.2.0/src/synapps/mcp/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/mcp/instructions.py +53 -0
- synapps_mcp-1.2.0/src/synapps/mcp/server.py +26 -0
- synapps_mcp-1.2.0/src/synapps/mcp/tools.py +503 -0
- synapps_mcp-1.2.0/src/synapps/onboarding/__init__.py +1 -0
- synapps_mcp-1.2.0/src/synapps/onboarding/init_wizard.py +182 -0
- synapps_mcp-1.2.0/src/synapps/onboarding/language_detector.py +22 -0
- synapps_mcp-1.2.0/src/synapps/onboarding/mcp_configurator.py +68 -0
- synapps_mcp-1.2.0/src/synapps/plugin/__init__.py +92 -0
- synapps_mcp-1.2.0/src/synapps/plugin/csharp.py +54 -0
- synapps_mcp-1.2.0/src/synapps/plugin/java.py +54 -0
- synapps_mcp-1.2.0/src/synapps/plugin/python.py +55 -0
- synapps_mcp-1.2.0/src/synapps/plugin/typescript.py +65 -0
- synapps_mcp-1.2.0/src/synapps/service/__init__.py +477 -0
- synapps_mcp-1.2.0/src/synapps/service/context.py +472 -0
- synapps_mcp-1.2.0/src/synapps/service/formatting.py +48 -0
- synapps_mcp-1.2.0/src/synapps/service/indexing.py +349 -0
- synapps_mcp-1.2.0/src/synapps/util/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/util/dotnet.py +156 -0
- synapps_mcp-1.2.0/src/synapps/util/file_system.py +437 -0
- synapps_mcp-1.2.0/src/synapps/util/text_utils.py +525 -0
- synapps_mcp-1.2.0/src/synapps/util/version.py +85 -0
- synapps_mcp-1.2.0/src/synapps/watcher/__init__.py +0 -0
- synapps_mcp-1.2.0/src/synapps/watcher/watcher.py +103 -0
- synapps_mcp-1.2.0/synapps-logo.svg +63 -0
- synapps_mcp-1.2.0/tests/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJSTest/package.json +1 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJSTest/src/animals.ts +42 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJSTest/src/index.ts +3 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJSTest/src/models.ts +9 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJSTest/src/services.ts +33 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJSTest/src/utils.js +9 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJSTest/tsconfig.json +10 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJavaTest/.gitignore +5 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJavaTest/pom.xml +15 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJavaTest/src/main/java/com/synappstest/Animal.java +21 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJavaTest/src/main/java/com/synappstest/AnimalService.java +29 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJavaTest/src/main/java/com/synappstest/Cat.java +19 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJavaTest/src/main/java/com/synappstest/Dog.java +17 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJavaTest/src/main/java/com/synappstest/Formatter.java +13 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsJavaTest/src/main/java/com/synappstest/IAnimal.java +6 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsPyTest/pyproject.toml +4 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsPyTest/synappspytest/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsPyTest/synappspytest/animals.py +40 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsPyTest/synappspytest/config.py +13 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsPyTest/synappspytest/models.py +16 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsPyTest/synappspytest/services.py +29 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsPyTest/synappspytest/utils.py +13 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/.gitignore +2 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Controllers/BaseController.cs +14 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Controllers/TaskController.cs +53 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Models/BaseEntity.cs +8 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Models/Project.cs +7 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Models/TaskItem.cs +9 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Services/IProjectService.cs +9 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Services/ITaskService.cs +13 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Services/ProjectService.cs +18 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/Services/TaskService.cs +45 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/SynappsTest.Tests/SynappsTest.Tests.csproj +10 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/SynappsTest.Tests/TaskServiceTests.cs +26 -0
- synapps_mcp-1.2.0/tests/fixtures/SynappsTest/SynappsTest.csproj +13 -0
- synapps_mcp-1.2.0/tests/integration/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/integration/conftest.py +195 -0
- synapps_mcp-1.2.0/tests/integration/test_cli_commands.py +249 -0
- synapps_mcp-1.2.0/tests/integration/test_cli_commands_java.py +275 -0
- synapps_mcp-1.2.0/tests/integration/test_cli_commands_python.py +276 -0
- synapps_mcp-1.2.0/tests/integration/test_cli_commands_typescript.py +284 -0
- synapps_mcp-1.2.0/tests/integration/test_http_cross_language.py +161 -0
- synapps_mcp-1.2.0/tests/integration/test_http_endpoints.py +58 -0
- synapps_mcp-1.2.0/tests/integration/test_mcp_tools.py +497 -0
- synapps_mcp-1.2.0/tests/integration/test_mcp_tools_java.py +376 -0
- synapps_mcp-1.2.0/tests/integration/test_mcp_tools_python.py +388 -0
- synapps_mcp-1.2.0/tests/integration/test_mcp_tools_typescript.py +393 -0
- synapps_mcp-1.2.0/tests/unit/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/conftest.py +14 -0
- synapps_mcp-1.2.0/tests/unit/container/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/container/test_manager.py +384 -0
- synapps_mcp-1.2.0/tests/unit/doctor/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_base.py +47 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_cli_doctor.py +147 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_csharp.py +113 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_docker_daemon.py +67 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_fix_strings.py +191 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_java.py +119 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_memgraph_bolt.py +144 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_python.py +105 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_service.py +68 -0
- synapps_mcp-1.2.0/tests/unit/doctor/test_typescript.py +106 -0
- synapps_mcp-1.2.0/tests/unit/graph/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_analysis.py +377 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_connection.py +160 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_edges.py +147 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_edges_delete_outgoing.py +49 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_http_graph_ops.py +87 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_nodes.py +410 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_nodes_commit_rename.py +113 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_orphan_endpoints.py +35 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_queries.py +403 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_resolve.py +69 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_schema.py +57 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_search_language_filter.py +65 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_staleness.py +43 -0
- synapps_mcp-1.2.0/tests/unit/graph/test_traversal.py +266 -0
- synapps_mcp-1.2.0/tests/unit/indexer/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/test_constants_resolver.py +130 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/test_csharp_http_extractor.py +459 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/test_interface.py +49 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/test_java_http_extractor.py +584 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/test_matcher.py +100 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/test_python_http_extractor.py +451 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/test_route_utils.py +111 -0
- synapps_mcp-1.2.0/tests/unit/indexer/http/test_typescript_http_extractor.py +349 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_call_indexer.py +127 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_csharp_attribute_extractor.py +202 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_csharp_base_type_extractor.py +92 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_csharp_call_extractor.py +108 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_csharp_import_extractor.py +51 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_csharp_type_ref_extractor.py +104 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_git.py +157 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_git_sync.py +136 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_http_phase.py +135 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_indexer.py +454 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_indexer_attributes.py +76 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_java_attribute_extractor.py +176 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_java_base_type_extractor.py +178 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_java_call_extractor.py +290 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_java_import_extractor.py +128 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_java_type_ref_extractor.py +244 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_method_implements_indexer.py +129 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_overrides_indexer.py +64 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_parsed_file.py +56 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_python_assignment_extractor.py +168 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_python_attribute_extractor.py +236 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_python_base_type_extractor.py +57 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_python_call_extractor.py +266 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_python_import_extractor.py +68 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_python_type_ref_extractor.py +147 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_reindex_upsert.py +175 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_structural_pass.py +824 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_symbol_resolver.py +540 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_sync.py +272 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_typescript_attribute_extractor.py +387 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_typescript_base_type_extractor.py +120 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_typescript_call_extractor.py +314 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_typescript_import_extractor.py +271 -0
- synapps_mcp-1.2.0/tests/unit/indexer/test_typescript_type_ref_extractor.py +185 -0
- synapps_mcp-1.2.0/tests/unit/lsp/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/lsp/test_csharp_adapter.py +219 -0
- synapps_mcp-1.2.0/tests/unit/lsp/test_java_adapter.py +496 -0
- synapps_mcp-1.2.0/tests/unit/lsp/test_python_adapter.py +425 -0
- synapps_mcp-1.2.0/tests/unit/lsp/test_typescript_adapter.py +675 -0
- synapps_mcp-1.2.0/tests/unit/onboarding/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/onboarding/test_init_wizard.py +280 -0
- synapps_mcp-1.2.0/tests/unit/onboarding/test_language_detector.py +82 -0
- synapps_mcp-1.2.0/tests/unit/onboarding/test_mcp_configurator.py +144 -0
- synapps_mcp-1.2.0/tests/unit/plugin/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/plugin/test_csharp_plugin.py +64 -0
- synapps_mcp-1.2.0/tests/unit/plugin/test_http_extractor_wiring.py +30 -0
- synapps_mcp-1.2.0/tests/unit/plugin/test_plugin_protocol.py +72 -0
- synapps_mcp-1.2.0/tests/unit/plugin/test_python_plugin.py +100 -0
- synapps_mcp-1.2.0/tests/unit/plugin/test_registry.py +152 -0
- synapps_mcp-1.2.0/tests/unit/plugin/test_typescript_plugin.py +91 -0
- synapps_mcp-1.2.0/tests/unit/test_auto_sync.py +98 -0
- synapps_mcp-1.2.0/tests/unit/test_banner.py +62 -0
- synapps_mcp-1.2.0/tests/unit/test_cli.py +260 -0
- synapps_mcp-1.2.0/tests/unit/test_cli_tree.py +425 -0
- synapps_mcp-1.2.0/tests/unit/test_config.py +68 -0
- synapps_mcp-1.2.0/tests/unit/test_http_endpoints.py +258 -0
- synapps_mcp-1.2.0/tests/unit/test_mcp_server.py +55 -0
- synapps_mcp-1.2.0/tests/unit/test_mcp_sync.py +53 -0
- synapps_mcp-1.2.0/tests/unit/test_packaging.py +67 -0
- synapps_mcp-1.2.0/tests/unit/test_project_file_filter.py +120 -0
- synapps_mcp-1.2.0/tests/unit/test_queries.py +347 -0
- synapps_mcp-1.2.0/tests/unit/test_service.py +1758 -0
- synapps_mcp-1.2.0/tests/unit/test_service_multi_plugin.py +78 -0
- synapps_mcp-1.2.0/tests/unit/test_service_resolve.py +43 -0
- synapps_mcp-1.2.0/tests/unit/test_service_smart_index.py +154 -0
- synapps_mcp-1.2.0/tests/unit/test_service_sync.py +81 -0
- synapps_mcp-1.2.0/tests/unit/test_synignore.py +152 -0
- synapps_mcp-1.2.0/tests/unit/test_tools.py +339 -0
- synapps_mcp-1.2.0/tests/unit/watcher/__init__.py +0 -0
- synapps_mcp-1.2.0/tests/unit/watcher/test_watcher.py +273 -0
- synapps_mcp-1.2.0/uv.lock +1253 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Report a bug in Synapps
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for reporting a bug! Please fill out the sections below so we can reproduce and fix it.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: description
|
|
12
|
+
attributes:
|
|
13
|
+
label: Description
|
|
14
|
+
description: A clear description of what the bug is.
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: reproduction
|
|
20
|
+
attributes:
|
|
21
|
+
label: Steps to reproduce
|
|
22
|
+
description: How can we reproduce this behavior?
|
|
23
|
+
placeholder: |
|
|
24
|
+
1. Index a project with `synapps index .`
|
|
25
|
+
2. Run `synapps callers "MyClass.MyMethod"`
|
|
26
|
+
3. See error...
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
|
|
30
|
+
- type: textarea
|
|
31
|
+
id: expected
|
|
32
|
+
attributes:
|
|
33
|
+
label: Expected behavior
|
|
34
|
+
description: What did you expect to happen?
|
|
35
|
+
validations:
|
|
36
|
+
required: true
|
|
37
|
+
|
|
38
|
+
- type: textarea
|
|
39
|
+
id: actual
|
|
40
|
+
attributes:
|
|
41
|
+
label: Actual behavior
|
|
42
|
+
description: What actually happened? Include error messages or output if applicable.
|
|
43
|
+
validations:
|
|
44
|
+
required: true
|
|
45
|
+
|
|
46
|
+
- type: input
|
|
47
|
+
id: synapps-version
|
|
48
|
+
attributes:
|
|
49
|
+
label: Synapps version
|
|
50
|
+
description: Output of `pip show synapps | grep Version`
|
|
51
|
+
placeholder: "0.1.0"
|
|
52
|
+
|
|
53
|
+
- type: dropdown
|
|
54
|
+
id: language
|
|
55
|
+
attributes:
|
|
56
|
+
label: Language being indexed
|
|
57
|
+
options:
|
|
58
|
+
- C#
|
|
59
|
+
- Python
|
|
60
|
+
- TypeScript / JavaScript
|
|
61
|
+
- Java
|
|
62
|
+
- Multiple
|
|
63
|
+
- N/A
|
|
64
|
+
|
|
65
|
+
- type: textarea
|
|
66
|
+
id: environment
|
|
67
|
+
attributes:
|
|
68
|
+
label: Environment
|
|
69
|
+
description: OS, Python version, Docker version, etc.
|
|
70
|
+
placeholder: |
|
|
71
|
+
- OS: macOS 14.5
|
|
72
|
+
- Python: 3.11.9
|
|
73
|
+
- Docker: 26.1.1
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Feature Request
|
|
2
|
+
description: Suggest a new feature or improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for suggesting a feature! Please describe what you'd like and why.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: problem
|
|
12
|
+
attributes:
|
|
13
|
+
label: Problem or motivation
|
|
14
|
+
description: What problem does this solve, or what workflow does it improve?
|
|
15
|
+
placeholder: "When I try to do X, I have to Y, which is slow / error-prone / impossible because..."
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: solution
|
|
21
|
+
attributes:
|
|
22
|
+
label: Proposed solution
|
|
23
|
+
description: How would you like this to work? Include example commands, tool signatures, or output if applicable.
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: alternatives
|
|
29
|
+
attributes:
|
|
30
|
+
label: Alternatives considered
|
|
31
|
+
description: Any workarounds or alternative approaches you've considered.
|
|
32
|
+
|
|
33
|
+
- type: dropdown
|
|
34
|
+
id: area
|
|
35
|
+
attributes:
|
|
36
|
+
label: Area
|
|
37
|
+
options:
|
|
38
|
+
- CLI
|
|
39
|
+
- MCP tools
|
|
40
|
+
- Indexing / graph
|
|
41
|
+
- Language support
|
|
42
|
+
- Docker / containers
|
|
43
|
+
- Documentation
|
|
44
|
+
- Other
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## What does this PR do?
|
|
2
|
+
|
|
3
|
+
<!-- A brief description of the change. -->
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
<!-- What problem does it solve? Link to an issue if applicable (Fixes #123). -->
|
|
8
|
+
|
|
9
|
+
## How was this tested?
|
|
10
|
+
|
|
11
|
+
- [ ] Unit tests pass (`pytest tests/unit/ -v`)
|
|
12
|
+
- [ ] Integration tests pass (if applicable)
|
|
13
|
+
- [ ] Manual testing (describe below)
|
|
14
|
+
|
|
15
|
+
## Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Changes are backwards-compatible (or breaking changes are documented)
|
|
18
|
+
- [ ] New code has tests
|
|
19
|
+
- [ ] Commit messages are clear and descriptive
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
- name: Run unit tests
|
|
30
|
+
run: pytest tests/unit/ -v
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: Build and smoke-test
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: astral-sh/setup-uv@v7
|
|
16
|
+
with:
|
|
17
|
+
enable-cache: true
|
|
18
|
+
|
|
19
|
+
- name: Build wheel and sdist
|
|
20
|
+
run: uv build
|
|
21
|
+
|
|
22
|
+
- name: Smoke test
|
|
23
|
+
run: |
|
|
24
|
+
python3 -m venv /tmp/smoke-venv
|
|
25
|
+
/tmp/smoke-venv/bin/python -m pip install --quiet dist/*.whl
|
|
26
|
+
/tmp/smoke-venv/bin/python -c "
|
|
27
|
+
import synapps
|
|
28
|
+
import solidlsp
|
|
29
|
+
import tree_sitter_python
|
|
30
|
+
import tree_sitter_c_sharp
|
|
31
|
+
import tree_sitter_typescript
|
|
32
|
+
import tree_sitter_java
|
|
33
|
+
print(f'synapps.__version__ = {synapps.__version__!r}')
|
|
34
|
+
assert synapps.__version__ != 'dev', 'version must not be dev in wheel'
|
|
35
|
+
print('All imports OK')
|
|
36
|
+
"
|
|
37
|
+
/tmp/smoke-venv/bin/synapps --help
|
|
38
|
+
/tmp/smoke-venv/bin/synapps-mcp --help
|
|
39
|
+
|
|
40
|
+
- uses: actions/upload-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
|
|
45
|
+
publish:
|
|
46
|
+
name: Publish to PyPI
|
|
47
|
+
needs: build
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
environment:
|
|
50
|
+
name: pypi
|
|
51
|
+
url: https://pypi.org/project/synapps-mcp/
|
|
52
|
+
permissions:
|
|
53
|
+
id-token: write
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/download-artifact@v4
|
|
56
|
+
with:
|
|
57
|
+
name: dist
|
|
58
|
+
path: dist/
|
|
59
|
+
|
|
60
|
+
- uses: astral-sh/setup-uv@v7
|
|
61
|
+
|
|
62
|
+
- name: Publish to PyPI
|
|
63
|
+
run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Synapps will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [1.2.0] - 2026-03-28
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **PyPI distribution** — install via `pip install synapps-mcp` (package renamed from `synapps` to `synapps-mcp`)
|
|
13
|
+
- **`synapps init` command** — interactive setup wizard that detects project languages, checks prerequisites, indexes the project, and configures MCP clients (Claude Desktop, Claude Code, Cursor, Copilot)
|
|
14
|
+
- **`__version__` attribute** — `synapps.__version__` returns the installed version at runtime via `importlib.metadata`
|
|
15
|
+
- **CI/CD publish workflow** — `.github/workflows/publish.yml` builds, smoke-tests, and publishes to PyPI on `v*` tags via OIDC trusted publishing
|
|
16
|
+
- **Wheel smoke test** — CI verifies `solidlsp` and all 4 tree-sitter grammars are included in the published wheel
|
|
17
|
+
- **Platform-aware doctor fix strings** — every failed check shows exact install commands for macOS (`brew`) or Linux (`apt-get`)
|
|
18
|
+
- **Actionable error messages** — Docker-not-running, Memgraph connection lost, project-not-indexed, and language server timeout errors all show recovery commands
|
|
19
|
+
- **MCP client auto-detection** — `synapps init` finds installed MCP clients and offers to write config with atomic merge (preserves existing server entries)
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Package distribution name changed from `synapps` to `synapps-mcp` (Python import paths unchanged)
|
|
23
|
+
- `synapps doctor` now exits with code 1 when any check fails (enables use in scripts and CI)
|
|
24
|
+
- SYNAPPS logo banner moved from `synapps index` (first run) to `synapps init`
|
|
25
|
+
- Version bumped from 1.0.0 to 1.2.0
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- Language server timeout no longer aborts the entire indexing pass — timed-out files are skipped with a warning naming the file
|
|
29
|
+
|
|
30
|
+
## [1.1.0] - 2026-03-28
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- `find_http_endpoints` MCP tool — search endpoints by route pattern, HTTP method, or language
|
|
34
|
+
- `trace_http_dependency` MCP tool — find server handler and all client call sites for an endpoint
|
|
35
|
+
- Route conflict detection — indexer warns when multiple methods serve the same (HTTP method, route) pair
|
|
36
|
+
- JAX-RS annotation support (`@Path`, `@GET`, `@POST`, etc.) in Java server-side extraction
|
|
37
|
+
- README HTTP Endpoint Tracing section with supported frameworks table, tool examples, and known limitations
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
- Nested class HTTP call attribution now uses narrowest-range matching instead of last-match across all 4 extractors
|
|
41
|
+
- JAX-RS route constraints (`{param: regex}`) correctly normalized to `{param}` during extraction
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- HTTP endpoint extraction now runs by default — no longer requires `experimental.http_endpoints` config flag
|
|
45
|
+
- MCP tool count increased from 19 to 21
|
|
46
|
+
- Removed all "experimental" qualifiers from schema notes, agent instructions, and log messages
|
|
47
|
+
|
|
48
|
+
## [1.0.0] - 2026-03-26
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
- Multi-language indexing: C#, Python, TypeScript/JavaScript, Java
|
|
52
|
+
- Graph-based code intelligence via Memgraph
|
|
53
|
+
- MCP server with 25+ tools for AI agents
|
|
54
|
+
- CLI with full query and management capabilities
|
|
55
|
+
- Automatic per-project Docker container management
|
|
56
|
+
- Incremental sync via git diff
|
|
57
|
+
- Live file watching with `synapps watch`
|
|
58
|
+
- Interface dispatch resolution in call graph traversal
|
|
59
|
+
- Impact analysis with test coverage detection
|
|
60
|
+
- Token-efficient output format for AI consumption
|
|
61
|
+
- Scoped context retrieval (`structure`, `method`, `edit`)
|
|
62
|
+
- Architectural audit rules
|
|
63
|
+
- Symbol summaries (manual and auto-generated)
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
*IMPORTANT*
|
|
2
|
+
- Never assume the user is correct. Trust but verify all statements, using the code as a source of truth. When in doubt, ask the user for clarification.
|
|
3
|
+
- Design all classes and functions with testability in mind. Use Dependency Injection liberally.
|
|
4
|
+
- Keep classes and functions small, clear, and with a singular purpose (SRP).
|
|
5
|
+
- Use comments sparingly. Comments should only exist to clarify a design choice/decision, not to explain what the code is doing. (WHY not WHAT)
|
|
6
|
+
- Make sure all unit and integration tests pass before considering a task complete.
|
|
7
|
+
- Every bugfix must include a regression test that would have caught the bug.
|
|
8
|
+
|
|
9
|
+
## Synapps MCP
|
|
10
|
+
|
|
11
|
+
This project is indexed by the Synapps MCP server. Use it instead of grep/read for navigating code relationships:
|
|
12
|
+
|
|
13
|
+
- Before modifying a method, use `get_context_for` (scope="edit") to understand its callers, callees, dependencies, and test coverage
|
|
14
|
+
- Use `find_callers` / `find_usages` to trace how a symbol is used across the codebase — prefer this over grep
|
|
15
|
+
- Use `find_callees` (with optional `depth` param for reachable call tree) to understand what a method depends on downstream
|
|
16
|
+
- After making changes, use `analyze_change_impact` to verify no unexpected breakage
|
|
17
|
+
- Use `get_hierarchy` to understand inheritance before modifying class structures
|
|
18
|
+
- Use `search_symbols` to find symbols by name, kind, file, or namespace — faster and more precise than file search
|
|
19
|
+
- Use `execute_query` for ad-hoc Cypher queries; call `get_schema` first to see available labels and relationships
|
|
20
|
+
- Use `summary` with action='set'/'get'/'list' to manage symbol summaries
|
|
21
|
+
- Use `find_usages` with `kind` param to filter type references, or `include_test_breakdown=True` for prod/test split
|
|
22
|
+
- CLI-only tools (not available via MCP): `synapps doctor`, `synapps delete <path>`, `synapps status <path>`
|
|
23
|
+
- If any issues with the MCP or inconsistencies in the graph vs filesystem are found, report this to the user as a side note.
|
|
24
|
+
|
|
25
|
+
## Common Commands
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Activate venv (always required before running Python commands)
|
|
29
|
+
source .venv/bin/activate
|
|
30
|
+
|
|
31
|
+
# Unit tests (no external dependencies, ~1.7s)
|
|
32
|
+
pytest tests/unit/ -v
|
|
33
|
+
|
|
34
|
+
# Integration tests (requires Memgraph on localhost:7687 and .NET SDK)
|
|
35
|
+
docker compose up -d # start Memgraph + Memgraph Lab (Lab UI at http://localhost:3000; in-memory — data lost on restart, tests always re-index from scratch)
|
|
36
|
+
pytest tests/integration/test_mcp_tools.py -v -m integration # MCP tool integration(C#) tests
|
|
37
|
+
pytest tests/integration/test_mcp_tools_typescript.py -v -m integration # Typescript integration tests (MCP)
|
|
38
|
+
pytest tests/integration/test_mcp_tools_python.py -v -m integration # Python integration tests (MCP)
|
|
39
|
+
|
|
40
|
+
pytest tests/integration/test_cli_commands.py -v -m integration # CLI command integration tests
|
|
41
|
+
pytest tests/integration/test_cli_commands_python.py -v -m integration # Python CLI command integration tests
|
|
42
|
+
pytest tests/integration/test_cli_commands_typescript.py -v -m integration # typescript CLI command integration tests
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
<!-- GSD:project-start source:PROJECT.md -->
|
|
46
|
+
## Project
|
|
47
|
+
|
|
48
|
+
**Synapps**
|
|
49
|
+
|
|
50
|
+
Synapps is a code intelligence MCP server that indexes multi-language codebases (C#, TypeScript, Python, Java) using tree-sitter and Language Server Protocol, stores symbols and relationships in a Memgraph graph database, and exposes semantic query tools (find callers, trace call chains, analyze change impact) for AI coding agents and developers via both MCP and CLI.
|
|
51
|
+
|
|
52
|
+
**Core Value:** AI coding agents can instantly understand code structure and relationships across an entire codebase without reading every file.
|
|
53
|
+
|
|
54
|
+
### Constraints
|
|
55
|
+
|
|
56
|
+
- **Tech stack**: Python 3.11, existing CLI (typer), existing MCP server (FastMCP) — new features must integrate with these
|
|
57
|
+
- **No auto-install**: Report + instructions only — users stay in control of their environment
|
|
58
|
+
- **Platform**: Must work on macOS and Linux at minimum (Docker required for Memgraph)
|
|
59
|
+
<!-- GSD:project-end -->
|
|
60
|
+
|
|
61
|
+
<!-- GSD:stack-start source:codebase/STACK.md -->
|
|
62
|
+
## Technology Stack
|
|
63
|
+
|
|
64
|
+
## Languages & Runtime
|
|
65
|
+
- **Python 3.11** — entire application codebase (`src/synapps/`, `src/solidlsp/`)
|
|
66
|
+
- **Cypher** — graph query language used in all `GraphConnection` calls (`src/synapps/graph/`)
|
|
67
|
+
- **C#, TypeScript, Python, Java** — target languages indexed by the tool (not part of the tool's own runtime)
|
|
68
|
+
## Frameworks & Libraries
|
|
69
|
+
| Library | Version | Purpose | Location |
|
|
70
|
+
|---------|---------|---------|----------|
|
|
71
|
+
| `mcp` | >=1.0.0 (installed: 1.26.0) | Model Context Protocol SDK — exposes the MCP server | `src/synapps/mcp/server.py` |
|
|
72
|
+
| `neo4j` | >=5.0.0 (installed: 6.1.0) | Bolt-protocol driver used against Memgraph | `src/synapps/graph/connection.py` |
|
|
73
|
+
| `typer` | >=0.12.0 (installed: 0.24.1) | CLI framework for the `synapps` command | `src/synapps/cli/app.py` |
|
|
74
|
+
| `watchdog` | >=4.0.0 (installed: 6.0.0) | Filesystem event watcher for live re-indexing | `src/synapps/watcher/watcher.py` |
|
|
75
|
+
| `pydantic` | >=2.0.0 | Data validation (declared; minimal direct usage observed) | `pyproject.toml` |
|
|
76
|
+
| `sensai-utils` | >=1.5.0 (installed: 1.6.0) | Pickle cache, string mixins, logging utilities | `src/solidlsp/ls.py`, `src/solidlsp/ls_process.py`, `src/synapps/util/file_system.py` |
|
|
77
|
+
| `overrides` | >=7.7.0 | Runtime enforcement of `@override` decorator | `src/solidlsp/` |
|
|
78
|
+
| `pathspec` | >=0.12.1 | `.gitignore`-style path matching for ignored paths | `src/synapps/util/file_system.py` |
|
|
79
|
+
| `psutil` | >=7.0.0 | Process management for language server subprocesses | `pyproject.toml` |
|
|
80
|
+
| `beautifulsoup4` | >=4.12.0 | HTML parsing in text utilities | `src/synapps/util/text_utils.py` |
|
|
81
|
+
| `joblib` | >=1.3.0 | Parallel execution for batch indexing operations | `src/synapps/util/text_utils.py` |
|
|
82
|
+
| `charset-normalizer` | >=3.0.0 | File encoding detection | `pyproject.toml` |
|
|
83
|
+
| `requests` | >=2.31.0 | HTTP calls (e.g., language server binary downloads) | `pyproject.toml` |
|
|
84
|
+
| `tree-sitter` | >=0.24.0 | Core parsing engine for AST extraction | `src/synapps/indexer/tree_sitter_util.py`, all language plugin indexers |
|
|
85
|
+
| `tree-sitter-c-sharp` | >=0.23.0 | C# grammar for tree-sitter | `src/synapps/indexer/indexer.py`, `src/synapps/plugin/csharp.py` |
|
|
86
|
+
| `tree-sitter-python` | >=0.25.0 | Python grammar for tree-sitter | `src/synapps/plugin/python.py`, `src/synapps/indexer/python/` |
|
|
87
|
+
| `tree-sitter-typescript` | >=0.23.2 | TypeScript/JavaScript grammar for tree-sitter | `src/synapps/plugin/typescript.py`, `src/synapps/indexer/typescript/` |
|
|
88
|
+
| `tree-sitter-java` | >=0.23.0 | Java grammar for tree-sitter | `src/synapps/plugin/java.py` |
|
|
89
|
+
| `docker` | >=7.0.0 | Docker SDK — manages per-project Memgraph containers | `src/synapps/container/manager.py` |
|
|
90
|
+
| `pyright` | >=1.1.0 | Python language server (bundled binary, used by solidlsp) | `src/solidlsp/language_servers/pyright_server.py` |
|
|
91
|
+
| Library | Version | Purpose |
|
|
92
|
+
|---------|---------|---------|
|
|
93
|
+
| `pytest` | >=8.0.0 | Test runner |
|
|
94
|
+
| `pytest-timeout` | >=2.0.0 | Per-test timeouts (default 10s via `pytest.ini`) |
|
|
95
|
+
## Key Dependencies
|
|
96
|
+
## Configuration
|
|
97
|
+
| File | Purpose |
|
|
98
|
+
|------|---------|
|
|
99
|
+
| `pyproject.toml` | Package metadata, all runtime dependencies, dev dependencies, build targets, CLI entry points |
|
|
100
|
+
| `pytest.ini` | Test runner config — 10s timeout, `tests/` path, `src tests/unit` on `pythonpath`, `integration` marker |
|
|
101
|
+
| `docker-compose.yml` | Development convenience — starts a shared Memgraph instance on `localhost:7687` and Memgraph Lab UI on `localhost:3000` |
|
|
102
|
+
| `.synapps/config.json` | Per-project runtime config (created on first run, not checked in) — stores container name and allocated Bolt port |
|
|
103
|
+
| `uv.lock` | Full dependency lockfile |
|
|
104
|
+
| Variable | Purpose |
|
|
105
|
+
|----------|---------|
|
|
106
|
+
| `SYNAPPS_BENCH_LOG` | Optional path to a JSONL file for tool call benchmarking (`src/synapps/mcp/tools.py`) |
|
|
107
|
+
## Build & Dev Tools
|
|
108
|
+
- `synapps` → `synapps.cli:app` (Typer app, `src/synapps/cli/app.py`)
|
|
109
|
+
- `synapps-mcp` → `synapps.mcp.server:main` (MCP server, `src/synapps/mcp/server.py`)
|
|
110
|
+
- `csharp-ls` (Microsoft) — C# indexing
|
|
111
|
+
- `typescript-language-server` + `tsserver` — TypeScript/JavaScript
|
|
112
|
+
- Eclipse JDT LS — Java
|
|
113
|
+
- OmniSharp — alternative C# (experimental)
|
|
114
|
+
<!-- GSD:stack-end -->
|
|
115
|
+
|
|
116
|
+
<!-- GSD:conventions-start source:CONVENTIONS.md -->
|
|
117
|
+
## Conventions
|
|
118
|
+
|
|
119
|
+
## Style & Formatting
|
|
120
|
+
- **Indentation:** 4 spaces (Python standard)
|
|
121
|
+
- **Quotes:** Double quotes for strings; single quotes appear occasionally but doubles dominate
|
|
122
|
+
- **Line length:** Not formally enforced (no ruff/black/isort config detected in `pyproject.toml`)
|
|
123
|
+
- **Trailing commas:** Used in multi-line argument lists and collections
|
|
124
|
+
- **`from __future__ import annotations`:** Present in virtually every source file — enables PEP 604 union syntax (`X | Y`) across the entire codebase regardless of Python version
|
|
125
|
+
- **Type hints:** Consistently applied to all function signatures; return types always annotated
|
|
126
|
+
- **No linter config detected:** No `[tool.ruff]`, `[tool.mypy]`, `[tool.black]`, or `.ruff.toml` present. Conventions are maintained by code review, not tooling.
|
|
127
|
+
## Naming Conventions
|
|
128
|
+
| Element | Convention | Example |
|
|
129
|
+
|---------|-----------|---------|
|
|
130
|
+
| Classes | PascalCase | `SynappsService`, `GraphConnection`, `PythonCallExtractor` |
|
|
131
|
+
| Functions (module-level) | snake_case | `upsert_repository`, `compute_sync_diff` |
|
|
132
|
+
| Methods | snake_case | `get_workspace_files`, `index_project` |
|
|
133
|
+
| Private methods/functions | `_snake_case` prefix | `_get_project_roots`, `_rel_path`, `_resolve` |
|
|
134
|
+
| Private module helpers | `_snake_case` prefix | `_p`, `_slim`, `_apply_limit`, `_short_ref` |
|
|
135
|
+
| Constants / module-level literals | `_UPPER_SNAKE` (private) | `_ALWAYS_SKIP`, `_MINIFIED_LINE_THRESHOLD`, `_PYTHON_CALLS_QUERY` |
|
|
136
|
+
| Variables | snake_case | `root_path`, `symbol_map`, `file_extensions` |
|
|
137
|
+
| Type aliases / Literals | PascalCase or `CamelCaseLiteral` | `SymbolKindLiteral`, `AuditRuleLiteral` |
|
|
138
|
+
| Dataclass fields | snake_case | `updated`, `deleted`, `unchanged` |
|
|
139
|
+
| Logger | always named `log` at module level | `log = logging.getLogger(__name__)` |
|
|
140
|
+
| Language-specific extractors | `{Language}{Concept}Extractor` | `PythonCallExtractor`, `CSharpBaseTypeExtractor` |
|
|
141
|
+
| LSP adapters | `{Language}LSPAdapter` | `PythonLSPAdapter`, `TypeScriptLSPAdapter` |
|
|
142
|
+
| Plugin classes | `{Language}Plugin` | `PythonPlugin`, `CSharpPlugin`, `JavaPlugin` |
|
|
143
|
+
## Common Patterns
|
|
144
|
+
## Error Handling
|
|
145
|
+
## Imports & Dependencies
|
|
146
|
+
<!-- GSD:conventions-end -->
|
|
147
|
+
|
|
148
|
+
<!-- GSD:architecture-start source:ARCHITECTURE.md -->
|
|
149
|
+
## Architecture
|
|
150
|
+
|
|
151
|
+
## Overview
|
|
152
|
+
## Pattern
|
|
153
|
+
```
|
|
154
|
+
```
|
|
155
|
+
- `ContainerManager` manages a per-project Memgraph Docker container
|
|
156
|
+
- `FileWatcher` provides live re-indexing via filesystem events
|
|
157
|
+
- `LanguageRegistry` + `LanguagePlugin` protocol enables multi-language support
|
|
158
|
+
## Layers & Components
|
|
159
|
+
- Purpose: Accept user commands or AI agent tool calls; delegate to `SynappsService`
|
|
160
|
+
- Location: `src/synapps/cli/app.py`, `src/synapps/mcp/server.py`
|
|
161
|
+
- Depends on: `SynappsService`, `ContainerManager`, `graph.schema`
|
|
162
|
+
- Purpose: Single orchestration point for all indexing, syncing, querying, and watching operations
|
|
163
|
+
- Location: `src/synapps/service.py`
|
|
164
|
+
- Holds: `GraphConnection`, `LanguageRegistry`, active `FileWatcher` instances
|
|
165
|
+
- Depends on: `graph.*`, `indexer.*`, `lsp.*`, `plugin.*`, `watcher.*`
|
|
166
|
+
- Purpose: Provision and manage per-project Memgraph containers via Docker; persist port assignments in `.synapps/config.json`
|
|
167
|
+
- Location: `src/synapps/container/manager.py`
|
|
168
|
+
- Provides: `GraphConnection` to the rest of the system
|
|
169
|
+
- Purpose: Walk project files, extract symbols via `LSPAdapter`, write nodes/edges to graph
|
|
170
|
+
- Location: `src/synapps/indexer/`
|
|
171
|
+
- Sub-components:
|
|
172
|
+
- Purpose: Decouple language-specific extraction from the indexer core; each language provides factory methods for LSP adapter, call extractor, import extractor, type-ref extractor, and attribute extractor
|
|
173
|
+
- Location: `src/synapps/plugin/` (one module per language: `csharp.py`, `python.py`, `typescript.py`, `java.py`)
|
|
174
|
+
- Protocol: `LanguagePlugin` (structural protocol, runtime-checkable) at `src/synapps/plugin/__init__.py`
|
|
175
|
+
- Registry: `LanguageRegistry` in the same file; `default_registry()` registers all four built-in plugins
|
|
176
|
+
- Purpose: Bridge between language server output and the `IndexSymbol` / `LSPAdapter` interface that the indexer consumes
|
|
177
|
+
- Location: `src/synapps/lsp/` — one adapter per language (`csharp.py`, `python.py`, `typescript.py`, `java.py`)
|
|
178
|
+
- Interface: `LSPAdapter` protocol and `IndexSymbol` dataclass at `src/synapps/lsp/interface.py`
|
|
179
|
+
- Backend: Adapters delegate to `solidlsp` (the bundled LSP process manager)
|
|
180
|
+
- Purpose: Launch, manage, and communicate with external language server processes over the LSP protocol (JSON-RPC stdio)
|
|
181
|
+
- Location: `src/solidlsp/`
|
|
182
|
+
- Key files: `ls.py` (base `LanguageServer` ABC), `ls_process.py` (process lifecycle), `lsp_protocol_handler/` (JSON-RPC transport)
|
|
183
|
+
- Language servers: `language_servers/csharp_language_server.py`, `language_servers/pyright_server.py`, `language_servers/typescript_language_server.py`, `language_servers/eclipse_jdtls.py`
|
|
184
|
+
- Purpose: All Cypher query logic; no business logic lives here — pure data access
|
|
185
|
+
- Location: `src/synapps/graph/`
|
|
186
|
+
- Purpose: Expose graph queries as MCP tools callable by AI agents; thin wrappers over `SynappsService`
|
|
187
|
+
- Location: `src/synapps/mcp/tools.py`, `src/synapps/mcp/server.py`, `src/synapps/mcp/instructions.py`
|
|
188
|
+
- Purpose: Watch a project directory for file changes and trigger re-indexing via callback
|
|
189
|
+
- Location: `src/synapps/watcher/watcher.py`
|
|
190
|
+
- Uses: `watchdog` library; debounce logic for rapid file saves
|
|
191
|
+
## Data Flow
|
|
192
|
+
- Persistent graph state lives in Memgraph (in-memory per container restart unless using persistent storage)
|
|
193
|
+
- Per-project config (port, container name) is persisted in `.synapps/config.json`
|
|
194
|
+
- Indexed commit SHA is stored on the `Repository` node in the graph
|
|
195
|
+
## Entry Points
|
|
196
|
+
| Entry Point | Type | Location |
|
|
197
|
+
|-------------|------|----------|
|
|
198
|
+
| `synapps` CLI | CLI (Typer) | `src/synapps/cli/app.py` |
|
|
199
|
+
| `synapps-mcp` MCP server | MCP (stdio) | `src/synapps/mcp/server.py` |
|
|
200
|
+
## Key Abstractions
|
|
201
|
+
- Structural protocol (`@runtime_checkable`) defining the contract for each language
|
|
202
|
+
- Methods: `create_lsp_adapter()`, `create_call_extractor()`, `create_import_extractor()`, `create_base_type_extractor()`, `create_attribute_extractor()`, `create_type_ref_extractor()`, `create_assignment_extractor()`, `parse_file()`
|
|
203
|
+
- Location: `src/synapps/plugin/__init__.py`
|
|
204
|
+
- Implementations: `src/synapps/plugin/csharp.py`, `python.py`, `typescript.py`, `java.py`
|
|
205
|
+
- Interface between language server output and the indexer
|
|
206
|
+
- Methods: `get_workspace_files()`, `get_document_symbols()`, `find_method_calls()`, `find_overridden_method()`
|
|
207
|
+
- Location: `src/synapps/lsp/interface.py`
|
|
208
|
+
- Implementations: `src/synapps/lsp/csharp.py`, `python.py`, `typescript.py`, `java.py`
|
|
209
|
+
- Canonical in-memory representation of a symbol extracted from source
|
|
210
|
+
- Fields: `name`, `full_name`, `kind`, `file_path`, `line`, `end_line`, `signature`, `base_types`, `parent_full_name`
|
|
211
|
+
- Location: `src/synapps/lsp/interface.py`
|
|
212
|
+
- Wraps a `neo4j.Driver` pointed at Memgraph via Bolt
|
|
213
|
+
- Methods: `query()`, `execute()`, `execute_implicit()`, `query_with_timeout()`
|
|
214
|
+
- Location: `src/synapps/graph/connection.py`
|
|
215
|
+
- Facade that owns the `GraphConnection` and `LanguageRegistry`; all public operations go through it
|
|
216
|
+
- Location: `src/synapps/service.py`
|
|
217
|
+
- Nodes: `Repository`, `Directory`, `File`, `Package`, `Class`, `Interface`, `Method`, `Property`, `Field`
|
|
218
|
+
- Edges: `CONTAINS`, `INHERITS`, `IMPLEMENTS`, `DISPATCHES_TO`, `CALLS`, `REFERENCES`, `OVERRIDES`, `IMPORTS`
|
|
219
|
+
- `DISPATCHES_TO` is the traversal-friendly inverse of method-level `IMPLEMENTS`, written at index time to allow interface-crossing path queries without mixed-direction variable-length patterns
|
|
220
|
+
## Error Handling
|
|
221
|
+
- `SynappsService._resolve()` raises `ValueError` for ambiguous short names with a list of candidates
|
|
222
|
+
- `ContainerManager.get_connection()` raises `RuntimeError` if Docker is not available
|
|
223
|
+
- `ContainerManager._wait_for_bolt()` raises `TimeoutError` if Memgraph does not become ready within 30s
|
|
224
|
+
- `GraphConnection.query_with_timeout()` raises `TimeoutError` with a user-friendly message after configurable timeout
|
|
225
|
+
## Cross-Cutting Concerns
|
|
226
|
+
<!-- GSD:architecture-end -->
|
|
227
|
+
|
|
228
|
+
<!-- GSD:workflow-start source:GSD defaults -->
|
|
229
|
+
## GSD Workflow Enforcement
|
|
230
|
+
|
|
231
|
+
Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.
|
|
232
|
+
|
|
233
|
+
Use these entry points:
|
|
234
|
+
- `/gsd:quick` for small fixes, doc updates, and ad-hoc tasks
|
|
235
|
+
- `/gsd:debug` for investigation and bug fixing
|
|
236
|
+
- `/gsd:execute-phase` for planned phase work
|
|
237
|
+
|
|
238
|
+
Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.
|
|
239
|
+
<!-- GSD:workflow-end -->
|
|
240
|
+
|
|
241
|
+
<!-- GSD:profile-start -->
|
|
242
|
+
## Developer Profile
|
|
243
|
+
|
|
244
|
+
> Profile not yet configured. Run `/gsd:profile-user` to generate your developer profile.
|
|
245
|
+
> This section is managed by `generate-claude-profile` -- do not edit manually.
|
|
246
|
+
<!-- GSD:profile-end -->
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Contributing to Synapps
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! This guide will help you get set up and make your first contribution.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Clone the repo
|
|
9
|
+
git clone https://github.com/SynappsCodeComprehension/synapps.git
|
|
10
|
+
cd synapps
|
|
11
|
+
|
|
12
|
+
# Create a virtual environment and install
|
|
13
|
+
python -m venv .venv
|
|
14
|
+
source .venv/bin/activate
|
|
15
|
+
pip install -e ".[dev]"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Running tests
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Unit tests (no external dependencies)
|
|
22
|
+
pytest tests/unit/ -v
|
|
23
|
+
|
|
24
|
+
# Integration tests (requires Docker + Memgraph)
|
|
25
|
+
docker compose up -d
|
|
26
|
+
pytest tests/integration/ -v -m integration
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Unit tests should always pass before submitting a PR. Integration tests require Docker and a running Memgraph instance.
|
|
30
|
+
|
|
31
|
+
## Making changes
|
|
32
|
+
|
|
33
|
+
1. Fork the repo and create a branch from `main`
|
|
34
|
+
2. Make your changes
|
|
35
|
+
3. Add or update tests for your changes
|
|
36
|
+
4. Run `pytest tests/unit/ -v` and ensure all tests pass
|
|
37
|
+
5. Commit with a clear message describing *why*, not just *what*
|
|
38
|
+
6. Open a pull request against `main`
|
|
39
|
+
|
|
40
|
+
## Code style
|
|
41
|
+
|
|
42
|
+
- Python 3.11+ with type annotations on all function signatures
|
|
43
|
+
- Double quotes for strings
|
|
44
|
+
- 4-space indentation
|
|
45
|
+
- `from __future__ import annotations` in every source file
|
|
46
|
+
- Comments explain *why*, not *what* — keep them sparse
|
|
47
|
+
- Classes and functions should be small with a single responsibility
|
|
48
|
+
|
|
49
|
+
## Project structure
|
|
50
|
+
|
|
51
|
+
- `src/synapps/` — main application code
|
|
52
|
+
- `src/solidlsp/` — LSP process management library
|
|
53
|
+
- `tests/unit/` — unit tests (no external dependencies)
|
|
54
|
+
- `tests/integration/` — integration tests (require Docker + Memgraph)
|
|
55
|
+
|
|
56
|
+
## Reporting bugs
|
|
57
|
+
|
|
58
|
+
Open an issue using the **Bug Report** template. Include reproduction steps, expected vs actual behavior, and your environment details.
|
|
59
|
+
|
|
60
|
+
## Suggesting features
|
|
61
|
+
|
|
62
|
+
Open an issue using the **Feature Request** template. Describe the problem you're solving and your proposed approach.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex Smith
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|