kodit 0.3.7__tar.gz → 0.3.8__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 kodit might be problematic. Click here for more details.
- {kodit-0.3.7 → kodit-0.3.8}/.github/workflows/docker.yaml +2 -2
- {kodit-0.3.7 → kodit-0.3.8}/Dockerfile +4 -0
- {kodit-0.3.7 → kodit-0.3.8}/PKG-INFO +1 -1
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/deployment/docker-compose.yaml +12 -3
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/mcp/index.md +4 -2
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/_version.py +2 -2
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/config.py +3 -2
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/cloning/git/working_copy.py +23 -2
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/slicing/slicer.py +12 -3
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/cloning/git_cloning/working_copy_test.py +137 -1
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/slicer_test.py +24 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/smoke.sh +3 -0
- kodit-0.3.7/docs/MIGRATION_TO_INDEX_AGGREGATE.md +0 -222
- {kodit-0.3.7 → kodit-0.3.8}/.claude/commands/debug.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.claude/commands/new-requirement.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.claude/commands/refactor.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.claude/commands/update-docs.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.claude/settings.json +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.cursor/rules/kodit.mdc +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.cursor/rules/style.mdc +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.dockerignore +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/CODE_OF_CONDUCT.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/CONTRIBUTING.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/dependabot.yml +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/workflows/docs.yaml +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/workflows/pull_request.yaml +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/workflows/pypi-test.yaml +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/workflows/pypi.yaml +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.github/workflows/test.yaml +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.gitignore +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.python-version +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.vscode/launch.json +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/.vscode/settings.json +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/CLAUDE.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/LICENSE +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/README.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/alembic.ini +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/_index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/demos/_index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/demos/go-simple-microservice/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/demos/knock-knock-auth/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/developer/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/getting-started/_index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/getting-started/installation/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/getting-started/integration/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/getting-started/quick-start/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/_index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/configuration/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/deployment/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/deployment/kubernetes.yaml +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/indexing/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/sync/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/docs/reference/telemetry/index.md +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/pyproject.toml +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/.gitignore +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/app.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/application/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/application/factories/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/application/factories/code_indexing_factory.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/application/services/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/application/services/code_indexing_application_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/application/services/sync_scheduler.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/cli.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/database.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/entities.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/errors.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/interfaces.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/protocols.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/services/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/services/bm25_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/services/embedding_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/services/enrichment_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/services/index_query_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/services/index_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/domain/value_objects.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/bm25/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/bm25/bm25_factory.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/bm25/local_bm25_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/bm25/vectorchord_bm25_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/cloning/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/cloning/git/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/cloning/metadata.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/embedding_factory.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/embedding_providers/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/embedding_providers/batching.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/embedding_providers/hash_embedding_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/embedding_providers/local_embedding_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/embedding_providers/openai_embedding_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/local_vector_search_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/embedding/vectorchord_vector_search_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/enrichment/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/enrichment/enrichment_factory.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/enrichment/local_enrichment_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/enrichment/null_enrichment_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/enrichment/openai_enrichment_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/git/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/git/git_utils.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/ignore/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/ignore/ignore_pattern_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/indexing/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/indexing/auto_indexing_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/indexing/fusion_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/mappers/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/mappers/index_mapper.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/slicing/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/slicing/language_detection_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/sqlalchemy/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/sqlalchemy/embedding_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/sqlalchemy/entities.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/sqlalchemy/index_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/ui/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/ui/progress.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/infrastructure/ui/spinner.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/log.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/mcp.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/middleware.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/README +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/env.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/script.py.mako +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/versions/4073b33f9436_add_file_processing_flag.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/versions/4552eb3f23ce_add_summary.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/versions/7c3bbc2ab32b_add_embeddings_table.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/versions/85155663351e_initial.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/versions/9e53ea8bb3b0_add_authors.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/versions/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/migrations/versions/c3f5137d30f5_index_all_the_things.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/reporting.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/utils/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/src/kodit/utils/path_utils.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/conftest.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/docker-smoke.sh +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/experiments/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/experiments/cline_prompt_tests/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/experiments/cline_prompt_tests/cline_prompt.txt +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/experiments/cline_prompt_tests/cline_prompt_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/application/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/application/services/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/application/services/test_sync_scheduler.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/application/test_code_indexing_application_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/cli_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/config_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/bm25_domain_service_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/enrichment_domain_service_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/entities_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/services/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/services/index_service_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/test_embedding_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/test_language_mapping.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/domain/test_multi_search_result.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/e2e.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/bm25/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/bm25/local_bm25_repository_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/bm25/vectorchord_bm25_repository_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/cloning/git_cloning/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/embedding_factory_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/embedding_provider/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/embedding_provider/test_hash_embedding_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/embedding_provider/test_local_embedding_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/embedding_provider/test_openai_embedding_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/test_batching.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/test_embedding_integration.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/test_local_vector_search_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/embedding/test_vectorchord_vector_search_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/enrichment/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/enrichment/enrichment_provider/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/enrichment/enrichment_provider/test_local_enrichment_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/enrichment/enrichment_provider/test_null_enrichment_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/enrichment/enrichment_provider/test_openai_enrichment_provider.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/enrichment/test_enrichment_factory.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/indexing/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/indexing/test_auto_indexing_service.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/mappers/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/mappers/test_index_mapper.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/c/main.c +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/c/models.c +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/c/models.h +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/c/utils.c +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/c/utils.h +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/cpp/main.cpp +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/cpp/models.cpp +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/cpp/models.hpp +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/cpp/utils.cpp +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/cpp/utils.hpp +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/csharp/Main.cs +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/csharp/Models.cs +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/csharp/Utils.cs +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/css/components.css +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/css/main.css +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/css/utilities.css +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/go/main.go +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/go/models.go +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/go/utils.go +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/html/components.html +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/html/forms.html +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/html/main.html +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/java/Main.java +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/java/Models.java +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/java/Utils.java +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/javascript/main.js +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/javascript/models.js +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/javascript/utils.js +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/python/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/python/main.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/python/models.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/python/utils.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/rust/main.rs +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/rust/models.rs +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/slicing/data/rust/utils.rs +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/snippets/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/snippets/csharp.cs +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/snippets/golang.go +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/snippets/javascript.js +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/snippets/knock_knock_server.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/snippets/python.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/snippets/typescript.tsx +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/sqlalchemy/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/sqlalchemy/test_embedding_repository.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/log_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/mcp_stdio_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/kodit/mcp_test.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/performance/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/performance/similarity.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/utils/__init__.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/utils/test_path_utils.py +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/tests/vectorchord-smoke.sh +0 -0
- {kodit-0.3.7 → kodit-0.3.8}/uv.lock +0 -0
|
@@ -2,9 +2,9 @@ version: "3.9"
|
|
|
2
2
|
|
|
3
3
|
services:
|
|
4
4
|
kodit:
|
|
5
|
-
image:
|
|
5
|
+
image: test:latest
|
|
6
6
|
ports:
|
|
7
|
-
- "8080:8080" #
|
|
7
|
+
- "8080:8080" # You may wish to pick a less common port
|
|
8
8
|
# Start the Kodit MCP server and bind to all interfaces
|
|
9
9
|
command: ["serve", "--host", "0.0.0.0", "--port", "8080"]
|
|
10
10
|
restart: unless-stopped
|
|
@@ -39,11 +39,20 @@ services:
|
|
|
39
39
|
SYNC_PERIODIC_INTERVAL_SECONDS: 1800 # 30 minutes
|
|
40
40
|
SYNC_PERIODIC_RETRY_ATTEMPTS: 3
|
|
41
41
|
|
|
42
|
+
# Logging configuration
|
|
43
|
+
LOG_LEVEL: INFO # Set to DEBUG for more detailed logging
|
|
44
|
+
|
|
45
|
+
volumes:
|
|
46
|
+
- kodit-data:/data
|
|
47
|
+
|
|
42
48
|
vectorchord:
|
|
43
49
|
image: tensorchord/vchord-suite:pg17-20250601
|
|
44
50
|
environment:
|
|
45
51
|
- POSTGRES_DB=kodit
|
|
46
52
|
- POSTGRES_PASSWORD=mysecretpassword
|
|
47
53
|
ports:
|
|
48
|
-
- "5432
|
|
54
|
+
- "5432"
|
|
49
55
|
restart: unless-stopped
|
|
56
|
+
|
|
57
|
+
volumes:
|
|
58
|
+
kodit-data:
|
|
@@ -95,7 +95,8 @@ claude mcp add kodit -- kodit stdio
|
|
|
95
95
|
|
|
96
96
|
#### Cursor Streaming HTTP Mode (recommended)
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+

|
|
99
|
+
{class="h-8 inline-block" href="cursor://anysphere.cursor-deeplink/mcp/install?name=kodit&config=eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvbWNwIn0%3D"}
|
|
99
100
|
|
|
100
101
|
Add the following to `$HOME/.cursor/mcp.json`:
|
|
101
102
|
|
|
@@ -114,7 +115,8 @@ where Kodit is hosted.
|
|
|
114
115
|
|
|
115
116
|
#### Cursor STDIO
|
|
116
117
|
|
|
117
|
-
|
|
118
|
+

|
|
119
|
+
{class="h-8 inline-block" href="cursor://anysphere.cursor-deeplink/mcp/install?name=kodit&config=eyJjb21tYW5kIjoicGlweCBydW4ga29kaXQgc3RkaW8ifQ%3D%3D"}
|
|
118
120
|
|
|
119
121
|
Add the following to `$HOME/.cursor/mcp.json`:
|
|
120
122
|
|
|
@@ -23,7 +23,6 @@ if TYPE_CHECKING:
|
|
|
23
23
|
from kodit.database import Database
|
|
24
24
|
|
|
25
25
|
DEFAULT_BASE_DIR = Path.home() / ".kodit"
|
|
26
|
-
DEFAULT_DB_URL = f"sqlite+aiosqlite:///{DEFAULT_BASE_DIR}/kodit.db"
|
|
27
26
|
DEFAULT_LOG_LEVEL = "INFO"
|
|
28
27
|
DEFAULT_LOG_FORMAT = "pretty"
|
|
29
28
|
DEFAULT_DISABLE_TELEMETRY = False
|
|
@@ -160,7 +159,9 @@ class AppContext(BaseSettings):
|
|
|
160
159
|
)
|
|
161
160
|
|
|
162
161
|
data_dir: Path = Field(default=DEFAULT_BASE_DIR)
|
|
163
|
-
db_url: str = Field(
|
|
162
|
+
db_url: str = Field(
|
|
163
|
+
default_factory=lambda data: f"sqlite+aiosqlite:///{data['data_dir']}/kodit.db"
|
|
164
|
+
)
|
|
164
165
|
log_level: str = Field(default=DEFAULT_LOG_LEVEL)
|
|
165
166
|
log_format: str = Field(default=DEFAULT_LOG_FORMAT)
|
|
166
167
|
disable_telemetry: bool = Field(default=DEFAULT_DISABLE_TELEMETRY)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Working copy provider for git-based sources."""
|
|
2
2
|
|
|
3
3
|
import hashlib
|
|
4
|
+
import shutil
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
import git
|
|
@@ -47,6 +48,26 @@ class GitWorkingCopyProvider:
|
|
|
47
48
|
async def sync(self, uri: str) -> Path:
|
|
48
49
|
"""Refresh a Git working copy."""
|
|
49
50
|
clone_path = self.get_clone_path(uri)
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
# Check if the clone directory exists and is a valid Git repository
|
|
53
|
+
if not clone_path.exists() or not (clone_path / ".git").exists():
|
|
54
|
+
self.log.info(
|
|
55
|
+
"Clone directory does not exist or is not a Git repository, "
|
|
56
|
+
"preparing...",
|
|
57
|
+
uri=uri, clone_path=str(clone_path)
|
|
58
|
+
)
|
|
59
|
+
return await self.prepare(uri)
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
repo = git.Repo(clone_path)
|
|
63
|
+
repo.remotes.origin.pull()
|
|
64
|
+
except git.InvalidGitRepositoryError:
|
|
65
|
+
self.log.warning(
|
|
66
|
+
"Invalid Git repository found, re-cloning...",
|
|
67
|
+
uri=uri, clone_path=str(clone_path)
|
|
68
|
+
)
|
|
69
|
+
# Remove the invalid directory and re-clone
|
|
70
|
+
shutil.rmtree(clone_path)
|
|
71
|
+
return await self.prepare(uri)
|
|
72
|
+
|
|
52
73
|
return clone_path
|
|
@@ -399,7 +399,10 @@ class Slicer:
|
|
|
399
399
|
"""Get tag name from start_tag node."""
|
|
400
400
|
for child in start_tag.children:
|
|
401
401
|
if child.type == "tag_name" and child.text:
|
|
402
|
-
|
|
402
|
+
try:
|
|
403
|
+
return child.text.decode("utf-8")
|
|
404
|
+
except UnicodeDecodeError:
|
|
405
|
+
return None
|
|
403
406
|
return None
|
|
404
407
|
|
|
405
408
|
def _get_element_id(self, start_tag: Node) -> str | None:
|
|
@@ -424,7 +427,10 @@ class Slicer:
|
|
|
424
427
|
"""Get attribute name."""
|
|
425
428
|
for child in attr_node.children:
|
|
426
429
|
if child.type == "attribute_name" and child.text:
|
|
427
|
-
|
|
430
|
+
try:
|
|
431
|
+
return child.text.decode("utf-8")
|
|
432
|
+
except UnicodeDecodeError:
|
|
433
|
+
return None
|
|
428
434
|
return None
|
|
429
435
|
|
|
430
436
|
def _get_attr_value(self, attr_node: Node) -> str | None:
|
|
@@ -433,7 +439,10 @@ class Slicer:
|
|
|
433
439
|
if child.type == "quoted_attribute_value":
|
|
434
440
|
for val_child in child.children:
|
|
435
441
|
if val_child.type == "attribute_value" and val_child.text:
|
|
436
|
-
|
|
442
|
+
try:
|
|
443
|
+
return val_child.text.decode("utf-8")
|
|
444
|
+
except UnicodeDecodeError:
|
|
445
|
+
return None
|
|
437
446
|
return None
|
|
438
447
|
|
|
439
448
|
def _extract_css_rule_name(self, node: Node) -> str | None:
|
{kodit-0.3.7 → kodit-0.3.8}/tests/kodit/infrastructure/cloning/git_cloning/working_copy_test.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import hashlib
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from unittest.mock import patch
|
|
5
|
+
from unittest.mock import MagicMock, patch
|
|
6
6
|
|
|
7
7
|
import git
|
|
8
8
|
import pytest
|
|
@@ -199,3 +199,139 @@ async def test_prepare_handles_already_exists_error(
|
|
|
199
199
|
# Verify that the directory was created
|
|
200
200
|
assert result_path.exists()
|
|
201
201
|
assert result_path.is_dir()
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@pytest.mark.asyncio
|
|
205
|
+
async def test_sync_directory_does_not_exist_should_call_prepare(
|
|
206
|
+
working_copy: GitWorkingCopyProvider,
|
|
207
|
+
) -> None:
|
|
208
|
+
"""Test that sync() calls prepare() when directory doesn't exist."""
|
|
209
|
+
url = "https://github.com/username/repo.git"
|
|
210
|
+
|
|
211
|
+
# Mock prepare method to avoid actual cloning
|
|
212
|
+
with patch.object(working_copy, "prepare") as mock_prepare:
|
|
213
|
+
mock_prepare.return_value = Path("/fake/path")
|
|
214
|
+
|
|
215
|
+
# Call sync method
|
|
216
|
+
result_path = await working_copy.sync(url)
|
|
217
|
+
|
|
218
|
+
# Verify prepare was called
|
|
219
|
+
mock_prepare.assert_called_once_with(url)
|
|
220
|
+
assert result_path == Path("/fake/path")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@pytest.mark.asyncio
|
|
224
|
+
async def test_sync_directory_exists_but_no_git_should_call_prepare(
|
|
225
|
+
working_copy: GitWorkingCopyProvider,
|
|
226
|
+
) -> None:
|
|
227
|
+
"""Test that sync() calls prepare() when directory exists but is not a Git repo."""
|
|
228
|
+
url = "https://github.com/username/repo.git"
|
|
229
|
+
|
|
230
|
+
# Create a directory that exists but is not a git repo
|
|
231
|
+
clone_path = working_copy.get_clone_path(url)
|
|
232
|
+
clone_path.mkdir(parents=True, exist_ok=True)
|
|
233
|
+
|
|
234
|
+
# Mock prepare method to avoid actual cloning
|
|
235
|
+
with patch.object(working_copy, "prepare") as mock_prepare:
|
|
236
|
+
mock_prepare.return_value = clone_path
|
|
237
|
+
|
|
238
|
+
# Call sync method
|
|
239
|
+
result_path = await working_copy.sync(url)
|
|
240
|
+
|
|
241
|
+
# Verify prepare was called
|
|
242
|
+
mock_prepare.assert_called_once_with(url)
|
|
243
|
+
assert result_path == clone_path
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@pytest.mark.asyncio
|
|
247
|
+
async def test_sync_valid_git_repository_should_pull(
|
|
248
|
+
working_copy: GitWorkingCopyProvider,
|
|
249
|
+
) -> None:
|
|
250
|
+
"""Test that sync() pulls from origin when repository is valid."""
|
|
251
|
+
url = "https://github.com/username/repo.git"
|
|
252
|
+
|
|
253
|
+
# Create a directory that exists with .git subdirectory
|
|
254
|
+
clone_path = working_copy.get_clone_path(url)
|
|
255
|
+
clone_path.mkdir(parents=True, exist_ok=True)
|
|
256
|
+
(clone_path / ".git").mkdir(parents=True, exist_ok=True)
|
|
257
|
+
|
|
258
|
+
# Mock git.Repo and origin.pull
|
|
259
|
+
mock_repo = MagicMock()
|
|
260
|
+
mock_origin = MagicMock()
|
|
261
|
+
mock_repo.remotes.origin = mock_origin
|
|
262
|
+
|
|
263
|
+
with patch("git.Repo") as mock_git_repo:
|
|
264
|
+
mock_git_repo.return_value = mock_repo
|
|
265
|
+
|
|
266
|
+
# Call sync method
|
|
267
|
+
result_path = await working_copy.sync(url)
|
|
268
|
+
|
|
269
|
+
# Verify git.Repo was called with the correct path
|
|
270
|
+
mock_git_repo.assert_called_once_with(clone_path)
|
|
271
|
+
|
|
272
|
+
# Verify origin.pull was called
|
|
273
|
+
mock_origin.pull.assert_called_once()
|
|
274
|
+
|
|
275
|
+
# Verify the correct path was returned
|
|
276
|
+
assert result_path == clone_path
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@pytest.mark.asyncio
|
|
280
|
+
async def test_sync_invalid_git_repository_should_reclone(
|
|
281
|
+
working_copy: GitWorkingCopyProvider,
|
|
282
|
+
) -> None:
|
|
283
|
+
"""Test that sync() re-clones when repository is invalid."""
|
|
284
|
+
url = "https://github.com/username/repo.git"
|
|
285
|
+
|
|
286
|
+
# Create a directory that exists with .git subdirectory
|
|
287
|
+
clone_path = working_copy.get_clone_path(url)
|
|
288
|
+
clone_path.mkdir(parents=True, exist_ok=True)
|
|
289
|
+
(clone_path / ".git").mkdir(parents=True, exist_ok=True)
|
|
290
|
+
|
|
291
|
+
# Mock git.Repo to raise InvalidGitRepositoryError
|
|
292
|
+
with patch("git.Repo") as mock_git_repo:
|
|
293
|
+
mock_git_repo.side_effect = git.InvalidGitRepositoryError("Invalid repo")
|
|
294
|
+
|
|
295
|
+
# Mock shutil.rmtree to track directory removal
|
|
296
|
+
with (
|
|
297
|
+
patch("shutil.rmtree") as mock_rmtree,
|
|
298
|
+
patch.object(working_copy, "prepare") as mock_prepare,
|
|
299
|
+
):
|
|
300
|
+
mock_prepare.return_value = clone_path
|
|
301
|
+
|
|
302
|
+
# Call sync method
|
|
303
|
+
result_path = await working_copy.sync(url)
|
|
304
|
+
|
|
305
|
+
# Verify git.Repo was called with the correct path
|
|
306
|
+
mock_git_repo.assert_called_once_with(clone_path)
|
|
307
|
+
|
|
308
|
+
# Verify the invalid directory was removed
|
|
309
|
+
mock_rmtree.assert_called_once_with(clone_path)
|
|
310
|
+
|
|
311
|
+
# Verify prepare was called to re-clone
|
|
312
|
+
mock_prepare.assert_called_once_with(url)
|
|
313
|
+
|
|
314
|
+
# Verify the correct path was returned
|
|
315
|
+
assert result_path == clone_path
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
@pytest.mark.asyncio
|
|
319
|
+
async def test_sync_get_clone_path_should_match_prepare(
|
|
320
|
+
working_copy: GitWorkingCopyProvider,
|
|
321
|
+
) -> None:
|
|
322
|
+
"""Test that sync() and prepare() use the same clone path."""
|
|
323
|
+
url = "https://github.com/username/repo.git"
|
|
324
|
+
|
|
325
|
+
# Get clone paths from both methods
|
|
326
|
+
sync_path = working_copy.get_clone_path(url)
|
|
327
|
+
|
|
328
|
+
# Mock prepare to return the expected path
|
|
329
|
+
with patch.object(working_copy, "prepare") as mock_prepare:
|
|
330
|
+
mock_prepare.return_value = sync_path
|
|
331
|
+
|
|
332
|
+
# Call sync method (will call prepare since directory doesn't exist)
|
|
333
|
+
result_path = await working_copy.sync(url)
|
|
334
|
+
|
|
335
|
+
# Verify paths match
|
|
336
|
+
assert result_path == sync_path
|
|
337
|
+
mock_prepare.assert_called_once_with(url)
|
|
@@ -828,3 +828,27 @@ class TestErrorHandling:
|
|
|
828
828
|
|
|
829
829
|
error_msg = str(exc_info.value)
|
|
830
830
|
assert "File not found" in error_msg
|
|
831
|
+
|
|
832
|
+
def test_binary_file_handling_in_html_parser(self) -> None:
|
|
833
|
+
"""Test that binary files don't crash HTML parser with UnicodeDecodeError."""
|
|
834
|
+
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
835
|
+
# Create a binary file that looks like an image
|
|
836
|
+
binary_file = Path(tmp_dir, "test.html")
|
|
837
|
+
# Write binary data that would cause UnicodeDecodeError if decoded as UTF-8
|
|
838
|
+
binary_data = b"\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
|
|
839
|
+
binary_file.write_bytes(binary_data)
|
|
840
|
+
|
|
841
|
+
file_obj = create_file_from_path(binary_file)
|
|
842
|
+
|
|
843
|
+
slicer = Slicer()
|
|
844
|
+
|
|
845
|
+
# This should not raise UnicodeDecodeError
|
|
846
|
+
try:
|
|
847
|
+
snippets = slicer.extract_snippets([file_obj], "html")
|
|
848
|
+
# Should return empty list or handle gracefully
|
|
849
|
+
assert isinstance(snippets, list)
|
|
850
|
+
except UnicodeDecodeError:
|
|
851
|
+
pytest.fail("UnicodeDecodeError should not be raised for binary files")
|
|
852
|
+
except RuntimeError:
|
|
853
|
+
# Tree-sitter setup issues are acceptable
|
|
854
|
+
pytest.skip("Tree-sitter setup not available")
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
# Migration to Index Aggregate Architecture
|
|
2
|
-
|
|
3
|
-
This document outlines the strategy for migrating from the current multiple-service architecture to the new Index aggregate root design.
|
|
4
|
-
|
|
5
|
-
## Current Architecture Issues
|
|
6
|
-
|
|
7
|
-
### Code Analysis of `CodeIndexingApplicationService`
|
|
8
|
-
|
|
9
|
-
The current application service has several problems:
|
|
10
|
-
|
|
11
|
-
1. **Service Proliferation**: 7+ domain services injected
|
|
12
|
-
2. **Manual Orchestration**: Application layer contains complex business logic
|
|
13
|
-
3. **Leaky Abstractions**: SQLAlchemy session management at application level
|
|
14
|
-
4. **Scattered State**: Snippet state tracked across multiple services
|
|
15
|
-
|
|
16
|
-
### Current Workflow Complexity
|
|
17
|
-
|
|
18
|
-
```python
|
|
19
|
-
# Current approach - complex orchestration
|
|
20
|
-
async def run_index(self, index_id: int) -> None:
|
|
21
|
-
# 1. Get index from indexing service
|
|
22
|
-
index = await self.indexing_domain_service.get_index(index_id)
|
|
23
|
-
|
|
24
|
-
# 2. Delete old snippets via snippet service
|
|
25
|
-
await self.snippet_domain_service.delete_snippets_for_index(index.id)
|
|
26
|
-
|
|
27
|
-
# 3. Extract snippets via snippet service
|
|
28
|
-
snippets = await self.snippet_domain_service.extract_and_create_snippets(...)
|
|
29
|
-
|
|
30
|
-
# 4. Manual transaction management
|
|
31
|
-
await self.session.commit()
|
|
32
|
-
|
|
33
|
-
# 5. Create BM25 index via separate service
|
|
34
|
-
await self._create_bm25_index(snippets, progress_callback)
|
|
35
|
-
|
|
36
|
-
# 6. Create embeddings via separate service
|
|
37
|
-
await self._create_code_embeddings(snippets, progress_callback)
|
|
38
|
-
|
|
39
|
-
# 7. Enrich snippets via separate service
|
|
40
|
-
await self._enrich_snippets(snippets, progress_callback)
|
|
41
|
-
|
|
42
|
-
# 8. More embeddings via separate service
|
|
43
|
-
await self._create_text_embeddings(snippets, progress_callback)
|
|
44
|
-
|
|
45
|
-
# 9. Update timestamp via indexing service
|
|
46
|
-
await self.indexing_domain_service.update_index_timestamp(index.id)
|
|
47
|
-
|
|
48
|
-
# 10. Final commit
|
|
49
|
-
await self.session.commit()
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## New Architecture Benefits
|
|
53
|
-
|
|
54
|
-
### Simplified Application Service
|
|
55
|
-
|
|
56
|
-
```python
|
|
57
|
-
# New approach - aggregate root handles complexity
|
|
58
|
-
async def run_complete_indexing_workflow(
|
|
59
|
-
self, uri: AnyUrl, local_path: Path
|
|
60
|
-
) -> domain_entities.Index:
|
|
61
|
-
# 1. Create index (aggregate root)
|
|
62
|
-
index = await self._index_domain_service.create_index(uri)
|
|
63
|
-
|
|
64
|
-
# 2. Populate working copy (aggregate method)
|
|
65
|
-
index = await self._index_domain_service.clone_and_populate_working_copy(
|
|
66
|
-
index, local_path, SourceType.GIT
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
# 3. Extract snippets (aggregate method)
|
|
70
|
-
index = await self._index_domain_service.extract_snippets(index)
|
|
71
|
-
|
|
72
|
-
# 4. Simple transaction management
|
|
73
|
-
await self._session.commit()
|
|
74
|
-
|
|
75
|
-
return index
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Migration Strategy
|
|
79
|
-
|
|
80
|
-
### Phase 1: Parallel Implementation ✅
|
|
81
|
-
|
|
82
|
-
- [x] Create new domain entities (`domain/models/entities.py`)
|
|
83
|
-
- [x] Create repository protocol (`domain/models/protocols.py`)
|
|
84
|
-
- [x] Create mapping layer (`infrastructure/mappers/index_mapper.py`)
|
|
85
|
-
- [x] Create repository implementation (`infrastructure/sqlalchemy/index_repository.py`)
|
|
86
|
-
- [x] Create domain service (`domain/services/index_service.py`)
|
|
87
|
-
- [x] Create simplified application service (`application/services/simplified_indexing_service.py`)
|
|
88
|
-
|
|
89
|
-
### Phase 2: Feature Parity (Next Steps)
|
|
90
|
-
|
|
91
|
-
#### 2.1 Complete Index Domain Service
|
|
92
|
-
- [ ] Implement actual cloning logic in `clone_and_populate_working_copy`
|
|
93
|
-
- [ ] Complete snippet enrichment in `enrich_snippets_with_summaries`
|
|
94
|
-
- [ ] Add snippet search capabilities to Index aggregate
|
|
95
|
-
- [ ] Add BM25/embedding integration
|
|
96
|
-
|
|
97
|
-
#### 2.2 Application Service Integration
|
|
98
|
-
- [ ] Update application factories to create new services
|
|
99
|
-
- [ ] Add legacy compatibility methods
|
|
100
|
-
- [ ] Implement search functionality migration
|
|
101
|
-
|
|
102
|
-
#### 2.3 CLI Integration
|
|
103
|
-
- [ ] Update CLI commands to use new application service
|
|
104
|
-
- [ ] Maintain backward compatibility for existing commands
|
|
105
|
-
|
|
106
|
-
### Phase 3: Gradual Migration
|
|
107
|
-
|
|
108
|
-
#### 3.1 New Endpoints First
|
|
109
|
-
- [ ] Create new CLI commands using Index aggregate
|
|
110
|
-
- [ ] Add new MCP tools using simplified service
|
|
111
|
-
- [ ] Implement new features with aggregate root
|
|
112
|
-
|
|
113
|
-
#### 3.2 Legacy Adaptation
|
|
114
|
-
- [ ] Wrap old API calls to use new domain service
|
|
115
|
-
- [ ] Provide compatibility layer for existing integrations
|
|
116
|
-
- [ ] Migrate tests gradually
|
|
117
|
-
|
|
118
|
-
#### 3.3 Search Migration
|
|
119
|
-
- [ ] Move search logic into Index aggregate
|
|
120
|
-
- [ ] Create search value objects in domain
|
|
121
|
-
- [ ] Simplify search application service
|
|
122
|
-
|
|
123
|
-
### Phase 4: Complete Migration
|
|
124
|
-
|
|
125
|
-
#### 4.1 Remove Old Services
|
|
126
|
-
- [ ] Remove `IndexingDomainService`
|
|
127
|
-
- [ ] Remove `SnippetDomainService`
|
|
128
|
-
- [ ] Remove `SourceService`
|
|
129
|
-
- [ ] Clean up old value objects
|
|
130
|
-
|
|
131
|
-
#### 4.2 Final Cleanup
|
|
132
|
-
- [ ] Remove legacy compatibility methods
|
|
133
|
-
- [ ] Update all tests to use new architecture
|
|
134
|
-
- [ ] Remove old application service
|
|
135
|
-
|
|
136
|
-
## Code Examples
|
|
137
|
-
|
|
138
|
-
### Before: Current Complexity
|
|
139
|
-
|
|
140
|
-
```python
|
|
141
|
-
class CodeIndexingApplicationService:
|
|
142
|
-
def __init__(self,
|
|
143
|
-
indexing_domain_service: IndexingDomainService,
|
|
144
|
-
snippet_domain_service: SnippetDomainService,
|
|
145
|
-
source_service: SourceService,
|
|
146
|
-
bm25_service: BM25DomainService,
|
|
147
|
-
code_search_service: EmbeddingDomainService,
|
|
148
|
-
text_search_service: EmbeddingDomainService,
|
|
149
|
-
enrichment_service: EnrichmentDomainService,
|
|
150
|
-
session: AsyncSession, # Leaky abstraction!
|
|
151
|
-
):
|
|
152
|
-
# 7+ services to coordinate
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### After: Aggregate Root Simplicity
|
|
156
|
-
|
|
157
|
-
```python
|
|
158
|
-
class SimplifiedIndexingApplicationService:
|
|
159
|
-
def __init__(self,
|
|
160
|
-
index_domain_service: IndexDomainService,
|
|
161
|
-
session: AsyncSession,
|
|
162
|
-
):
|
|
163
|
-
# Single domain service + session
|
|
164
|
-
# All business logic in domain
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## Benefits of Migration
|
|
168
|
-
|
|
169
|
-
### 1. **Reduced Complexity**
|
|
170
|
-
- Single domain service instead of 7+
|
|
171
|
-
- Business logic moves to domain layer
|
|
172
|
-
- Application layer focuses on coordination
|
|
173
|
-
|
|
174
|
-
### 2. **Better Domain Modeling**
|
|
175
|
-
- Index as true aggregate root
|
|
176
|
-
- Rich domain objects with behavior
|
|
177
|
-
- Proper encapsulation of business rules
|
|
178
|
-
|
|
179
|
-
### 3. **Improved Testability**
|
|
180
|
-
- Domain service can be tested in isolation
|
|
181
|
-
- No SQLAlchemy dependencies in domain tests
|
|
182
|
-
- Cleaner mocking for application tests
|
|
183
|
-
|
|
184
|
-
### 4. **Enhanced Maintainability**
|
|
185
|
-
- Clear boundaries between layers
|
|
186
|
-
- Easier to add new features
|
|
187
|
-
- Reduced coupling between services
|
|
188
|
-
|
|
189
|
-
### 5. **Better Performance**
|
|
190
|
-
- Fewer repository round trips
|
|
191
|
-
- Optimized aggregate loading
|
|
192
|
-
- Reduced object mapping overhead
|
|
193
|
-
|
|
194
|
-
## Risks and Mitigation
|
|
195
|
-
|
|
196
|
-
### Risk: Breaking Changes
|
|
197
|
-
**Mitigation**: Implement compatibility layer during transition
|
|
198
|
-
|
|
199
|
-
### Risk: Feature Regression
|
|
200
|
-
**Mitigation**: Comprehensive test coverage for both old and new
|
|
201
|
-
|
|
202
|
-
### Risk: Performance Impact
|
|
203
|
-
**Mitigation**: Benchmark and optimize aggregate loading
|
|
204
|
-
|
|
205
|
-
### Risk: Complex Migration
|
|
206
|
-
**Mitigation**: Gradual, phase-by-phase approach
|
|
207
|
-
|
|
208
|
-
## Success Metrics
|
|
209
|
-
|
|
210
|
-
- [ ] Reduced lines of code in application service (target: 50% reduction)
|
|
211
|
-
- [ ] Improved test coverage for domain logic
|
|
212
|
-
- [ ] Faster indexing workflow execution
|
|
213
|
-
- [ ] Fewer bugs related to state management
|
|
214
|
-
- [ ] Easier onboarding for new developers
|
|
215
|
-
|
|
216
|
-
## Next Immediate Steps
|
|
217
|
-
|
|
218
|
-
1. **Complete Domain Service**: Finish implementing cloning and enrichment
|
|
219
|
-
2. **Factory Integration**: Update application factories
|
|
220
|
-
3. **Simple CLI Command**: Create one new command using aggregate
|
|
221
|
-
4. **Performance Test**: Benchmark against current implementation
|
|
222
|
-
5. **Migration Plan**: Detail specific steps for first legacy endpoint
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|