kodit 0.2.8__py3-none-any.whl → 0.2.9__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 (34) hide show
  1. kodit/_version.py +2 -2
  2. kodit/application/factories/__init__.py +1 -0
  3. kodit/application/factories/code_indexing_factory.py +119 -0
  4. kodit/application/services/{indexing_application_service.py → code_indexing_application_service.py} +159 -198
  5. kodit/cli.py +199 -62
  6. kodit/domain/entities.py +7 -5
  7. kodit/domain/repositories.py +33 -0
  8. kodit/domain/services/bm25_service.py +14 -17
  9. kodit/domain/services/embedding_service.py +10 -14
  10. kodit/domain/services/snippet_service.py +198 -0
  11. kodit/domain/value_objects.py +301 -21
  12. kodit/infrastructure/bm25/local_bm25_repository.py +20 -12
  13. kodit/infrastructure/bm25/vectorchord_bm25_repository.py +31 -11
  14. kodit/infrastructure/cloning/metadata.py +1 -0
  15. kodit/infrastructure/embedding/embedding_providers/hash_embedding_provider.py +14 -25
  16. kodit/infrastructure/embedding/local_vector_search_repository.py +26 -38
  17. kodit/infrastructure/embedding/vectorchord_vector_search_repository.py +50 -35
  18. kodit/infrastructure/enrichment/enrichment_factory.py +1 -1
  19. kodit/infrastructure/indexing/indexing_factory.py +8 -91
  20. kodit/infrastructure/indexing/snippet_domain_service_factory.py +37 -0
  21. kodit/infrastructure/snippet_extraction/languages/java.scm +12 -0
  22. kodit/infrastructure/snippet_extraction/snippet_extraction_factory.py +3 -31
  23. kodit/infrastructure/sqlalchemy/embedding_repository.py +14 -3
  24. kodit/infrastructure/sqlalchemy/snippet_repository.py +174 -2
  25. kodit/mcp.py +61 -49
  26. {kodit-0.2.8.dist-info → kodit-0.2.9.dist-info}/METADATA +1 -1
  27. {kodit-0.2.8.dist-info → kodit-0.2.9.dist-info}/RECORD +30 -29
  28. kodit/application/commands/__init__.py +0 -1
  29. kodit/application/commands/snippet_commands.py +0 -22
  30. kodit/application/services/snippet_application_service.py +0 -149
  31. kodit/infrastructure/enrichment/legacy_enrichment_models.py +0 -42
  32. {kodit-0.2.8.dist-info → kodit-0.2.9.dist-info}/WHEEL +0 -0
  33. {kodit-0.2.8.dist-info → kodit-0.2.9.dist-info}/entry_points.txt +0 -0
  34. {kodit-0.2.8.dist-info → kodit-0.2.9.dist-info}/licenses/LICENSE +0 -0
@@ -82,7 +82,11 @@ class SqlAlchemyEmbeddingRepository:
82
82
  await self.session.delete(embedding)
83
83
 
84
84
  async def list_semantic_results(
85
- self, embedding_type: EmbeddingType, embedding: list[float], top_k: int = 10
85
+ self,
86
+ embedding_type: EmbeddingType,
87
+ embedding: list[float],
88
+ top_k: int = 10,
89
+ snippet_ids: list[int] | None = None,
86
90
  ) -> list[tuple[int, float]]:
87
91
  """List semantic results using cosine similarity.
88
92
 
@@ -93,13 +97,14 @@ class SqlAlchemyEmbeddingRepository:
93
97
  embedding_type: The type of embeddings to search
94
98
  embedding: The query embedding vector
95
99
  top_k: Number of results to return
100
+ snippet_ids: Optional list of snippet IDs to filter by
96
101
 
97
102
  Returns:
98
103
  List of (snippet_id, similarity_score) tuples, sorted by similarity
99
104
 
100
105
  """
101
106
  # Step 1: Fetch embeddings from database
102
- embeddings = await self._list_embedding_values(embedding_type)
107
+ embeddings = await self._list_embedding_values(embedding_type, snippet_ids)
103
108
  if not embeddings:
104
109
  return []
105
110
 
@@ -113,12 +118,13 @@ class SqlAlchemyEmbeddingRepository:
113
118
  return self._get_top_k_results(similarities, embeddings, top_k)
114
119
 
115
120
  async def _list_embedding_values(
116
- self, embedding_type: EmbeddingType
121
+ self, embedding_type: EmbeddingType, snippet_ids: list[int] | None = None
117
122
  ) -> list[tuple[int, list[float]]]:
118
123
  """List all embeddings of a given type from the database.
119
124
 
120
125
  Args:
121
126
  embedding_type: The type of embeddings to fetch
127
+ snippet_ids: Optional list of snippet IDs to filter by
122
128
 
123
129
  Returns:
124
130
  List of (snippet_id, embedding) tuples
@@ -128,6 +134,11 @@ class SqlAlchemyEmbeddingRepository:
128
134
  query = select(Embedding.snippet_id, Embedding.embedding).where(
129
135
  Embedding.type == embedding_type
130
136
  )
137
+
138
+ # Add snippet_ids filter if provided
139
+ if snippet_ids is not None:
140
+ query = query.where(Embedding.snippet_id.in_(snippet_ids))
141
+
131
142
  rows = await self.session.execute(query)
132
143
  return [tuple(row) for row in rows.all()] # Convert Row objects to tuples
133
144
 
@@ -1,12 +1,25 @@
1
1
  """SQLAlchemy implementation of snippet repository."""
2
2
 
3
3
  from collections.abc import Sequence
4
+ from pathlib import Path
4
5
 
5
- from sqlalchemy import delete, select
6
+ from sqlalchemy import delete, or_, select
6
7
  from sqlalchemy.ext.asyncio import AsyncSession
7
8
 
8
- from kodit.domain.entities import Snippet
9
+ from kodit.domain.entities import (
10
+ Author,
11
+ AuthorFileMapping,
12
+ Embedding,
13
+ File,
14
+ Snippet,
15
+ Source,
16
+ )
9
17
  from kodit.domain.repositories import SnippetRepository
18
+ from kodit.domain.value_objects import (
19
+ LanguageMapping,
20
+ MultiSearchRequest,
21
+ SnippetListItem,
22
+ )
10
23
 
11
24
 
12
25
  class SqlAlchemySnippetRepository(SnippetRepository):
@@ -75,5 +88,164 @@ class SqlAlchemySnippetRepository(SnippetRepository):
75
88
  index_id: The ID of the index to delete snippets for
76
89
 
77
90
  """
91
+ # First get all snippets for this index
92
+ snippets = await self.get_by_index(index_id)
93
+
94
+ # Delete all embeddings for these snippets, if there are any
95
+ for snippet in snippets:
96
+ query = delete(Embedding).where(Embedding.snippet_id == snippet.id)
97
+ await self.session.execute(query)
98
+
99
+ # Now delete the snippets
78
100
  query = delete(Snippet).where(Snippet.index_id == index_id)
79
101
  await self.session.execute(query)
102
+
103
+ async def list_snippets(
104
+ self, file_path: str | None = None, source_uri: str | None = None
105
+ ) -> Sequence[SnippetListItem]:
106
+ """List snippets with optional filtering by file path and source URI.
107
+
108
+ Args:
109
+ file_path: Optional file or directory path to filter by. Can be relative
110
+ (uri) or absolute (cloned_path).
111
+ source_uri: Optional source URI to filter by. If None, returns snippets from
112
+ all sources.
113
+
114
+ Returns:
115
+ A sequence of SnippetListItem instances matching the criteria
116
+
117
+ """
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
+ )
129
+
130
+ # Apply filters
131
+ if file_path is not None:
132
+ query = query.where(
133
+ or_(
134
+ File.cloned_path.like(f"%{file_path}%"),
135
+ File.uri.like(f"%{file_path}%"),
136
+ )
137
+ )
138
+
139
+ if source_uri is not None:
140
+ query = query.where(Source.uri == source_uri)
141
+
142
+ 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
+ ]
157
+
158
+ def _get_relative_path(self, file_path: str, source_path: str) -> str:
159
+ """Calculate the relative path of a file from the source root.
160
+
161
+ Args:
162
+ file_path: The full path to the file
163
+ source_path: The full path to the source root
164
+
165
+ Returns:
166
+ The relative path from the source root
167
+
168
+ """
169
+ try:
170
+ file_path_obj = Path(file_path)
171
+ source_path_obj = Path(source_path)
172
+ return str(file_path_obj.relative_to(source_path_obj))
173
+ except ValueError:
174
+ # If the file is not relative to the source, return the filename
175
+ return Path(file_path).name
176
+
177
+ async def search(self, request: MultiSearchRequest) -> Sequence[SnippetListItem]:
178
+ """Search snippets with filters.
179
+
180
+ Args:
181
+ request: The search request containing queries and optional filters.
182
+
183
+ Returns:
184
+ A sequence of SnippetListItem instances matching the search criteria.
185
+
186
+ """
187
+ # Build the base query with joins
188
+ query = (
189
+ select(
190
+ Snippet,
191
+ File.cloned_path,
192
+ Source.cloned_path.label("source_cloned_path"),
193
+ Source.uri.label("source_uri"),
194
+ )
195
+ .join(File, Snippet.file_id == File.id)
196
+ .join(Source, File.source_id == Source.id)
197
+ )
198
+
199
+ # Apply filters if provided
200
+ if request.filters:
201
+ filters = request.filters
202
+
203
+ # Language filter (using file extension)
204
+ if filters.language:
205
+ extensions = LanguageMapping.get_extensions_with_fallback(
206
+ filters.language
207
+ )
208
+ query = query.where(File.extension.in_(extensions))
209
+
210
+ # Author filter
211
+ if filters.author:
212
+ query = (
213
+ query.join(AuthorFileMapping, File.id == AuthorFileMapping.file_id)
214
+ .join(Author, AuthorFileMapping.author_id == Author.id)
215
+ .where(Author.name.ilike(f"%{filters.author}%"))
216
+ )
217
+
218
+ # Date filters
219
+ if filters.created_after:
220
+ query = query.where(Snippet.created_at >= filters.created_after)
221
+
222
+ if filters.created_before:
223
+ query = query.where(Snippet.created_at <= filters.created_before)
224
+
225
+ # Source repository filter
226
+ if filters.source_repo:
227
+ query = query.where(Source.uri.like(f"%{filters.source_repo}%"))
228
+
229
+ # Only apply top_k limit if there are no search queries
230
+ # This ensures that when used for pre-filtering (with search queries),
231
+ # all matching snippets are returned for the search services to consider
232
+ if request.top_k and not any(
233
+ [request.keywords, request.code_query, request.text_query]
234
+ ):
235
+ query = query.limit(request.top_k)
236
+
237
+ 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
+ ]
kodit/mcp.py CHANGED
@@ -1,4 +1,4 @@
1
- """MCP server implementation for kodit."""
1
+ """MCP server for kodit."""
2
2
 
3
3
  from collections.abc import AsyncIterator
4
4
  from contextlib import asynccontextmanager
@@ -12,21 +12,21 @@ from pydantic import Field
12
12
  from sqlalchemy.ext.asyncio import AsyncSession
13
13
 
14
14
  from kodit._version import version
15
- from kodit.application.services.snippet_application_service import (
16
- SnippetApplicationService,
15
+ from kodit.application.factories.code_indexing_factory import (
16
+ create_code_indexing_application_service,
17
17
  )
18
18
  from kodit.config import AppContext
19
19
  from kodit.database import Database
20
20
  from kodit.domain.services.source_service import SourceService
21
- from kodit.domain.value_objects import MultiSearchRequest, MultiSearchResult
22
- from kodit.infrastructure.indexing.indexing_factory import (
23
- create_indexing_application_service,
24
- )
25
- from kodit.infrastructure.snippet_extraction.snippet_extraction_factory import (
26
- create_snippet_extraction_domain_service,
27
- create_snippet_repositories,
21
+ from kodit.domain.value_objects import (
22
+ MultiSearchRequest,
23
+ MultiSearchResult,
24
+ SnippetSearchFilters,
28
25
  )
29
26
 
27
+ # Global database connection for MCP server
28
+ _mcp_db: Database | None = None
29
+
30
30
 
31
31
  @dataclass
32
32
  class MCPContext:
@@ -36,14 +36,11 @@ class MCPContext:
36
36
  app_context: AppContext
37
37
 
38
38
 
39
- _mcp_db: Database | None = None
40
-
41
-
42
39
  @asynccontextmanager
43
40
  async def mcp_lifespan(_: FastMCP) -> AsyncIterator[MCPContext]:
44
- """Lifespan for the MCP server.
41
+ """Lifespan context manager for the MCP server.
45
42
 
46
- The MCP server is running with a completely separate lifecycle and event loop from
43
+ This is called for each request. The MCP server is designed to work with both
47
44
  the CLI and the FastAPI server. Therefore, we must carefully reconstruct the
48
45
  application context. uvicorn does not pass through CLI args, so we must rely on
49
46
  parsing env vars set in the CLI.
@@ -74,35 +71,8 @@ mcp = FastMCP(
74
71
  )
75
72
 
76
73
 
77
- def create_snippet_application_service(
78
- session: AsyncSession,
79
- ) -> SnippetApplicationService:
80
- """Create a snippet application service with all dependencies.
81
-
82
- Args:
83
- session: SQLAlchemy session
84
-
85
- Returns:
86
- Configured snippet application service
87
-
88
- """
89
- # Create domain service
90
- snippet_extraction_service = create_snippet_extraction_domain_service()
91
-
92
- # Create repositories
93
- snippet_repository, file_repository = create_snippet_repositories(session)
94
-
95
- # Create application service
96
- return SnippetApplicationService(
97
- snippet_extraction_service=snippet_extraction_service,
98
- snippet_repository=snippet_repository,
99
- file_repository=file_repository,
100
- session=session,
101
- )
102
-
103
-
104
74
  @mcp.tool()
105
- async def search(
75
+ async def search( # noqa: PLR0913
106
76
  ctx: Context,
107
77
  user_intent: Annotated[
108
78
  str,
@@ -131,6 +101,39 @@ async def search(
131
101
  description="A list of keywords that are relevant to the desired outcome."
132
102
  ),
133
103
  ],
104
+ language: Annotated[
105
+ str | None,
106
+ Field(description="Filter by language (e.g., 'python', 'go', 'javascript')."),
107
+ ] = None,
108
+ author: Annotated[
109
+ str | None,
110
+ Field(description=("Filter to search for snippets by a specific author.")),
111
+ ] = None,
112
+ created_after: Annotated[
113
+ str | None,
114
+ Field(
115
+ description=(
116
+ "Filter for snippets created after this date (ISO format: YYYY-MM-DD)."
117
+ )
118
+ ),
119
+ ] = None,
120
+ created_before: Annotated[
121
+ str | None,
122
+ Field(
123
+ description=(
124
+ "Filter for snippets created before this date (ISO format: YYYY-MM-DD)."
125
+ )
126
+ ),
127
+ ] = None,
128
+ source_repo: Annotated[
129
+ str | None,
130
+ Field(
131
+ description=(
132
+ "Filter results by project source repository (e.g., "
133
+ "github.com/example/repo)"
134
+ )
135
+ ),
136
+ ] = None,
134
137
  ) -> str:
135
138
  """Search for pre-existing examples of relevant code.
136
139
 
@@ -162,21 +165,30 @@ async def search(
162
165
  clone_dir=mcp_context.app_context.get_clone_dir(),
163
166
  session_factory=lambda: mcp_context.session,
164
167
  )
165
- # Create snippet application service
166
- snippet_application_service = create_snippet_application_service(
167
- mcp_context.session
168
- )
169
- service = create_indexing_application_service(
168
+
169
+ # Use the unified application service
170
+ service = create_code_indexing_application_service(
170
171
  app_context=mcp_context.app_context,
171
172
  session=mcp_context.session,
172
173
  source_service=source_service,
173
- snippet_application_service=snippet_application_service,
174
+ )
175
+
176
+ log.debug("Searching for snippets")
177
+
178
+ # Create filters if any filter parameters are provided
179
+ filters = SnippetSearchFilters.from_cli_params(
180
+ language=language,
181
+ author=author,
182
+ created_after=created_after,
183
+ created_before=created_before,
184
+ source_repo=source_repo,
174
185
  )
175
186
 
176
187
  search_request = MultiSearchRequest(
177
188
  keywords=keywords,
178
189
  code_query="\n".join(related_file_contents),
179
190
  text_query=user_intent,
191
+ filters=filters,
180
192
  )
181
193
 
182
194
  log.debug("Searching for snippets")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kodit
3
- Version: 0.2.8
3
+ Version: 0.2.9
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/
@@ -1,42 +1,42 @@
1
1
  kodit/.gitignore,sha256=ztkjgRwL9Uud1OEi36hGQeDGk3OLK1NfDEO8YqGYy8o,11
2
2
  kodit/__init__.py,sha256=aEKHYninUq1yh6jaNfvJBYg-6fenpN132nJt1UU6Jxs,59
3
- kodit/_version.py,sha256=zkhRarrvPoGA1yWjS9_zVM80dWqpDesNn9DiHcF4JWM,511
3
+ kodit/_version.py,sha256=Iq6CyehddPOWDVsW9Hnb65BEkCEkAnt4bl0MAuqXKLA,511
4
4
  kodit/app.py,sha256=qKBWJ0VNSY_M6G3VFfAQ0133q5bnS99cUFD0p396taw,1032
5
- kodit/cli.py,sha256=JnhTlG1s04O0m8AzsBdrwP8T_BqSZMPXnRLvI7T_Gxc,12004
5
+ kodit/cli.py,sha256=BbJU4ne5bQnl3NCB2AWr_j9E7pTwc1dK_2oHkbnGbBU,16300
6
6
  kodit/config.py,sha256=3yh7hfLSILjZK_qJMhcExwRcrWJ0b5Eb1JjjOvMPJZo,4146
7
7
  kodit/database.py,sha256=kI9yBm4uunsgV4-QeVoCBL0wLzU4kYmYv5qZilGnbPE,1740
8
8
  kodit/log.py,sha256=sHPHYetlMcKTor2VaFLMyao1_fZ_xhuzqXCAt5F5UMU,8575
9
- kodit/mcp.py,sha256=bUvG4by2CDN3QSkKNUer0yxpzAGbq-hg8HTU7S5fMv4,6217
9
+ kodit/mcp.py,sha256=onmUbZ1-mnBkQOUF6KymNZMiTo19tt6pDOmyBQEz8Jg,6454
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
- kodit/application/commands/__init__.py,sha256=AOVs25fwboBnMCWdgDB7fPbAYTljurAPVMkATIGRKuk,38
14
- kodit/application/commands/snippet_commands.py,sha256=WzRrnJOnLpIK8-wvN7c-ecGs_4LosQ_jR30dQkFqFBY,600
13
+ kodit/application/factories/__init__.py,sha256=bU5CvEnaBePZ7JbkCOp1MGTNP752bnU2uEqmfy5FdRk,37
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/indexing_application_service.py,sha256=tfdEiFTVvqkZQ6I_ZkW5IECQJHZi35OJX4bj96lkZrc,14455
17
- kodit/application/services/snippet_application_service.py,sha256=2qW7ZIUQ63bdtAngf6xgQ09N-vygNpd12sXwyKwOcSs,5037
16
+ kodit/application/services/code_indexing_application_service.py,sha256=EHg2X3tN2nU8XBvIoB1xqV7jGypACmawiBmg7HZ0lcs,12537
18
17
  kodit/domain/__init__.py,sha256=TCpg4Xx-oF4mKV91lo4iXqMEfBT1OoRSYnbG-zVWolA,66
19
- kodit/domain/entities.py,sha256=6XVuwDIQjkBw5Bm51io5ZUxB6_O4A774CDke2bfKWTY,5584
18
+ kodit/domain/entities.py,sha256=fErA9ZTAqlofkqhBte8FOnV0PHf1MUORb37bW0-Dgc4,5624
20
19
  kodit/domain/enums.py,sha256=Ik_h3D3eZ0FsSlPsU0ikm-Yv3Rmvzicffi9yBn19UIE,191
21
20
  kodit/domain/errors.py,sha256=yIsgCjM_yOFIg8l7l-t7jM8pgeAX4cfPq0owf7iz3DA,106
22
21
  kodit/domain/interfaces.py,sha256=Jkd0Ob4qSvhZHI9jRPFQ1n5Cv0SvU-y3Z-HCw2ikc4I,742
23
- kodit/domain/repositories.py,sha256=bdKxSKGI6XzrpzeKcv-NDV2JBirbEMRK-Y4UCZmDtoY,2706
24
- kodit/domain/value_objects.py,sha256=4Vs7Uk1wQgTjnCkZlOlw7E1Q8NiyAmBpFv38Lhs3WZ0,3869
22
+ kodit/domain/repositories.py,sha256=KAIx_-qZD68pAByc1JNVxSCRLjseayHKn5ykqsE6uWw,3781
23
+ kodit/domain/value_objects.py,sha256=iIFtn9D75NLx0NjHrxXvwTO6Z06Lrx0gKFkezzlwTGc,12777
25
24
  kodit/domain/services/__init__.py,sha256=Q1GhCK_PqKHYwYE4tkwDz5BIyXkJngLBBOHhzvX8nzo,42
26
- kodit/domain/services/bm25_service.py,sha256=N3kAcsRjxn22bbYNRhGu-VY6fnLsE-M2WyzEIk7Im3s,3809
27
- kodit/domain/services/embedding_service.py,sha256=ZgC4n7vuqwW_NOCTRiNxezmCs73OB-G1dTDRGYorGGo,4588
25
+ kodit/domain/services/bm25_service.py,sha256=nsfTan3XtDwXuuAu1LUv-6Jukm6qFKVqqCVymjyepZQ,3625
26
+ kodit/domain/services/embedding_service.py,sha256=Wh6Y2NR_GRnud8dq1Q7S6F40aNe-S2UyD5Nqz9LChTM,4507
28
27
  kodit/domain/services/enrichment_service.py,sha256=XsXg3nV-KN4rqtC7Zro_ZiZ6RSq-1eA1MG6IDzFGyBA,1316
29
28
  kodit/domain/services/ignore_service.py,sha256=boEN-IRLmUtwO9ZnuACaVFZbIKrtUG8YwnsXKEDIG28,1136
30
29
  kodit/domain/services/indexing_service.py,sha256=FEizu2GkvZA32xHOYXXch0LuHoWg6Z-BbJMPjZslzjc,5853
31
30
  kodit/domain/services/snippet_extraction_service.py,sha256=QW_99bXWpr8g6ZI-hp4Aj57VCSrUf71dLwQca5T6pyg,3065
31
+ kodit/domain/services/snippet_service.py,sha256=Mefq6IbMEv_O9YZeHoMprKKdn1K1hixA9MLCeq_qZ64,6485
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
35
35
  kodit/infrastructure/bm25/bm25_factory.py,sha256=I4eo7qRslnyXIRkBf-StZ5ga2Evrr5J5YFocTChFD3g,884
36
- kodit/infrastructure/bm25/local_bm25_repository.py,sha256=HjhzY24FU5R81qfzXfzJl14E3JafLO0l0ug6psutErQ,4276
37
- kodit/infrastructure/bm25/vectorchord_bm25_repository.py,sha256=0Db9XWFjiS4TFrsNazBMo6FxhX9SxLGNVQB0rDHqnL4,6875
36
+ kodit/infrastructure/bm25/local_bm25_repository.py,sha256=B1ggfHdjC9sFIh62MmSul2tsutWsWFQx5S1Xn07X_I8,4531
37
+ kodit/infrastructure/bm25/vectorchord_bm25_repository.py,sha256=Jyic55V-38XeTad462Ge751iKyc0X8RNVBM9pr_DVJk,7439
38
38
  kodit/infrastructure/cloning/__init__.py,sha256=IzIvX-yeRRFZ-lfvPVSEe_qXszO6DGQdjKwwDigexyQ,30
39
- kodit/infrastructure/cloning/metadata.py,sha256=C5LLmsUzi29RhSbzVDNqiShbekg7qdp1ihGUyFXy5yM,4277
39
+ kodit/infrastructure/cloning/metadata.py,sha256=Z8Vtr7Nl5UuS7NZYf9Aooedr8SMk4nEkBjNUPyaPMVQ,4342
40
40
  kodit/infrastructure/cloning/folder/__init__.py,sha256=w6ykrVtbYJlUDEXAjqgf6w2rMsUMCrrpIbl3QMjubgY,37
41
41
  kodit/infrastructure/cloning/folder/factory.py,sha256=vl1hwnYA7lczjotn2fahJQAt7IK96CSArx8cSaRFKeY,4242
42
42
  kodit/infrastructure/cloning/folder/working_copy.py,sha256=FPhwzuPj40yGoYvwcm9VG8mv8MbJxwfby_N5JS-_daA,1154
@@ -45,16 +45,15 @@ kodit/infrastructure/cloning/git/factory.py,sha256=cY0cxapp0NCvjMRpzesW_qRzbWbh-
45
45
  kodit/infrastructure/cloning/git/working_copy.py,sha256=IwXQ0Ta59ykVkrxAyhJk0ijOO6aaub7UI-bXFDyNT0k,1562
46
46
  kodit/infrastructure/embedding/__init__.py,sha256=F-8nLlWAerYJ0MOIA4tbXHLan8bW5rRR84vzxx6tRKI,39
47
47
  kodit/infrastructure/embedding/embedding_factory.py,sha256=1AypjhWJGxvLnZt1SEH_FHPk9P0Vkt9fXdSGzFPp2ow,3432
48
- kodit/infrastructure/embedding/local_vector_search_repository.py,sha256=UO8A3Eb_djFVrWKKSukAo4u7k8djDD1SlOPHk2pP9ps,3921
49
- kodit/infrastructure/embedding/vectorchord_vector_search_repository.py,sha256=7P5Uz8heQOi-x0k5wrNSE2biiy8FaC4VTfX0vPdfy6Y,7638
48
+ kodit/infrastructure/embedding/local_vector_search_repository.py,sha256=cEclb0tllFDsFBMKUUh8sL4FXFId1Nymh8WTqIORfow,3486
49
+ kodit/infrastructure/embedding/vectorchord_vector_search_repository.py,sha256=BFB9txeoNKHkuB0PJA-mZ2zi78zJogW9XvAQzIFeroA,8011
50
50
  kodit/infrastructure/embedding/embedding_providers/__init__.py,sha256=qeZ-oAIAxMl5QqebGtO1lq-tHjl_ucAwOXePklcwwGk,34
51
51
  kodit/infrastructure/embedding/embedding_providers/batching.py,sha256=a8CL9PX2VLmbeg616fc_lQzfC4BWTVn32m4SEhXpHxc,3279
52
- kodit/infrastructure/embedding/embedding_providers/hash_embedding_provider.py,sha256=HfilGGJ-hiw3mHOj6Zf7jlouSIIDaDFqwPe-4vKPREE,2611
52
+ kodit/infrastructure/embedding/embedding_providers/hash_embedding_provider.py,sha256=V6OdCuWyQQOvo3OJGRi-gBKDApIcrELydFg7T696P5s,2257
53
53
  kodit/infrastructure/embedding/embedding_providers/local_embedding_provider.py,sha256=U5fc8jUP8wF-nq1zo-CfSbJbLQyE-3muKmRCaYGtytk,4387
54
54
  kodit/infrastructure/embedding/embedding_providers/openai_embedding_provider.py,sha256=LIK9Iir7geraZoqiaNbeHv3hXrghZRDpYGJDEjZaqzQ,4086
55
55
  kodit/infrastructure/enrichment/__init__.py,sha256=8acZKNzql8Fs0lceFu9U3KoUrOptRBtVIxr_Iw6lz3Y,40
56
- kodit/infrastructure/enrichment/enrichment_factory.py,sha256=4saTSHJY9o1LC4wkkL0I_fCsLPh0-Wb7GdZt9-1lXVA,1827
57
- kodit/infrastructure/enrichment/legacy_enrichment_models.py,sha256=YS-sNEH-b4hoy2ThcqhfkiefsftUsFgIjZjbvfU7j6w,1035
56
+ kodit/infrastructure/enrichment/enrichment_factory.py,sha256=Pz0Rb1I68udL_zXY3KvJ3LR3aK_9mdF1nMRGQUu4lM0,1828
58
57
  kodit/infrastructure/enrichment/local_enrichment_provider.py,sha256=8CATNtgMHgBRt24GrYEwaZKrroNCxMJS-39xQJoG3N0,3818
59
58
  kodit/infrastructure/enrichment/null_enrichment_provider.py,sha256=5Ksyxl3qDLxUjmOeIdHZ0UAIULy7RcbLXJoT7_CNXoQ,775
60
59
  kodit/infrastructure/enrichment/openai_enrichment_provider.py,sha256=fenq4HiJ2UkrzsE2D0A0qpmro38z9mKaIzKKU5v7hnY,3189
@@ -65,22 +64,24 @@ kodit/infrastructure/ignore/ignore_pattern_provider.py,sha256=9m2XCsgW87UBTfzHr6
65
64
  kodit/infrastructure/indexing/__init__.py,sha256=7UPRa2jwCAsa0Orsp6PqXSF8iIXJVzXHMFmrKkI9yH8,38
66
65
  kodit/infrastructure/indexing/fusion_service.py,sha256=mXUUcx3-8e75mWkxXMfl30HIoFXrTNHzB1w90MmEbak,1806
67
66
  kodit/infrastructure/indexing/index_repository.py,sha256=4aSCBE_Gn9ihOx_kXOpUTTIv6_Q71-VRFHEBgpWaAEw,8906
68
- kodit/infrastructure/indexing/indexing_factory.py,sha256=KHA8c0XR9QrgqSR6gRUQk9wp6md97_oA1lwZFzoJAtk,3964
67
+ kodit/infrastructure/indexing/indexing_factory.py,sha256=LPjPCps_wJ9M_fZGRP02bfc2pvYc50ZSTYI99XwRRPg,918
68
+ kodit/infrastructure/indexing/snippet_domain_service_factory.py,sha256=OMp9qRJSAT3oWqsMyF1fgI2Mb_G-SA22crbbaCb7c-Q,1253
69
69
  kodit/infrastructure/snippet_extraction/__init__.py,sha256=v6KqrRDjSj0nt87m7UwRGx2GN_fz_14VWq9Q0uABR_s,54
70
70
  kodit/infrastructure/snippet_extraction/language_detection_service.py,sha256=Lo9xPLVia-70yP9gzyH4cQcBQzsp7WXjGOa5NBggScg,1158
71
- kodit/infrastructure/snippet_extraction/snippet_extraction_factory.py,sha256=LGbm614KCPNsM9K8r1z-E763NyAMIZA9ETJ_C61EknA,2759
71
+ kodit/infrastructure/snippet_extraction/snippet_extraction_factory.py,sha256=YA72kneJhR1nvgbYwH7fFAvTSMJw9bDoLGLhAAVpmq0,2272
72
72
  kodit/infrastructure/snippet_extraction/snippet_query_provider.py,sha256=pLjFExJx5bX4s6a_mMA4-AfjtfBaC2wjTV3GjYD2HVE,1284
73
73
  kodit/infrastructure/snippet_extraction/tree_sitter_snippet_extractor.py,sha256=8B14jy_QS9SBA5jNpLtSSOayKP1WgMeCQEsZPuyAs8o,6190
74
74
  kodit/infrastructure/snippet_extraction/languages/csharp.scm,sha256=gbBN4RiV1FBuTJF6orSnDFi8H9JwTw-d4piLJYsWUsc,222
75
75
  kodit/infrastructure/snippet_extraction/languages/go.scm,sha256=SEX9mTOrhP2KiQW7oflDKkd21u5dK56QbJ4LvTDxY8A,533
76
+ kodit/infrastructure/snippet_extraction/languages/java.scm,sha256=kSEZT0QJAuhT7WpR2PklYiCX-03qRRpCAlcxfIbXPt4,227
76
77
  kodit/infrastructure/snippet_extraction/languages/javascript.scm,sha256=Ini5TsVNmcBKQ8aL46a5Id9ut0g9UdmvmVqdMqRJtFk,446
77
78
  kodit/infrastructure/snippet_extraction/languages/python.scm,sha256=ee85R9PBzwye3IMTE7-iVoKWd_ViU3EJISTyrFGrVeo,429
78
79
  kodit/infrastructure/snippet_extraction/languages/typescript.scm,sha256=U-ujbbv4tylbUBj9wuhL-e5cW6hmgPCNs4xrIX3r_hE,448
79
80
  kodit/infrastructure/sqlalchemy/__init__.py,sha256=UXPMSF_hgWaqr86cawRVqM8XdVNumQyyK5B8B97GnlA,33
80
- kodit/infrastructure/sqlalchemy/embedding_repository.py,sha256=dCCRV5rD8T5xBksPKvdr-z4F72WKo4-dH9mXazDByXQ,7476
81
+ kodit/infrastructure/sqlalchemy/embedding_repository.py,sha256=u29RVt4W0WqHj6TkrydMHw2iF5_jERHtlidDjWRQvqc,7886
81
82
  kodit/infrastructure/sqlalchemy/file_repository.py,sha256=9_kXHJ1YiWA1ingpvBNq8cuxkMu59PHwl_m9_Ttnq2o,2353
82
83
  kodit/infrastructure/sqlalchemy/repository.py,sha256=EpZnOjR3wfPEqIauWw_KczpkSqBQPTq5sIyCpJCuW2w,4565
83
- kodit/infrastructure/sqlalchemy/snippet_repository.py,sha256=RYhBnyvvBo-6obrUkds6BhEjchs4HYQL8k9x0Cy7BtM,2430
84
+ kodit/infrastructure/sqlalchemy/snippet_repository.py,sha256=4Hb_K7rPevzCgqZDIJPBTM3lzF36QXjmUES9WwW9E2k,8252
84
85
  kodit/infrastructure/ui/__init__.py,sha256=CzbLOBwIZ6B6iAHEd1L8cIBydCj-n_kobxJAhz2I9_Y,32
85
86
  kodit/infrastructure/ui/progress.py,sha256=BaAeMEgXlSSb0c_t_NPxnThIktkzzCS9kegb5ExULJs,4791
86
87
  kodit/infrastructure/ui/spinner.py,sha256=GcP115qtR0VEnGfMEtsGoAUpRzVGUSfiUXfoJJERngA,2357
@@ -93,8 +94,8 @@ kodit/migrations/versions/85155663351e_initial.py,sha256=Cg7zlF871o9ShV5rQMQ1v7h
93
94
  kodit/migrations/versions/9e53ea8bb3b0_add_authors.py,sha256=a32Zm8KUQyiiLkjKNPYdaJDgjW6VsV-GhaLnPnK_fpI,3884
94
95
  kodit/migrations/versions/__init__.py,sha256=9-lHzptItTzq_fomdIRBegQNm4Znx6pVjwD4MiqRIdo,36
95
96
  kodit/migrations/versions/c3f5137d30f5_index_all_the_things.py,sha256=rI8LmjF-I2OMxZ2nOIF_NRmqOLXe45hL_iz_nx97DTQ,1680
96
- kodit-0.2.8.dist-info/METADATA,sha256=uxuFXAnAellsx3-Isah750l4jBAme9DT2imIzjjBmHg,5867
97
- kodit-0.2.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
98
- kodit-0.2.8.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
99
- kodit-0.2.8.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
100
- kodit-0.2.8.dist-info/RECORD,,
97
+ kodit-0.2.9.dist-info/METADATA,sha256=s454eRkiLIe50_PWl9sODi3_9NGtt-Q6pFNofPywwLA,5867
98
+ kodit-0.2.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
99
+ kodit-0.2.9.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
100
+ kodit-0.2.9.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
101
+ kodit-0.2.9.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- """Application commands for Kodit."""
@@ -1,22 +0,0 @@
1
- """Application commands for snippet operations."""
2
-
3
- from dataclasses import dataclass
4
- from pathlib import Path
5
-
6
- from kodit.domain.enums import SnippetExtractionStrategy
7
-
8
-
9
- @dataclass
10
- class ExtractSnippetsCommand:
11
- """Application command for extracting snippets from files."""
12
-
13
- file_path: Path
14
- strategy: SnippetExtractionStrategy = SnippetExtractionStrategy.METHOD_BASED
15
-
16
-
17
- @dataclass
18
- class CreateIndexSnippetsCommand:
19
- """Application command for creating snippets for an entire index."""
20
-
21
- index_id: int
22
- strategy: SnippetExtractionStrategy = SnippetExtractionStrategy.METHOD_BASED