cocoindex-code 0.2.3__tar.gz → 0.2.5__tar.gz

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.
Files changed (22) hide show
  1. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/PKG-INFO +2 -2
  2. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/pyproject.toml +1 -1
  3. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/_version.py +2 -2
  4. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/cli.py +31 -59
  5. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/client.py +203 -186
  6. cocoindex_code-0.2.5/src/cocoindex_code/daemon.py +429 -0
  7. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/indexer.py +7 -7
  8. cocoindex_code-0.2.5/src/cocoindex_code/project.py +285 -0
  9. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/server.py +21 -31
  10. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/settings.py +0 -4
  11. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/shared.py +3 -5
  12. cocoindex_code-0.2.3/src/cocoindex_code/daemon.py +0 -642
  13. cocoindex_code-0.2.3/src/cocoindex_code/project.py +0 -124
  14. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/.gitignore +0 -0
  15. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/LICENSE +0 -0
  16. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/README.md +0 -0
  17. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/__init__.py +0 -0
  18. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/__main__.py +0 -0
  19. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/config.py +0 -0
  20. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/protocol.py +0 -0
  21. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/query.py +0 -0
  22. {cocoindex_code-0.2.3 → cocoindex_code-0.2.5}/src/cocoindex_code/schema.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex-code
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: MCP server for indexing and querying codebases using CocoIndex
5
5
  Project-URL: Homepage, https://github.com/cocoindex-io/cocoindex-code
6
6
  Project-URL: Repository, https://github.com/cocoindex-io/cocoindex-code
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Requires-Python: >=3.11
20
- Requires-Dist: cocoindex[litellm]==1.0.0a33
20
+ Requires-Dist: cocoindex[litellm]==1.0.0a35
21
21
  Requires-Dist: einops>=0.8.2
22
22
  Requires-Dist: mcp>=1.0.0
23
23
  Requires-Dist: msgspec>=0.19.0
@@ -23,7 +23,7 @@ classifiers = [
23
23
 
24
24
  dependencies = [
25
25
  "mcp>=1.0.0",
26
- "cocoindex[litellm]==1.0.0a33",
26
+ "cocoindex[litellm]==1.0.0a35",
27
27
  "sentence-transformers>=2.2.0",
28
28
  "sqlite-vec>=0.1.0",
29
29
  "pydantic>=2.0.0",
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.3'
32
- __version_tuple__ = version_tuple = (0, 2, 3)
31
+ __version__ = version = '0.2.5'
32
+ __version_tuple__ = version_tuple = (0, 2, 5)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -3,13 +3,9 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from pathlib import Path
6
- from typing import TYPE_CHECKING
7
6
 
8
7
  import typer as _typer
9
8
 
10
- if TYPE_CHECKING:
11
- from .client import DaemonClient
12
-
13
9
  from .protocol import IndexingProgress, ProjectStatusResponse, SearchResponse
14
10
  from .settings import (
15
11
  default_project_settings,
@@ -52,22 +48,6 @@ def require_project_root() -> Path:
52
48
  return root
53
49
 
54
50
 
55
- def require_daemon_for_project() -> tuple[DaemonClient, str]:
56
- """Resolve project root, then connect to daemon (auto-starting if needed).
57
-
58
- Returns ``(client, project_root_str)``. Exits on failure.
59
- """
60
- from .client import ensure_daemon
61
-
62
- project_root = require_project_root()
63
- try:
64
- client = ensure_daemon()
65
- except Exception as e:
66
- _typer.echo(f"Error: Failed to connect to daemon: {e}", err=True)
67
- raise _typer.Exit(code=1)
68
- return client, str(project_root)
69
-
70
-
71
51
  def resolve_default_path(project_root: Path) -> str | None:
72
52
  """Compute default ``--path`` filter from CWD relative to project root."""
73
53
  cwd = Path.cwd().resolve()
@@ -101,7 +81,7 @@ def print_index_stats(status: ProjectStatusResponse) -> None:
101
81
  if status.progress is not None:
102
82
  _typer.echo(f"Indexing in progress: {_format_progress(status.progress)}")
103
83
  if not status.index_exists:
104
- _typer.echo("\nIndex not created yet. Run `ccc index` to build the index.")
84
+ _typer.echo("\nIndex not created yet.")
105
85
  return
106
86
  _typer.echo("\nIndex stats:")
107
87
  _typer.echo(f" Chunks: {status.total_chunks}")
@@ -128,12 +108,14 @@ def print_search_results(response: SearchResponse) -> None:
128
108
  _typer.echo(r.content)
129
109
 
130
110
 
131
- def _run_index_with_progress(client: DaemonClient, project_root: str) -> None:
111
+ def _run_index_with_progress(project_root: str) -> None:
132
112
  """Run indexing with streaming progress display. Exits on failure."""
133
113
  from rich.console import Console as _Console
134
114
  from rich.live import Live as _Live
135
115
  from rich.spinner import Spinner as _Spinner
136
116
 
117
+ from . import client as _client
118
+
137
119
  err_console = _Console(stderr=True)
138
120
  last_progress_line: str | None = None
139
121
 
@@ -153,7 +135,7 @@ def _run_index_with_progress(client: DaemonClient, project_root: str) -> None:
153
135
  live.update(_Spinner("dots", last_progress_line))
154
136
 
155
137
  try:
156
- resp = client.index(project_root, on_progress=_on_progress, on_waiting=_on_waiting)
138
+ resp = _client.index(project_root, on_progress=_on_progress, on_waiting=_on_waiting)
157
139
  except RuntimeError as e:
158
140
  live.stop()
159
141
  _typer.echo(f"Indexing failed: {e}", err=True)
@@ -169,7 +151,6 @@ def _run_index_with_progress(client: DaemonClient, project_root: str) -> None:
169
151
 
170
152
 
171
153
  def _search_with_wait_spinner(
172
- client: DaemonClient,
173
154
  project_root: str,
174
155
  query: str,
175
156
  languages: list[str] | None = None,
@@ -182,6 +163,8 @@ def _search_with_wait_spinner(
182
163
  from rich.live import Live as _Live
183
164
  from rich.spinner import Spinner as _Spinner
184
165
 
166
+ from . import client as _client
167
+
185
168
  err_console = _Console(stderr=True)
186
169
 
187
170
  with _Live(_Spinner("dots", "Searching..."), console=err_console, transient=True) as live:
@@ -192,7 +175,7 @@ def _search_with_wait_spinner(
192
175
  refresh=True,
193
176
  )
194
177
 
195
- resp = client.search(
178
+ resp = _client.search(
196
179
  project_root=project_root,
197
180
  query=query,
198
181
  languages=languages,
@@ -305,13 +288,12 @@ def init(
305
288
  @app.command()
306
289
  def index() -> None:
307
290
  """Create/update index for the codebase."""
308
- client, project_root = require_daemon_for_project()
309
- print_project_header(project_root)
310
-
311
- _run_index_with_progress(client, project_root)
291
+ from . import client as _client
312
292
 
313
- status = client.project_status(project_root)
314
- print_index_stats(status)
293
+ project_root = str(require_project_root())
294
+ print_project_header(project_root)
295
+ _run_index_with_progress(project_root)
296
+ print_index_stats(_client.project_status(project_root))
315
297
 
316
298
 
317
299
  @app.command()
@@ -324,12 +306,11 @@ def search(
324
306
  refresh: bool = _typer.Option(False, "--refresh", help="Refresh index before searching"),
325
307
  ) -> None:
326
308
  """Semantic search across the codebase."""
327
- client, project_root = require_daemon_for_project()
309
+ project_root = str(require_project_root())
328
310
  query_str = " ".join(query)
329
311
 
330
- # Refresh index with progress display before searching
331
312
  if refresh:
332
- _run_index_with_progress(client, project_root)
313
+ _run_index_with_progress(project_root)
333
314
 
334
315
  # Default path filter from CWD
335
316
  paths: list[str] | None = None
@@ -341,7 +322,6 @@ def search(
341
322
  paths = [default]
342
323
 
343
324
  resp = _search_with_wait_spinner(
344
- client,
345
325
  project_root=project_root,
346
326
  query=query_str,
347
327
  languages=lang or None,
@@ -355,10 +335,11 @@ def search(
355
335
  @app.command()
356
336
  def status() -> None:
357
337
  """Show project status."""
358
- client, project_root = require_daemon_for_project()
338
+ from . import client as _client
339
+
340
+ project_root = str(require_project_root())
359
341
  print_project_header(project_root)
360
- resp = client.project_status(project_root)
361
- print_index_stats(resp)
342
+ print_index_stats(_client.project_status(project_root))
362
343
 
363
344
 
364
345
  @app.command()
@@ -400,12 +381,9 @@ def reset(
400
381
 
401
382
  # Remove project from daemon first so it releases file handles
402
383
  try:
403
- from .client import DaemonClient
384
+ from . import client as _client
404
385
 
405
- client = DaemonClient.connect()
406
- client.handshake()
407
- client.remove_project(str(project_root))
408
- client.close()
386
+ _client.remove_project(str(project_root))
409
387
  except (ConnectionRefusedError, OSError, RuntimeError):
410
388
  pass # Daemon not running — that's fine
411
389
 
@@ -442,26 +420,27 @@ def mcp() -> None:
442
420
  """Run as MCP server (stdio mode)."""
443
421
  import asyncio
444
422
 
445
- client, project_root = require_daemon_for_project()
423
+ project_root = str(require_project_root())
446
424
 
447
425
  async def _run_mcp() -> None:
448
426
  from .server import create_mcp_server
449
427
 
450
- mcp_server = create_mcp_server(client, project_root)
451
- # Trigger initial indexing in background
452
- asyncio.create_task(_bg_index(client, project_root))
428
+ mcp_server = create_mcp_server(project_root)
429
+ asyncio.create_task(_bg_index(project_root))
453
430
  await mcp_server.run_stdio_async()
454
431
 
455
432
  asyncio.run(_run_mcp())
456
433
 
457
434
 
458
- async def _bg_index(client, project_root: str) -> None: # type: ignore[no-untyped-def]
459
- """Index in background, swallowing errors."""
435
+ async def _bg_index(project_root: str) -> None:
436
+ """Index in background. Each call opens its own daemon connection."""
460
437
  import asyncio
461
438
 
439
+ from . import client as _client
440
+
462
441
  loop = asyncio.get_event_loop()
463
442
  try:
464
- await loop.run_in_executor(None, client.index, project_root)
443
+ await loop.run_in_executor(None, lambda: _client.index(project_root))
465
444
  except Exception:
466
445
  pass
467
446
 
@@ -472,15 +451,9 @@ async def _bg_index(client, project_root: str) -> None: # type: ignore[no-untyp
472
451
  @daemon_app.command("status")
473
452
  def daemon_status() -> None:
474
453
  """Show daemon status."""
475
- from .client import ensure_daemon
476
-
477
- try:
478
- client = ensure_daemon()
479
- except Exception as e:
480
- _typer.echo(f"Error: {e}", err=True)
481
- raise _typer.Exit(code=1)
454
+ from . import client as _client
482
455
 
483
- resp = client.daemon_status()
456
+ resp = _client.daemon_status()
484
457
  _typer.echo(f"Daemon version: {resp.version}")
485
458
  _typer.echo(f"Uptime: {resp.uptime_seconds:.1f}s")
486
459
  if resp.projects:
@@ -490,7 +463,6 @@ def daemon_status() -> None:
490
463
  _typer.echo(f" {p.project_root} [{state}]")
491
464
  else:
492
465
  _typer.echo("No projects loaded.")
493
- client.close()
494
466
 
495
467
 
496
468
  @daemon_app.command("restart")