kodit 0.2.8__py3-none-any.whl → 0.3.0__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 (37) hide show
  1. kodit/_version.py +2 -2
  2. kodit/app.py +36 -1
  3. kodit/application/factories/__init__.py +1 -0
  4. kodit/application/factories/code_indexing_factory.py +119 -0
  5. kodit/application/services/{indexing_application_service.py → code_indexing_application_service.py} +159 -198
  6. kodit/cli.py +214 -62
  7. kodit/config.py +40 -3
  8. kodit/domain/entities.py +7 -5
  9. kodit/domain/repositories.py +33 -0
  10. kodit/domain/services/bm25_service.py +14 -17
  11. kodit/domain/services/embedding_service.py +10 -14
  12. kodit/domain/services/snippet_service.py +198 -0
  13. kodit/domain/value_objects.py +301 -21
  14. kodit/infrastructure/bm25/local_bm25_repository.py +20 -12
  15. kodit/infrastructure/bm25/vectorchord_bm25_repository.py +31 -11
  16. kodit/infrastructure/cloning/metadata.py +1 -0
  17. kodit/infrastructure/embedding/embedding_providers/hash_embedding_provider.py +14 -25
  18. kodit/infrastructure/embedding/local_vector_search_repository.py +26 -38
  19. kodit/infrastructure/embedding/vectorchord_vector_search_repository.py +50 -35
  20. kodit/infrastructure/enrichment/enrichment_factory.py +1 -1
  21. kodit/infrastructure/indexing/auto_indexing_service.py +84 -0
  22. kodit/infrastructure/indexing/indexing_factory.py +8 -91
  23. kodit/infrastructure/indexing/snippet_domain_service_factory.py +37 -0
  24. kodit/infrastructure/snippet_extraction/languages/java.scm +12 -0
  25. kodit/infrastructure/snippet_extraction/snippet_extraction_factory.py +3 -31
  26. kodit/infrastructure/sqlalchemy/embedding_repository.py +14 -3
  27. kodit/infrastructure/sqlalchemy/snippet_repository.py +174 -2
  28. kodit/mcp.py +61 -49
  29. {kodit-0.2.8.dist-info → kodit-0.3.0.dist-info}/METADATA +1 -1
  30. {kodit-0.2.8.dist-info → kodit-0.3.0.dist-info}/RECORD +33 -31
  31. kodit/application/commands/__init__.py +0 -1
  32. kodit/application/commands/snippet_commands.py +0 -22
  33. kodit/application/services/snippet_application_service.py +0 -149
  34. kodit/infrastructure/enrichment/legacy_enrichment_models.py +0 -42
  35. {kodit-0.2.8.dist-info → kodit-0.3.0.dist-info}/WHEEL +0 -0
  36. {kodit-0.2.8.dist-info → kodit-0.3.0.dist-info}/entry_points.txt +0 -0
  37. {kodit-0.2.8.dist-info → kodit-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -9,6 +9,7 @@ from kodit.domain.repositories import FileRepository, SnippetRepository
9
9
  from kodit.domain.services.snippet_extraction_service import (
10
10
  SnippetExtractionDomainService,
11
11
  )
12
+ from kodit.domain.value_objects import LanguageMapping
12
13
  from kodit.infrastructure.snippet_extraction.language_detection_service import (
13
14
  FileSystemLanguageDetectionService,
14
15
  )
@@ -31,37 +32,8 @@ def create_snippet_extraction_domain_service() -> SnippetExtractionDomainService
31
32
  Configured snippet extraction domain service
32
33
 
33
34
  """
34
- # Language mapping from the existing languages module
35
- language_map = {
36
- # JavaScript/TypeScript
37
- "js": "javascript",
38
- "jsx": "javascript",
39
- "ts": "typescript",
40
- "tsx": "typescript",
41
- # Python
42
- "py": "python",
43
- # Rust
44
- "rs": "rust",
45
- # Go
46
- "go": "go",
47
- # C/C++
48
- "cpp": "cpp",
49
- "hpp": "cpp",
50
- "c": "c",
51
- "h": "c",
52
- # C#
53
- "cs": "csharp",
54
- # Ruby
55
- "rb": "ruby",
56
- # Java
57
- "java": "java",
58
- # PHP
59
- "php": "php",
60
- # Swift
61
- "swift": "swift",
62
- # Kotlin
63
- "kt": "kotlin",
64
- }
35
+ # Use the unified language mapping from the domain layer
36
+ language_map = LanguageMapping.get_extension_to_language_map()
65
37
 
66
38
  # Create infrastructure services
67
39
  language_detector = FileSystemLanguageDetectionService(language_map)
@@ -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.3.0
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
4
- kodit/app.py,sha256=qKBWJ0VNSY_M6G3VFfAQ0133q5bnS99cUFD0p396taw,1032
5
- kodit/cli.py,sha256=JnhTlG1s04O0m8AzsBdrwP8T_BqSZMPXnRLvI7T_Gxc,12004
6
- kodit/config.py,sha256=3yh7hfLSILjZK_qJMhcExwRcrWJ0b5Eb1JjjOvMPJZo,4146
3
+ kodit/_version.py,sha256=AGmG_Lx0-9ztFw_7d9mYbaYuC-2abxE1oXOUNAY29YY,511
4
+ kodit/app.py,sha256=uv67TE83fZE7wrA7cz-sKosFrAXlKRr1B7fT-X_gMZQ,2103
5
+ kodit/cli.py,sha256=ihecBP7Og0F-wXYZ63TMeYzuqgFpfd7O-g4NRB3pufo,16864
6
+ kodit/config.py,sha256=myWtVujjd7xQh3tPK_zGC1L5D5PYoPknYvUBoMLJ1kM,5414
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
@@ -63,24 +62,27 @@ kodit/infrastructure/git/git_utils.py,sha256=2DH6cyTjDRwFfL5Bzt1y2w0DwHZNypbC6R0
63
62
  kodit/infrastructure/ignore/__init__.py,sha256=VzFv8XOzHmsu0MEGnWVSF6KsgqLBmvHlRqAkT1Xb1MY,36
64
63
  kodit/infrastructure/ignore/ignore_pattern_provider.py,sha256=9m2XCsgW87UBTfzHr6Z0Ns6WpzwkLir3zyBY3PwsgXk,2225
65
64
  kodit/infrastructure/indexing/__init__.py,sha256=7UPRa2jwCAsa0Orsp6PqXSF8iIXJVzXHMFmrKkI9yH8,38
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
67
  kodit/infrastructure/indexing/index_repository.py,sha256=4aSCBE_Gn9ihOx_kXOpUTTIv6_Q71-VRFHEBgpWaAEw,8906
68
- kodit/infrastructure/indexing/indexing_factory.py,sha256=KHA8c0XR9QrgqSR6gRUQk9wp6md97_oA1lwZFzoJAtk,3964
68
+ kodit/infrastructure/indexing/indexing_factory.py,sha256=LPjPCps_wJ9M_fZGRP02bfc2pvYc50ZSTYI99XwRRPg,918
69
+ kodit/infrastructure/indexing/snippet_domain_service_factory.py,sha256=OMp9qRJSAT3oWqsMyF1fgI2Mb_G-SA22crbbaCb7c-Q,1253
69
70
  kodit/infrastructure/snippet_extraction/__init__.py,sha256=v6KqrRDjSj0nt87m7UwRGx2GN_fz_14VWq9Q0uABR_s,54
70
71
  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
72
+ kodit/infrastructure/snippet_extraction/snippet_extraction_factory.py,sha256=YA72kneJhR1nvgbYwH7fFAvTSMJw9bDoLGLhAAVpmq0,2272
72
73
  kodit/infrastructure/snippet_extraction/snippet_query_provider.py,sha256=pLjFExJx5bX4s6a_mMA4-AfjtfBaC2wjTV3GjYD2HVE,1284
73
74
  kodit/infrastructure/snippet_extraction/tree_sitter_snippet_extractor.py,sha256=8B14jy_QS9SBA5jNpLtSSOayKP1WgMeCQEsZPuyAs8o,6190
74
75
  kodit/infrastructure/snippet_extraction/languages/csharp.scm,sha256=gbBN4RiV1FBuTJF6orSnDFi8H9JwTw-d4piLJYsWUsc,222
75
76
  kodit/infrastructure/snippet_extraction/languages/go.scm,sha256=SEX9mTOrhP2KiQW7oflDKkd21u5dK56QbJ4LvTDxY8A,533
77
+ kodit/infrastructure/snippet_extraction/languages/java.scm,sha256=kSEZT0QJAuhT7WpR2PklYiCX-03qRRpCAlcxfIbXPt4,227
76
78
  kodit/infrastructure/snippet_extraction/languages/javascript.scm,sha256=Ini5TsVNmcBKQ8aL46a5Id9ut0g9UdmvmVqdMqRJtFk,446
77
79
  kodit/infrastructure/snippet_extraction/languages/python.scm,sha256=ee85R9PBzwye3IMTE7-iVoKWd_ViU3EJISTyrFGrVeo,429
78
80
  kodit/infrastructure/snippet_extraction/languages/typescript.scm,sha256=U-ujbbv4tylbUBj9wuhL-e5cW6hmgPCNs4xrIX3r_hE,448
79
81
  kodit/infrastructure/sqlalchemy/__init__.py,sha256=UXPMSF_hgWaqr86cawRVqM8XdVNumQyyK5B8B97GnlA,33
80
- kodit/infrastructure/sqlalchemy/embedding_repository.py,sha256=dCCRV5rD8T5xBksPKvdr-z4F72WKo4-dH9mXazDByXQ,7476
82
+ kodit/infrastructure/sqlalchemy/embedding_repository.py,sha256=u29RVt4W0WqHj6TkrydMHw2iF5_jERHtlidDjWRQvqc,7886
81
83
  kodit/infrastructure/sqlalchemy/file_repository.py,sha256=9_kXHJ1YiWA1ingpvBNq8cuxkMu59PHwl_m9_Ttnq2o,2353
82
84
  kodit/infrastructure/sqlalchemy/repository.py,sha256=EpZnOjR3wfPEqIauWw_KczpkSqBQPTq5sIyCpJCuW2w,4565
83
- kodit/infrastructure/sqlalchemy/snippet_repository.py,sha256=RYhBnyvvBo-6obrUkds6BhEjchs4HYQL8k9x0Cy7BtM,2430
85
+ kodit/infrastructure/sqlalchemy/snippet_repository.py,sha256=4Hb_K7rPevzCgqZDIJPBTM3lzF36QXjmUES9WwW9E2k,8252
84
86
  kodit/infrastructure/ui/__init__.py,sha256=CzbLOBwIZ6B6iAHEd1L8cIBydCj-n_kobxJAhz2I9_Y,32
85
87
  kodit/infrastructure/ui/progress.py,sha256=BaAeMEgXlSSb0c_t_NPxnThIktkzzCS9kegb5ExULJs,4791
86
88
  kodit/infrastructure/ui/spinner.py,sha256=GcP115qtR0VEnGfMEtsGoAUpRzVGUSfiUXfoJJERngA,2357
@@ -93,8 +95,8 @@ kodit/migrations/versions/85155663351e_initial.py,sha256=Cg7zlF871o9ShV5rQMQ1v7h
93
95
  kodit/migrations/versions/9e53ea8bb3b0_add_authors.py,sha256=a32Zm8KUQyiiLkjKNPYdaJDgjW6VsV-GhaLnPnK_fpI,3884
94
96
  kodit/migrations/versions/__init__.py,sha256=9-lHzptItTzq_fomdIRBegQNm4Znx6pVjwD4MiqRIdo,36
95
97
  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,,
98
+ kodit-0.3.0.dist-info/METADATA,sha256=7VZ989c731WalePCDWB1KSIUKJ9vS5hcgYVuI2Souiw,5867
99
+ kodit-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
100
+ kodit-0.3.0.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
101
+ kodit-0.3.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
102
+ kodit-0.3.0.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