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.
- kodit/_version.py +2 -2
- kodit/app.py +51 -23
- kodit/application/factories/reporting_factory.py +6 -2
- kodit/application/factories/server_factory.py +353 -0
- kodit/application/services/code_search_application_service.py +144 -0
- kodit/application/services/commit_indexing_application_service.py +700 -0
- kodit/application/services/indexing_worker_service.py +13 -44
- kodit/application/services/queue_service.py +24 -3
- kodit/application/services/reporting.py +0 -2
- kodit/application/services/sync_scheduler.py +15 -31
- kodit/cli.py +2 -753
- kodit/cli_utils.py +2 -9
- kodit/config.py +4 -97
- kodit/database.py +38 -1
- kodit/domain/enrichments/__init__.py +1 -0
- kodit/domain/enrichments/architecture/__init__.py +1 -0
- kodit/domain/enrichments/architecture/architecture.py +20 -0
- kodit/domain/enrichments/architecture/physical/__init__.py +1 -0
- kodit/domain/enrichments/architecture/physical/discovery_notes.py +14 -0
- kodit/domain/enrichments/architecture/physical/formatter.py +11 -0
- kodit/domain/enrichments/architecture/physical/physical.py +17 -0
- kodit/domain/enrichments/development/__init__.py +1 -0
- kodit/domain/enrichments/development/development.py +18 -0
- kodit/domain/enrichments/development/snippet/__init__.py +1 -0
- kodit/domain/enrichments/development/snippet/snippet.py +21 -0
- kodit/domain/enrichments/enricher.py +17 -0
- kodit/domain/enrichments/enrichment.py +39 -0
- kodit/domain/enrichments/request.py +12 -0
- kodit/domain/enrichments/response.py +11 -0
- kodit/domain/enrichments/usage/__init__.py +1 -0
- kodit/domain/enrichments/usage/api_docs.py +19 -0
- kodit/domain/enrichments/usage/usage.py +18 -0
- kodit/domain/{entities.py → entities/__init__.py} +50 -195
- kodit/domain/entities/git.py +190 -0
- kodit/domain/factories/__init__.py +1 -0
- kodit/domain/factories/git_repo_factory.py +76 -0
- kodit/domain/protocols.py +264 -64
- kodit/domain/services/bm25_service.py +5 -1
- kodit/domain/services/embedding_service.py +3 -0
- kodit/domain/services/enrichment_service.py +9 -30
- kodit/domain/services/git_repository_service.py +429 -0
- kodit/domain/services/git_service.py +300 -0
- kodit/domain/services/physical_architecture_service.py +182 -0
- kodit/domain/services/task_status_query_service.py +2 -2
- kodit/domain/value_objects.py +87 -135
- kodit/infrastructure/api/client/__init__.py +0 -2
- kodit/infrastructure/api/v1/__init__.py +0 -4
- kodit/infrastructure/api/v1/dependencies.py +92 -46
- kodit/infrastructure/api/v1/routers/__init__.py +0 -6
- kodit/infrastructure/api/v1/routers/commits.py +352 -0
- kodit/infrastructure/api/v1/routers/queue.py +2 -2
- kodit/infrastructure/api/v1/routers/repositories.py +282 -0
- kodit/infrastructure/api/v1/routers/search.py +31 -14
- kodit/infrastructure/api/v1/schemas/__init__.py +0 -24
- kodit/infrastructure/api/v1/schemas/commit.py +96 -0
- kodit/infrastructure/api/v1/schemas/context.py +2 -0
- kodit/infrastructure/api/v1/schemas/enrichment.py +29 -0
- kodit/infrastructure/api/v1/schemas/repository.py +128 -0
- kodit/infrastructure/api/v1/schemas/search.py +12 -9
- kodit/infrastructure/api/v1/schemas/snippet.py +58 -0
- kodit/infrastructure/api/v1/schemas/tag.py +31 -0
- kodit/infrastructure/api/v1/schemas/task_status.py +2 -0
- kodit/infrastructure/bm25/local_bm25_repository.py +16 -4
- kodit/infrastructure/bm25/vectorchord_bm25_repository.py +68 -52
- kodit/infrastructure/cloning/git/git_python_adaptor.py +534 -0
- kodit/infrastructure/cloning/git/working_copy.py +1 -1
- kodit/infrastructure/embedding/embedding_factory.py +3 -2
- kodit/infrastructure/embedding/local_vector_search_repository.py +1 -1
- kodit/infrastructure/embedding/vectorchord_vector_search_repository.py +111 -84
- kodit/infrastructure/enricher/__init__.py +1 -0
- kodit/infrastructure/enricher/enricher_factory.py +53 -0
- kodit/infrastructure/{enrichment/litellm_enrichment_provider.py → enricher/litellm_enricher.py} +36 -56
- kodit/infrastructure/{enrichment/local_enrichment_provider.py → enricher/local_enricher.py} +19 -24
- kodit/infrastructure/enricher/null_enricher.py +36 -0
- kodit/infrastructure/indexing/fusion_service.py +1 -1
- kodit/infrastructure/mappers/enrichment_mapper.py +83 -0
- kodit/infrastructure/mappers/git_mapper.py +193 -0
- kodit/infrastructure/mappers/snippet_mapper.py +104 -0
- kodit/infrastructure/mappers/task_mapper.py +5 -44
- kodit/infrastructure/physical_architecture/__init__.py +1 -0
- kodit/infrastructure/physical_architecture/detectors/__init__.py +1 -0
- kodit/infrastructure/physical_architecture/detectors/docker_compose_detector.py +336 -0
- kodit/infrastructure/physical_architecture/formatters/__init__.py +1 -0
- kodit/infrastructure/physical_architecture/formatters/narrative_formatter.py +149 -0
- kodit/infrastructure/reporting/log_progress.py +8 -5
- kodit/infrastructure/reporting/telemetry_progress.py +21 -0
- kodit/infrastructure/slicing/api_doc_extractor.py +836 -0
- kodit/infrastructure/slicing/ast_analyzer.py +1128 -0
- kodit/infrastructure/slicing/slicer.py +87 -421
- kodit/infrastructure/sqlalchemy/embedding_repository.py +43 -23
- kodit/infrastructure/sqlalchemy/enrichment_v2_repository.py +118 -0
- kodit/infrastructure/sqlalchemy/entities.py +402 -158
- kodit/infrastructure/sqlalchemy/git_branch_repository.py +274 -0
- kodit/infrastructure/sqlalchemy/git_commit_repository.py +346 -0
- kodit/infrastructure/sqlalchemy/git_repository.py +262 -0
- kodit/infrastructure/sqlalchemy/git_tag_repository.py +268 -0
- kodit/infrastructure/sqlalchemy/snippet_v2_repository.py +479 -0
- kodit/infrastructure/sqlalchemy/task_repository.py +29 -23
- kodit/infrastructure/sqlalchemy/task_status_repository.py +24 -12
- kodit/infrastructure/sqlalchemy/unit_of_work.py +10 -14
- kodit/mcp.py +12 -30
- kodit/migrations/env.py +1 -0
- kodit/migrations/versions/04b80f802e0c_foreign_key_review.py +100 -0
- kodit/migrations/versions/19f8c7faf8b9_add_generic_enrichment_type.py +260 -0
- kodit/migrations/versions/7f15f878c3a1_add_new_git_entities.py +690 -0
- kodit/migrations/versions/f9e5ef5e688f_add_git_commits_number.py +43 -0
- kodit/py.typed +0 -0
- kodit/utils/dump_config.py +361 -0
- kodit/utils/dump_openapi.py +6 -4
- kodit/utils/path_utils.py +29 -0
- {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/METADATA +3 -3
- kodit-0.5.1.dist-info/RECORD +168 -0
- kodit/application/factories/code_indexing_factory.py +0 -195
- kodit/application/services/auto_indexing_service.py +0 -99
- kodit/application/services/code_indexing_application_service.py +0 -410
- kodit/domain/services/index_query_service.py +0 -70
- kodit/domain/services/index_service.py +0 -269
- kodit/infrastructure/api/client/index_client.py +0 -57
- kodit/infrastructure/api/v1/routers/indexes.py +0 -164
- kodit/infrastructure/api/v1/schemas/index.py +0 -101
- kodit/infrastructure/bm25/bm25_factory.py +0 -28
- kodit/infrastructure/cloning/__init__.py +0 -1
- kodit/infrastructure/cloning/metadata.py +0 -98
- kodit/infrastructure/enrichment/__init__.py +0 -1
- kodit/infrastructure/enrichment/enrichment_factory.py +0 -52
- kodit/infrastructure/enrichment/null_enrichment_provider.py +0 -19
- kodit/infrastructure/mappers/index_mapper.py +0 -345
- kodit/infrastructure/reporting/tdqm_progress.py +0 -38
- kodit/infrastructure/slicing/language_detection_service.py +0 -18
- kodit/infrastructure/sqlalchemy/index_repository.py +0 -646
- kodit-0.4.3.dist-info/RECORD +0 -125
- /kodit/infrastructure/{enrichment → enricher}/utils.py +0 -0
- {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/WHEEL +0 -0
- {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/entry_points.txt +0 -0
- {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(
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
94
|
-
"""Process a
|
|
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
|
-
|
|
109
|
-
|
|
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
|
|
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
|
|
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(
|
|
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.
|
|
12
|
-
from kodit.domain.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
21
|
+
queue_service: QueueService,
|
|
22
|
+
repo_repository: GitRepoRepository,
|
|
24
23
|
) -> None:
|
|
25
24
|
"""Initialize the sync scheduler service."""
|
|
26
|
-
self.
|
|
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
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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")
|