kodit 0.4.3__py3-none-any.whl → 0.5.1__py3-none-any.whl

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.

Files changed (135) hide show
  1. kodit/_version.py +2 -2
  2. kodit/app.py +51 -23
  3. kodit/application/factories/reporting_factory.py +6 -2
  4. kodit/application/factories/server_factory.py +353 -0
  5. kodit/application/services/code_search_application_service.py +144 -0
  6. kodit/application/services/commit_indexing_application_service.py +700 -0
  7. kodit/application/services/indexing_worker_service.py +13 -44
  8. kodit/application/services/queue_service.py +24 -3
  9. kodit/application/services/reporting.py +0 -2
  10. kodit/application/services/sync_scheduler.py +15 -31
  11. kodit/cli.py +2 -753
  12. kodit/cli_utils.py +2 -9
  13. kodit/config.py +4 -97
  14. kodit/database.py +38 -1
  15. kodit/domain/enrichments/__init__.py +1 -0
  16. kodit/domain/enrichments/architecture/__init__.py +1 -0
  17. kodit/domain/enrichments/architecture/architecture.py +20 -0
  18. kodit/domain/enrichments/architecture/physical/__init__.py +1 -0
  19. kodit/domain/enrichments/architecture/physical/discovery_notes.py +14 -0
  20. kodit/domain/enrichments/architecture/physical/formatter.py +11 -0
  21. kodit/domain/enrichments/architecture/physical/physical.py +17 -0
  22. kodit/domain/enrichments/development/__init__.py +1 -0
  23. kodit/domain/enrichments/development/development.py +18 -0
  24. kodit/domain/enrichments/development/snippet/__init__.py +1 -0
  25. kodit/domain/enrichments/development/snippet/snippet.py +21 -0
  26. kodit/domain/enrichments/enricher.py +17 -0
  27. kodit/domain/enrichments/enrichment.py +39 -0
  28. kodit/domain/enrichments/request.py +12 -0
  29. kodit/domain/enrichments/response.py +11 -0
  30. kodit/domain/enrichments/usage/__init__.py +1 -0
  31. kodit/domain/enrichments/usage/api_docs.py +19 -0
  32. kodit/domain/enrichments/usage/usage.py +18 -0
  33. kodit/domain/{entities.py → entities/__init__.py} +50 -195
  34. kodit/domain/entities/git.py +190 -0
  35. kodit/domain/factories/__init__.py +1 -0
  36. kodit/domain/factories/git_repo_factory.py +76 -0
  37. kodit/domain/protocols.py +264 -64
  38. kodit/domain/services/bm25_service.py +5 -1
  39. kodit/domain/services/embedding_service.py +3 -0
  40. kodit/domain/services/enrichment_service.py +9 -30
  41. kodit/domain/services/git_repository_service.py +429 -0
  42. kodit/domain/services/git_service.py +300 -0
  43. kodit/domain/services/physical_architecture_service.py +182 -0
  44. kodit/domain/services/task_status_query_service.py +2 -2
  45. kodit/domain/value_objects.py +87 -135
  46. kodit/infrastructure/api/client/__init__.py +0 -2
  47. kodit/infrastructure/api/v1/__init__.py +0 -4
  48. kodit/infrastructure/api/v1/dependencies.py +92 -46
  49. kodit/infrastructure/api/v1/routers/__init__.py +0 -6
  50. kodit/infrastructure/api/v1/routers/commits.py +352 -0
  51. kodit/infrastructure/api/v1/routers/queue.py +2 -2
  52. kodit/infrastructure/api/v1/routers/repositories.py +282 -0
  53. kodit/infrastructure/api/v1/routers/search.py +31 -14
  54. kodit/infrastructure/api/v1/schemas/__init__.py +0 -24
  55. kodit/infrastructure/api/v1/schemas/commit.py +96 -0
  56. kodit/infrastructure/api/v1/schemas/context.py +2 -0
  57. kodit/infrastructure/api/v1/schemas/enrichment.py +29 -0
  58. kodit/infrastructure/api/v1/schemas/repository.py +128 -0
  59. kodit/infrastructure/api/v1/schemas/search.py +12 -9
  60. kodit/infrastructure/api/v1/schemas/snippet.py +58 -0
  61. kodit/infrastructure/api/v1/schemas/tag.py +31 -0
  62. kodit/infrastructure/api/v1/schemas/task_status.py +2 -0
  63. kodit/infrastructure/bm25/local_bm25_repository.py +16 -4
  64. kodit/infrastructure/bm25/vectorchord_bm25_repository.py +68 -52
  65. kodit/infrastructure/cloning/git/git_python_adaptor.py +534 -0
  66. kodit/infrastructure/cloning/git/working_copy.py +1 -1
  67. kodit/infrastructure/embedding/embedding_factory.py +3 -2
  68. kodit/infrastructure/embedding/local_vector_search_repository.py +1 -1
  69. kodit/infrastructure/embedding/vectorchord_vector_search_repository.py +111 -84
  70. kodit/infrastructure/enricher/__init__.py +1 -0
  71. kodit/infrastructure/enricher/enricher_factory.py +53 -0
  72. kodit/infrastructure/{enrichment/litellm_enrichment_provider.py → enricher/litellm_enricher.py} +36 -56
  73. kodit/infrastructure/{enrichment/local_enrichment_provider.py → enricher/local_enricher.py} +19 -24
  74. kodit/infrastructure/enricher/null_enricher.py +36 -0
  75. kodit/infrastructure/indexing/fusion_service.py +1 -1
  76. kodit/infrastructure/mappers/enrichment_mapper.py +83 -0
  77. kodit/infrastructure/mappers/git_mapper.py +193 -0
  78. kodit/infrastructure/mappers/snippet_mapper.py +104 -0
  79. kodit/infrastructure/mappers/task_mapper.py +5 -44
  80. kodit/infrastructure/physical_architecture/__init__.py +1 -0
  81. kodit/infrastructure/physical_architecture/detectors/__init__.py +1 -0
  82. kodit/infrastructure/physical_architecture/detectors/docker_compose_detector.py +336 -0
  83. kodit/infrastructure/physical_architecture/formatters/__init__.py +1 -0
  84. kodit/infrastructure/physical_architecture/formatters/narrative_formatter.py +149 -0
  85. kodit/infrastructure/reporting/log_progress.py +8 -5
  86. kodit/infrastructure/reporting/telemetry_progress.py +21 -0
  87. kodit/infrastructure/slicing/api_doc_extractor.py +836 -0
  88. kodit/infrastructure/slicing/ast_analyzer.py +1128 -0
  89. kodit/infrastructure/slicing/slicer.py +87 -421
  90. kodit/infrastructure/sqlalchemy/embedding_repository.py +43 -23
  91. kodit/infrastructure/sqlalchemy/enrichment_v2_repository.py +118 -0
  92. kodit/infrastructure/sqlalchemy/entities.py +402 -158
  93. kodit/infrastructure/sqlalchemy/git_branch_repository.py +274 -0
  94. kodit/infrastructure/sqlalchemy/git_commit_repository.py +346 -0
  95. kodit/infrastructure/sqlalchemy/git_repository.py +262 -0
  96. kodit/infrastructure/sqlalchemy/git_tag_repository.py +268 -0
  97. kodit/infrastructure/sqlalchemy/snippet_v2_repository.py +479 -0
  98. kodit/infrastructure/sqlalchemy/task_repository.py +29 -23
  99. kodit/infrastructure/sqlalchemy/task_status_repository.py +24 -12
  100. kodit/infrastructure/sqlalchemy/unit_of_work.py +10 -14
  101. kodit/mcp.py +12 -30
  102. kodit/migrations/env.py +1 -0
  103. kodit/migrations/versions/04b80f802e0c_foreign_key_review.py +100 -0
  104. kodit/migrations/versions/19f8c7faf8b9_add_generic_enrichment_type.py +260 -0
  105. kodit/migrations/versions/7f15f878c3a1_add_new_git_entities.py +690 -0
  106. kodit/migrations/versions/f9e5ef5e688f_add_git_commits_number.py +43 -0
  107. kodit/py.typed +0 -0
  108. kodit/utils/dump_config.py +361 -0
  109. kodit/utils/dump_openapi.py +6 -4
  110. kodit/utils/path_utils.py +29 -0
  111. {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/METADATA +3 -3
  112. kodit-0.5.1.dist-info/RECORD +168 -0
  113. kodit/application/factories/code_indexing_factory.py +0 -195
  114. kodit/application/services/auto_indexing_service.py +0 -99
  115. kodit/application/services/code_indexing_application_service.py +0 -410
  116. kodit/domain/services/index_query_service.py +0 -70
  117. kodit/domain/services/index_service.py +0 -269
  118. kodit/infrastructure/api/client/index_client.py +0 -57
  119. kodit/infrastructure/api/v1/routers/indexes.py +0 -164
  120. kodit/infrastructure/api/v1/schemas/index.py +0 -101
  121. kodit/infrastructure/bm25/bm25_factory.py +0 -28
  122. kodit/infrastructure/cloning/__init__.py +0 -1
  123. kodit/infrastructure/cloning/metadata.py +0 -98
  124. kodit/infrastructure/enrichment/__init__.py +0 -1
  125. kodit/infrastructure/enrichment/enrichment_factory.py +0 -52
  126. kodit/infrastructure/enrichment/null_enrichment_provider.py +0 -19
  127. kodit/infrastructure/mappers/index_mapper.py +0 -345
  128. kodit/infrastructure/reporting/tdqm_progress.py +0 -38
  129. kodit/infrastructure/slicing/language_detection_service.py +0 -18
  130. kodit/infrastructure/sqlalchemy/index_repository.py +0 -646
  131. kodit-0.4.3.dist-info/RECORD +0 -125
  132. /kodit/infrastructure/{enrichment → enricher}/utils.py +0 -0
  133. {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/WHEEL +0 -0
  134. {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/entry_points.txt +0 -0
  135. {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/licenses/LICENSE +0 -0
@@ -8,14 +8,11 @@ from datetime import UTC, datetime
8
8
  import structlog
9
9
  from sqlalchemy.ext.asyncio import AsyncSession
10
10
 
11
- from kodit.application.factories.code_indexing_factory import (
12
- create_code_indexing_application_service,
13
- )
14
11
  from kodit.application.factories.reporting_factory import create_noop_operation
12
+ from kodit.application.factories.server_factory import ServerFactory
15
13
  from kodit.application.services.reporting import ProgressTracker
16
14
  from kodit.config import AppContext
17
15
  from kodit.domain.entities import Task
18
- from kodit.domain.value_objects import TaskType
19
16
  from kodit.infrastructure.sqlalchemy.task_repository import create_task_repository
20
17
 
21
18
 
@@ -30,10 +27,12 @@ class IndexingWorkerService:
30
27
  self,
31
28
  app_context: AppContext,
32
29
  session_factory: Callable[[], AsyncSession],
30
+ server_factory: ServerFactory,
33
31
  ) -> None:
34
32
  """Initialize the indexing worker service."""
35
33
  self.app_context = app_context
36
34
  self.session_factory = session_factory
35
+ self.server_factory = server_factory
37
36
  self._worker_task: asyncio.Task | None = None
38
37
  self._shutdown_event = asyncio.Event()
39
38
  self.task_repository = create_task_repository(session_factory)
@@ -45,7 +44,7 @@ class IndexingWorkerService:
45
44
  self._running = True
46
45
 
47
46
  # Start single worker task
48
- self._worker_task = asyncio.create_task(self._worker_loop(operation))
47
+ self._worker_task = asyncio.create_task(self._worker_loop())
49
48
 
50
49
  self.log.info(
51
50
  "Indexing worker started",
@@ -63,18 +62,20 @@ class IndexingWorkerService:
63
62
 
64
63
  self.log.info("Indexing worker stopped")
65
64
 
66
- async def _worker_loop(self, operation: ProgressTracker) -> None:
65
+ async def _worker_loop(self) -> None:
67
66
  self.log.debug("Worker loop started")
68
67
 
69
68
  while not self._shutdown_event.is_set():
70
69
  try:
71
70
  async with self.session_factory() as session:
72
- task = await self.task_repository.take()
71
+ task = await self.task_repository.next()
73
72
  await session.commit()
74
73
 
75
74
  # If there's a task, process it in a new thread
76
75
  if task:
77
- await self._process_task(task, operation)
76
+ await self._process_task(task)
77
+ # Only remove the task if it was processed successfully
78
+ await self.task_repository.remove(task)
78
79
  continue
79
80
 
80
81
  # If no task, sleep for a bit
@@ -90,8 +91,8 @@ class IndexingWorkerService:
90
91
 
91
92
  self.log.info("Worker loop stopped")
92
93
 
93
- async def _process_task(self, task: Task, operation: ProgressTracker) -> None:
94
- """Process a single task."""
94
+ async def _process_task(self, task: Task) -> None:
95
+ """Process a task based on its type."""
95
96
  self.log.info(
96
97
  "Processing task",
97
98
  task_id=task.id,
@@ -105,16 +106,8 @@ class IndexingWorkerService:
105
106
  asyncio.set_event_loop(loop)
106
107
 
107
108
  try:
108
- # Process based on task type (currently only INDEX_UPDATE is supported)
109
- if task.type is TaskType.INDEX_UPDATE:
110
- await self._process_index_update(task, operation)
111
- else:
112
- self.log.warning(
113
- "Unknown task type",
114
- task_id=task.id,
115
- task_type=task.type,
116
- )
117
- return
109
+ commit_service = self.server_factory.commit_indexing_application_service()
110
+ await commit_service.run_task(task)
118
111
  finally:
119
112
  loop.close()
120
113
 
@@ -124,27 +117,3 @@ class IndexingWorkerService:
124
117
  task_id=task.id,
125
118
  duration_seconds=duration,
126
119
  )
127
-
128
- async def _process_index_update(
129
- self, task: Task, operation: ProgressTracker
130
- ) -> None:
131
- """Process index update/sync task."""
132
- index_id = task.payload.get("index_id")
133
- if not index_id:
134
- raise ValueError("Missing index_id in task payload")
135
-
136
- # Create a fresh database connection for this thread's event loop
137
- db = await self.app_context.new_db(run_migrations=True)
138
- try:
139
- service = create_code_indexing_application_service(
140
- app_context=self.app_context,
141
- session_factory=self.session_factory,
142
- operation=operation,
143
- )
144
- index = await service.index_repository.get(index_id)
145
- if not index:
146
- raise ValueError(f"Index not found: {index_id}")
147
-
148
- await service.run_index(index)
149
- finally:
150
- await db.close()
@@ -1,12 +1,13 @@
1
1
  """Queue service for managing tasks."""
2
2
 
3
3
  from collections.abc import Callable
4
+ from typing import Any
4
5
 
5
6
  import structlog
6
7
  from sqlalchemy.ext.asyncio import AsyncSession
7
8
 
8
9
  from kodit.domain.entities import Task
9
- from kodit.domain.value_objects import TaskType
10
+ from kodit.domain.value_objects import QueuePriority, TaskOperation
10
11
  from kodit.infrastructure.sqlalchemy.task_repository import (
11
12
  create_task_repository,
12
13
  )
@@ -46,9 +47,29 @@ class QueueService:
46
47
  payload=task.payload,
47
48
  )
48
49
 
49
- async def list_tasks(self, task_type: TaskType | None = None) -> list[Task]:
50
+ async def enqueue_tasks(
51
+ self,
52
+ tasks: list[TaskOperation],
53
+ base_priority: QueuePriority,
54
+ payload: dict[str, Any],
55
+ ) -> None:
56
+ """Queue repository tasks."""
57
+ priority_offset = len(tasks) * 10
58
+ for task in tasks:
59
+ await self.enqueue_task(
60
+ Task.create(
61
+ task,
62
+ base_priority + priority_offset,
63
+ payload,
64
+ )
65
+ )
66
+ priority_offset -= 10
67
+
68
+ async def list_tasks(
69
+ self, task_operation: TaskOperation | None = None
70
+ ) -> list[Task]:
50
71
  """List all tasks in the queue."""
51
- return await self.task_repository.list(task_type)
72
+ return await self.task_repository.list(task_operation)
52
73
 
53
74
  async def get_task(self, task_id: str) -> Task | None:
54
75
  """Get a specific task by ID."""
@@ -82,7 +82,6 @@ class ProgressTracker:
82
82
  async def skip(self, reason: str) -> None:
83
83
  """Skip the step."""
84
84
  self.task_status.skip(reason)
85
- await self.notify_subscribers()
86
85
 
87
86
  def subscribe(self, subscriber: "ReportingModule") -> None:
88
87
  """Subscribe to the step."""
@@ -91,7 +90,6 @@ class ProgressTracker:
91
90
  async def set_total(self, total: int) -> None:
92
91
  """Set the total for the step."""
93
92
  self.task_status.set_total(total)
94
- await self.notify_subscribers()
95
93
 
96
94
  async def set_current(self, current: int, message: str | None = None) -> None:
97
95
  """Progress the step."""
@@ -1,18 +1,16 @@
1
1
  """Service for scheduling periodic sync operations."""
2
2
 
3
3
  import asyncio
4
- from collections.abc import Callable
5
4
  from contextlib import suppress
6
5
 
7
6
  import structlog
8
- from sqlalchemy.ext.asyncio import AsyncSession
9
7
 
10
8
  from kodit.application.services.queue_service import QueueService
11
- from kodit.domain.entities import Task
12
- from kodit.domain.services.index_query_service import IndexQueryService
13
- from kodit.domain.value_objects import QueuePriority
14
- from kodit.infrastructure.indexing.fusion_service import ReciprocalRankFusionService
15
- from kodit.infrastructure.sqlalchemy.index_repository import create_index_repository
9
+ from kodit.domain.protocols import GitRepoRepository
10
+ from kodit.domain.value_objects import (
11
+ PrescribedOperations,
12
+ QueuePriority,
13
+ )
16
14
 
17
15
 
18
16
  class SyncSchedulerService:
@@ -20,10 +18,12 @@ class SyncSchedulerService:
20
18
 
21
19
  def __init__(
22
20
  self,
23
- session_factory: Callable[[], AsyncSession],
21
+ queue_service: QueueService,
22
+ repo_repository: GitRepoRepository,
24
23
  ) -> None:
25
24
  """Initialize the sync scheduler service."""
26
- self.session_factory = session_factory
25
+ self.queue_service = queue_service
26
+ self.repo_repository = repo_repository
27
27
  self.log = structlog.get_logger(__name__)
28
28
  self._sync_task: asyncio.Task | None = None
29
29
  self._shutdown_event = asyncio.Event()
@@ -67,28 +67,12 @@ class SyncSchedulerService:
67
67
  """Perform a sync operation on all indexes."""
68
68
  self.log.info("Starting sync operation")
69
69
 
70
- # Create services
71
- queue_service = QueueService(session_factory=self.session_factory)
72
- index_query_service = IndexQueryService(
73
- index_repository=create_index_repository(
74
- session_factory=self.session_factory
75
- ),
76
- fusion_service=ReciprocalRankFusionService(),
77
- )
78
-
79
- # Get all existing indexes
80
- all_indexes = await index_query_service.list_indexes()
81
-
82
- if not all_indexes:
83
- self.log.info("No indexes found to sync")
84
- return
85
-
86
- self.log.info("Adding sync tasks to queue", count=len(all_indexes))
87
-
88
- # Sync each index
89
- for index in all_indexes:
90
- await queue_service.enqueue_task(
91
- Task.create_index_update_task(index.id, QueuePriority.BACKGROUND)
70
+ # Sync each index - queue all 5 tasks with priority ordering
71
+ for repo in await self.repo_repository.get_all():
72
+ await self.queue_service.enqueue_tasks(
73
+ tasks=PrescribedOperations.SYNC_REPOSITORY,
74
+ base_priority=QueuePriority.BACKGROUND,
75
+ payload={"repository_id": repo.id},
92
76
  )
93
77
 
94
78
  self.log.info("Sync operation completed")