kodit 0.3.1__py3-none-any.whl → 0.3.2__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/application/services/code_indexing_application_service.py +15 -12
- kodit/cli.py +35 -11
- kodit/domain/entities.py +9 -1
- kodit/domain/repositories.py +5 -5
- kodit/domain/services/indexing_service.py +3 -3
- kodit/domain/services/snippet_service.py +22 -18
- kodit/domain/value_objects.py +82 -39
- kodit/infrastructure/indexing/index_repository.py +33 -20
- kodit/infrastructure/sqlalchemy/snippet_repository.py +86 -78
- kodit/log.py +4 -1
- kodit/mcp.py +1 -6
- kodit/migrations/versions/4552eb3f23ce_add_summary.py +34 -0
- {kodit-0.3.1.dist-info → kodit-0.3.2.dist-info}/METADATA +1 -1
- {kodit-0.3.1.dist-info → kodit-0.3.2.dist-info}/RECORD +18 -17
- {kodit-0.3.1.dist-info → kodit-0.3.2.dist-info}/WHEEL +0 -0
- {kodit-0.3.1.dist-info → kodit-0.3.2.dist-info}/entry_points.txt +0 -0
- {kodit-0.3.1.dist-info → kodit-0.3.2.dist-info}/licenses/LICENSE +0 -0
kodit/_version.py
CHANGED
|
@@ -157,7 +157,7 @@ class CodeIndexingApplicationService:
|
|
|
157
157
|
snippet_results = await self.snippet_domain_service.search_snippets(
|
|
158
158
|
prefilter_request
|
|
159
159
|
)
|
|
160
|
-
filtered_snippet_ids = [snippet.id for snippet in snippet_results]
|
|
160
|
+
filtered_snippet_ids = [snippet.snippet.id for snippet in snippet_results]
|
|
161
161
|
|
|
162
162
|
# Gather results from different search modes
|
|
163
163
|
fusion_list: list[list[FusionRequest]] = []
|
|
@@ -225,9 +225,20 @@ class CodeIndexingApplicationService:
|
|
|
225
225
|
return [
|
|
226
226
|
MultiSearchResult(
|
|
227
227
|
id=result.snippet.id,
|
|
228
|
-
uri=result.file.uri,
|
|
229
228
|
content=result.snippet.content,
|
|
230
229
|
original_scores=fr.original_scores,
|
|
230
|
+
# Enhanced fields
|
|
231
|
+
source_uri=result.source.uri,
|
|
232
|
+
relative_path=MultiSearchResult.calculate_relative_path(
|
|
233
|
+
result.file.cloned_path, result.source.cloned_path
|
|
234
|
+
),
|
|
235
|
+
language=MultiSearchResult.detect_language_from_extension(
|
|
236
|
+
result.file.extension
|
|
237
|
+
),
|
|
238
|
+
authors=[author.name for author in result.authors],
|
|
239
|
+
created_at=result.snippet.created_at,
|
|
240
|
+
# Summary from snippet entity
|
|
241
|
+
summary=result.snippet.summary,
|
|
231
242
|
)
|
|
232
243
|
for result, fr in zip(search_results, final_results, strict=True)
|
|
233
244
|
]
|
|
@@ -300,16 +311,8 @@ class CodeIndexingApplicationService:
|
|
|
300
311
|
async for result in self.enrichment_service.enrich_documents(
|
|
301
312
|
enrichment_request
|
|
302
313
|
):
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
result.text
|
|
306
|
-
+ "\n\n```\n"
|
|
307
|
-
+ next(s.content for s in snippets if s.id == result.snippet_id)
|
|
308
|
-
+ "\n```"
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
await self.snippet_domain_service.update_snippet_content(
|
|
312
|
-
result.snippet_id, enriched_content
|
|
314
|
+
await self.snippet_domain_service.update_snippet_summary(
|
|
315
|
+
result.snippet_id, result.text
|
|
313
316
|
)
|
|
314
317
|
|
|
315
318
|
processed += 1
|
kodit/cli.py
CHANGED
|
@@ -20,7 +20,11 @@ from kodit.config import (
|
|
|
20
20
|
)
|
|
21
21
|
from kodit.domain.errors import EmptySourceError
|
|
22
22
|
from kodit.domain.services.source_service import SourceService
|
|
23
|
-
from kodit.domain.value_objects import
|
|
23
|
+
from kodit.domain.value_objects import (
|
|
24
|
+
MultiSearchRequest,
|
|
25
|
+
MultiSearchResult,
|
|
26
|
+
SnippetSearchFilters,
|
|
27
|
+
)
|
|
24
28
|
from kodit.infrastructure.ui.progress import (
|
|
25
29
|
create_lazy_progress_callback,
|
|
26
30
|
create_multi_stage_progress_callback,
|
|
@@ -219,6 +223,7 @@ def _parse_filters(
|
|
|
219
223
|
@click.option(
|
|
220
224
|
"--source-repo", help="Filter by source repository (e.g., github.com/example/repo)"
|
|
221
225
|
)
|
|
226
|
+
@click.option("--output-format", default="text", help="Format to display snippets in")
|
|
222
227
|
@with_app_context
|
|
223
228
|
@with_session
|
|
224
229
|
async def code( # noqa: PLR0913
|
|
@@ -231,6 +236,7 @@ async def code( # noqa: PLR0913
|
|
|
231
236
|
created_after: str | None,
|
|
232
237
|
created_before: str | None,
|
|
233
238
|
source_repo: str | None,
|
|
239
|
+
output_format: str,
|
|
234
240
|
) -> None:
|
|
235
241
|
"""Search for snippets using semantic code search.
|
|
236
242
|
|
|
@@ -259,8 +265,10 @@ async def code( # noqa: PLR0913
|
|
|
259
265
|
click.echo("No snippets found")
|
|
260
266
|
return
|
|
261
267
|
|
|
262
|
-
|
|
263
|
-
click.echo(
|
|
268
|
+
if output_format == "text":
|
|
269
|
+
click.echo(MultiSearchResult.to_string(snippets))
|
|
270
|
+
elif output_format == "json":
|
|
271
|
+
click.echo(MultiSearchResult.to_jsonlines(snippets))
|
|
264
272
|
|
|
265
273
|
|
|
266
274
|
@search.command()
|
|
@@ -279,6 +287,7 @@ async def code( # noqa: PLR0913
|
|
|
279
287
|
@click.option(
|
|
280
288
|
"--source-repo", help="Filter by source repository (e.g., github.com/example/repo)"
|
|
281
289
|
)
|
|
290
|
+
@click.option("--output-format", default="text", help="Format to display snippets in")
|
|
282
291
|
@with_app_context
|
|
283
292
|
@with_session
|
|
284
293
|
async def keyword( # noqa: PLR0913
|
|
@@ -291,6 +300,7 @@ async def keyword( # noqa: PLR0913
|
|
|
291
300
|
created_after: str | None,
|
|
292
301
|
created_before: str | None,
|
|
293
302
|
source_repo: str | None,
|
|
303
|
+
output_format: str,
|
|
294
304
|
) -> None:
|
|
295
305
|
"""Search for snippets using keyword search."""
|
|
296
306
|
log_event("kodit.cli.search.keyword")
|
|
@@ -316,8 +326,10 @@ async def keyword( # noqa: PLR0913
|
|
|
316
326
|
click.echo("No snippets found")
|
|
317
327
|
return
|
|
318
328
|
|
|
319
|
-
|
|
320
|
-
click.echo(
|
|
329
|
+
if output_format == "text":
|
|
330
|
+
click.echo(MultiSearchResult.to_string(snippets))
|
|
331
|
+
elif output_format == "json":
|
|
332
|
+
click.echo(MultiSearchResult.to_jsonlines(snippets))
|
|
321
333
|
|
|
322
334
|
|
|
323
335
|
@search.command()
|
|
@@ -336,6 +348,7 @@ async def keyword( # noqa: PLR0913
|
|
|
336
348
|
@click.option(
|
|
337
349
|
"--source-repo", help="Filter by source repository (e.g., github.com/example/repo)"
|
|
338
350
|
)
|
|
351
|
+
@click.option("--output-format", default="text", help="Format to display snippets in")
|
|
339
352
|
@with_app_context
|
|
340
353
|
@with_session
|
|
341
354
|
async def text( # noqa: PLR0913
|
|
@@ -348,6 +361,7 @@ async def text( # noqa: PLR0913
|
|
|
348
361
|
created_after: str | None,
|
|
349
362
|
created_before: str | None,
|
|
350
363
|
source_repo: str | None,
|
|
364
|
+
output_format: str,
|
|
351
365
|
) -> None:
|
|
352
366
|
"""Search for snippets using semantic text search.
|
|
353
367
|
|
|
@@ -376,8 +390,10 @@ async def text( # noqa: PLR0913
|
|
|
376
390
|
click.echo("No snippets found")
|
|
377
391
|
return
|
|
378
392
|
|
|
379
|
-
|
|
380
|
-
click.echo(
|
|
393
|
+
if output_format == "text":
|
|
394
|
+
click.echo(MultiSearchResult.to_string(snippets))
|
|
395
|
+
elif output_format == "json":
|
|
396
|
+
click.echo(MultiSearchResult.to_jsonlines(snippets))
|
|
381
397
|
|
|
382
398
|
|
|
383
399
|
@search.command()
|
|
@@ -398,6 +414,7 @@ async def text( # noqa: PLR0913
|
|
|
398
414
|
@click.option(
|
|
399
415
|
"--source-repo", help="Filter by source repository (e.g., github.com/example/repo)"
|
|
400
416
|
)
|
|
417
|
+
@click.option("--output-format", default="text", help="Format to display snippets in")
|
|
401
418
|
@with_app_context
|
|
402
419
|
@with_session
|
|
403
420
|
async def hybrid( # noqa: PLR0913
|
|
@@ -412,6 +429,7 @@ async def hybrid( # noqa: PLR0913
|
|
|
412
429
|
created_after: str | None,
|
|
413
430
|
created_before: str | None,
|
|
414
431
|
source_repo: str | None,
|
|
432
|
+
output_format: str,
|
|
415
433
|
) -> None:
|
|
416
434
|
"""Search for snippets using hybrid search."""
|
|
417
435
|
log_event("kodit.cli.search.hybrid")
|
|
@@ -446,8 +464,10 @@ async def hybrid( # noqa: PLR0913
|
|
|
446
464
|
click.echo("No snippets found")
|
|
447
465
|
return
|
|
448
466
|
|
|
449
|
-
|
|
450
|
-
click.echo(
|
|
467
|
+
if output_format == "text":
|
|
468
|
+
click.echo(MultiSearchResult.to_string(snippets))
|
|
469
|
+
elif output_format == "json":
|
|
470
|
+
click.echo(MultiSearchResult.to_jsonlines(snippets))
|
|
451
471
|
|
|
452
472
|
|
|
453
473
|
@cli.group()
|
|
@@ -458,6 +478,7 @@ def show() -> None:
|
|
|
458
478
|
@show.command()
|
|
459
479
|
@click.option("--by-path", help="File or directory path to search for snippets")
|
|
460
480
|
@click.option("--by-source", help="Source URI to filter snippets by")
|
|
481
|
+
@click.option("--output-format", default="text", help="Format to display snippets in")
|
|
461
482
|
@with_app_context
|
|
462
483
|
@with_session
|
|
463
484
|
async def snippets(
|
|
@@ -465,6 +486,7 @@ async def snippets(
|
|
|
465
486
|
app_context: AppContext,
|
|
466
487
|
by_path: str | None,
|
|
467
488
|
by_source: str | None,
|
|
489
|
+
output_format: str,
|
|
468
490
|
) -> None:
|
|
469
491
|
"""Show snippets with optional filtering by path or source."""
|
|
470
492
|
log_event("kodit.cli.show.snippets")
|
|
@@ -478,8 +500,10 @@ async def snippets(
|
|
|
478
500
|
source_service=source_service,
|
|
479
501
|
)
|
|
480
502
|
snippets = await service.list_snippets(file_path=by_path, source_uri=by_source)
|
|
481
|
-
|
|
482
|
-
click.echo(
|
|
503
|
+
if output_format == "text":
|
|
504
|
+
click.echo(MultiSearchResult.to_string(snippets))
|
|
505
|
+
elif output_format == "json":
|
|
506
|
+
click.echo(MultiSearchResult.to_jsonlines(snippets))
|
|
483
507
|
|
|
484
508
|
|
|
485
509
|
@cli.command()
|
kodit/domain/entities.py
CHANGED
|
@@ -183,10 +183,18 @@ class Snippet(Base, CommonMixin):
|
|
|
183
183
|
file_id: Mapped[int] = mapped_column(ForeignKey("files.id"), index=True)
|
|
184
184
|
index_id: Mapped[int] = mapped_column(ForeignKey("indexes.id"), index=True)
|
|
185
185
|
content: Mapped[str] = mapped_column(UnicodeText, default="")
|
|
186
|
+
summary: Mapped[str] = mapped_column(UnicodeText, default="")
|
|
186
187
|
|
|
187
|
-
def __init__(
|
|
188
|
+
def __init__(
|
|
189
|
+
self,
|
|
190
|
+
file_id: int,
|
|
191
|
+
index_id: int,
|
|
192
|
+
content: str,
|
|
193
|
+
summary: str = "",
|
|
194
|
+
) -> None:
|
|
188
195
|
"""Initialize the snippet."""
|
|
189
196
|
super().__init__()
|
|
190
197
|
self.file_id = file_id
|
|
191
198
|
self.index_id = index_id
|
|
192
199
|
self.content = content
|
|
200
|
+
self.summary = summary
|
kodit/domain/repositories.py
CHANGED
|
@@ -13,7 +13,7 @@ from kodit.domain.entities import (
|
|
|
13
13
|
)
|
|
14
14
|
from kodit.domain.value_objects import (
|
|
15
15
|
MultiSearchRequest,
|
|
16
|
-
|
|
16
|
+
SnippetWithContext,
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
T = TypeVar("T")
|
|
@@ -92,7 +92,7 @@ class SnippetRepository(GenericRepository[Snippet]):
|
|
|
92
92
|
|
|
93
93
|
async def list_snippets(
|
|
94
94
|
self, file_path: str | None = None, source_uri: str | None = None
|
|
95
|
-
) -> Sequence[
|
|
95
|
+
) -> Sequence[SnippetWithContext]:
|
|
96
96
|
"""List snippets with optional filtering by file path and source URI.
|
|
97
97
|
|
|
98
98
|
Args:
|
|
@@ -102,19 +102,19 @@ class SnippetRepository(GenericRepository[Snippet]):
|
|
|
102
102
|
all sources.
|
|
103
103
|
|
|
104
104
|
Returns:
|
|
105
|
-
A sequence of
|
|
105
|
+
A sequence of SnippetWithContext instances matching the criteria
|
|
106
106
|
|
|
107
107
|
"""
|
|
108
108
|
raise NotImplementedError
|
|
109
109
|
|
|
110
|
-
async def search(self, request: MultiSearchRequest) -> Sequence[
|
|
110
|
+
async def search(self, request: MultiSearchRequest) -> Sequence[SnippetWithContext]:
|
|
111
111
|
"""Search snippets with filters.
|
|
112
112
|
|
|
113
113
|
Args:
|
|
114
114
|
request: The search request containing queries and optional filters.
|
|
115
115
|
|
|
116
116
|
Returns:
|
|
117
|
-
A sequence of
|
|
117
|
+
A sequence of SnippetWithContext instances matching the search criteria.
|
|
118
118
|
|
|
119
119
|
"""
|
|
120
120
|
raise NotImplementedError
|
|
@@ -8,7 +8,7 @@ from kodit.domain.value_objects import (
|
|
|
8
8
|
FusionResult,
|
|
9
9
|
IndexCreateRequest,
|
|
10
10
|
IndexView,
|
|
11
|
-
|
|
11
|
+
SnippetWithContext,
|
|
12
12
|
)
|
|
13
13
|
|
|
14
14
|
|
|
@@ -52,7 +52,7 @@ class IndexRepository(ABC):
|
|
|
52
52
|
"""Update the content of an existing snippet."""
|
|
53
53
|
|
|
54
54
|
@abstractmethod
|
|
55
|
-
async def list_snippets_by_ids(self, ids: list[int]) -> list[
|
|
55
|
+
async def list_snippets_by_ids(self, ids: list[int]) -> list[SnippetWithContext]:
|
|
56
56
|
"""List snippets by IDs."""
|
|
57
57
|
|
|
58
58
|
|
|
@@ -191,7 +191,7 @@ class IndexingDomainService:
|
|
|
191
191
|
"""
|
|
192
192
|
return self.fusion_service.reciprocal_rank_fusion(rankings, k)
|
|
193
193
|
|
|
194
|
-
async def get_snippets_by_ids(self, ids: list[int]) -> list[
|
|
194
|
+
async def get_snippets_by_ids(self, ids: list[int]) -> list[SnippetWithContext]:
|
|
195
195
|
"""Get snippets by IDs.
|
|
196
196
|
|
|
197
197
|
Args:
|
|
@@ -16,7 +16,7 @@ from kodit.domain.value_objects import (
|
|
|
16
16
|
MultiSearchRequest,
|
|
17
17
|
MultiSearchResult,
|
|
18
18
|
SnippetExtractionRequest,
|
|
19
|
-
|
|
19
|
+
SnippetWithContext,
|
|
20
20
|
)
|
|
21
21
|
from kodit.reporting import Reporter
|
|
22
22
|
|
|
@@ -93,6 +93,7 @@ class SnippetDomainService:
|
|
|
93
93
|
file_id=file.id,
|
|
94
94
|
index_id=index_id,
|
|
95
95
|
content=snippet_content,
|
|
96
|
+
summary="", # Initially empty, will be populated by enrichment
|
|
96
97
|
)
|
|
97
98
|
saved_snippet = await self.snippet_repository.save(snippet)
|
|
98
99
|
created_snippets.append(saved_snippet)
|
|
@@ -128,22 +129,16 @@ class SnippetDomainService:
|
|
|
128
129
|
# This delegates to the repository but provides a domain-level interface
|
|
129
130
|
return list(await self.snippet_repository.get_by_index(index_id))
|
|
130
131
|
|
|
131
|
-
async def
|
|
132
|
-
"""Update the
|
|
133
|
-
|
|
134
|
-
Args:
|
|
135
|
-
snippet_id: The ID of the snippet to update
|
|
136
|
-
content: The new content for the snippet
|
|
137
|
-
|
|
138
|
-
"""
|
|
132
|
+
async def update_snippet_summary(self, snippet_id: int, summary: str) -> None:
|
|
133
|
+
"""Update the summary of an existing snippet."""
|
|
139
134
|
# Get the snippet first to ensure it exists
|
|
140
135
|
snippet = await self.snippet_repository.get(snippet_id)
|
|
141
136
|
if not snippet:
|
|
142
137
|
msg = f"Snippet not found: {snippet_id}"
|
|
143
138
|
raise ValueError(msg)
|
|
144
139
|
|
|
145
|
-
# Update the
|
|
146
|
-
snippet.
|
|
140
|
+
# Update the summary
|
|
141
|
+
snippet.summary = summary
|
|
147
142
|
await self.snippet_repository.save(snippet)
|
|
148
143
|
|
|
149
144
|
async def delete_snippets_for_index(self, index_id: int) -> None:
|
|
@@ -157,14 +152,14 @@ class SnippetDomainService:
|
|
|
157
152
|
|
|
158
153
|
async def search_snippets(
|
|
159
154
|
self, request: MultiSearchRequest
|
|
160
|
-
) -> list[
|
|
155
|
+
) -> list[SnippetWithContext]:
|
|
161
156
|
"""Search snippets with filters.
|
|
162
157
|
|
|
163
158
|
Args:
|
|
164
159
|
request: The search request containing filters
|
|
165
160
|
|
|
166
161
|
Returns:
|
|
167
|
-
List of matching snippet items
|
|
162
|
+
List of matching snippet items with context
|
|
168
163
|
|
|
169
164
|
"""
|
|
170
165
|
return list(await self.snippet_repository.search(request))
|
|
@@ -185,13 +180,22 @@ class SnippetDomainService:
|
|
|
185
180
|
snippet_items = await self.snippet_repository.list_snippets(
|
|
186
181
|
file_path, source_uri
|
|
187
182
|
)
|
|
188
|
-
# Convert
|
|
183
|
+
# Convert SnippetWithContext to MultiSearchResult for unified display format
|
|
189
184
|
return [
|
|
190
185
|
MultiSearchResult(
|
|
191
|
-
id=item.id,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
186
|
+
id=item.snippet.id,
|
|
187
|
+
content=item.snippet.content,
|
|
188
|
+
original_scores=[], # No scores for list operation
|
|
189
|
+
source_uri=item.source.uri,
|
|
190
|
+
relative_path=MultiSearchResult.calculate_relative_path(
|
|
191
|
+
item.file.cloned_path, item.source.cloned_path
|
|
192
|
+
),
|
|
193
|
+
language=MultiSearchResult.detect_language_from_extension(
|
|
194
|
+
item.file.extension
|
|
195
|
+
),
|
|
196
|
+
authors=[author.name for author in item.authors],
|
|
197
|
+
created_at=item.snippet.created_at,
|
|
198
|
+
summary=item.snippet.summary,
|
|
195
199
|
)
|
|
196
200
|
for item in snippet_items
|
|
197
201
|
]
|
kodit/domain/value_objects.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Domain value objects and DTOs."""
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
from enum import Enum
|
|
@@ -9,7 +10,7 @@ from typing import Any, ClassVar
|
|
|
9
10
|
from sqlalchemy import JSON, DateTime, Integer, Text
|
|
10
11
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
11
12
|
|
|
12
|
-
from kodit.domain.entities import Base
|
|
13
|
+
from kodit.domain.entities import Author, Base, File, Snippet, Source
|
|
13
14
|
from kodit.domain.enums import SnippetExtractionStrategy
|
|
14
15
|
|
|
15
16
|
|
|
@@ -175,25 +176,90 @@ class MultiSearchRequest:
|
|
|
175
176
|
|
|
176
177
|
@dataclass
|
|
177
178
|
class MultiSearchResult:
|
|
178
|
-
"""
|
|
179
|
+
"""Enhanced search result with comprehensive snippet metadata."""
|
|
179
180
|
|
|
180
181
|
id: int
|
|
181
|
-
uri: str
|
|
182
182
|
content: str
|
|
183
183
|
original_scores: list[float]
|
|
184
|
+
source_uri: str
|
|
185
|
+
relative_path: str
|
|
186
|
+
language: str
|
|
187
|
+
authors: list[str]
|
|
188
|
+
created_at: datetime
|
|
189
|
+
summary: str
|
|
184
190
|
|
|
185
191
|
def __str__(self) -> str:
|
|
186
|
-
"""Return formatted string representation
|
|
192
|
+
"""Return enhanced formatted string representation."""
|
|
187
193
|
lines = [
|
|
188
|
-
"
|
|
189
|
-
f"
|
|
190
|
-
f"
|
|
191
|
-
self.
|
|
192
|
-
"
|
|
193
|
-
"",
|
|
194
|
+
"---",
|
|
195
|
+
f"id: {self.id}",
|
|
196
|
+
f"source: {self.source_uri}",
|
|
197
|
+
f"path: {self.relative_path}",
|
|
198
|
+
f"lang: {self.language}",
|
|
199
|
+
f"created: {self.created_at.isoformat()}",
|
|
200
|
+
f"authors: {', '.join(self.authors)}",
|
|
201
|
+
f"scores: {self.original_scores}",
|
|
202
|
+
"---",
|
|
203
|
+
f"{self.summary}\n",
|
|
204
|
+
f"```{self.language}",
|
|
205
|
+
f"{self.content}",
|
|
206
|
+
"```\n",
|
|
194
207
|
]
|
|
195
208
|
return "\n".join(lines)
|
|
196
209
|
|
|
210
|
+
def to_json(self) -> str:
|
|
211
|
+
"""Return LLM-optimized JSON representation following the compact schema."""
|
|
212
|
+
json_obj = {
|
|
213
|
+
"id": self.id,
|
|
214
|
+
"source": self.source_uri,
|
|
215
|
+
"path": self.relative_path,
|
|
216
|
+
"lang": self.language.lower(),
|
|
217
|
+
"created": self.created_at.isoformat() if self.created_at else "",
|
|
218
|
+
"author": ", ".join(self.authors),
|
|
219
|
+
"score": self.original_scores,
|
|
220
|
+
"code": self.content,
|
|
221
|
+
"summary": self.summary,
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return json.dumps(json_obj, separators=(",", ":"))
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def to_jsonlines(cls, results: list["MultiSearchResult"]) -> str:
|
|
228
|
+
"""Convert multiple MultiSearchResult objects to JSON Lines format.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
results: List of MultiSearchResult objects
|
|
232
|
+
include_summary: Whether to include summary fields
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
JSON Lines string (one JSON object per line)
|
|
236
|
+
|
|
237
|
+
"""
|
|
238
|
+
return "\n".join(result.to_json() for result in results)
|
|
239
|
+
|
|
240
|
+
@classmethod
|
|
241
|
+
def to_string(cls, results: list["MultiSearchResult"]) -> str:
|
|
242
|
+
"""Convert multiple MultiSearchResult objects to a string."""
|
|
243
|
+
return "\n\n".join(str(result) for result in results)
|
|
244
|
+
|
|
245
|
+
@staticmethod
|
|
246
|
+
def calculate_relative_path(file_path: str, source_path: str) -> str:
|
|
247
|
+
"""Calculate relative path from source root."""
|
|
248
|
+
try:
|
|
249
|
+
return str(Path(file_path).relative_to(Path(source_path)))
|
|
250
|
+
except ValueError:
|
|
251
|
+
# If file_path is not relative to source_path, return the file name
|
|
252
|
+
return Path(file_path).name
|
|
253
|
+
|
|
254
|
+
@staticmethod
|
|
255
|
+
def detect_language_from_extension(extension: str) -> str:
|
|
256
|
+
"""Detect programming language from file extension."""
|
|
257
|
+
try:
|
|
258
|
+
return LanguageMapping.get_language_for_extension(extension).title()
|
|
259
|
+
except ValueError:
|
|
260
|
+
# Unknown extension, return a default
|
|
261
|
+
return "Unknown"
|
|
262
|
+
|
|
197
263
|
|
|
198
264
|
@dataclass
|
|
199
265
|
class FusionRequest:
|
|
@@ -292,36 +358,13 @@ class IndexView:
|
|
|
292
358
|
|
|
293
359
|
|
|
294
360
|
@dataclass
|
|
295
|
-
class
|
|
296
|
-
"""Domain model for snippet
|
|
297
|
-
|
|
298
|
-
id: int
|
|
299
|
-
file_path: str
|
|
300
|
-
content: str
|
|
301
|
-
source_uri: str
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
@dataclass
|
|
305
|
-
class FileInfo:
|
|
306
|
-
"""Domain model for file information."""
|
|
307
|
-
|
|
308
|
-
uri: str
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
@dataclass
|
|
312
|
-
class SnippetInfo:
|
|
313
|
-
"""Domain model for snippet information."""
|
|
314
|
-
|
|
315
|
-
id: int
|
|
316
|
-
content: str
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
@dataclass
|
|
320
|
-
class SnippetWithFile:
|
|
321
|
-
"""Domain model for snippet with associated file information."""
|
|
361
|
+
class SnippetWithContext:
|
|
362
|
+
"""Domain model for snippet with associated context information."""
|
|
322
363
|
|
|
323
|
-
|
|
324
|
-
|
|
364
|
+
source: Source
|
|
365
|
+
file: File
|
|
366
|
+
authors: list[Author]
|
|
367
|
+
snippet: Snippet
|
|
325
368
|
|
|
326
369
|
|
|
327
370
|
class LanguageMapping:
|
|
@@ -6,9 +6,20 @@ from typing import TypeVar
|
|
|
6
6
|
from sqlalchemy import delete, func, select
|
|
7
7
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
8
8
|
|
|
9
|
-
from kodit.domain.entities import
|
|
9
|
+
from kodit.domain.entities import (
|
|
10
|
+
Author,
|
|
11
|
+
AuthorFileMapping,
|
|
12
|
+
Embedding,
|
|
13
|
+
File,
|
|
14
|
+
Index,
|
|
15
|
+
Snippet,
|
|
16
|
+
Source,
|
|
17
|
+
)
|
|
10
18
|
from kodit.domain.services.indexing_service import IndexRepository
|
|
11
|
-
from kodit.domain.value_objects import
|
|
19
|
+
from kodit.domain.value_objects import (
|
|
20
|
+
IndexView,
|
|
21
|
+
SnippetWithContext,
|
|
22
|
+
)
|
|
12
23
|
|
|
13
24
|
T = TypeVar("T")
|
|
14
25
|
|
|
@@ -202,6 +213,7 @@ class SQLAlchemyIndexRepository(IndexRepository):
|
|
|
202
213
|
file_id=snippet["file_id"],
|
|
203
214
|
index_id=snippet["index_id"],
|
|
204
215
|
content=snippet["content"],
|
|
216
|
+
summary=snippet.get("summary", ""),
|
|
205
217
|
)
|
|
206
218
|
self.session.add(db_snippet)
|
|
207
219
|
|
|
@@ -221,30 +233,31 @@ class SQLAlchemyIndexRepository(IndexRepository):
|
|
|
221
233
|
snippet.content = content
|
|
222
234
|
# SQLAlchemy will automatically track this change
|
|
223
235
|
|
|
224
|
-
async def list_snippets_by_ids(self, ids: list[int]) -> list[
|
|
225
|
-
"""List snippets by IDs.
|
|
226
|
-
|
|
227
|
-
Args:
|
|
228
|
-
ids: List of snippet IDs to retrieve.
|
|
229
|
-
|
|
230
|
-
Returns:
|
|
231
|
-
List of SnippetWithFile objects containing file and snippet information.
|
|
232
|
-
|
|
233
|
-
"""
|
|
236
|
+
async def list_snippets_by_ids(self, ids: list[int]) -> list[SnippetWithContext]:
|
|
237
|
+
"""List snippets by IDs."""
|
|
234
238
|
query = (
|
|
235
|
-
select(Snippet, File)
|
|
239
|
+
select(Snippet, File, Source, Author)
|
|
236
240
|
.where(Snippet.id.in_(ids))
|
|
237
241
|
.join(File, Snippet.file_id == File.id)
|
|
242
|
+
.join(Source, File.source_id == Source.id)
|
|
243
|
+
.outerjoin(AuthorFileMapping, AuthorFileMapping.file_id == File.id)
|
|
244
|
+
.outerjoin(Author, AuthorFileMapping.author_id == Author.id)
|
|
238
245
|
)
|
|
239
246
|
rows = await self.session.execute(query)
|
|
240
247
|
|
|
241
|
-
#
|
|
242
|
-
id_to_result = {}
|
|
243
|
-
for snippet, file in rows.all():
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
+
# Group results by snippet ID and collect authors
|
|
249
|
+
id_to_result: dict[int, SnippetWithContext] = {}
|
|
250
|
+
for snippet, file, source, author in rows.all():
|
|
251
|
+
if snippet.id not in id_to_result:
|
|
252
|
+
id_to_result[snippet.id] = SnippetWithContext(
|
|
253
|
+
snippet=snippet,
|
|
254
|
+
file=file,
|
|
255
|
+
source=source,
|
|
256
|
+
authors=[],
|
|
257
|
+
)
|
|
258
|
+
# Add author if it exists (outer join might return None)
|
|
259
|
+
if author is not None:
|
|
260
|
+
id_to_result[snippet.id].authors.append(author)
|
|
248
261
|
|
|
249
262
|
# Check that all IDs are present
|
|
250
263
|
if len(id_to_result) != len(ids):
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"""SQLAlchemy implementation of snippet repository."""
|
|
2
2
|
|
|
3
|
+
import builtins
|
|
3
4
|
from collections.abc import Sequence
|
|
4
5
|
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
5
7
|
|
|
6
8
|
from sqlalchemy import delete, or_, select
|
|
7
9
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
@@ -18,7 +20,7 @@ from kodit.domain.repositories import SnippetRepository
|
|
|
18
20
|
from kodit.domain.value_objects import (
|
|
19
21
|
LanguageMapping,
|
|
20
22
|
MultiSearchRequest,
|
|
21
|
-
|
|
23
|
+
SnippetWithContext,
|
|
22
24
|
)
|
|
23
25
|
|
|
24
26
|
|
|
@@ -102,7 +104,7 @@ class SqlAlchemySnippetRepository(SnippetRepository):
|
|
|
102
104
|
|
|
103
105
|
async def list_snippets(
|
|
104
106
|
self, file_path: str | None = None, source_uri: str | None = None
|
|
105
|
-
) -> Sequence[
|
|
107
|
+
) -> Sequence[SnippetWithContext]:
|
|
106
108
|
"""List snippets with optional filtering by file path and source URI.
|
|
107
109
|
|
|
108
110
|
Args:
|
|
@@ -112,20 +114,11 @@ class SqlAlchemySnippetRepository(SnippetRepository):
|
|
|
112
114
|
all sources.
|
|
113
115
|
|
|
114
116
|
Returns:
|
|
115
|
-
A sequence of
|
|
117
|
+
A sequence of SnippetWithContext instances matching the criteria
|
|
116
118
|
|
|
117
119
|
"""
|
|
118
|
-
# Build the base query
|
|
119
|
-
query = (
|
|
120
|
-
select(
|
|
121
|
-
Snippet,
|
|
122
|
-
File.cloned_path,
|
|
123
|
-
Source.cloned_path.label("source_cloned_path"),
|
|
124
|
-
Source.uri.label("source_uri"),
|
|
125
|
-
)
|
|
126
|
-
.join(File, Snippet.file_id == File.id)
|
|
127
|
-
.join(Source, File.source_id == Source.id)
|
|
128
|
-
)
|
|
120
|
+
# Build the base query with joins for all required entities
|
|
121
|
+
query = self._build_base_query()
|
|
129
122
|
|
|
130
123
|
# Apply filters
|
|
131
124
|
if file_path is not None:
|
|
@@ -140,20 +133,7 @@ class SqlAlchemySnippetRepository(SnippetRepository):
|
|
|
140
133
|
query = query.where(Source.uri == source_uri)
|
|
141
134
|
|
|
142
135
|
result = await self.session.execute(query)
|
|
143
|
-
return
|
|
144
|
-
SnippetListItem(
|
|
145
|
-
id=snippet.id,
|
|
146
|
-
file_path=self._get_relative_path(file_cloned_path, source_cloned_path),
|
|
147
|
-
content=snippet.content,
|
|
148
|
-
source_uri=source_uri_val,
|
|
149
|
-
)
|
|
150
|
-
for (
|
|
151
|
-
snippet,
|
|
152
|
-
file_cloned_path,
|
|
153
|
-
source_cloned_path,
|
|
154
|
-
source_uri_val,
|
|
155
|
-
) in result.all()
|
|
156
|
-
]
|
|
136
|
+
return self._process_results(result)
|
|
157
137
|
|
|
158
138
|
def _get_relative_path(self, file_path: str, source_path: str) -> str:
|
|
159
139
|
"""Calculate the relative path of a file from the source root.
|
|
@@ -174,57 +154,98 @@ class SqlAlchemySnippetRepository(SnippetRepository):
|
|
|
174
154
|
# If the file is not relative to the source, return the filename
|
|
175
155
|
return Path(file_path).name
|
|
176
156
|
|
|
177
|
-
|
|
178
|
-
"""
|
|
157
|
+
def _apply_filters(self, query: Any, filters: Any) -> Any:
|
|
158
|
+
"""Apply filters to the query.
|
|
179
159
|
|
|
180
160
|
Args:
|
|
181
|
-
|
|
161
|
+
query: The base query to apply filters to
|
|
162
|
+
filters: The filters to apply
|
|
182
163
|
|
|
183
164
|
Returns:
|
|
184
|
-
|
|
165
|
+
The modified query with filters applied
|
|
185
166
|
|
|
186
167
|
"""
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
168
|
+
if not filters:
|
|
169
|
+
return query
|
|
170
|
+
|
|
171
|
+
# Language filter (using file extension)
|
|
172
|
+
if filters.language:
|
|
173
|
+
extensions = LanguageMapping.get_extensions_with_fallback(filters.language)
|
|
174
|
+
query = query.where(File.extension.in_(extensions))
|
|
175
|
+
|
|
176
|
+
# Author filter
|
|
177
|
+
if filters.author:
|
|
178
|
+
query = query.where(Author.name.ilike(f"%{filters.author}%"))
|
|
179
|
+
|
|
180
|
+
# Date filters
|
|
181
|
+
if filters.created_after:
|
|
182
|
+
query = query.where(Snippet.created_at >= filters.created_after)
|
|
183
|
+
|
|
184
|
+
if filters.created_before:
|
|
185
|
+
query = query.where(Snippet.created_at <= filters.created_before)
|
|
186
|
+
|
|
187
|
+
# Source repository filter
|
|
188
|
+
if filters.source_repo:
|
|
189
|
+
query = query.where(Source.uri.like(f"%{filters.source_repo}%"))
|
|
190
|
+
|
|
191
|
+
return query
|
|
192
|
+
|
|
193
|
+
def _build_base_query(self) -> Any:
|
|
194
|
+
"""Build the base query with joins for all required entities.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
The base query with joins
|
|
198
|
+
|
|
199
|
+
"""
|
|
200
|
+
return (
|
|
201
|
+
select(Snippet, File, Source, Author)
|
|
195
202
|
.join(File, Snippet.file_id == File.id)
|
|
196
203
|
.join(Source, File.source_id == Source.id)
|
|
204
|
+
.outerjoin(AuthorFileMapping, AuthorFileMapping.file_id == File.id)
|
|
205
|
+
.outerjoin(Author, AuthorFileMapping.author_id == Author.id)
|
|
197
206
|
)
|
|
198
207
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
filters = request.filters
|
|
208
|
+
def _process_results(self, result: Any) -> builtins.list[SnippetWithContext]:
|
|
209
|
+
"""Process query results into SnippetWithContext objects.
|
|
202
210
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
211
|
+
Args:
|
|
212
|
+
result: The query result
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
List of SnippetWithContext objects
|
|
216
|
+
|
|
217
|
+
"""
|
|
218
|
+
# Group results by snippet ID and collect authors
|
|
219
|
+
id_to_result: dict[int, SnippetWithContext] = {}
|
|
220
|
+
for snippet, file, source, author in result.all():
|
|
221
|
+
if snippet.id not in id_to_result:
|
|
222
|
+
id_to_result[snippet.id] = SnippetWithContext(
|
|
223
|
+
snippet=snippet,
|
|
224
|
+
file=file,
|
|
225
|
+
source=source,
|
|
226
|
+
authors=[],
|
|
216
227
|
)
|
|
228
|
+
# Add author if it exists (outer join might return None)
|
|
229
|
+
if author is not None:
|
|
230
|
+
id_to_result[snippet.id].authors.append(author)
|
|
231
|
+
|
|
232
|
+
return list(id_to_result.values())
|
|
217
233
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
query = query.where(Snippet.created_at >= filters.created_after)
|
|
234
|
+
async def search(self, request: MultiSearchRequest) -> Sequence[SnippetWithContext]:
|
|
235
|
+
"""Search snippets with filters.
|
|
221
236
|
|
|
222
|
-
|
|
223
|
-
|
|
237
|
+
Args:
|
|
238
|
+
request: The search request containing queries and optional filters.
|
|
224
239
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
240
|
+
Returns:
|
|
241
|
+
A sequence of SnippetWithContext instances matching the search criteria.
|
|
242
|
+
|
|
243
|
+
"""
|
|
244
|
+
# Build the base query with joins for all required entities
|
|
245
|
+
query = self._build_base_query()
|
|
246
|
+
|
|
247
|
+
# Apply filters if provided
|
|
248
|
+
query = self._apply_filters(query, request.filters)
|
|
228
249
|
|
|
229
250
|
# Only apply top_k limit if there are no search queries
|
|
230
251
|
# This ensures that when used for pre-filtering (with search queries),
|
|
@@ -235,17 +256,4 @@ class SqlAlchemySnippetRepository(SnippetRepository):
|
|
|
235
256
|
query = query.limit(request.top_k)
|
|
236
257
|
|
|
237
258
|
result = await self.session.execute(query)
|
|
238
|
-
return
|
|
239
|
-
SnippetListItem(
|
|
240
|
-
id=snippet.id,
|
|
241
|
-
file_path=self._get_relative_path(file_cloned_path, source_cloned_path),
|
|
242
|
-
content=snippet.content,
|
|
243
|
-
source_uri=source_uri_val,
|
|
244
|
-
)
|
|
245
|
-
for (
|
|
246
|
-
snippet,
|
|
247
|
-
file_cloned_path,
|
|
248
|
-
source_cloned_path,
|
|
249
|
-
source_uri_val,
|
|
250
|
-
) in result.all()
|
|
251
|
-
]
|
|
259
|
+
return self._process_results(result)
|
kodit/log.py
CHANGED
|
@@ -190,11 +190,14 @@ def _from_sysfs() -> list[int]:
|
|
|
190
190
|
macs: list[int] = []
|
|
191
191
|
for iface in base.iterdir():
|
|
192
192
|
try:
|
|
193
|
+
# Skip if iface is not a directory (e.g., bonding_masters is a file)
|
|
194
|
+
if not iface.is_dir():
|
|
195
|
+
continue
|
|
193
196
|
with (base / iface / "address").open() as f:
|
|
194
197
|
content = f.read().strip()
|
|
195
198
|
if _MAC_RE.fullmatch(content):
|
|
196
199
|
macs.append(_mac_int(content))
|
|
197
|
-
except (FileNotFoundError, PermissionError):
|
|
200
|
+
except (FileNotFoundError, PermissionError, NotADirectoryError):
|
|
198
201
|
pass
|
|
199
202
|
return macs
|
|
200
203
|
|
kodit/mcp.py
CHANGED
|
@@ -195,17 +195,12 @@ async def search( # noqa: PLR0913
|
|
|
195
195
|
snippets = await service.search(request=search_request)
|
|
196
196
|
|
|
197
197
|
log.debug("Fusing output")
|
|
198
|
-
output =
|
|
198
|
+
output = MultiSearchResult.to_jsonlines(results=snippets)
|
|
199
199
|
|
|
200
200
|
log.debug("Output", output=output)
|
|
201
201
|
return output
|
|
202
202
|
|
|
203
203
|
|
|
204
|
-
def output_fusion(snippets: list[MultiSearchResult]) -> str:
|
|
205
|
-
"""Fuse the snippets into a single output."""
|
|
206
|
-
return "\n\n".join(str(snippet) for snippet in snippets)
|
|
207
|
-
|
|
208
|
-
|
|
209
204
|
@mcp.tool()
|
|
210
205
|
async def get_version() -> str:
|
|
211
206
|
"""Get the version of the kodit project."""
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# ruff: noqa
|
|
2
|
+
"""add summary
|
|
3
|
+
|
|
4
|
+
Revision ID: 4552eb3f23ce
|
|
5
|
+
Revises: 9e53ea8bb3b0
|
|
6
|
+
Create Date: 2025-06-30 16:32:49.293087
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Sequence, Union
|
|
11
|
+
|
|
12
|
+
from alembic import op
|
|
13
|
+
import sqlalchemy as sa
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# revision identifiers, used by Alembic.
|
|
17
|
+
revision: str = '4552eb3f23ce'
|
|
18
|
+
down_revision: Union[str, None] = '9e53ea8bb3b0'
|
|
19
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
20
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def upgrade() -> None:
|
|
24
|
+
"""Upgrade schema."""
|
|
25
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
26
|
+
op.add_column('snippets', sa.Column('summary', sa.UnicodeText(), nullable=False))
|
|
27
|
+
# ### end Alembic commands ###
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def downgrade() -> None:
|
|
31
|
+
"""Downgrade schema."""
|
|
32
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
33
|
+
op.drop_column('snippets', 'summary')
|
|
34
|
+
# ### end Alembic commands ###
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
kodit/.gitignore,sha256=ztkjgRwL9Uud1OEi36hGQeDGk3OLK1NfDEO8YqGYy8o,11
|
|
2
2
|
kodit/__init__.py,sha256=aEKHYninUq1yh6jaNfvJBYg-6fenpN132nJt1UU6Jxs,59
|
|
3
|
-
kodit/_version.py,sha256=
|
|
3
|
+
kodit/_version.py,sha256=5NopxuphNnyGZECYEkvIUFi0KZxwtDHmTpW5R266eSo,511
|
|
4
4
|
kodit/app.py,sha256=uv67TE83fZE7wrA7cz-sKosFrAXlKRr1B7fT-X_gMZQ,2103
|
|
5
|
-
kodit/cli.py,sha256=
|
|
5
|
+
kodit/cli.py,sha256=a-bJQ_Jyz201TEbgJPNvPDa0Qyt3kfSKqBuypeVqG_k,17219
|
|
6
6
|
kodit/config.py,sha256=VUoUi2t2yGhqOtm5MSZuaasNSklH50hfWn6GOrz3jnU,7518
|
|
7
7
|
kodit/database.py,sha256=kI9yBm4uunsgV4-QeVoCBL0wLzU4kYmYv5qZilGnbPE,1740
|
|
8
|
-
kodit/log.py,sha256=
|
|
9
|
-
kodit/mcp.py,sha256=
|
|
8
|
+
kodit/log.py,sha256=WOsLRitpCBtJa5IcsyZpKr146kXXHK2nU5VA90gcJdQ,8736
|
|
9
|
+
kodit/mcp.py,sha256=6gCJvjTqWGWUicuidbpMPtM1Vtqvlc0fKUua3l-EVPQ,6273
|
|
10
10
|
kodit/middleware.py,sha256=I6FOkqG9-8RH5kR1-0ZoQWfE4qLCB8lZYv8H_OCH29o,2714
|
|
11
11
|
kodit/reporting.py,sha256=icce1ZyiADsA_Qz-mSjgn2H4SSqKuGfLKnw-yrl9nsg,2722
|
|
12
12
|
kodit/application/__init__.py,sha256=mH50wTpgP9dhbKztFsL8Dda9Hi18TSnMVxXtpp4aGOA,35
|
|
13
13
|
kodit/application/factories/__init__.py,sha256=bU5CvEnaBePZ7JbkCOp1MGTNP752bnU2uEqmfy5FdRk,37
|
|
14
14
|
kodit/application/factories/code_indexing_factory.py,sha256=pyGcTmqhBRjw0tDvp5UpG0roBf3ROqYvBcHyvaLZ-qQ,4927
|
|
15
15
|
kodit/application/services/__init__.py,sha256=p5UQNw-H5sxQvs5Etfte93B3cJ1kKW6DNxK34uFvU1E,38
|
|
16
|
-
kodit/application/services/code_indexing_application_service.py,sha256=
|
|
16
|
+
kodit/application/services/code_indexing_application_service.py,sha256=PXnBbDnaYqU6xnKGTcOjmYZbjcQZed-_ehf6Uzhx5v4,12809
|
|
17
17
|
kodit/domain/__init__.py,sha256=TCpg4Xx-oF4mKV91lo4iXqMEfBT1OoRSYnbG-zVWolA,66
|
|
18
|
-
kodit/domain/entities.py,sha256=
|
|
18
|
+
kodit/domain/entities.py,sha256=6UBPi7zH9bCIgeXg0Poq6LQu01O5JvoHaWqNusNJ3iA,5787
|
|
19
19
|
kodit/domain/enums.py,sha256=Ik_h3D3eZ0FsSlPsU0ikm-Yv3Rmvzicffi9yBn19UIE,191
|
|
20
20
|
kodit/domain/errors.py,sha256=yIsgCjM_yOFIg8l7l-t7jM8pgeAX4cfPq0owf7iz3DA,106
|
|
21
21
|
kodit/domain/interfaces.py,sha256=Jkd0Ob4qSvhZHI9jRPFQ1n5Cv0SvU-y3Z-HCw2ikc4I,742
|
|
22
|
-
kodit/domain/repositories.py,sha256=
|
|
23
|
-
kodit/domain/value_objects.py,sha256=
|
|
22
|
+
kodit/domain/repositories.py,sha256=VgNV4NXywh6LtxN1GU2fg8bn8mNZ2wgVXZEugqOOb1M,3796
|
|
23
|
+
kodit/domain/value_objects.py,sha256=h9KMAB0neX3gQT2mTC8JxyxxuDXuJ2lyG0czUhkZc0E,15575
|
|
24
24
|
kodit/domain/services/__init__.py,sha256=Q1GhCK_PqKHYwYE4tkwDz5BIyXkJngLBBOHhzvX8nzo,42
|
|
25
25
|
kodit/domain/services/bm25_service.py,sha256=nsfTan3XtDwXuuAu1LUv-6Jukm6qFKVqqCVymjyepZQ,3625
|
|
26
26
|
kodit/domain/services/embedding_service.py,sha256=Wh6Y2NR_GRnud8dq1Q7S6F40aNe-S2UyD5Nqz9LChTM,4507
|
|
27
27
|
kodit/domain/services/enrichment_service.py,sha256=XsXg3nV-KN4rqtC7Zro_ZiZ6RSq-1eA1MG6IDzFGyBA,1316
|
|
28
28
|
kodit/domain/services/ignore_service.py,sha256=boEN-IRLmUtwO9ZnuACaVFZbIKrtUG8YwnsXKEDIG28,1136
|
|
29
|
-
kodit/domain/services/indexing_service.py,sha256=
|
|
29
|
+
kodit/domain/services/indexing_service.py,sha256=7Yb6lyyd_VpZldK_CVMeOXpzXq-08Et-WRhulCWDQdM,5920
|
|
30
30
|
kodit/domain/services/snippet_extraction_service.py,sha256=QW_99bXWpr8g6ZI-hp4Aj57VCSrUf71dLwQca5T6pyg,3065
|
|
31
|
-
kodit/domain/services/snippet_service.py,sha256=
|
|
31
|
+
kodit/domain/services/snippet_service.py,sha256=EyJQoT9UkJdMM2yfC1cFlj0yZVxK5a7NzleeM8lqWR0,7355
|
|
32
32
|
kodit/domain/services/source_service.py,sha256=9XGS3imJn65v855cztsJSaaFod6LhkF2xfUVMaytx-A,3068
|
|
33
33
|
kodit/infrastructure/__init__.py,sha256=HzEYIjoXnkz_i_MHO2e0sIVYweUcRnl2RpyBiTbMObU,28
|
|
34
34
|
kodit/infrastructure/bm25/__init__.py,sha256=DmGbrEO34FOJy4e685BbyxLA7gPW1eqs2gAxsp6JOuM,34
|
|
@@ -64,7 +64,7 @@ kodit/infrastructure/ignore/ignore_pattern_provider.py,sha256=9m2XCsgW87UBTfzHr6
|
|
|
64
64
|
kodit/infrastructure/indexing/__init__.py,sha256=7UPRa2jwCAsa0Orsp6PqXSF8iIXJVzXHMFmrKkI9yH8,38
|
|
65
65
|
kodit/infrastructure/indexing/auto_indexing_service.py,sha256=uXggladN3PTU5Jzhz0Kq-0aObvq3Dq9YbjYKCSkaQA8,3131
|
|
66
66
|
kodit/infrastructure/indexing/fusion_service.py,sha256=mXUUcx3-8e75mWkxXMfl30HIoFXrTNHzB1w90MmEbak,1806
|
|
67
|
-
kodit/infrastructure/indexing/index_repository.py,sha256=
|
|
67
|
+
kodit/infrastructure/indexing/index_repository.py,sha256=4m_kFHQ3OSQdf2pgR1RM72g-k4UZHyHbtYKUwJ8huRs,8719
|
|
68
68
|
kodit/infrastructure/indexing/indexing_factory.py,sha256=LPjPCps_wJ9M_fZGRP02bfc2pvYc50ZSTYI99XwRRPg,918
|
|
69
69
|
kodit/infrastructure/indexing/snippet_domain_service_factory.py,sha256=OMp9qRJSAT3oWqsMyF1fgI2Mb_G-SA22crbbaCb7c-Q,1253
|
|
70
70
|
kodit/infrastructure/snippet_extraction/__init__.py,sha256=v6KqrRDjSj0nt87m7UwRGx2GN_fz_14VWq9Q0uABR_s,54
|
|
@@ -82,7 +82,7 @@ kodit/infrastructure/sqlalchemy/__init__.py,sha256=UXPMSF_hgWaqr86cawRVqM8XdVNum
|
|
|
82
82
|
kodit/infrastructure/sqlalchemy/embedding_repository.py,sha256=u29RVt4W0WqHj6TkrydMHw2iF5_jERHtlidDjWRQvqc,7886
|
|
83
83
|
kodit/infrastructure/sqlalchemy/file_repository.py,sha256=9_kXHJ1YiWA1ingpvBNq8cuxkMu59PHwl_m9_Ttnq2o,2353
|
|
84
84
|
kodit/infrastructure/sqlalchemy/repository.py,sha256=EpZnOjR3wfPEqIauWw_KczpkSqBQPTq5sIyCpJCuW2w,4565
|
|
85
|
-
kodit/infrastructure/sqlalchemy/snippet_repository.py,sha256=
|
|
85
|
+
kodit/infrastructure/sqlalchemy/snippet_repository.py,sha256=aBsr2U6RUQftWnkOHka809WH9YxS4Tpg34knZ--WNms,8473
|
|
86
86
|
kodit/infrastructure/ui/__init__.py,sha256=CzbLOBwIZ6B6iAHEd1L8cIBydCj-n_kobxJAhz2I9_Y,32
|
|
87
87
|
kodit/infrastructure/ui/progress.py,sha256=BaAeMEgXlSSb0c_t_NPxnThIktkzzCS9kegb5ExULJs,4791
|
|
88
88
|
kodit/infrastructure/ui/spinner.py,sha256=GcP115qtR0VEnGfMEtsGoAUpRzVGUSfiUXfoJJERngA,2357
|
|
@@ -90,13 +90,14 @@ kodit/migrations/README,sha256=ISVtAOvqvKk_5ThM5ioJE-lMkvf9IbknFUFVU_vPma4,58
|
|
|
90
90
|
kodit/migrations/__init__.py,sha256=lP5MuwlyWRMO6UcDWnQcQ3G-GYHcFb6rl9gYPHJ1sjo,40
|
|
91
91
|
kodit/migrations/env.py,sha256=j89vEWdSgfnreTAz5ZvFAPlsMGI8SfKti0MlWhm7Jbc,2364
|
|
92
92
|
kodit/migrations/script.py.mako,sha256=zWziKtiwYKEWuwPV_HBNHwa9LCT45_bi01-uSNFaOOE,703
|
|
93
|
+
kodit/migrations/versions/4552eb3f23ce_add_summary.py,sha256=_saoHs5HGzc_z2OzBkFKrifTLQfoNox3BpSBeiKg_f8,870
|
|
93
94
|
kodit/migrations/versions/7c3bbc2ab32b_add_embeddings_table.py,sha256=-61qol9PfQKILCDQRA5jEaats9aGZs9Wdtp-j-38SF4,1644
|
|
94
95
|
kodit/migrations/versions/85155663351e_initial.py,sha256=Cg7zlF871o9ShV5rQMQ1v7hRV7fI59veDY9cjtTrs-8,3306
|
|
95
96
|
kodit/migrations/versions/9e53ea8bb3b0_add_authors.py,sha256=a32Zm8KUQyiiLkjKNPYdaJDgjW6VsV-GhaLnPnK_fpI,3884
|
|
96
97
|
kodit/migrations/versions/__init__.py,sha256=9-lHzptItTzq_fomdIRBegQNm4Znx6pVjwD4MiqRIdo,36
|
|
97
98
|
kodit/migrations/versions/c3f5137d30f5_index_all_the_things.py,sha256=rI8LmjF-I2OMxZ2nOIF_NRmqOLXe45hL_iz_nx97DTQ,1680
|
|
98
|
-
kodit-0.3.
|
|
99
|
-
kodit-0.3.
|
|
100
|
-
kodit-0.3.
|
|
101
|
-
kodit-0.3.
|
|
102
|
-
kodit-0.3.
|
|
99
|
+
kodit-0.3.2.dist-info/METADATA,sha256=JDWIO27pGDjCMUm5gRWUWjdQhRgEGC8J0O3gMFki6p8,6358
|
|
100
|
+
kodit-0.3.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
101
|
+
kodit-0.3.2.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
|
|
102
|
+
kodit-0.3.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
103
|
+
kodit-0.3.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|