kodit 0.3.6__py3-none-any.whl → 0.3.7__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 CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.3.6'
21
- __version_tuple__ = version_tuple = (0, 3, 6)
20
+ __version__ = version = '0.3.7'
21
+ __version_tuple__ = version_tuple = (0, 3, 7)
kodit/app.py CHANGED
@@ -51,14 +51,19 @@ async def app_lifespan(_: FastAPI) -> AsyncIterator[None]:
51
51
  await _auto_indexing_service.stop()
52
52
 
53
53
 
54
- # See https://gofastmcp.com/deployment/asgi#fastapi-integration
55
- mcp_app = mcp.sse_app()
54
+ # See https://gofastmcp.com/integrations/fastapi#mounting-an-mcp-server
55
+ mcp_sse_app = mcp.http_app(transport="sse", path="/")
56
+ mcp_http_app = mcp.http_app(transport="http", path="/")
56
57
 
57
58
 
58
59
  @asynccontextmanager
59
60
  async def combined_lifespan(app: FastAPI) -> AsyncIterator[None]:
60
61
  """Combine app and MCP lifespans."""
61
- async with app_lifespan(app), mcp_app.router.lifespan_context(app):
62
+ async with (
63
+ app_lifespan(app),
64
+ mcp_sse_app.router.lifespan_context(app),
65
+ mcp_http_app.router.lifespan_context(app),
66
+ ):
62
67
  yield
63
68
 
64
69
 
@@ -82,8 +87,10 @@ async def healthz() -> dict[str, str]:
82
87
 
83
88
 
84
89
  # Add mcp routes last, otherwise previous routes aren't added
85
- app.mount("", mcp_app)
90
+ # Mount both apps at root - they have different internal paths
91
+ app.mount("/sse", mcp_sse_app)
92
+ app.mount("/mcp", mcp_http_app)
86
93
 
87
94
  # Wrap the entire app with ASGI middleware after all routes are added to suppress
88
95
  # CancelledError at the ASGI level
89
- app = ASGICancelledErrorMiddleware(app)
96
+ app = ASGICancelledErrorMiddleware(app) # type: ignore[assignment]
kodit/cli.py CHANGED
@@ -1,13 +1,14 @@
1
1
  """Command line interface for kodit."""
2
2
 
3
3
  import signal
4
+ import warnings
4
5
  from pathlib import Path
5
6
  from typing import Any
6
7
 
7
8
  import click
8
9
  import structlog
9
10
  import uvicorn
10
- from pytable_formatter import Cell, Table
11
+ from pytable_formatter import Cell, Table # type: ignore[import-untyped]
11
12
  from sqlalchemy.ext.asyncio import AsyncSession
12
13
 
13
14
  from kodit.application.factories.code_indexing_factory import (
@@ -32,6 +33,7 @@ from kodit.infrastructure.ui.progress import (
32
33
  create_multi_stage_progress_callback,
33
34
  )
34
35
  from kodit.log import configure_logging, configure_telemetry, log_event
36
+ from kodit.mcp import create_stdio_mcp_server
35
37
 
36
38
 
37
39
  @click.group(context_settings={"max_content_width": 100})
@@ -54,7 +56,7 @@ def cli(
54
56
  config = AppContext()
55
57
  # First check if env-file is set and reload config if it is
56
58
  if env_file:
57
- config = AppContext(_env_file=env_file) # type: ignore[reportCallIssue]
59
+ config = AppContext(_env_file=env_file) # type: ignore[call-arg]
58
60
 
59
61
  configure_logging(config)
60
62
  configure_telemetry(config)
@@ -100,7 +102,8 @@ async def _handle_sync(
100
102
  # Filter indexes that match the provided sources
101
103
  source_uris = set(sources)
102
104
  indexes_to_sync = [
103
- index for index in all_indexes
105
+ index
106
+ for index in all_indexes
104
107
  if str(index.source.working_copy.remote_uri) in source_uris
105
108
  ]
106
109
 
@@ -124,9 +127,7 @@ async def _handle_sync(
124
127
  click.echo(f"✓ Sync completed: {index.source.working_copy.remote_uri}")
125
128
  except Exception as e:
126
129
  log.exception("Sync failed", index_id=index.id, error=e)
127
- click.echo(
128
- f"✗ Sync failed: {index.source.working_copy.remote_uri} - {e}"
129
- )
130
+ click.echo(f"✗ Sync failed: {index.source.working_copy.remote_uri} - {e}")
130
131
 
131
132
 
132
133
  async def _handle_list_indexes(index_query_service: IndexQueryService) -> None:
@@ -159,9 +160,7 @@ async def _handle_list_indexes(index_query_service: IndexQueryService) -> None:
159
160
  @click.option(
160
161
  "--auto-index", is_flag=True, help="Index all configured auto-index sources"
161
162
  )
162
- @click.option(
163
- "--sync", is_flag=True, help="Sync existing indexes with their remotes"
164
- )
163
+ @click.option("--sync", is_flag=True, help="Sync existing indexes with their remotes")
165
164
  @with_app_context
166
165
  @with_session
167
166
  async def index(
@@ -561,11 +560,15 @@ def serve(
561
560
  host: str,
562
561
  port: int,
563
562
  ) -> None:
564
- """Start the kodit server, which hosts the MCP server and the kodit API."""
563
+ """Start the kodit HTTP/SSE server with FastAPI integration."""
565
564
  log = structlog.get_logger(__name__)
566
565
  log.info("Starting kodit server", host=host, port=port)
567
566
  log_event("kodit.cli.serve")
568
567
 
568
+ # Disable uvicorn's websockets deprecation warnings
569
+ warnings.filterwarnings("ignore", category=DeprecationWarning, module="websockets")
570
+ warnings.filterwarnings("ignore", category=DeprecationWarning, module="uvicorn")
571
+
569
572
  # Configure uvicorn with graceful shutdown
570
573
  config = uvicorn.Config(
571
574
  "kodit.app:app",
@@ -587,6 +590,13 @@ def serve(
587
590
  server.run()
588
591
 
589
592
 
593
+ @cli.command()
594
+ def stdio() -> None:
595
+ """Start the kodit MCP server in STDIO mode."""
596
+ log_event("kodit.cli.stdio")
597
+ create_stdio_mcp_server()
598
+
599
+
590
600
  @cli.command()
591
601
  def version() -> None:
592
602
  """Show the version of kodit."""
@@ -7,7 +7,7 @@ from pathlib import Path
7
7
  from typing import TYPE_CHECKING
8
8
 
9
9
  import aiofiles
10
- import Stemmer
10
+ import Stemmer # type: ignore[import-not-found]
11
11
  import structlog
12
12
 
13
13
  from kodit.domain.services.bm25_service import BM25Repository
@@ -19,8 +19,8 @@ from kodit.domain.value_objects import (
19
19
  )
20
20
 
21
21
  if TYPE_CHECKING:
22
- import bm25s
23
- from bm25s.tokenization import Tokenized
22
+ import bm25s # type: ignore[import-untyped]
23
+ from bm25s.tokenization import Tokenized # type: ignore[import-untyped]
24
24
 
25
25
  SNIPPET_IDS_FILE = "snippet_ids.jsonl"
26
26
 
@@ -1,9 +1,14 @@
1
1
  """Factory for creating embedding services with DDD architecture."""
2
2
 
3
+ from openai import AsyncOpenAI
3
4
  from sqlalchemy.ext.asyncio import AsyncSession
4
5
 
5
6
  from kodit.config import AppContext, Endpoint
6
- from kodit.domain.services.embedding_service import EmbeddingDomainService
7
+ from kodit.domain.services.embedding_service import (
8
+ EmbeddingDomainService,
9
+ EmbeddingProvider,
10
+ VectorSearchRepository,
11
+ )
7
12
  from kodit.infrastructure.embedding.embedding_providers.local_embedding_provider import ( # noqa: E501
8
13
  CODE,
9
14
  LocalEmbeddingProvider,
@@ -38,11 +43,10 @@ def embedding_domain_service_factory(
38
43
  embedding_repository = SqlAlchemyEmbeddingRepository(session=session)
39
44
 
40
45
  # Create embedding provider
46
+ embedding_provider: EmbeddingProvider | None = None
41
47
  endpoint = _get_endpoint_configuration(app_context)
42
48
  if endpoint and endpoint.type == "openai":
43
49
  log_event("kodit.embedding", {"provider": "openai"})
44
- from openai import AsyncOpenAI
45
-
46
50
  embedding_provider = OpenAIEmbeddingProvider(
47
51
  openai_client=AsyncOpenAI(
48
52
  api_key=endpoint.api_key or "default",
@@ -57,6 +61,7 @@ def embedding_domain_service_factory(
57
61
  embedding_provider = LocalEmbeddingProvider(CODE)
58
62
 
59
63
  # Create vector search repository based on configuration
64
+ vector_search_repository: VectorSearchRepository | None = None
60
65
  if app_context.default_search.provider == "vectorchord":
61
66
  log_event("kodit.database", {"provider": "vectorchord"})
62
67
  vector_search_repository = VectorChordVectorSearchRepository(
@@ -1,7 +1,10 @@
1
1
  """Enrichment factory for creating enrichment domain services."""
2
2
 
3
3
  from kodit.config import AppContext, Endpoint
4
- from kodit.domain.services.enrichment_service import EnrichmentDomainService
4
+ from kodit.domain.services.enrichment_service import (
5
+ EnrichmentDomainService,
6
+ EnrichmentProvider,
7
+ )
5
8
  from kodit.infrastructure.enrichment.local_enrichment_provider import (
6
9
  LocalEnrichmentProvider,
7
10
  )
@@ -38,6 +41,7 @@ def enrichment_domain_service_factory(
38
41
  """
39
42
  endpoint = _get_endpoint_configuration(app_context)
40
43
 
44
+ enrichment_provider: EnrichmentProvider | None = None
41
45
  if endpoint and endpoint.type == "openai":
42
46
  log_event("kodit.enrichment", {"provider": "openai"})
43
47
  from openai import AsyncOpenAI
@@ -81,7 +81,7 @@ class LocalEnrichmentProvider(EnrichmentProvider):
81
81
  prompts = [
82
82
  {
83
83
  "id": req.snippet_id,
84
- "text": self.tokenizer.apply_chat_template(
84
+ "text": self.tokenizer.apply_chat_template( # type: ignore[attr-defined]
85
85
  [
86
86
  {"role": "system", "content": ENRICHMENT_SYSTEM_PROMPT},
87
87
  {"role": "user", "content": req.text},
@@ -95,18 +95,18 @@ class LocalEnrichmentProvider(EnrichmentProvider):
95
95
  ]
96
96
 
97
97
  for prompt in prompts:
98
- model_inputs = self.tokenizer(
98
+ model_inputs = self.tokenizer( # type: ignore[misc]
99
99
  prompt["text"],
100
100
  return_tensors="pt",
101
101
  padding=True,
102
102
  truncation=True,
103
- ).to(self.model.device)
104
- generated_ids = self.model.generate(
103
+ ).to(self.model.device) # type: ignore[attr-defined]
104
+ generated_ids = self.model.generate( # type: ignore[attr-defined]
105
105
  **model_inputs, max_new_tokens=self.context_window
106
106
  )
107
107
  input_ids = model_inputs["input_ids"][0]
108
108
  output_ids = generated_ids[0][len(input_ids) :].tolist()
109
- content = self.tokenizer.decode(output_ids, skip_special_tokens=True).strip(
109
+ content = self.tokenizer.decode(output_ids, skip_special_tokens=True).strip( # type: ignore[attr-defined]
110
110
  "\n"
111
111
  )
112
112
  yield EnrichmentResponse(
@@ -2,7 +2,7 @@
2
2
 
3
3
  from collections.abc import Callable
4
4
 
5
- from tqdm import tqdm
5
+ from tqdm import tqdm # type: ignore[import-untyped]
6
6
 
7
7
  from kodit.domain.interfaces import ProgressCallback
8
8
  from kodit.domain.value_objects import ProgressEvent
kodit/log.py CHANGED
@@ -12,7 +12,7 @@ from functools import lru_cache
12
12
  from pathlib import Path
13
13
  from typing import Any
14
14
 
15
- import rudderstack.analytics as rudder_analytics
15
+ import rudderstack.analytics as rudder_analytics # type: ignore[import-untyped]
16
16
  import structlog
17
17
  from structlog.types import EventDict
18
18
 
kodit/mcp.py CHANGED
@@ -58,10 +58,160 @@ async def mcp_lifespan(_: FastMCP) -> AsyncIterator[MCPContext]:
58
58
  yield MCPContext(session=session, app_context=app_context)
59
59
 
60
60
 
61
- mcp = FastMCP(
62
- "Kodit",
63
- lifespan=mcp_lifespan,
64
- # Note that instructions are not used by Cline.
61
+ def create_mcp_server(name: str, instructions: str | None = None) -> FastMCP:
62
+ """Create a FastMCP server with common configuration."""
63
+ return FastMCP(
64
+ name,
65
+ lifespan=mcp_lifespan,
66
+ instructions=instructions,
67
+ )
68
+
69
+
70
+ def register_mcp_tools(mcp_server: FastMCP) -> None:
71
+ """Register MCP tools on the provided FastMCP instance."""
72
+
73
+ @mcp_server.tool()
74
+ async def search( # noqa: PLR0913
75
+ ctx: Context,
76
+ user_intent: Annotated[
77
+ str,
78
+ Field(
79
+ description="Think about what the user wants to achieve. Describe the "
80
+ "user's intent in one sentence."
81
+ ),
82
+ ],
83
+ related_file_paths: Annotated[
84
+ list[Path],
85
+ Field(
86
+ description=(
87
+ "A list of absolute paths to files that are relevant to the "
88
+ "user's intent."
89
+ )
90
+ ),
91
+ ],
92
+ related_file_contents: Annotated[
93
+ list[str],
94
+ Field(
95
+ description=(
96
+ "A list of the contents of the files that are relevant to the "
97
+ "user's intent."
98
+ )
99
+ ),
100
+ ],
101
+ keywords: Annotated[
102
+ list[str],
103
+ Field(
104
+ description=(
105
+ "A list of keywords that are relevant to the desired outcome."
106
+ )
107
+ ),
108
+ ],
109
+ language: Annotated[
110
+ str | None,
111
+ Field(
112
+ description="Filter by language (e.g., 'python', 'go', 'javascript')."
113
+ ),
114
+ ] = None,
115
+ author: Annotated[
116
+ str | None,
117
+ Field(description=("Filter to search for snippets by a specific author.")),
118
+ ] = None,
119
+ created_after: Annotated[
120
+ str | None,
121
+ Field(
122
+ description=(
123
+ "Filter for snippets created after this date "
124
+ "(ISO format: YYYY-MM-DD)."
125
+ )
126
+ ),
127
+ ] = None,
128
+ created_before: Annotated[
129
+ str | None,
130
+ Field(
131
+ description=(
132
+ "Filter for snippets created before this date "
133
+ "(ISO format: YYYY-MM-DD)."
134
+ )
135
+ ),
136
+ ] = None,
137
+ source_repo: Annotated[
138
+ str | None,
139
+ Field(
140
+ description=(
141
+ "Filter results by project source repository (e.g., "
142
+ "github.com/example/repo)"
143
+ )
144
+ ),
145
+ ] = None,
146
+ ) -> str:
147
+ """Search for pre-existing examples of relevant code.
148
+
149
+ ⚠️ **ENFORCEMENT:**
150
+ For *every* user request that involves writing or modifying code (of any
151
+ language or domain), the assistant's *first* action **must** be to call the
152
+ kodit.search MCP tool. You may only produce or edit code *after* that tool
153
+ call and its successful result.
154
+ """
155
+ # This docstring is used by the AI assistant to decide when to call the tool.
156
+ # If you want to update it, please make sure you thoroughly test the
157
+ # assistant's response to the updated tool call. See:
158
+ # tests/experiments/cline-prompt-regression-tests/cline_prompt_test.py
159
+
160
+ log = structlog.get_logger(__name__)
161
+
162
+ log.debug(
163
+ "Searching for relevant snippets",
164
+ user_intent=user_intent,
165
+ keywords=keywords,
166
+ file_count=len(related_file_paths),
167
+ file_paths=related_file_paths,
168
+ file_contents=related_file_contents,
169
+ )
170
+
171
+ mcp_context: MCPContext = ctx.request_context.lifespan_context
172
+
173
+ # Use the unified application service
174
+ service = create_code_indexing_application_service(
175
+ app_context=mcp_context.app_context,
176
+ session=mcp_context.session,
177
+ )
178
+
179
+ log.debug("Searching for snippets")
180
+
181
+ # Create filters if any filter parameters are provided
182
+ filters = SnippetSearchFilters.from_cli_params(
183
+ language=language,
184
+ author=author,
185
+ created_after=created_after,
186
+ created_before=created_before,
187
+ source_repo=source_repo,
188
+ )
189
+
190
+ search_request = MultiSearchRequest(
191
+ keywords=keywords,
192
+ code_query="\n".join(related_file_contents),
193
+ text_query=user_intent,
194
+ filters=filters,
195
+ )
196
+
197
+ log.debug("Searching for snippets")
198
+ snippets = await service.search(request=search_request)
199
+
200
+ log.debug("Fusing output")
201
+ output = MultiSearchResult.to_jsonlines(results=snippets)
202
+
203
+ log.debug("Output", output=output)
204
+ return output
205
+
206
+ @mcp_server.tool()
207
+ async def get_version() -> str:
208
+ """Get the version of the kodit project."""
209
+ return version
210
+
211
+
212
+ # FastAPI-integrated MCP server
213
+ mcp = create_mcp_server(
214
+ name="Kodit",
65
215
  instructions=(
66
216
  "This server is used to assist with code generation by retrieving "
67
217
  "code examples related to the user's intent."
@@ -69,132 +219,10 @@ mcp = FastMCP(
69
219
  ),
70
220
  )
71
221
 
72
-
73
- @mcp.tool()
74
- async def search( # noqa: PLR0913
75
- ctx: Context,
76
- user_intent: Annotated[
77
- str,
78
- Field(
79
- description="Think about what the user wants to achieve. Describe the "
80
- "user's intent in one sentence."
81
- ),
82
- ],
83
- related_file_paths: Annotated[
84
- list[Path],
85
- Field(
86
- description="A list of absolute paths to files that are relevant to the "
87
- "user's intent."
88
- ),
89
- ],
90
- related_file_contents: Annotated[
91
- list[str],
92
- Field(
93
- description="A list of the contents of the files that are relevant to the "
94
- "user's intent."
95
- ),
96
- ],
97
- keywords: Annotated[
98
- list[str],
99
- Field(
100
- description="A list of keywords that are relevant to the desired outcome."
101
- ),
102
- ],
103
- language: Annotated[
104
- str | None,
105
- Field(description="Filter by language (e.g., 'python', 'go', 'javascript')."),
106
- ] = None,
107
- author: Annotated[
108
- str | None,
109
- Field(description=("Filter to search for snippets by a specific author.")),
110
- ] = None,
111
- created_after: Annotated[
112
- str | None,
113
- Field(
114
- description=(
115
- "Filter for snippets created after this date (ISO format: YYYY-MM-DD)."
116
- )
117
- ),
118
- ] = None,
119
- created_before: Annotated[
120
- str | None,
121
- Field(
122
- description=(
123
- "Filter for snippets created before this date (ISO format: YYYY-MM-DD)."
124
- )
125
- ),
126
- ] = None,
127
- source_repo: Annotated[
128
- str | None,
129
- Field(
130
- description=(
131
- "Filter results by project source repository (e.g., "
132
- "github.com/example/repo)"
133
- )
134
- ),
135
- ] = None,
136
- ) -> str:
137
- """Search for pre-existing examples of relevant code.
138
-
139
- ⚠️ **ENFORCEMENT:**
140
- For *every* user request that involves writing or modifying code (of any language or
141
- domain), the assistant's *first* action **must** be to call the kodit.search MCP
142
- tool. You may only produce or edit code *after* that tool call and its successful
143
- result.
144
- """
145
- # This docstring is used by the AI assistant to decide when to call the tool. If you
146
- # want to update it, please make sure you thoroughly test the assistant's response
147
- # to the updated tool call. See:
148
- # tests/experiments/cline-prompt-regression-tests/cline_prompt_test.py
149
-
150
- log = structlog.get_logger(__name__)
151
-
152
- log.debug(
153
- "Searching for relevant snippets",
154
- user_intent=user_intent,
155
- keywords=keywords,
156
- file_count=len(related_file_paths),
157
- file_paths=related_file_paths,
158
- file_contents=related_file_contents,
159
- )
160
-
161
- mcp_context: MCPContext = ctx.request_context.lifespan_context
162
-
163
- # Use the unified application service
164
- service = create_code_indexing_application_service(
165
- app_context=mcp_context.app_context,
166
- session=mcp_context.session,
167
- )
168
-
169
- log.debug("Searching for snippets")
170
-
171
- # Create filters if any filter parameters are provided
172
- filters = SnippetSearchFilters.from_cli_params(
173
- language=language,
174
- author=author,
175
- created_after=created_after,
176
- created_before=created_before,
177
- source_repo=source_repo,
178
- )
179
-
180
- search_request = MultiSearchRequest(
181
- keywords=keywords,
182
- code_query="\n".join(related_file_contents),
183
- text_query=user_intent,
184
- filters=filters,
185
- )
186
-
187
- log.debug("Searching for snippets")
188
- snippets = await service.search(request=search_request)
189
-
190
- log.debug("Fusing output")
191
- output = MultiSearchResult.to_jsonlines(results=snippets)
192
-
193
- log.debug("Output", output=output)
194
- return output
222
+ # Register the MCP tools
223
+ register_mcp_tools(mcp)
195
224
 
196
225
 
197
- @mcp.tool()
198
- async def get_version() -> str:
199
- """Get the version of the kodit project."""
200
- return version
226
+ def create_stdio_mcp_server() -> None:
227
+ """Create and run a STDIO MCP server for kodit."""
228
+ mcp.run(transport="stdio", show_banner=False)
kodit/middleware.py CHANGED
@@ -36,8 +36,8 @@ async def logging_middleware(request: Request, call_next: Callable) -> Response:
36
36
  finally:
37
37
  process_time = time.perf_counter_ns() - start_time
38
38
  status_code = response.status_code
39
- client_host = request.client.host
40
- client_port = request.client.port
39
+ client_host = request.client.host if request.client else None
40
+ client_port = request.client.port if request.client else None
41
41
  http_method = request.method
42
42
  http_version = request.scope["http_version"]
43
43
  # Recreate the Uvicorn access log format, but add all parameters as
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kodit
3
- Version: 0.3.6
3
+ Version: 0.3.7
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/
@@ -30,7 +30,7 @@ Requires-Dist: click>=8.1.8
30
30
  Requires-Dist: colorama>=0.4.6
31
31
  Requires-Dist: dotenv>=0.9.9
32
32
  Requires-Dist: fastapi[standard]>=0.115.12
33
- Requires-Dist: fastmcp>=2.3.3
33
+ Requires-Dist: fastmcp>=2.10.4
34
34
  Requires-Dist: gitpython>=3.1.44
35
35
  Requires-Dist: hf-xet>=1.1.2
36
36
  Requires-Dist: httpx-retries>=0.3.2
@@ -38,6 +38,7 @@ Requires-Dist: httpx>=0.28.1
38
38
  Requires-Dist: openai>=1.82.0
39
39
  Requires-Dist: pathspec>=0.12.1
40
40
  Requires-Dist: pydantic-settings>=2.9.1
41
+ Requires-Dist: pystemmer>=3.0.0
41
42
  Requires-Dist: pytable-formatter>=0.1.1
42
43
  Requires-Dist: rudder-sdk-python>=2.1.4
43
44
  Requires-Dist: sentence-transformers>=4.1.0
@@ -1,13 +1,13 @@
1
1
  kodit/.gitignore,sha256=ztkjgRwL9Uud1OEi36hGQeDGk3OLK1NfDEO8YqGYy8o,11
2
2
  kodit/__init__.py,sha256=aEKHYninUq1yh6jaNfvJBYg-6fenpN132nJt1UU6Jxs,59
3
- kodit/_version.py,sha256=5ZRqa3YWFznn7rzKg8d9Vi2wEKohJwIFxhrpOUL3pYQ,511
4
- kodit/app.py,sha256=Q6M9XcMY4s-srHiWjvaPrrkzUveYBRGMOgnlomoIDRo,2738
5
- kodit/cli.py,sha256=7iP1rHVoObnKosNJD87a_JBdidFJtIxo_1fpkELb_jc,18894
3
+ kodit/_version.py,sha256=Mzy3NhAqfY25ymly5Ji2ZQDBbOVx_D1-5ADbqwHbtak,511
4
+ kodit/app.py,sha256=3_smkoioIQEYtRLIGHDtgGkmkP6Movd5CygQEMOStP8,3043
5
+ kodit/cli.py,sha256=ZOS_VzCHGjJRZzZpaVR00QXSPIwRXPYu-pTrbEtlyR0,19328
6
6
  kodit/config.py,sha256=Dh1ybowJyOqZIoQnvF3DykaX2ze1MC0Rjs9oK1iZ7cs,8060
7
7
  kodit/database.py,sha256=kI9yBm4uunsgV4-QeVoCBL0wLzU4kYmYv5qZilGnbPE,1740
8
- kodit/log.py,sha256=WOsLRitpCBtJa5IcsyZpKr146kXXHK2nU5VA90gcJdQ,8736
9
- kodit/mcp.py,sha256=OPscMbGQ05nFHJ_UkntobocZ6Y9wO2ZyRx1tVj7XSsY,6016
10
- kodit/middleware.py,sha256=I6FOkqG9-8RH5kR1-0ZoQWfE4qLCB8lZYv8H_OCH29o,2714
8
+ kodit/log.py,sha256=r0o7IpNvV-dNW-cTNWu1ouJF71vD9wHYzvqDPzeDYfw,8768
9
+ kodit/mcp.py,sha256=aEcPc8dQiZaR0AswCZZNxcm_rhhUZNsEBimYti0ibSI,7221
10
+ kodit/middleware.py,sha256=xBmC6keFeNsS0y8XUcIKzJzuefkE9bq2UhW1fR5cqxg,2770
11
11
  kodit/reporting.py,sha256=icce1ZyiADsA_Qz-mSjgn2H4SSqKuGfLKnw-yrl9nsg,2722
12
12
  kodit/application/__init__.py,sha256=mH50wTpgP9dhbKztFsL8Dda9Hi18TSnMVxXtpp4aGOA,35
13
13
  kodit/application/factories/__init__.py,sha256=bU5CvEnaBePZ7JbkCOp1MGTNP752bnU2uEqmfy5FdRk,37
@@ -30,14 +30,14 @@ kodit/domain/services/index_service.py,sha256=ezVGbWdII25adri4_yyvsAF2eJOt4xmoHR
30
30
  kodit/infrastructure/__init__.py,sha256=HzEYIjoXnkz_i_MHO2e0sIVYweUcRnl2RpyBiTbMObU,28
31
31
  kodit/infrastructure/bm25/__init__.py,sha256=DmGbrEO34FOJy4e685BbyxLA7gPW1eqs2gAxsp6JOuM,34
32
32
  kodit/infrastructure/bm25/bm25_factory.py,sha256=I4eo7qRslnyXIRkBf-StZ5ga2Evrr5J5YFocTChFD3g,884
33
- kodit/infrastructure/bm25/local_bm25_repository.py,sha256=B1ggfHdjC9sFIh62MmSul2tsutWsWFQx5S1Xn07X_I8,4531
33
+ kodit/infrastructure/bm25/local_bm25_repository.py,sha256=rDx8orGhg38n0zSpybEt5QLOWHY2Yt5IxIf9UtlhXXU,4629
34
34
  kodit/infrastructure/bm25/vectorchord_bm25_repository.py,sha256=Jyic55V-38XeTad462Ge751iKyc0X8RNVBM9pr_DVJk,7439
35
35
  kodit/infrastructure/cloning/__init__.py,sha256=IzIvX-yeRRFZ-lfvPVSEe_qXszO6DGQdjKwwDigexyQ,30
36
36
  kodit/infrastructure/cloning/metadata.py,sha256=GD2UnCC1oR82RD0SVUqk9CJOqzXPxhOAHVOp7jqN6Qc,3571
37
37
  kodit/infrastructure/cloning/git/__init__.py,sha256=20ePcp0qE6BuLsjsv4KYB1DzKhMIMsPXwEqIEZtjTJs,34
38
38
  kodit/infrastructure/cloning/git/working_copy.py,sha256=SvaLAJa7FRsLuWjJz-xUeTJ-EkpPi_rIOP-gyuHLIdM,1835
39
39
  kodit/infrastructure/embedding/__init__.py,sha256=F-8nLlWAerYJ0MOIA4tbXHLan8bW5rRR84vzxx6tRKI,39
40
- kodit/infrastructure/embedding/embedding_factory.py,sha256=A6if4XW7Kp-23qrWlLLNyhijwxZLxmhcyCX-ayvQKY4,3451
40
+ kodit/infrastructure/embedding/embedding_factory.py,sha256=SOVX3wGxW8Qo2lJmMZ0kRssXKn6A4W7DmSpgo0zWTfM,3625
41
41
  kodit/infrastructure/embedding/local_vector_search_repository.py,sha256=ExweyNEL5cP-g3eDhGqZSih7zhdOrop2WdFPPJL-tB4,3505
42
42
  kodit/infrastructure/embedding/vectorchord_vector_search_repository.py,sha256=PIoU0HsDlaoXDXnGjOR0LAkAcW4JiE3ymJy_SBhEopc,8030
43
43
  kodit/infrastructure/embedding/embedding_providers/__init__.py,sha256=qeZ-oAIAxMl5QqebGtO1lq-tHjl_ucAwOXePklcwwGk,34
@@ -46,8 +46,8 @@ kodit/infrastructure/embedding/embedding_providers/hash_embedding_provider.py,sh
46
46
  kodit/infrastructure/embedding/embedding_providers/local_embedding_provider.py,sha256=U5fc8jUP8wF-nq1zo-CfSbJbLQyE-3muKmRCaYGtytk,4387
47
47
  kodit/infrastructure/embedding/embedding_providers/openai_embedding_provider.py,sha256=LIK9Iir7geraZoqiaNbeHv3hXrghZRDpYGJDEjZaqzQ,4086
48
48
  kodit/infrastructure/enrichment/__init__.py,sha256=8acZKNzql8Fs0lceFu9U3KoUrOptRBtVIxr_Iw6lz3Y,40
49
- kodit/infrastructure/enrichment/enrichment_factory.py,sha256=Pz0Rb1I68udL_zXY3KvJ3LR3aK_9mdF1nMRGQUu4lM0,1828
50
- kodit/infrastructure/enrichment/local_enrichment_provider.py,sha256=8CATNtgMHgBRt24GrYEwaZKrroNCxMJS-39xQJoG3N0,3818
49
+ kodit/infrastructure/enrichment/enrichment_factory.py,sha256=2h-c96FWgSi0UG6IeL9Yjae80KYdzJqes5HIJQrkpc8,1919
50
+ kodit/infrastructure/enrichment/local_enrichment_provider.py,sha256=7Vlwu1jPJ5KNUn1a51M1P-laUd5YVFJA8EeH6KO-95k,3960
51
51
  kodit/infrastructure/enrichment/null_enrichment_provider.py,sha256=DhZkJBnkvXg_XSAs-oKiFnKqYFPnmTl3ikdxrqeEfbc,713
52
52
  kodit/infrastructure/enrichment/openai_enrichment_provider.py,sha256=fenq4HiJ2UkrzsE2D0A0qpmro38z9mKaIzKKU5v7hnY,3189
53
53
  kodit/infrastructure/git/__init__.py,sha256=0iMosFzudj4_xNIMe2SRbV6l5bWqkjnUsZoFsoZFuM8,33
@@ -57,7 +57,6 @@ kodit/infrastructure/ignore/ignore_pattern_provider.py,sha256=zdxun3GodLfXxyssBK
57
57
  kodit/infrastructure/indexing/__init__.py,sha256=7UPRa2jwCAsa0Orsp6PqXSF8iIXJVzXHMFmrKkI9yH8,38
58
58
  kodit/infrastructure/indexing/auto_indexing_service.py,sha256=PgAyrmR8jNkAOlGnhQjFkqoE22oh-IwYTCg_v4o45Fo,2764
59
59
  kodit/infrastructure/indexing/fusion_service.py,sha256=2B0guBsuKz19uWcs18sIJpUJPzXoRvULgl7UNWQGysA,1809
60
- kodit/infrastructure/indexing/indexing_factory.py,sha256=LPjPCps_wJ9M_fZGRP02bfc2pvYc50ZSTYI99XwRRPg,918
61
60
  kodit/infrastructure/mappers/__init__.py,sha256=QPHOjNreXmBPPovZ6elnYFS0vD-IsmrGl4TT01FCKro,77
62
61
  kodit/infrastructure/mappers/index_mapper.py,sha256=ZSfu8kjTaa8_UY0nTqr4b02NS3VrjqZYkduCN71AL2g,12743
63
62
  kodit/infrastructure/slicing/__init__.py,sha256=x7cjvHA9Ay2weUYE_dpdAaPaStp20M-4U2b5MLgT5KM,37
@@ -68,7 +67,7 @@ kodit/infrastructure/sqlalchemy/embedding_repository.py,sha256=dC2Wzj_zQiWExwfSc
68
67
  kodit/infrastructure/sqlalchemy/entities.py,sha256=Dmh0z-dMI0wfMAPpf62kxU4md6NUH9P5Nx1QSTITOfg,5961
69
68
  kodit/infrastructure/sqlalchemy/index_repository.py,sha256=fMnR3OxZN37dtp1M2Menf0xy31GjK1iv_0zn7EvRKYs,22575
70
69
  kodit/infrastructure/ui/__init__.py,sha256=CzbLOBwIZ6B6iAHEd1L8cIBydCj-n_kobxJAhz2I9_Y,32
71
- kodit/infrastructure/ui/progress.py,sha256=BaAeMEgXlSSb0c_t_NPxnThIktkzzCS9kegb5ExULJs,4791
70
+ kodit/infrastructure/ui/progress.py,sha256=LmEAQKWWSspqb0fOwruyxBfzBG7gmHd6z1iBco1d7_4,4823
72
71
  kodit/infrastructure/ui/spinner.py,sha256=GcP115qtR0VEnGfMEtsGoAUpRzVGUSfiUXfoJJERngA,2357
73
72
  kodit/migrations/README,sha256=ISVtAOvqvKk_5ThM5ioJE-lMkvf9IbknFUFVU_vPma4,58
74
73
  kodit/migrations/__init__.py,sha256=lP5MuwlyWRMO6UcDWnQcQ3G-GYHcFb6rl9gYPHJ1sjo,40
@@ -83,8 +82,8 @@ kodit/migrations/versions/__init__.py,sha256=9-lHzptItTzq_fomdIRBegQNm4Znx6pVjwD
83
82
  kodit/migrations/versions/c3f5137d30f5_index_all_the_things.py,sha256=r7ukmJ_axXLAWewYx-F1fEmZ4JbtFd37i7cSb0tq3y0,1722
84
83
  kodit/utils/__init__.py,sha256=DPEB1i8evnLF4Ns3huuAYg-0pKBFKUFuiDzOKG9r-sw,33
85
84
  kodit/utils/path_utils.py,sha256=thK6YGGNvQThdBaCYCCeCvS1L8x-lwl3AoGht2jnjGw,1645
86
- kodit-0.3.6.dist-info/METADATA,sha256=-niGc2LDxpWdJXSNSFCu9Xwp0nu6O96Be-Cb1RTTwSA,6940
87
- kodit-0.3.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
88
- kodit-0.3.6.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
89
- kodit-0.3.6.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
90
- kodit-0.3.6.dist-info/RECORD,,
85
+ kodit-0.3.7.dist-info/METADATA,sha256=2uWFTgaZtUWs3e1n6b04UHuELp7FCs24P_sxGOz4g7g,6973
86
+ kodit-0.3.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
87
+ kodit-0.3.7.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
88
+ kodit-0.3.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
89
+ kodit-0.3.7.dist-info/RECORD,,
@@ -1,30 +0,0 @@
1
- """Factory for creating indexing services."""
2
-
3
- from sqlalchemy.ext.asyncio import AsyncSession
4
-
5
- from kodit.domain.services.indexing_service import IndexingDomainService
6
- from kodit.infrastructure.indexing.fusion_service import ReciprocalRankFusionService
7
- from kodit.infrastructure.indexing.index_repository import SQLAlchemyIndexRepository
8
-
9
-
10
- def indexing_domain_service_factory(session: AsyncSession) -> IndexingDomainService:
11
- """Create an indexing domain service with all dependencies.
12
-
13
- Args:
14
- session: SQLAlchemy session
15
-
16
- Returns:
17
- Configured indexing domain service
18
-
19
- """
20
- # Create repositories
21
- index_repository = SQLAlchemyIndexRepository(session)
22
-
23
- # Create fusion service
24
- fusion_service = ReciprocalRankFusionService()
25
-
26
- # Create domain service
27
- return IndexingDomainService(
28
- index_repository=index_repository,
29
- fusion_service=fusion_service,
30
- )
File without changes