kodit 0.2.2__py3-none-any.whl → 0.2.4__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 (29) hide show
  1. kodit/_version.py +2 -2
  2. kodit/app.py +6 -0
  3. kodit/cli.py +8 -2
  4. kodit/embedding/embedding_factory.py +11 -0
  5. kodit/embedding/embedding_provider/embedding_provider.py +42 -14
  6. kodit/embedding/embedding_provider/hash_embedding_provider.py +16 -7
  7. kodit/embedding/embedding_provider/local_embedding_provider.py +43 -11
  8. kodit/embedding/embedding_provider/openai_embedding_provider.py +18 -22
  9. kodit/embedding/local_vector_search_service.py +46 -13
  10. kodit/embedding/vector_search_service.py +18 -1
  11. kodit/embedding/vectorchord_vector_search_service.py +63 -16
  12. kodit/enrichment/enrichment_factory.py +3 -0
  13. kodit/enrichment/enrichment_provider/enrichment_provider.py +21 -1
  14. kodit/enrichment/enrichment_provider/local_enrichment_provider.py +39 -28
  15. kodit/enrichment/enrichment_provider/openai_enrichment_provider.py +25 -27
  16. kodit/enrichment/enrichment_service.py +19 -7
  17. kodit/indexing/indexing_service.py +50 -23
  18. kodit/log.py +126 -24
  19. kodit/migrations/versions/9e53ea8bb3b0_add_authors.py +103 -0
  20. kodit/source/source_factories.py +356 -0
  21. kodit/source/source_models.py +17 -5
  22. kodit/source/source_repository.py +49 -20
  23. kodit/source/source_service.py +41 -218
  24. {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/METADATA +2 -2
  25. {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/RECORD +28 -27
  26. kodit/migrations/versions/42e836b21102_add_authors.py +0 -64
  27. {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/WHEEL +0 -0
  28. {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/entry_points.txt +0 -0
  29. {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/licenses/LICENSE +0 -0
@@ -106,35 +106,64 @@ class SourceRepository:
106
106
  result = await self.session.execute(query)
107
107
  return result.scalar_one_or_none()
108
108
 
109
- async def get_or_create_author(self, name: str, email: str) -> Author:
110
- """Get or create an author by name and email.
109
+ async def get_author_by_email(self, email: str) -> Author | None:
110
+ """Get an author by email."""
111
+ query = select(Author).where(Author.email == email)
112
+ result = await self.session.execute(query)
113
+ return result.scalar_one_or_none()
114
+
115
+ async def upsert_author(self, author: Author) -> Author:
116
+ """Create a new author or return existing one if email already exists.
111
117
 
112
118
  Args:
113
- name: The name of the author.
114
- email: The email of the author.
119
+ author: The Author instance to upsert.
120
+
121
+ Returns:
122
+ The existing Author if one with the same email exists, otherwise the newly
123
+ created Author.
115
124
 
116
125
  """
117
- query = select(Author).where(Author.name == name, Author.email == email)
126
+ # First check if author already exists with same name and email
127
+ query = select(Author).where(
128
+ Author.name == author.name, Author.email == author.email
129
+ )
118
130
  result = await self.session.execute(query)
119
- author = result.scalar_one_or_none()
120
- if not author:
121
- author = Author(name=name, email=email)
122
- self.session.add(author)
123
- await self.session.commit()
131
+ existing_author = result.scalar_one_or_none()
132
+
133
+ if existing_author:
134
+ return existing_author
135
+
136
+ # Author doesn't exist, create new one
137
+ self.session.add(author)
138
+ await self.session.commit()
124
139
  return author
125
140
 
126
- async def get_or_create_author_file_mapping(
127
- self, author_id: int, file_id: int
141
+ async def upsert_author_file_mapping(
142
+ self, mapping: AuthorFileMapping
128
143
  ) -> AuthorFileMapping:
129
- """Create a new author file mapping record in the database."""
144
+ """Create a new author file mapping or return existing one if already exists."""
145
+ # First check if mapping already exists with same author_id and file_id
130
146
  query = select(AuthorFileMapping).where(
131
- AuthorFileMapping.author_id == author_id,
132
- AuthorFileMapping.file_id == file_id,
147
+ AuthorFileMapping.author_id == mapping.author_id,
148
+ AuthorFileMapping.file_id == mapping.file_id,
133
149
  )
134
150
  result = await self.session.execute(query)
135
- mapping = result.scalar_one_or_none()
136
- if not mapping:
137
- mapping = AuthorFileMapping(author_id=author_id, file_id=file_id)
138
- self.session.add(mapping)
139
- await self.session.commit()
151
+ existing_mapping = result.scalar_one_or_none()
152
+
153
+ if existing_mapping:
154
+ return existing_mapping
155
+
156
+ # Mapping doesn't exist, create new one
157
+ self.session.add(mapping)
158
+ await self.session.commit()
140
159
  return mapping
160
+
161
+ async def list_files_for_author(self, author_id: int) -> list[File]:
162
+ """List all files for an author."""
163
+ query = (
164
+ select(File)
165
+ .join(AuthorFileMapping)
166
+ .where(AuthorFileMapping.author_id == author_id)
167
+ )
168
+ result = await self.session.execute(query)
169
+ return list(result.scalars())
@@ -6,26 +6,22 @@ system, database operations (via SourceRepository), and provides a clean API for
6
6
  source management.
7
7
  """
8
8
 
9
- import mimetypes
10
- import shutil
11
- import tempfile
12
- from datetime import UTC, datetime
13
- from hashlib import sha256
9
+ from datetime import datetime
14
10
  from pathlib import Path
15
11
 
16
- import aiofiles
17
- import git
18
12
  import pydantic
19
13
  import structlog
20
- from tqdm import tqdm
21
14
 
22
15
  from kodit.source.git import is_valid_clone_target
23
- from kodit.source.ignore import IgnorePatterns
24
- from kodit.source.source_models import (
25
- Author,
26
- File,
27
- Source,
28
- SourceType,
16
+ from kodit.source.source_factories import (
17
+ FolderFileMetadataExtractor,
18
+ FolderSourceFactory,
19
+ FolderWorkingCopyProvider,
20
+ GitAuthorExtractor,
21
+ GitFileMetadataExtractor,
22
+ GitSourceFactory,
23
+ GitWorkingCopyProvider,
24
+ NoOpAuthorExtractor,
29
25
  )
30
26
  from kodit.source.source_repository import SourceRepository
31
27
 
@@ -69,6 +65,32 @@ class SourceService:
69
65
  self.repository = repository
70
66
  self.log = structlog.get_logger(__name__)
71
67
 
68
+ # Initialize factories
69
+ self._setup_factories()
70
+
71
+ def _setup_factories(self) -> None:
72
+ # Git-specific dependencies
73
+ git_working_copy = GitWorkingCopyProvider(self.clone_dir)
74
+ git_metadata_extractor = GitFileMetadataExtractor()
75
+ git_author_extractor = GitAuthorExtractor(self.repository)
76
+ self.git_factory = GitSourceFactory(
77
+ working_copy=git_working_copy,
78
+ metadata_extractor=git_metadata_extractor,
79
+ author_extractor=git_author_extractor,
80
+ repository=self.repository,
81
+ )
82
+
83
+ # Folder-specific dependencies
84
+ folder_working_copy = FolderWorkingCopyProvider(self.clone_dir)
85
+ folder_metadata_extractor = FolderFileMetadataExtractor()
86
+ no_op_author_extractor = NoOpAuthorExtractor()
87
+ self.folder_factory = FolderSourceFactory(
88
+ working_copy=folder_working_copy,
89
+ metadata_extractor=folder_metadata_extractor,
90
+ author_extractor=no_op_author_extractor,
91
+ repository=self.repository,
92
+ )
93
+
72
94
  async def get(self, source_id: int) -> SourceView:
73
95
  """Get a source by ID.
74
96
 
@@ -92,137 +114,13 @@ class SourceService:
92
114
  """Create a new source from a URI or path."""
93
115
  # If it's possible to clone it, then do so
94
116
  if is_valid_clone_target(uri_or_path_like):
95
- return await self._create_git_source(uri_or_path_like)
96
-
117
+ source = await self.git_factory.create(uri_or_path_like)
97
118
  # Otherwise just treat it as a directory
98
- if Path(uri_or_path_like).is_dir():
99
- return await self._create_folder_source(Path(uri_or_path_like))
100
-
101
- msg = f"Unsupported source: {uri_or_path_like}"
102
- raise ValueError(msg)
103
-
104
- async def _create_folder_source(self, directory: Path) -> SourceView:
105
- """Create a folder source.
106
-
107
- Args:
108
- directory: The path to the local directory.
109
-
110
- Raises:
111
- ValueError: If the folder doesn't exist.
112
- SourceAlreadyExistsError: If the folder is already added.
113
-
114
- """
115
- # Resolve the directory to an absolute path
116
- directory = directory.expanduser().resolve()
117
-
118
- source = await self.repository.get_source_by_uri(directory.as_uri())
119
- if source:
120
- self.log.info("Source already exists, reusing...", source_id=source.id)
119
+ elif Path(uri_or_path_like).is_dir():
120
+ source = await self.folder_factory.create(uri_or_path_like)
121
121
  else:
122
- # Check if the folder exists
123
- if not directory.exists():
124
- msg = f"Folder does not exist: {directory}"
125
- raise ValueError(msg)
126
-
127
- # Check if the folder is already added
128
- if await self.repository.get_source_by_uri(directory.as_uri()):
129
- msg = f"Directory already added: {directory}"
130
- raise ValueError(msg)
131
-
132
- # Clone into a local directory
133
- clone_path = self.clone_dir / directory.as_posix().replace("/", "_")
134
- clone_path.mkdir(parents=True, exist_ok=True)
135
-
136
- # Copy all files recursively, preserving directory structure, ignoring
137
- # hidden files
138
- shutil.copytree(
139
- directory,
140
- clone_path,
141
- ignore=shutil.ignore_patterns(".*"),
142
- dirs_exist_ok=True,
143
- )
144
-
145
- source = await self.repository.create_source(
146
- Source(
147
- uri=directory.as_uri(),
148
- cloned_path=str(clone_path),
149
- source_type=SourceType.FOLDER,
150
- ),
151
- )
152
-
153
- # Add all files to the source
154
- # Count total files for progress bar
155
- file_count = sum(1 for _ in clone_path.rglob("*") if _.is_file())
156
-
157
- # Process each file in the source directory
158
- for path in tqdm(clone_path.rglob("*"), total=file_count, leave=False):
159
- await self._process_file(source, path.absolute())
160
-
161
- return SourceView(
162
- id=source.id,
163
- uri=source.uri,
164
- cloned_path=Path(source.cloned_path),
165
- created_at=source.created_at,
166
- num_files=await self.repository.num_files_for_source(source.id),
167
- )
168
-
169
- async def _create_git_source(self, uri: str) -> SourceView:
170
- """Create a git source.
171
-
172
- Args:
173
- uri: The URI of the git repository.
174
-
175
- Raises:
176
- ValueError: If the repository cloning fails.
177
-
178
- """
179
- self.log.debug("Normalising git uri", uri=uri)
180
- with tempfile.TemporaryDirectory() as temp_dir:
181
- git.Repo.clone_from(uri, temp_dir)
182
- remote = git.Repo(temp_dir).remote()
183
- uri = remote.url
184
-
185
- self.log.debug("Checking if source already exists", uri=uri)
186
- source = await self.repository.get_source_by_uri(uri)
187
-
188
- if source:
189
- self.log.info("Source already exists, reusing...", source_id=source.id)
190
- else:
191
- # Create a unique directory name for the clone
192
- clone_path = self.clone_dir / uri.replace("/", "_").replace(":", "_")
193
- clone_path.mkdir(parents=True, exist_ok=True)
194
-
195
- try:
196
- self.log.info("Cloning repository", uri=uri, clone_path=str(clone_path))
197
- git.Repo.clone_from(uri, clone_path)
198
- except git.GitCommandError as e:
199
- if "already exists and is not an empty directory" in str(e):
200
- self.log.info("Repository already exists, reusing...", uri=uri)
201
- else:
202
- msg = f"Failed to clone repository: {e}"
203
- raise ValueError(msg) from e
204
-
205
- self.log.debug("Creating source", uri=uri, clone_path=str(clone_path))
206
- source = await self.repository.create_source(
207
- Source(
208
- uri=uri,
209
- cloned_path=str(clone_path),
210
- source_type=SourceType.GIT,
211
- ),
212
- )
213
-
214
- # Get the ignore patterns for this source
215
- ignore_patterns = IgnorePatterns(clone_path)
216
-
217
- # Get all files that are not ignored
218
- files = [
219
- f for f in clone_path.rglob("*") if not ignore_patterns.should_ignore(f)
220
- ]
221
-
222
- # Process each file in the source directory
223
- self.log.info("Inspecting files", source_id=source.id, num_files=len(files))
224
- for path in tqdm(files, total=len(files), leave=False):
225
- await self._process_file(source, path.absolute())
122
+ msg = f"Unsupported source: {uri_or_path_like}"
123
+ raise ValueError(msg)
226
124
 
227
125
  return SourceView(
228
126
  id=source.id,
@@ -232,81 +130,6 @@ class SourceService:
232
130
  num_files=await self.repository.num_files_for_source(source.id),
233
131
  )
234
132
 
235
- async def _process_file(
236
- self,
237
- source: Source,
238
- cloned_file: Path,
239
- ) -> None:
240
- """Process a single file for indexing."""
241
- if not cloned_file.is_file():
242
- return
243
-
244
- # If this file exists in a git repository, pull out the file's metadata
245
- authors: list[Author] = []
246
- first_modified_at: datetime | None = None
247
- last_modified_at: datetime | None = None
248
- if source.type == SourceType.GIT:
249
- # Get the git repository
250
- git_repo = git.Repo(source.cloned_path)
251
-
252
- # Get the last commit that touched this file
253
- commits = list(
254
- git_repo.iter_commits(
255
- paths=str(cloned_file),
256
- all=True,
257
- )
258
- )
259
- if len(commits) > 0:
260
- last_modified_at = commits[0].committed_datetime
261
- first_modified_at = commits[-1].committed_datetime
262
-
263
- # Get the file's blame
264
- blames = git_repo.blame("HEAD", str(cloned_file))
265
-
266
- # Extract the blame's authors
267
- actors = [
268
- commit.author
269
- for blame in blames or []
270
- for commit in blame
271
- if isinstance(commit, git.Commit)
272
- ]
273
-
274
- # Get or create the authors in the database
275
- for actor in actors:
276
- if actor.name or actor.email:
277
- author = await self.repository.get_or_create_author(
278
- actor.name or "", actor.email or ""
279
- )
280
- authors.append(author)
281
-
282
- # Create the file record
283
- async with aiofiles.open(cloned_file, "rb") as f:
284
- content = await f.read()
285
- mime_type = mimetypes.guess_type(cloned_file)
286
- sha = sha256(content).hexdigest()
287
-
288
- # Create file record
289
- file = File(
290
- created_at=first_modified_at or datetime.now(UTC),
291
- updated_at=last_modified_at or datetime.now(UTC),
292
- source_id=source.id,
293
- cloned_path=str(cloned_file),
294
- mime_type=mime_type[0]
295
- if mime_type and mime_type[0]
296
- else "application/octet-stream",
297
- uri=cloned_file.as_uri(),
298
- sha256=sha,
299
- size_bytes=len(content),
300
- )
301
-
302
- await self.repository.create_file(file)
303
-
304
- # Create mapping of authors to the file
305
- for author in authors:
306
- await self.repository.get_or_create_author_file_mapping(
307
- author_id=author.id, file_id=file.id
308
- )
309
-
310
133
  async def list_sources(self) -> list[SourceView]:
311
134
  """List all available sources.
312
135
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kodit
3
- Version: 0.2.2
3
+ Version: 0.2.4
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/
@@ -37,9 +37,9 @@ Requires-Dist: httpx-retries>=0.3.2
37
37
  Requires-Dist: httpx>=0.28.1
38
38
  Requires-Dist: openai>=1.82.0
39
39
  Requires-Dist: pathspec>=0.12.1
40
- Requires-Dist: posthog>=4.0.1
41
40
  Requires-Dist: pydantic-settings>=2.9.1
42
41
  Requires-Dist: pytable-formatter>=0.1.1
42
+ Requires-Dist: rudder-sdk-python>=2.1.4
43
43
  Requires-Dist: sentence-transformers>=4.1.0
44
44
  Requires-Dist: sqlalchemy[asyncio]>=2.0.40
45
45
  Requires-Dist: structlog>=25.3.0
@@ -1,11 +1,11 @@
1
1
  kodit/.gitignore,sha256=ztkjgRwL9Uud1OEi36hGQeDGk3OLK1NfDEO8YqGYy8o,11
2
2
  kodit/__init__.py,sha256=aEKHYninUq1yh6jaNfvJBYg-6fenpN132nJt1UU6Jxs,59
3
- kodit/_version.py,sha256=OjGGK5TcHVG44Y62aAqeJH4CskkZoY9ydbHOtCDew50,511
4
- kodit/app.py,sha256=Mr5BFHOHx5zppwjC4XPWVvHjwgl1yrKbUjTWXKubJQM,891
5
- kodit/cli.py,sha256=i7eEt0FdIQGEfXKFte-8fBcZZGE8BPXBp40aGwJDQGI,11323
3
+ kodit/_version.py,sha256=1LUN_sRKOiFInoB6AlW6TYoQMCh1Z4KutwcHNvHcfB0,511
4
+ kodit/app.py,sha256=qKBWJ0VNSY_M6G3VFfAQ0133q5bnS99cUFD0p396taw,1032
5
+ kodit/cli.py,sha256=wKFXGUMX-fDLooaK-3po2TBpNNRBwgSD7BRbUddg-_M,11562
6
6
  kodit/config.py,sha256=3yh7hfLSILjZK_qJMhcExwRcrWJ0b5Eb1JjjOvMPJZo,4146
7
7
  kodit/database.py,sha256=WB1KpVxUYPgiJGU0gJa2hqytYB8wJEJ5z3WayhWzNMU,2403
8
- kodit/log.py,sha256=HU1OmuxO4FcVw61k4WW7Y4WM7BrDaeplw1PcBHhuIZY,5434
8
+ kodit/log.py,sha256=sHPHYetlMcKTor2VaFLMyao1_fZ_xhuzqXCAt5F5UMU,8575
9
9
  kodit/mcp.py,sha256=QruyPskWB0_x59pkfj5BBeXuR13GMny5TAZEa2j4U9s,5752
10
10
  kodit/middleware.py,sha256=I6FOkqG9-8RH5kR1-0ZoQWfE4qLCB8lZYv8H_OCH29o,2714
11
11
  kodit/bm25/__init__.py,sha256=j8zyriNWhbwE5Lbybzg1hQAhANlU9mKHWw4beeUR6og,19
@@ -14,36 +14,36 @@ kodit/bm25/keyword_search_service.py,sha256=aBbWQKgQmi2re3EIHdXFS00n7Wj3b2D0pZsL
14
14
  kodit/bm25/local_bm25.py,sha256=nokrd_xAeqXi3m68X5P1R5KBhRRB1E2L_J6Zgm26PCg,3869
15
15
  kodit/bm25/vectorchord_bm25.py,sha256=0p_FgliaoevB8GLSmzWnV3zUjdcWgCgOKIpLURr7Qfo,6549
16
16
  kodit/embedding/__init__.py,sha256=h9NXzDA1r-K23nvBajBV-RJzHJN0p3UJ7UQsmdnOoRw,24
17
- kodit/embedding/embedding_factory.py,sha256=UbrTl3NEqBBH3ecvRG7vGW5wuvUMbWJEWbAAFALOGqs,2141
17
+ kodit/embedding/embedding_factory.py,sha256=lFcgqsDxw8L5mygq-TppQ2wtoIA2p2OL7XmtOyX8Omw,2683
18
18
  kodit/embedding/embedding_models.py,sha256=rN90vSs86dYiqoawcp8E9jtwY31JoJXYfaDlsJK7uqc,656
19
19
  kodit/embedding/embedding_repository.py,sha256=-ux3scpBzel8c0pMH9fNOEsSXFIzl-IfgaWrkTb1szo,6907
20
- kodit/embedding/local_vector_search_service.py,sha256=dgMi8hQNUbYEgHnEYmLIpon4yLduoNUpu7k7VP6sOHI,2042
21
- kodit/embedding/vector_search_service.py,sha256=pQJ129QjGrAWOXzqkywmgtDRpy8_gtzYgkivyqF9Vrs,1009
22
- kodit/embedding/vectorchord_vector_search_service.py,sha256=TKNR3HgWHwwWtJ1SsvSaj_BXLJ_uw6Bdr_tpaePMeAA,5383
20
+ kodit/embedding/local_vector_search_service.py,sha256=yZm0ahQQKhfYZ943yxKHp04cairmzgGBUNi5PB_GDbo,3002
21
+ kodit/embedding/vector_search_service.py,sha256=frN9baAlqFmsY3xiv1ZeSgsfhK9FzKPkVR55MEvMV4I,1416
22
+ kodit/embedding/vectorchord_vector_search_service.py,sha256=JQeIl9mtR4E_izOoFD_4ZRfENHNfwoKr16pQkkGoK3o,6884
23
23
  kodit/embedding/embedding_provider/__init__.py,sha256=h9NXzDA1r-K23nvBajBV-RJzHJN0p3UJ7UQsmdnOoRw,24
24
- kodit/embedding/embedding_provider/embedding_provider.py,sha256=IC7fZaZ_ze-DxpxKfK44pRDwHWUQhVIqVKKQ3alO5Qc,1882
25
- kodit/embedding/embedding_provider/hash_embedding_provider.py,sha256=nAhlhh8j8PqqCCbhVl26Y8ntFBm2vJBCtB4X04g5Wwg,2638
26
- kodit/embedding/embedding_provider/local_embedding_provider.py,sha256=WP8lw6XG7v1_5Mw4_rhIOETooYRsxhkwmFaXCqCouQU,1977
27
- kodit/embedding/embedding_provider/openai_embedding_provider.py,sha256=-phz5FKYM_tI3Q4_3SPzjzIOK3k92Uk52TAOTmoVoWI,2722
24
+ kodit/embedding/embedding_provider/embedding_provider.py,sha256=WDHifrsQOnpXwIDzSfau32Eq8z8BF3XNeVYd6X989uc,2841
25
+ kodit/embedding/embedding_provider/hash_embedding_provider.py,sha256=AhGize94EoScyQMhCjo26zlO0eP_m3F_1qvrVmB6MTE,2941
26
+ kodit/embedding/embedding_provider/local_embedding_provider.py,sha256=kqbGd7TW6BUsOq_f_IzPCsD7z8LsFieTOZ7saY11I8o,2877
27
+ kodit/embedding/embedding_provider/openai_embedding_provider.py,sha256=2FTIL34yVstf0NTJNSi-sjk38OJd4Aa66TH5FMPJul0,2425
28
28
  kodit/enrichment/__init__.py,sha256=vBEolHpKaHUhfINX0dSGyAPlvgpLNAer9YzFtdvCB24,18
29
- kodit/enrichment/enrichment_factory.py,sha256=JbWFNciB6Yf79SFVjG9UhLgCcrXZ1rIJrenU8QmNLBE,1411
30
- kodit/enrichment/enrichment_service.py,sha256=87Sd3gGbEMJYb_wVrHG8L1yGIZmQNR7foUS4_y94azI,977
29
+ kodit/enrichment/enrichment_factory.py,sha256=AAzvxgjo-FQU5aAm9Zla4DAwUMKGrcw8mQwJsMhIsHY,1566
30
+ kodit/enrichment/enrichment_service.py,sha256=z7VrrQ-Jhb-oO26rQCaqlpmkGRlDQGAu7qVsI0cwHak,1310
31
31
  kodit/enrichment/enrichment_provider/__init__.py,sha256=klf8iuLVWX4iRz-DZQauFFNAoJC5CByczh48TBZPW-o,27
32
- kodit/enrichment/enrichment_provider/enrichment_provider.py,sha256=E0H5rq3OENM0yYbA8K_3nSnj5lUHCpoIOqpWLo-2MVU,413
33
- kodit/enrichment/enrichment_provider/local_enrichment_provider.py,sha256=RqwUD0BnwRQ8zlkFNkaKq8d58r33k2jIdnSdf6zla1w,3325
34
- kodit/enrichment/enrichment_provider/openai_enrichment_provider.py,sha256=0Yw7h9RXptoI4bKuqJSKIRQXPUUhNV7eACavgoy_T8s,2874
32
+ kodit/enrichment/enrichment_provider/enrichment_provider.py,sha256=kiDgg2G8G85K4KqwCQKHE_ANybANURPO6NbASf4yAr0,751
33
+ kodit/enrichment/enrichment_provider/local_enrichment_provider.py,sha256=JipvgZwfNvHaECqLJRmQo3W10yb9rOVSrV2U0Jpp4d8,3456
34
+ kodit/enrichment/enrichment_provider/openai_enrichment_provider.py,sha256=xAzbGHJHqGxZxa3yPvHAcPgjOMzQ05qLes0XW6OIdYc,2758
35
35
  kodit/indexing/__init__.py,sha256=cPyi2Iej3G1JFWlWr7X80_UrsMaTu5W5rBwgif1B3xo,75
36
36
  kodit/indexing/fusion.py,sha256=TZb4fPAedXdEUXzwzOofW98QIOymdbclBOP1KOijuEk,1674
37
37
  kodit/indexing/indexing_models.py,sha256=6NX9HVcj6Pu9ePwHC7n-PWSyAgukpJq0nCNmUIigtbo,1282
38
38
  kodit/indexing/indexing_repository.py,sha256=dqOS0pxKM6bUjMXWqYukAK8XdiD36OnskFASgZRXRQM,6955
39
- kodit/indexing/indexing_service.py,sha256=79BZ4yaSJqADkivzjsq1bDCBtbfWikVRC7Fjlp1HmZw,10885
39
+ kodit/indexing/indexing_service.py,sha256=UD7RKQRkAlpmepl20vcdEgQapwEA2kDJQBmn4_kGWwU,11841
40
40
  kodit/migrations/README,sha256=ISVtAOvqvKk_5ThM5ioJE-lMkvf9IbknFUFVU_vPma4,58
41
41
  kodit/migrations/__init__.py,sha256=lP5MuwlyWRMO6UcDWnQcQ3G-GYHcFb6rl9gYPHJ1sjo,40
42
42
  kodit/migrations/env.py,sha256=w1M7OZh-ZeR2dPHS0ByXAUxQjfZQ8xIzMseWuzLDTWw,2469
43
43
  kodit/migrations/script.py.mako,sha256=zWziKtiwYKEWuwPV_HBNHwa9LCT45_bi01-uSNFaOOE,703
44
- kodit/migrations/versions/42e836b21102_add_authors.py,sha256=KmXlHb_y8bIa_ABNU67zZi13r0DAfHA9G8tjQNkdITM,2638
45
44
  kodit/migrations/versions/7c3bbc2ab32b_add_embeddings_table.py,sha256=-61qol9PfQKILCDQRA5jEaats9aGZs9Wdtp-j-38SF4,1644
46
45
  kodit/migrations/versions/85155663351e_initial.py,sha256=Cg7zlF871o9ShV5rQMQ1v7hRV7fI59veDY9cjtTrs-8,3306
46
+ kodit/migrations/versions/9e53ea8bb3b0_add_authors.py,sha256=a32Zm8KUQyiiLkjKNPYdaJDgjW6VsV-GhaLnPnK_fpI,3884
47
47
  kodit/migrations/versions/__init__.py,sha256=9-lHzptItTzq_fomdIRBegQNm4Znx6pVjwD4MiqRIdo,36
48
48
  kodit/migrations/versions/c3f5137d30f5_index_all_the_things.py,sha256=rI8LmjF-I2OMxZ2nOIF_NRmqOLXe45hL_iz_nx97DTQ,1680
49
49
  kodit/snippets/__init__.py,sha256=-2coNoCRjTixU9KcP6alpmt7zqf37tCRWH3D7FPJ8dg,48
@@ -58,13 +58,14 @@ kodit/snippets/languages/typescript.scm,sha256=U-ujbbv4tylbUBj9wuhL-e5cW6hmgPCNs
58
58
  kodit/source/__init__.py,sha256=1NTZyPdjThVQpZO1Mp1ColVsS7sqYanOVLqnoqV9Ipo,83
59
59
  kodit/source/git.py,sha256=CpNczc06SbxpzfQKq76lZFzuol10ZJvTRSzeXW9DFUs,363
60
60
  kodit/source/ignore.py,sha256=W7cuIrYlgfu3S1qyoIepXe8PqYmtFv61Tt5RO8cbZbg,1701
61
- kodit/source/source_models.py,sha256=lCaaoukLlMHuRWJBuYM2nkNKGtFASgbk7ZXq8kp4H5c,3519
62
- kodit/source/source_repository.py,sha256=4L-W0uE4LOB9LQlefk5f2sgHlsJjj8t33USPxU0na40,4448
63
- kodit/source/source_service.py,sha256=v-lY-7tsNFCyXo9yCUo7Q00NOWYKGiDB_M2-Hr8hp3U,11391
61
+ kodit/source/source_factories.py,sha256=qTjKBKu62vynHUxf3-lgxQCoj1nGn8aI9ExFUWNk5B8,11678
62
+ kodit/source/source_models.py,sha256=XlgrY2dlpJkOFZQjrwMGwebAcwQ4rSfjshvCrHKA18Q,3916
63
+ kodit/source/source_repository.py,sha256=eme0C3pRqwFZ1ZSbqq4Z6SV9CC6AvRmiOjy3eHQoEN0,5443
64
+ kodit/source/source_service.py,sha256=E1KPG7TrorqdreJVHxZPx8CVLncOxGEvZ5uDQ6yZugo,5050
64
65
  kodit/util/__init__.py,sha256=bPu6CtqDWCRGU7VgW2_aiQrCBi8G89FS6k1PjvDajJ0,37
65
66
  kodit/util/spinner.py,sha256=R9bzrHtBiIH6IfLbmsIVHL53s8vg-tqW4lwGGALu4dw,1932
66
- kodit-0.2.2.dist-info/METADATA,sha256=UU1curOx-XMql_IiXty-eoz-MJrd5QdlzfCj7ZoSzhg,5857
67
- kodit-0.2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
68
- kodit-0.2.2.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
69
- kodit-0.2.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
70
- kodit-0.2.2.dist-info/RECORD,,
67
+ kodit-0.2.4.dist-info/METADATA,sha256=PLQQVNKVnMyyliP9TEapeXUuog_N1bTFlup6F89B7NU,5867
68
+ kodit-0.2.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
69
+ kodit-0.2.4.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
70
+ kodit-0.2.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
71
+ kodit-0.2.4.dist-info/RECORD,,
@@ -1,64 +0,0 @@
1
- # ruff: noqa
2
- """add authors
3
-
4
- Revision ID: 42e836b21102
5
- Revises: c3f5137d30f5
6
- Create Date: 2025-06-13 14:48:50.152940
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 = '42e836b21102'
18
- down_revision: Union[str, None] = 'c3f5137d30f5'
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.create_table('authors',
27
- sa.Column('name', sa.String(length=255), nullable=False),
28
- sa.Column('email', sa.String(length=255), nullable=False),
29
- sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
30
- sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
31
- sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
32
- sa.PrimaryKeyConstraint('id')
33
- )
34
- op.create_index(op.f('ix_authors_email'), 'authors', ['email'], unique=True)
35
- op.create_index(op.f('ix_authors_name'), 'authors', ['name'], unique=True)
36
- op.create_table('author_file_mappings',
37
- sa.Column('author_id', sa.Integer(), nullable=False),
38
- sa.Column('file_id', sa.Integer(), nullable=False),
39
- sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
40
- sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
41
- sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
42
- sa.ForeignKeyConstraint(['author_id'], ['authors.id'], ),
43
- sa.ForeignKeyConstraint(['file_id'], ['files.id'], ),
44
- sa.PrimaryKeyConstraint('id')
45
- )
46
- op.add_column('files', sa.Column('extension', sa.String(length=255), nullable=False))
47
- op.create_index(op.f('ix_files_extension'), 'files', ['extension'], unique=False)
48
- op.add_column('sources', sa.Column('type', sa.Enum('UNKNOWN', 'FOLDER', 'GIT', name='sourcetype'), nullable=False))
49
- op.create_index(op.f('ix_sources_type'), 'sources', ['type'], unique=False)
50
- # ### end Alembic commands ###
51
-
52
-
53
- def downgrade() -> None:
54
- """Downgrade schema."""
55
- # ### commands auto generated by Alembic - please adjust! ###
56
- op.drop_index(op.f('ix_sources_type'), table_name='sources')
57
- op.drop_column('sources', 'type')
58
- op.drop_index(op.f('ix_files_extension'), table_name='files')
59
- op.drop_column('files', 'extension')
60
- op.drop_table('author_file_mappings')
61
- op.drop_index(op.f('ix_authors_name'), table_name='authors')
62
- op.drop_index(op.f('ix_authors_email'), table_name='authors')
63
- op.drop_table('authors')
64
- # ### end Alembic commands ###
File without changes