kodit 0.4.1__tar.gz → 0.4.2__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.
Files changed (291) hide show
  1. {kodit-0.4.1 → kodit-0.4.2}/PKG-INFO +1 -1
  2. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/api/index.md +1 -1
  3. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/api/openapi.json +1 -1
  4. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/_version.py +2 -2
  5. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/app.py +4 -2
  6. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/factories/code_indexing_factory.py +54 -7
  7. kodit-0.4.2/src/kodit/application/factories/reporting_factory.py +27 -0
  8. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/services/auto_indexing_service.py +16 -4
  9. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/services/code_indexing_application_service.py +115 -133
  10. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/services/indexing_worker_service.py +18 -20
  11. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/services/queue_service.py +12 -14
  12. kodit-0.4.2/src/kodit/application/services/reporting.py +86 -0
  13. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/services/sync_scheduler.py +21 -20
  14. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/cli.py +14 -18
  15. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/config.py +24 -1
  16. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/database.py +2 -1
  17. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/protocols.py +9 -1
  18. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/services/bm25_service.py +1 -6
  19. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/services/index_service.py +22 -58
  20. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/value_objects.py +57 -9
  21. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/dependencies.py +23 -10
  22. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/cloning/git/working_copy.py +36 -7
  23. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/embedding_factory.py +8 -3
  24. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/embedding_providers/litellm_embedding_provider.py +48 -55
  25. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/git/git_utils.py +3 -2
  26. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/mappers/index_mapper.py +1 -0
  27. kodit-0.4.2/src/kodit/infrastructure/reporting/__init__.py +1 -0
  28. kodit-0.4.2/src/kodit/infrastructure/reporting/log_progress.py +65 -0
  29. kodit-0.4.2/src/kodit/infrastructure/reporting/tdqm_progress.py +73 -0
  30. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/sqlalchemy/embedding_repository.py +47 -68
  31. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/sqlalchemy/entities.py +28 -2
  32. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/sqlalchemy/index_repository.py +274 -236
  33. kodit-0.4.2/src/kodit/infrastructure/sqlalchemy/task_repository.py +97 -0
  34. kodit-0.4.2/src/kodit/infrastructure/sqlalchemy/unit_of_work.py +59 -0
  35. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/mcp.py +10 -2
  36. {kodit-0.4.1 → kodit-0.4.2}/tests/conftest.py +14 -1
  37. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/application/code_indexing_application_service_test.py +10 -35
  38. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/application/services/indexing_worker_service_test.py +7 -17
  39. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/application/services/queue_service_get_task_test.py +12 -6
  40. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/application/services/queue_service_test.py +22 -12
  41. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/application/services/sync_scheduler_test.py +4 -4
  42. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/cli_test.py +30 -15
  43. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/cloning/git_cloning/working_copy_test.py +5 -5
  44. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/embedding_factory_test.py +13 -3
  45. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/embedding_provider/litellm_embedding_provider_test.py +27 -29
  46. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/local_vector_search_repository_test.py +58 -54
  47. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/test_embedding_integration.py +329 -297
  48. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/test_litellm_socket_providers.py +4 -4
  49. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/sqlalchemy/embedding_repository_test.py +76 -68
  50. kodit-0.4.2/tests/kodit/infrastructure/sqlalchemy/index_repository_test.py +1190 -0
  51. kodit-0.4.2/tests/kodit/infrastructure/sqlalchemy/task_repository_test.py +375 -0
  52. {kodit-0.4.1 → kodit-0.4.2}/tests/performance/similarity.py +52 -47
  53. kodit-0.4.1/src/kodit/domain/interfaces.py +0 -27
  54. kodit-0.4.1/src/kodit/infrastructure/sqlalchemy/task_repository.py +0 -81
  55. kodit-0.4.1/src/kodit/infrastructure/ui/__init__.py +0 -1
  56. kodit-0.4.1/src/kodit/infrastructure/ui/progress.py +0 -170
  57. kodit-0.4.1/src/kodit/infrastructure/ui/spinner.py +0 -74
  58. kodit-0.4.1/src/kodit/reporting.py +0 -78
  59. {kodit-0.4.1 → kodit-0.4.2}/.claude/commands/debug.md +0 -0
  60. {kodit-0.4.1 → kodit-0.4.2}/.claude/commands/new-requirement.md +0 -0
  61. {kodit-0.4.1 → kodit-0.4.2}/.claude/commands/refactor.md +0 -0
  62. {kodit-0.4.1 → kodit-0.4.2}/.claude/commands/update-docs.md +0 -0
  63. {kodit-0.4.1 → kodit-0.4.2}/.claude/settings.json +0 -0
  64. {kodit-0.4.1 → kodit-0.4.2}/.cursor/rules/kodit.mdc +0 -0
  65. {kodit-0.4.1 → kodit-0.4.2}/.cursor/rules/style.mdc +0 -0
  66. {kodit-0.4.1 → kodit-0.4.2}/.dockerignore +0 -0
  67. {kodit-0.4.1 → kodit-0.4.2}/.github/CODE_OF_CONDUCT.md +0 -0
  68. {kodit-0.4.1 → kodit-0.4.2}/.github/CONTRIBUTING.md +0 -0
  69. {kodit-0.4.1 → kodit-0.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  70. {kodit-0.4.1 → kodit-0.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  71. {kodit-0.4.1 → kodit-0.4.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  72. {kodit-0.4.1 → kodit-0.4.2}/.github/dependabot.yml +0 -0
  73. {kodit-0.4.1 → kodit-0.4.2}/.github/workflows/docker.yaml +0 -0
  74. {kodit-0.4.1 → kodit-0.4.2}/.github/workflows/docs.yaml +0 -0
  75. {kodit-0.4.1 → kodit-0.4.2}/.github/workflows/pull_request.yaml +0 -0
  76. {kodit-0.4.1 → kodit-0.4.2}/.github/workflows/pypi-test.yaml +0 -0
  77. {kodit-0.4.1 → kodit-0.4.2}/.github/workflows/pypi.yaml +0 -0
  78. {kodit-0.4.1 → kodit-0.4.2}/.github/workflows/test.yaml +0 -0
  79. {kodit-0.4.1 → kodit-0.4.2}/.gitignore +0 -0
  80. {kodit-0.4.1 → kodit-0.4.2}/.python-version +0 -0
  81. {kodit-0.4.1 → kodit-0.4.2}/.vscode/launch.json +0 -0
  82. {kodit-0.4.1 → kodit-0.4.2}/.vscode/settings.json +0 -0
  83. {kodit-0.4.1 → kodit-0.4.2}/CLAUDE.md +0 -0
  84. {kodit-0.4.1 → kodit-0.4.2}/Dockerfile +0 -0
  85. {kodit-0.4.1 → kodit-0.4.2}/LICENSE +0 -0
  86. {kodit-0.4.1 → kodit-0.4.2}/Makefile +0 -0
  87. {kodit-0.4.1 → kodit-0.4.2}/README.md +0 -0
  88. {kodit-0.4.1 → kodit-0.4.2}/alembic.ini +0 -0
  89. {kodit-0.4.1 → kodit-0.4.2}/docs/_index.md +0 -0
  90. {kodit-0.4.1 → kodit-0.4.2}/docs/demos/_index.md +0 -0
  91. {kodit-0.4.1 → kodit-0.4.2}/docs/demos/go-simple-microservice/index.md +0 -0
  92. {kodit-0.4.1 → kodit-0.4.2}/docs/demos/knock-knock-auth/index.md +0 -0
  93. {kodit-0.4.1 → kodit-0.4.2}/docs/developer/index.md +0 -0
  94. {kodit-0.4.1 → kodit-0.4.2}/docs/getting-started/_index.md +0 -0
  95. {kodit-0.4.1 → kodit-0.4.2}/docs/getting-started/installation/index.md +0 -0
  96. {kodit-0.4.1 → kodit-0.4.2}/docs/getting-started/integration/index.md +0 -0
  97. {kodit-0.4.1 → kodit-0.4.2}/docs/getting-started/quick-start/index.md +0 -0
  98. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/_index.md +0 -0
  99. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/api/templates/_content.md.j2 +0 -0
  100. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/api/templates/_example.md.j2 +0 -0
  101. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/api/templates/_object_schema.md.j2 +0 -0
  102. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/api/templates/_security_scheme.md.j2 +0 -0
  103. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/api/templates/api_doc_template.md.j2 +0 -0
  104. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/configuration/index.md +0 -0
  105. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/deployment/docker-compose.yaml +0 -0
  106. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/deployment/index.md +0 -0
  107. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/deployment/kubernetes.yaml +0 -0
  108. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/hosted-kodit/index.md +0 -0
  109. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/indexing/index.md +0 -0
  110. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/mcp/index.md +0 -0
  111. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/sync/index.md +0 -0
  112. {kodit-0.4.1 → kodit-0.4.2}/docs/reference/telemetry/index.md +0 -0
  113. {kodit-0.4.1 → kodit-0.4.2}/pyproject.toml +0 -0
  114. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/.gitignore +0 -0
  115. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/__init__.py +0 -0
  116. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/__init__.py +0 -0
  117. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/factories/__init__.py +0 -0
  118. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/application/services/__init__.py +0 -0
  119. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/cli_utils.py +0 -0
  120. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/__init__.py +0 -0
  121. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/entities.py +0 -0
  122. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/errors.py +0 -0
  123. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/services/__init__.py +0 -0
  124. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/services/embedding_service.py +0 -0
  125. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/services/enrichment_service.py +0 -0
  126. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/domain/services/index_query_service.py +0 -0
  127. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/__init__.py +0 -0
  128. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/__init__.py +0 -0
  129. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/client/__init__.py +0 -0
  130. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/client/base.py +0 -0
  131. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/client/exceptions.py +0 -0
  132. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/client/generated_endpoints.py +0 -0
  133. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/client/index_client.py +0 -0
  134. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/client/search_client.py +0 -0
  135. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/middleware/__init__.py +0 -0
  136. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/middleware/auth.py +0 -0
  137. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/__init__.py +0 -0
  138. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/routers/__init__.py +0 -0
  139. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/routers/indexes.py +0 -0
  140. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/routers/queue.py +0 -0
  141. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/routers/search.py +0 -0
  142. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/schemas/__init__.py +0 -0
  143. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/schemas/context.py +0 -0
  144. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/schemas/index.py +0 -0
  145. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/schemas/queue.py +0 -0
  146. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/api/v1/schemas/search.py +0 -0
  147. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/bm25/__init__.py +0 -0
  148. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/bm25/bm25_factory.py +0 -0
  149. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/bm25/local_bm25_repository.py +0 -0
  150. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/bm25/vectorchord_bm25_repository.py +0 -0
  151. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/cloning/__init__.py +0 -0
  152. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/cloning/git/__init__.py +0 -0
  153. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/cloning/metadata.py +0 -0
  154. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/__init__.py +0 -0
  155. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/embedding_providers/__init__.py +0 -0
  156. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/embedding_providers/batching.py +0 -0
  157. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/embedding_providers/hash_embedding_provider.py +0 -0
  158. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/embedding_providers/local_embedding_provider.py +0 -0
  159. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/local_vector_search_repository.py +0 -0
  160. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/embedding/vectorchord_vector_search_repository.py +0 -0
  161. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/enrichment/__init__.py +0 -0
  162. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/enrichment/enrichment_factory.py +0 -0
  163. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/enrichment/litellm_enrichment_provider.py +0 -0
  164. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/enrichment/local_enrichment_provider.py +0 -0
  165. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/enrichment/null_enrichment_provider.py +0 -0
  166. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/enrichment/utils.py +0 -0
  167. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/git/__init__.py +0 -0
  168. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/ignore/__init__.py +0 -0
  169. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/ignore/ignore_pattern_provider.py +0 -0
  170. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/indexing/__init__.py +0 -0
  171. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/indexing/fusion_service.py +0 -0
  172. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/mappers/__init__.py +0 -0
  173. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/mappers/task_mapper.py +0 -0
  174. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/slicing/__init__.py +0 -0
  175. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/slicing/language_detection_service.py +0 -0
  176. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/slicing/slicer.py +0 -0
  177. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/infrastructure/sqlalchemy/__init__.py +0 -0
  178. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/log.py +0 -0
  179. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/middleware.py +0 -0
  180. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/README +0 -0
  181. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/__init__.py +0 -0
  182. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/env.py +0 -0
  183. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/script.py.mako +0 -0
  184. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/versions/4073b33f9436_add_file_processing_flag.py +0 -0
  185. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/versions/4552eb3f23ce_add_summary.py +0 -0
  186. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/versions/7c3bbc2ab32b_add_embeddings_table.py +0 -0
  187. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/versions/85155663351e_initial.py +0 -0
  188. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/versions/9cf0e87de578_add_queue.py +0 -0
  189. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/versions/9e53ea8bb3b0_add_authors.py +0 -0
  190. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/versions/__init__.py +0 -0
  191. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/migrations/versions/c3f5137d30f5_index_all_the_things.py +0 -0
  192. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/utils/__init__.py +0 -0
  193. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/utils/dump_openapi.py +0 -0
  194. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/utils/generate_api_paths.py +0 -0
  195. {kodit-0.4.1 → kodit-0.4.2}/src/kodit/utils/path_utils.py +0 -0
  196. {kodit-0.4.1 → kodit-0.4.2}/tests/__init__.py +0 -0
  197. {kodit-0.4.1 → kodit-0.4.2}/tests/docker-smoke.sh +0 -0
  198. {kodit-0.4.1 → kodit-0.4.2}/tests/experiments/__init__.py +0 -0
  199. {kodit-0.4.1 → kodit-0.4.2}/tests/experiments/cline_prompt_tests/__init__.py +0 -0
  200. {kodit-0.4.1 → kodit-0.4.2}/tests/experiments/cline_prompt_tests/cline_prompt.txt +0 -0
  201. {kodit-0.4.1 → kodit-0.4.2}/tests/experiments/cline_prompt_tests/cline_prompt_test.py +0 -0
  202. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/__init__.py +0 -0
  203. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/app_test.py +0 -0
  204. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/application/__init__.py +0 -0
  205. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/application/services/__init__.py +0 -0
  206. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/application/services/auto_indexing_service_test.py +0 -0
  207. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/config_test.py +0 -0
  208. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/__init__.py +0 -0
  209. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/bm25_service_test.py +0 -0
  210. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/embedding_service_test.py +0 -0
  211. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/enrichment_service_test.py +0 -0
  212. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/entities_test.py +0 -0
  213. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/language_detection_service_test.py +0 -0
  214. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/services/__init__.py +0 -0
  215. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/services/index_service_test.py +0 -0
  216. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/domain/value_objects_test.py +0 -0
  217. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/e2e.py +0 -0
  218. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/__init__.py +0 -0
  219. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/bm25/__init__.py +0 -0
  220. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/bm25/local_bm25_repository_test.py +0 -0
  221. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/bm25/vectorchord_bm25_repository_test.py +0 -0
  222. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/cloning/git_cloning/__init__.py +0 -0
  223. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/__init__.py +0 -0
  224. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/batching_test.py +0 -0
  225. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/embedding_provider/__init__.py +0 -0
  226. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/embedding_provider/hash_embedding_provider_test.py +0 -0
  227. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/embedding_provider/local_embedding_provider_test.py +0 -0
  228. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/embedding/vectorchord_vector_search_repository_test.py +0 -0
  229. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/enrichment/__init__.py +0 -0
  230. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/enrichment/enrichment_factory_test.py +0 -0
  231. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/enrichment/enrichment_provider/__init__.py +0 -0
  232. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/enrichment/enrichment_provider/litellm_enrichment_provider_test.py +0 -0
  233. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/enrichment/enrichment_provider/local_enrichment_provider_test.py +0 -0
  234. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/enrichment/enrichment_provider/null_enrichment_provider_test.py +0 -0
  235. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/enrichment/utils_test.py +0 -0
  236. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/mappers/__init__.py +0 -0
  237. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/mappers/index_mapper_test.py +0 -0
  238. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/__init__.py +0 -0
  239. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/__init__.py +0 -0
  240. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/c/main.c +0 -0
  241. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/c/models.c +0 -0
  242. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/c/models.h +0 -0
  243. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/c/utils.c +0 -0
  244. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/c/utils.h +0 -0
  245. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/cpp/main.cpp +0 -0
  246. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/cpp/models.cpp +0 -0
  247. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/cpp/models.hpp +0 -0
  248. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/cpp/utils.cpp +0 -0
  249. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/cpp/utils.hpp +0 -0
  250. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/csharp/Main.cs +0 -0
  251. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/csharp/Models.cs +0 -0
  252. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/csharp/Utils.cs +0 -0
  253. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/css/components.css +0 -0
  254. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/css/main.css +0 -0
  255. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/css/utilities.css +0 -0
  256. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/go/main.go +0 -0
  257. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/go/models.go +0 -0
  258. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/go/utils.go +0 -0
  259. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/html/components.html +0 -0
  260. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/html/forms.html +0 -0
  261. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/html/main.html +0 -0
  262. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/java/Main.java +0 -0
  263. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/java/Models.java +0 -0
  264. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/java/Utils.java +0 -0
  265. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/javascript/main.js +0 -0
  266. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/javascript/models.js +0 -0
  267. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/javascript/utils.js +0 -0
  268. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/python/__init__.py +0 -0
  269. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/python/main.py +0 -0
  270. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/python/models.py +0 -0
  271. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/python/utils.py +0 -0
  272. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/rust/main.rs +0 -0
  273. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/rust/models.rs +0 -0
  274. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/data/rust/utils.rs +0 -0
  275. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/slicing/slicer_test.py +0 -0
  276. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/snippets/__init__.py +0 -0
  277. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/snippets/csharp.cs +0 -0
  278. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/snippets/golang.go +0 -0
  279. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/snippets/javascript.js +0 -0
  280. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/snippets/knock_knock_server.py +0 -0
  281. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/snippets/python.py +0 -0
  282. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/snippets/typescript.tsx +0 -0
  283. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/infrastructure/sqlalchemy/__init__.py +0 -0
  284. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/log_test.py +0 -0
  285. {kodit-0.4.1 → kodit-0.4.2}/tests/kodit/mcp_test.py +0 -0
  286. {kodit-0.4.1 → kodit-0.4.2}/tests/performance/__init__.py +0 -0
  287. {kodit-0.4.1 → kodit-0.4.2}/tests/smoke.sh +0 -0
  288. {kodit-0.4.1 → kodit-0.4.2}/tests/utils/__init__.py +0 -0
  289. {kodit-0.4.1 → kodit-0.4.2}/tests/utils/path_utils_test.py +0 -0
  290. {kodit-0.4.1 → kodit-0.4.2}/tests/vectorchord-smoke.sh +0 -0
  291. {kodit-0.4.1 → kodit-0.4.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kodit
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: Code indexing for better AI code generation
5
5
  Project-URL: Homepage, https://docs.helixml.tech/kodit/
6
6
  Project-URL: Documentation, https://docs.helixml.tech/kodit/
@@ -12,7 +12,7 @@ look at the [hosted version](https://kodit.helix.ml/docs).
12
12
  This is the REST API for the Kodit server. Please refer to the
13
13
  [Kodit documentation](https://docs.helix.ml/kodit/) for more information.
14
14
 
15
- Current version: 0.3.18
15
+ Current version: 0.4.2
16
16
 
17
17
  ## Authentication
18
18
 
@@ -3,7 +3,7 @@
3
3
  "info": {
4
4
  "title": "kodit API",
5
5
  "description": "\nThis is the REST API for the Kodit server. Please refer to the\n[Kodit documentation](https://docs.helix.ml/kodit/) for more information.\n ",
6
- "version": "0.3.18"
6
+ "version": "0.4.2"
7
7
  },
8
8
  "paths": {
9
9
  "/healthz": {
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.4.1'
32
- __version_tuple__ = version_tuple = (0, 4, 1)
31
+ __version__ = version = '0.4.2'
32
+ __version_tuple__ = version_tuple = (0, 4, 2)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -8,6 +8,7 @@ from fastapi import FastAPI, Response
8
8
  from fastapi.responses import RedirectResponse
9
9
 
10
10
  from kodit._version import version
11
+ from kodit.application.factories.reporting_factory import create_server_operation
11
12
  from kodit.application.services.auto_indexing_service import AutoIndexingService
12
13
  from kodit.application.services.indexing_worker_service import IndexingWorkerService
13
14
  from kodit.application.services.sync_scheduler import SyncSchedulerService
@@ -34,20 +35,21 @@ async def app_lifespan(_: FastAPI) -> AsyncIterator[AppLifespanState]:
34
35
  # App context has already been configured by the CLI.
35
36
  app_context = AppContext()
36
37
  db = await app_context.get_db()
38
+ operation = create_server_operation()
37
39
 
38
40
  # Start the queue worker service
39
41
  _indexing_worker_service = IndexingWorkerService(
40
42
  app_context=app_context,
41
43
  session_factory=db.session_factory,
42
44
  )
43
- await _indexing_worker_service.start()
45
+ await _indexing_worker_service.start(operation)
44
46
 
45
47
  # Start auto-indexing service
46
48
  _auto_indexing_service = AutoIndexingService(
47
49
  app_context=app_context,
48
50
  session_factory=db.session_factory,
49
51
  )
50
- await _auto_indexing_service.start_background_indexing()
52
+ await _auto_indexing_service.start_background_indexing(operation)
51
53
 
52
54
  # Start sync scheduler service
53
55
  if app_context.periodic_sync.enabled:
@@ -1,10 +1,20 @@
1
1
  """Factory for creating the unified code indexing application service."""
2
2
 
3
+ from collections.abc import Callable
4
+
3
5
  from sqlalchemy.ext.asyncio import AsyncSession
4
6
 
7
+ from kodit.application.factories.reporting_factory import (
8
+ create_cli_operation,
9
+ create_noop_operation,
10
+ create_server_operation,
11
+ )
5
12
  from kodit.application.services.code_indexing_application_service import (
6
13
  CodeIndexingApplicationService,
7
14
  )
15
+ from kodit.application.services.reporting import (
16
+ ProgressTracker,
17
+ )
8
18
  from kodit.config import AppContext
9
19
  from kodit.domain.services.bm25_service import BM25DomainService
10
20
  from kodit.domain.services.embedding_service import EmbeddingDomainService
@@ -35,23 +45,31 @@ from kodit.infrastructure.slicing.language_detection_service import (
35
45
  FileSystemLanguageDetectionService,
36
46
  )
37
47
  from kodit.infrastructure.sqlalchemy.embedding_repository import (
38
- SqlAlchemyEmbeddingRepository,
48
+ create_embedding_repository,
39
49
  )
40
50
  from kodit.infrastructure.sqlalchemy.entities import EmbeddingType
41
- from kodit.infrastructure.sqlalchemy.index_repository import SqlAlchemyIndexRepository
51
+ from kodit.infrastructure.sqlalchemy.index_repository import (
52
+ create_index_repository,
53
+ )
42
54
 
43
55
 
44
56
  def create_code_indexing_application_service(
45
57
  app_context: AppContext,
46
58
  session: AsyncSession,
59
+ session_factory: Callable[[], AsyncSession],
60
+ operation: ProgressTracker,
47
61
  ) -> CodeIndexingApplicationService:
48
62
  """Create a unified code indexing application service with all dependencies."""
49
63
  # Create domain services
50
64
  bm25_service = BM25DomainService(bm25_repository_factory(app_context, session))
51
- code_search_service = embedding_domain_service_factory("code", app_context, session)
52
- text_search_service = embedding_domain_service_factory("text", app_context, session)
65
+ code_search_service = embedding_domain_service_factory(
66
+ "code", app_context, session, session_factory
67
+ )
68
+ text_search_service = embedding_domain_service_factory(
69
+ "text", app_context, session, session_factory
70
+ )
53
71
  enrichment_service = enrichment_domain_service_factory(app_context)
54
- index_repository = SqlAlchemyIndexRepository(session=session)
72
+ index_repository = create_index_repository(session_factory=session_factory)
55
73
  # Use the unified language mapping from the domain layer
56
74
  language_map = LanguageMapping.get_extension_to_language_map()
57
75
 
@@ -78,17 +96,45 @@ def create_code_indexing_application_service(
78
96
  text_search_service=text_search_service,
79
97
  enrichment_service=enrichment_service,
80
98
  session=session,
99
+ operation=operation,
100
+ )
101
+
102
+
103
+ def create_cli_code_indexing_application_service(
104
+ app_context: AppContext,
105
+ session: AsyncSession,
106
+ session_factory: Callable[[], AsyncSession],
107
+ ) -> CodeIndexingApplicationService:
108
+ """Create a CLI code indexing application service."""
109
+ return create_code_indexing_application_service(
110
+ app_context,
111
+ session,
112
+ session_factory,
113
+ create_cli_operation(),
114
+ )
115
+
116
+
117
+ def create_server_code_indexing_application_service(
118
+ app_context: AppContext,
119
+ session: AsyncSession,
120
+ session_factory: Callable[[], AsyncSession],
121
+ ) -> CodeIndexingApplicationService:
122
+ """Create a server code indexing application service."""
123
+ return create_code_indexing_application_service(
124
+ app_context, session, session_factory, create_server_operation()
81
125
  )
82
126
 
83
127
 
84
128
  def create_fast_test_code_indexing_application_service(
85
129
  app_context: AppContext,
86
130
  session: AsyncSession,
131
+ session_factory: Callable[[], AsyncSession],
87
132
  ) -> CodeIndexingApplicationService:
88
133
  """Create a fast test code indexing application service."""
89
134
  # Create domain services
90
135
  bm25_service = BM25DomainService(bm25_repository_factory(app_context, session))
91
- embedding_repository = SqlAlchemyEmbeddingRepository(session=session)
136
+ embedding_repository = create_embedding_repository(session_factory=session_factory)
137
+ operation = create_noop_operation()
92
138
 
93
139
  code_search_repository = LocalVectorSearchRepository(
94
140
  embedding_repository=embedding_repository,
@@ -116,7 +162,7 @@ def create_fast_test_code_indexing_application_service(
116
162
  enrichment_provider=NullEnrichmentProvider()
117
163
  )
118
164
 
119
- index_repository = SqlAlchemyIndexRepository(session=session)
165
+ index_repository = create_index_repository(session_factory=session_factory)
120
166
  # Use the unified language mapping from the domain layer
121
167
  language_map = LanguageMapping.get_extension_to_language_map()
122
168
 
@@ -143,4 +189,5 @@ def create_fast_test_code_indexing_application_service(
143
189
  text_search_service=text_search_service,
144
190
  enrichment_service=enrichment_service,
145
191
  session=session,
192
+ operation=operation,
146
193
  )
@@ -0,0 +1,27 @@
1
+ """Reporting factory."""
2
+
3
+ from kodit.application.services.reporting import OperationType, ProgressTracker
4
+ from kodit.config import ReportingConfig
5
+ from kodit.infrastructure.reporting.log_progress import LoggingReportingModule
6
+ from kodit.infrastructure.reporting.tdqm_progress import TQDMReportingModule
7
+
8
+
9
+ def create_noop_operation() -> ProgressTracker:
10
+ """Create a noop reporter."""
11
+ return ProgressTracker(OperationType.ROOT.value)
12
+
13
+
14
+ def create_cli_operation(config: ReportingConfig | None = None) -> ProgressTracker:
15
+ """Create a CLI reporter."""
16
+ shared_config = config or ReportingConfig()
17
+ s = ProgressTracker(OperationType.ROOT.value)
18
+ s.subscribe(TQDMReportingModule(shared_config))
19
+ return s
20
+
21
+
22
+ def create_server_operation(config: ReportingConfig | None = None) -> ProgressTracker:
23
+ """Create a server reporter."""
24
+ shared_config = config or ReportingConfig()
25
+ s = ProgressTracker(OperationType.ROOT.value)
26
+ s.subscribe(LoggingReportingModule(shared_config))
27
+ return s
@@ -11,7 +11,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
11
11
  from kodit.application.factories.code_indexing_factory import (
12
12
  create_code_indexing_application_service,
13
13
  )
14
+ from kodit.application.factories.reporting_factory import create_noop_operation
14
15
  from kodit.application.services.queue_service import QueueService
16
+ from kodit.application.services.reporting import ProgressTracker
15
17
  from kodit.config import AppContext
16
18
  from kodit.domain.entities import Task
17
19
  from kodit.domain.value_objects import QueuePriority
@@ -31,8 +33,11 @@ class AutoIndexingService:
31
33
  self.log = structlog.get_logger(__name__)
32
34
  self._indexing_task: asyncio.Task | None = None
33
35
 
34
- async def start_background_indexing(self) -> None:
36
+ async def start_background_indexing(
37
+ self, operation: ProgressTracker | None = None
38
+ ) -> None:
35
39
  """Start background indexing of configured sources."""
40
+ operation = operation or create_noop_operation()
36
41
  if (
37
42
  not self.app_context.auto_indexing
38
43
  or len(self.app_context.auto_indexing.sources) == 0
@@ -48,15 +53,22 @@ class AutoIndexingService:
48
53
 
49
54
  auto_sources = [source.uri for source in self.app_context.auto_indexing.sources]
50
55
  self.log.info("Starting background indexing", num_sources=len(auto_sources))
51
- self._indexing_task = asyncio.create_task(self._index_sources(auto_sources))
56
+ self._indexing_task = asyncio.create_task(
57
+ self._index_sources(auto_sources, operation)
58
+ )
52
59
 
53
- async def _index_sources(self, sources: list[str]) -> None:
60
+ async def _index_sources(
61
+ self, sources: list[str], operation: ProgressTracker | None = None
62
+ ) -> None:
54
63
  """Index all configured sources in the background."""
64
+ operation = operation or create_noop_operation()
55
65
  async with self.session_factory() as session:
56
- queue_service = QueueService(session=session)
66
+ queue_service = QueueService(session_factory=self.session_factory)
57
67
  service = create_code_indexing_application_service(
58
68
  app_context=self.app_context,
59
69
  session=session,
70
+ session_factory=self.session_factory,
71
+ operation=operation,
60
72
  )
61
73
 
62
74
  for source in sources:
@@ -6,8 +6,11 @@ from datetime import UTC, datetime
6
6
  import structlog
7
7
  from sqlalchemy.ext.asyncio import AsyncSession
8
8
 
9
+ from kodit.application.services.reporting import (
10
+ OperationType,
11
+ ProgressTracker,
12
+ )
9
13
  from kodit.domain.entities import Index, Snippet
10
- from kodit.domain.interfaces import ProgressCallback
11
14
  from kodit.domain.protocols import IndexRepository
12
15
  from kodit.domain.services.bm25_service import BM25DomainService
13
16
  from kodit.domain.services.embedding_service import EmbeddingDomainService
@@ -25,7 +28,6 @@ from kodit.domain.value_objects import (
25
28
  SnippetSearchFilters,
26
29
  )
27
30
  from kodit.log import log_event
28
- from kodit.reporting import Reporter
29
31
 
30
32
 
31
33
  class CodeIndexingApplicationService:
@@ -41,6 +43,7 @@ class CodeIndexingApplicationService:
41
43
  text_search_service: EmbeddingDomainService,
42
44
  enrichment_service: EnrichmentDomainService,
43
45
  session: AsyncSession,
46
+ operation: ProgressTracker,
44
47
  ) -> None:
45
48
  """Initialize the code indexing application service."""
46
49
  self.index_domain_service = indexing_domain_service
@@ -51,6 +54,7 @@ class CodeIndexingApplicationService:
51
54
  self.text_search_service = text_search_service
52
55
  self.enrichment_service = enrichment_service
53
56
  self.session = session
57
+ self.operation = operation
54
58
  self.log = structlog.get_logger(__name__)
55
59
 
56
60
  async def does_index_exist(self, uri: str) -> bool:
@@ -60,107 +64,117 @@ class CodeIndexingApplicationService:
60
64
  existing_index = await self.index_repository.get_by_uri(sanitized_uri)
61
65
  return existing_index is not None
62
66
 
63
- async def create_index_from_uri(
64
- self, uri: str, progress_callback: ProgressCallback | None = None
65
- ) -> Index:
67
+ async def create_index_from_uri(self, uri: str) -> Index:
66
68
  """Create a new index for a source."""
67
69
  log_event("kodit.index.create")
70
+ with self.operation.create_child(OperationType.CREATE_INDEX.value) as operation:
71
+ # Check if index already exists
72
+ sanitized_uri, _ = self.index_domain_service.sanitize_uri(uri)
73
+ self.log.info("Creating index from URI", uri=str(sanitized_uri))
74
+ existing_index = await self.index_repository.get_by_uri(sanitized_uri)
75
+ if existing_index:
76
+ self.log.debug(
77
+ "Index already exists",
78
+ uri=str(sanitized_uri),
79
+ index_id=existing_index.id,
80
+ )
81
+ return existing_index
68
82
 
69
- # Check if index already exists
70
- sanitized_uri, _ = self.index_domain_service.sanitize_uri(uri)
71
- existing_index = await self.index_repository.get_by_uri(sanitized_uri)
72
- if existing_index:
73
- self.log.debug(
74
- "Index already exists",
75
- uri=str(sanitized_uri),
76
- index_id=existing_index.id,
77
- )
78
- return existing_index
79
-
80
- # Only prepare working copy if we need to create a new index
81
- working_copy = await self.index_domain_service.prepare_index(
82
- uri, progress_callback
83
- )
83
+ # Only prepare working copy if we need to create a new index
84
+ self.log.info("Preparing working copy", uri=str(sanitized_uri))
85
+ working_copy = await self.index_domain_service.prepare_index(uri, operation)
84
86
 
85
- # Create new index
86
- index = await self.index_repository.create(sanitized_uri, working_copy)
87
- await self.session.commit()
88
- return index
87
+ # Create new index
88
+ self.log.info("Creating index", uri=str(sanitized_uri))
89
+ index = await self.index_repository.create(sanitized_uri, working_copy)
90
+ await self.session.commit()
91
+ return index
89
92
 
90
- async def run_index(
91
- self, index: Index, progress_callback: ProgressCallback | None = None
92
- ) -> None:
93
+ async def run_index(self, index: Index) -> None:
93
94
  """Run the complete indexing process for a specific index."""
94
- log_event("kodit.index.run")
95
-
96
- if not index or not index.id:
97
- msg = f"Index has no ID: {index}"
98
- raise ValueError(msg)
99
-
100
- # Refresh working copy
101
- index.source.working_copy = (
102
- await self.index_domain_service.refresh_working_copy(
103
- index.source.working_copy
104
- )
105
- )
106
- if len(index.source.working_copy.changed_files()) == 0:
107
- self.log.info("No new changes to index", index_id=index.id)
108
- return
109
-
110
- # Delete the old snippets from the files that have changed
111
- await self.index_repository.delete_snippets_by_file_ids(
112
- [file.id for file in index.source.working_copy.changed_files() if file.id]
113
- )
114
-
115
- # Extract and create snippets (domain service handles progress)
116
- self.log.info("Creating snippets for files", index_id=index.id)
117
- index = await self.index_domain_service.extract_snippets_from_index(
118
- index=index, progress_callback=progress_callback
119
- )
120
-
121
- await self.index_repository.update(index)
122
- await self.session.flush()
123
-
124
- # Refresh index to get snippets with IDs, required as a ref for subsequent steps
125
- flushed_index = await self.index_repository.get(index.id)
126
- if not flushed_index:
127
- msg = f"Index {index.id} not found after snippet extraction"
128
- raise ValueError(msg)
129
- index = flushed_index
130
- if len(index.snippets) == 0:
131
- self.log.info("No snippets to index after extraction", index_id=index.id)
132
- return
133
-
134
- # Create BM25 index
135
- self.log.info("Creating keyword index")
136
- await self._create_bm25_index(index.snippets, progress_callback)
137
-
138
- # Create code embeddings
139
- self.log.info("Creating semantic code index")
140
- await self._create_code_embeddings(index.snippets, progress_callback)
141
-
142
- # Enrich snippets
143
- self.log.info("Enriching snippets", num_snippets=len(index.snippets))
144
- enriched_snippets = await self.index_domain_service.enrich_snippets_in_index(
145
- snippets=index.snippets, progress_callback=progress_callback
146
- )
147
- # Update snippets in repository
148
- await self.index_repository.update_snippets(index.id, enriched_snippets)
95
+ # Create a new operation
96
+ with self.operation.create_child(OperationType.RUN_INDEX.value) as operation:
97
+ # TODO(philwinder): Move this into a reporter # noqa: TD003, FIX002
98
+ log_event("kodit.index.run")
99
+
100
+ if not index or not index.id:
101
+ msg = f"Index has no ID: {index}"
102
+ raise ValueError(msg)
103
+
104
+ # Refresh working copy
105
+ with operation.create_child("Refresh working copy") as step:
106
+ index.source.working_copy = (
107
+ await self.index_domain_service.refresh_working_copy(
108
+ index.source.working_copy, step
109
+ )
110
+ )
111
+ if len(index.source.working_copy.changed_files()) == 0:
112
+ self.log.info("No new changes to index", index_id=index.id)
113
+ step.skip("No new changes to index")
114
+ return
115
+
116
+ # Delete the old snippets from the files that have changed
117
+ with operation.create_child("Delete old snippets") as step:
118
+ await self.index_repository.delete_snippets_by_file_ids(
119
+ [
120
+ file.id
121
+ for file in index.source.working_copy.changed_files()
122
+ if file.id
123
+ ]
124
+ )
149
125
 
150
- # Create text embeddings (on enriched content)
151
- self.log.info("Creating semantic text index")
152
- await self._create_text_embeddings(enriched_snippets, progress_callback)
126
+ # Extract and create snippets (domain service handles progress)
127
+ with operation.create_child("Extract snippets") as step:
128
+ index = await self.index_domain_service.extract_snippets_from_index(
129
+ index=index, step=step
130
+ )
131
+ await self.index_repository.update(index)
132
+
133
+ # Refresh index to get snippets with IDs, required for subsequent steps
134
+ flushed_index = await self.index_repository.get(index.id)
135
+ if not flushed_index:
136
+ msg = f"Index {index.id} not found after snippet extraction"
137
+ raise ValueError(msg)
138
+ index = flushed_index
139
+ if len(index.snippets) == 0:
140
+ self.log.info(
141
+ "No snippets to index after extraction", index_id=index.id
142
+ )
143
+ step.skip("No snippets to index after extraction")
144
+ return
145
+
146
+ # Create BM25 index
147
+ self.log.info("Creating keyword index")
148
+ with operation.create_child("Create BM25 index") as step:
149
+ await self._create_bm25_index(index.snippets)
150
+
151
+ # Create code embeddings
152
+ with operation.create_child("Create code embeddings") as step:
153
+ await self._create_code_embeddings(index.snippets, step)
154
+
155
+ # Enrich snippets
156
+ with operation.create_child("Enrich snippets") as step:
157
+ enriched_snippets = (
158
+ await self.index_domain_service.enrich_snippets_in_index(
159
+ snippets=index.snippets,
160
+ reporting_step=step,
161
+ )
162
+ )
163
+ # Update snippets in repository
164
+ await self.index_repository.update_snippets(index.id, enriched_snippets)
153
165
 
154
- # Update index timestamp
155
- await self.index_repository.update_index_timestamp(index.id)
166
+ # Create text embeddings (on enriched content)
167
+ with operation.create_child("Create text embeddings") as step:
168
+ await self._create_text_embeddings(enriched_snippets, step)
156
169
 
157
- # Now that all file dependencies have been captured, enact the file processing
158
- # statuses
159
- index.source.working_copy.clear_file_processing_statuses()
160
- await self.index_repository.update(index)
170
+ # Update index timestamp
171
+ with operation.create_child("Update index timestamp") as step:
172
+ await self.index_repository.update_index_timestamp(index.id)
161
173
 
162
- # Single transaction commit for the entire operation
163
- await self.session.commit()
174
+ # After indexing, clear the file processing statuses
175
+ with operation.create_child("Clear file processing statuses") as step:
176
+ index.source.working_copy.clear_file_processing_statuses()
177
+ await self.index_repository.update(index)
164
178
 
165
179
  async def search(self, request: MultiSearchRequest) -> list[MultiSearchResult]:
166
180
  """Search for relevant snippets across all indexes."""
@@ -312,15 +326,7 @@ class CodeIndexingApplicationService:
312
326
  ]
313
327
 
314
328
  # FUTURE: BM25 index enriched content too
315
- async def _create_bm25_index(
316
- self, snippets: list[Snippet], progress_callback: ProgressCallback | None = None
317
- ) -> None:
318
- reporter = Reporter(self.log, progress_callback)
319
- await reporter.start("bm25_index", len(snippets), "Creating keyword index...")
320
-
321
- for _snippet in snippets:
322
- pass
323
-
329
+ async def _create_bm25_index(self, snippets: list[Snippet]) -> None:
324
330
  await self.bm25_service.index_documents(
325
331
  IndexRequest(
326
332
  documents=[
@@ -331,16 +337,10 @@ class CodeIndexingApplicationService:
331
337
  )
332
338
  )
333
339
 
334
- await reporter.done("bm25_index", "Keyword index created")
335
-
336
340
  async def _create_code_embeddings(
337
- self, snippets: list[Snippet], progress_callback: ProgressCallback | None = None
341
+ self, snippets: list[Snippet], reporting_step: ProgressTracker
338
342
  ) -> None:
339
- reporter = Reporter(self.log, progress_callback)
340
- await reporter.start(
341
- "code_embeddings", len(snippets), "Creating code embeddings..."
342
- )
343
-
343
+ reporting_step.set_total(len(snippets))
344
344
  processed = 0
345
345
  async for result in self.code_search_service.index_documents(
346
346
  IndexRequest(
@@ -352,23 +352,11 @@ class CodeIndexingApplicationService:
352
352
  )
353
353
  ):
354
354
  processed += len(result)
355
- await reporter.step(
356
- "code_embeddings",
357
- processed,
358
- len(snippets),
359
- "Creating code embeddings...",
360
- )
361
-
362
- await reporter.done("code_embeddings")
355
+ reporting_step.set_current(processed)
363
356
 
364
357
  async def _create_text_embeddings(
365
- self, snippets: list[Snippet], progress_callback: ProgressCallback | None = None
358
+ self, snippets: list[Snippet], reporting_step: ProgressTracker
366
359
  ) -> None:
367
- reporter = Reporter(self.log, progress_callback)
368
- await reporter.start(
369
- "text_embeddings", len(snippets), "Creating text embeddings..."
370
- )
371
-
372
360
  # Only create text embeddings for snippets that have summary content
373
361
  documents_with_summaries = []
374
362
  for snippet in snippets:
@@ -384,22 +372,16 @@ class CodeIndexingApplicationService:
384
372
  continue
385
373
 
386
374
  if not documents_with_summaries:
387
- await reporter.done("text_embeddings", "No summaries to index")
375
+ reporting_step.skip("No snippets with summaries to create text embeddings")
388
376
  return
389
377
 
378
+ reporting_step.set_total(len(documents_with_summaries))
390
379
  processed = 0
391
380
  async for result in self.text_search_service.index_documents(
392
381
  IndexRequest(documents=documents_with_summaries)
393
382
  ):
394
383
  processed += len(result)
395
- await reporter.step(
396
- "text_embeddings",
397
- processed,
398
- len(snippets),
399
- "Creating text embeddings...",
400
- )
401
-
402
- await reporter.done("text_embeddings")
384
+ reporting_step.set_current(processed)
403
385
 
404
386
  async def delete_index(self, index: Index) -> None:
405
387
  """Delete an index."""