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.
- kodit/_version.py +2 -2
- kodit/app.py +6 -0
- kodit/cli.py +8 -2
- kodit/embedding/embedding_factory.py +11 -0
- kodit/embedding/embedding_provider/embedding_provider.py +42 -14
- kodit/embedding/embedding_provider/hash_embedding_provider.py +16 -7
- kodit/embedding/embedding_provider/local_embedding_provider.py +43 -11
- kodit/embedding/embedding_provider/openai_embedding_provider.py +18 -22
- kodit/embedding/local_vector_search_service.py +46 -13
- kodit/embedding/vector_search_service.py +18 -1
- kodit/embedding/vectorchord_vector_search_service.py +63 -16
- kodit/enrichment/enrichment_factory.py +3 -0
- kodit/enrichment/enrichment_provider/enrichment_provider.py +21 -1
- kodit/enrichment/enrichment_provider/local_enrichment_provider.py +39 -28
- kodit/enrichment/enrichment_provider/openai_enrichment_provider.py +25 -27
- kodit/enrichment/enrichment_service.py +19 -7
- kodit/indexing/indexing_service.py +50 -23
- kodit/log.py +126 -24
- kodit/migrations/versions/9e53ea8bb3b0_add_authors.py +103 -0
- kodit/source/source_factories.py +356 -0
- kodit/source/source_models.py +17 -5
- kodit/source/source_repository.py +49 -20
- kodit/source/source_service.py +41 -218
- {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/METADATA +2 -2
- {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/RECORD +28 -27
- kodit/migrations/versions/42e836b21102_add_authors.py +0 -64
- {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/WHEEL +0 -0
- {kodit-0.2.2.dist-info → kodit-0.2.4.dist-info}/entry_points.txt +0 -0
- {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
|
|
110
|
-
"""Get
|
|
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
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
|
127
|
-
self,
|
|
141
|
+
async def upsert_author_file_mapping(
|
|
142
|
+
self, mapping: AuthorFileMapping
|
|
128
143
|
) -> AuthorFileMapping:
|
|
129
|
-
"""Create a new author file mapping
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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())
|
kodit/source/source_service.py
CHANGED
|
@@ -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
|
|
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.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
96
|
-
|
|
117
|
+
source = await self.git_factory.create(uri_or_path_like)
|
|
97
118
|
# Otherwise just treat it as a directory
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
123
|
-
|
|
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.
|
|
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=
|
|
4
|
-
kodit/app.py,sha256=
|
|
5
|
-
kodit/cli.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
21
|
-
kodit/embedding/vector_search_service.py,sha256=
|
|
22
|
-
kodit/embedding/vectorchord_vector_search_service.py,sha256=
|
|
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=
|
|
25
|
-
kodit/embedding/embedding_provider/hash_embedding_provider.py,sha256=
|
|
26
|
-
kodit/embedding/embedding_provider/local_embedding_provider.py,sha256=
|
|
27
|
-
kodit/embedding/embedding_provider/openai_embedding_provider.py,sha256
|
|
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=
|
|
30
|
-
kodit/enrichment/enrichment_service.py,sha256=
|
|
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=
|
|
33
|
-
kodit/enrichment/enrichment_provider/local_enrichment_provider.py,sha256=
|
|
34
|
-
kodit/enrichment/enrichment_provider/openai_enrichment_provider.py,sha256=
|
|
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=
|
|
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/
|
|
62
|
-
kodit/source/
|
|
63
|
-
kodit/source/
|
|
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.
|
|
67
|
-
kodit-0.2.
|
|
68
|
-
kodit-0.2.
|
|
69
|
-
kodit-0.2.
|
|
70
|
-
kodit-0.2.
|
|
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
|
|
File without changes
|
|
File without changes
|