cocoindex-code 0.2.32__tar.gz → 0.2.34__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 (25) hide show
  1. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/.gitignore +3 -0
  2. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/PKG-INFO +35 -6
  3. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/README.md +30 -1
  4. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/pyproject.toml +5 -5
  5. cocoindex_code-0.2.34/src/cocoindex_code/__init__.py +29 -0
  6. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/_version.py +2 -2
  7. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/cli.py +16 -4
  8. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/client.py +4 -1
  9. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/daemon.py +7 -1
  10. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/protocol.py +6 -0
  11. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/settings.py +6 -2
  12. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/shared.py +6 -2
  13. cocoindex_code-0.2.32/src/cocoindex_code/__init__.py +0 -10
  14. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/LICENSE +0 -0
  15. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/__main__.py +0 -0
  16. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/_daemon_paths.py +0 -0
  17. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/chunking.py +0 -0
  18. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/embedder_defaults.py +0 -0
  19. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/embedder_params.py +0 -0
  20. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/indexer.py +0 -0
  21. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/litellm_embedder.py +0 -0
  22. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/project.py +0 -0
  23. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/query.py +0 -0
  24. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/schema.py +0 -0
  25. {cocoindex_code-0.2.32 → cocoindex_code-0.2.34}/src/cocoindex_code/server.py +0 -0
@@ -33,6 +33,9 @@ ENV/
33
33
  *.swp
34
34
  *.swo
35
35
 
36
+ # Claude Code local config and state
37
+ /.claude/
38
+
36
39
  # Testing
37
40
  .tox/
38
41
  .coverage
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex-code
3
- Version: 0.2.32
3
+ Version: 0.2.34
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.1.0,>=1.0.0
20
+ Requires-Dist: cocoindex[litellm]<1.1.0,>=1.0.6
21
21
  Requires-Dist: einops>=0.8.2
22
22
  Requires-Dist: mcp>=1.0.0
23
23
  Requires-Dist: msgspec>=0.19.0
@@ -29,7 +29,7 @@ Requires-Dist: questionary>=2.0.0
29
29
  Requires-Dist: sqlite-vec>=0.1.0
30
30
  Requires-Dist: typer>=0.9.0
31
31
  Provides-Extra: dev
32
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.0; extra == 'dev'
32
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'dev'
33
33
  Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
34
  Requires-Dist: prek>=0.1.0; extra == 'dev'
35
35
  Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
@@ -37,9 +37,9 @@ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
37
37
  Requires-Dist: pytest>=7.0.0; extra == 'dev'
38
38
  Requires-Dist: ruff>=0.1.0; extra == 'dev'
39
39
  Provides-Extra: embeddings-local
40
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.0; extra == 'embeddings-local'
40
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'embeddings-local'
41
41
  Provides-Extra: full
42
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.0; extra == 'full'
42
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'full'
43
43
  Description-Content-Type: text/markdown
44
44
 
45
45
  <p align="center">
@@ -568,6 +568,23 @@ envs:
568
568
 
569
569
  </details>
570
570
 
571
+ <details>
572
+ <summary>OpenAI-compatible (custom endpoint)</summary>
573
+
574
+ Many providers (vLLM, LM Studio, LocalAI, Together, Fireworks, DeepInfra, …) expose an OpenAI-compatible embedding API. Use the `openai/` prefix and point `OPENAI_BASE_URL` at your endpoint:
575
+
576
+ ```yaml
577
+ embedding:
578
+ model: openai/your-model-name
579
+ envs:
580
+ OPENAI_BASE_URL: https://your-endpoint/v1
581
+ OPENAI_API_KEY: your-api-key
582
+ ```
583
+
584
+ Don't append `/embeddings` to the base URL — LiteLLM handles that.
585
+
586
+ </details>
587
+
571
588
  <details>
572
589
  <summary>Azure OpenAI</summary>
573
590
 
@@ -656,7 +673,7 @@ envs:
656
673
 
657
674
  </details>
658
675
 
659
- Any [LiteLLM-supported model](https://docs.litellm.ai/docs/embedding/supported_embedding) works. When using a LiteLLM model, set `provider: litellm` (or omit `provider` — LiteLLM is the default for non-`sentence-transformers` models).
676
+ Any [LiteLLM-supported model](https://docs.litellm.ai/docs/embedding/supported_embedding) works. When using a LiteLLM model, set `provider: litellm` (or omit `provider` — LiteLLM is the default for non-`sentence-transformers` models). For the full list of env vars each provider reads (API keys, base URLs, regions, …), see LiteLLM's [Setting API Keys](https://docs.litellm.ai/docs/set_keys).
660
677
 
661
678
  ### Local SentenceTransformers Models
662
679
 
@@ -776,6 +793,18 @@ If you previously configured `cocoindex-code` via environment variables, the `co
776
793
  | `COCOINDEX_CODE_EXCLUDED_PATTERNS` | `exclude_patterns` in project `settings.yml` |
777
794
  | `COCOINDEX_CODE_EXTRA_EXTENSIONS` | `include_patterns` + `language_overrides` in project `settings.yml` |
778
795
 
796
+ ## Telemetry
797
+
798
+ `cocoindex-code` sends anonymous usage telemetry through CocoIndex so we can see how the tool is used in aggregate and prioritize improvements. The events identify themselves as `application: cocoindex-code`.
799
+
800
+ We **do not** collect your source code, file paths, queries, search results, embeddings, settings, or any other content from your codebase or environment.
801
+
802
+ To opt out, set:
803
+
804
+ ```bash
805
+ export COCOINDEX_DISABLE_USAGE_TRACKING=1
806
+ ```
807
+
779
808
  ## Large codebase / Enterprise
780
809
  [CocoIndex](https://github.com/cocoindex-io/cocoindex) is an ultra efficient indexing engine that also works on large codebases at scale for enterprises. In enterprise scenarios it is a lot more efficient to share indexes with teammates when there are large or many repos. We also have advanced features like branch dedupe etc designed for enterprise users.
781
810
 
@@ -524,6 +524,23 @@ envs:
524
524
 
525
525
  </details>
526
526
 
527
+ <details>
528
+ <summary>OpenAI-compatible (custom endpoint)</summary>
529
+
530
+ Many providers (vLLM, LM Studio, LocalAI, Together, Fireworks, DeepInfra, …) expose an OpenAI-compatible embedding API. Use the `openai/` prefix and point `OPENAI_BASE_URL` at your endpoint:
531
+
532
+ ```yaml
533
+ embedding:
534
+ model: openai/your-model-name
535
+ envs:
536
+ OPENAI_BASE_URL: https://your-endpoint/v1
537
+ OPENAI_API_KEY: your-api-key
538
+ ```
539
+
540
+ Don't append `/embeddings` to the base URL — LiteLLM handles that.
541
+
542
+ </details>
543
+
527
544
  <details>
528
545
  <summary>Azure OpenAI</summary>
529
546
 
@@ -612,7 +629,7 @@ envs:
612
629
 
613
630
  </details>
614
631
 
615
- Any [LiteLLM-supported model](https://docs.litellm.ai/docs/embedding/supported_embedding) works. When using a LiteLLM model, set `provider: litellm` (or omit `provider` — LiteLLM is the default for non-`sentence-transformers` models).
632
+ Any [LiteLLM-supported model](https://docs.litellm.ai/docs/embedding/supported_embedding) works. When using a LiteLLM model, set `provider: litellm` (or omit `provider` — LiteLLM is the default for non-`sentence-transformers` models). For the full list of env vars each provider reads (API keys, base URLs, regions, …), see LiteLLM's [Setting API Keys](https://docs.litellm.ai/docs/set_keys).
616
633
 
617
634
  ### Local SentenceTransformers Models
618
635
 
@@ -732,6 +749,18 @@ If you previously configured `cocoindex-code` via environment variables, the `co
732
749
  | `COCOINDEX_CODE_EXCLUDED_PATTERNS` | `exclude_patterns` in project `settings.yml` |
733
750
  | `COCOINDEX_CODE_EXTRA_EXTENSIONS` | `include_patterns` + `language_overrides` in project `settings.yml` |
734
751
 
752
+ ## Telemetry
753
+
754
+ `cocoindex-code` sends anonymous usage telemetry through CocoIndex so we can see how the tool is used in aggregate and prioritize improvements. The events identify themselves as `application: cocoindex-code`.
755
+
756
+ We **do not** collect your source code, file paths, queries, search results, embeddings, settings, or any other content from your codebase or environment.
757
+
758
+ To opt out, set:
759
+
760
+ ```bash
761
+ export COCOINDEX_DISABLE_USAGE_TRACKING=1
762
+ ```
763
+
735
764
  ## Large codebase / Enterprise
736
765
  [CocoIndex](https://github.com/cocoindex-io/cocoindex) is an ultra efficient indexing engine that also works on large codebases at scale for enterprises. In enterprise scenarios it is a lot more efficient to share indexes with teammates when there are large or many repos. We also have advanced features like branch dedupe etc designed for enterprise users.
737
766
 
@@ -23,7 +23,7 @@ classifiers = [
23
23
 
24
24
  dependencies = [
25
25
  "mcp>=1.0.0",
26
- "cocoindex[litellm]>=1.0.0,<1.1.0",
26
+ "cocoindex[litellm]>=1.0.6,<1.1.0",
27
27
  "sqlite-vec>=0.1.0",
28
28
  "pydantic>=2.0.0",
29
29
  "numpy>=1.24.0",
@@ -39,7 +39,7 @@ dependencies = [
39
39
  # `embeddings-local` is the primary feature extra: it pulls in
40
40
  # `sentence-transformers` (via cocoindex) so local embeddings work without
41
41
  # an API key.
42
- embeddings-local = ["cocoindex[sentence-transformers]>=1.0.0,<1.1.0"]
42
+ embeddings-local = ["cocoindex[sentence-transformers]>=1.0.6,<1.1.0"]
43
43
  # `full` is the umbrella "batteries-included" alias. Today it's just
44
44
  # `embeddings-local`, but we expect to bundle more optional niceties under
45
45
  # it over time — users who want everything can keep using `[full]` and pick
@@ -47,7 +47,7 @@ embeddings-local = ["cocoindex[sentence-transformers]>=1.0.0,<1.1.0"]
47
47
  # `:full` image variant for consistency across install paths. Contents are
48
48
  # inlined rather than self-referencing `cocoindex-code[embeddings-local]`
49
49
  # to avoid resolver edge cases with older pip.
50
- full = ["cocoindex[sentence-transformers]>=1.0.0,<1.1.0"]
50
+ full = ["cocoindex[sentence-transformers]>=1.0.6,<1.1.0"]
51
51
  dev = [
52
52
  "pytest>=7.0.0",
53
53
  "pytest-asyncio>=0.21.0",
@@ -55,7 +55,7 @@ dev = [
55
55
  "ruff>=0.1.0",
56
56
  "mypy>=1.0.0",
57
57
  "prek>=0.1.0",
58
- "cocoindex[sentence-transformers]>=1.0.0,<1.1.0",
58
+ "cocoindex[sentence-transformers]>=1.0.6,<1.1.0",
59
59
  ]
60
60
 
61
61
  [project.scripts]
@@ -89,7 +89,7 @@ dev = [
89
89
  "mypy>=1.0.0",
90
90
  "prek>=0.1.0",
91
91
  "types-pyyaml>=6.0.12.20250915",
92
- "cocoindex[sentence-transformers]>=1.0.3,<1.1.0",
92
+ "cocoindex[sentence-transformers]>=1.0.7,<1.1.0",
93
93
  ]
94
94
 
95
95
  [tool.ruff]
@@ -0,0 +1,29 @@
1
+ """CocoIndex Code - MCP server for indexing and querying codebases."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import os
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ # Identify this application in cocoindex's telemetry payloads. Must be set
10
+ # before any `import cocoindex` runs (the value is read once at telemetry
11
+ # init time). See cocoindex-io/cocoindex#1992.
12
+ os.environ.setdefault("COCOINDEX_APPLICATION_FOR_TRACKING", "cocoindex-code")
13
+
14
+ logging.basicConfig(level=logging.WARNING)
15
+
16
+ from ._version import __version__ # noqa: E402
17
+
18
+ if TYPE_CHECKING:
19
+ from .server import main as main
20
+
21
+ __all__ = ["main", "__version__"]
22
+
23
+
24
+ def __getattr__(name: str) -> Any:
25
+ if name == "main":
26
+ from .server import main
27
+
28
+ return main
29
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.2.32'
22
- __version_tuple__ = version_tuple = (0, 2, 32)
21
+ __version__ = version = '0.2.34'
22
+ __version_tuple__ = version_tuple = (0, 2, 34)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -7,12 +7,18 @@ import os
7
7
  import sys
8
8
  from collections.abc import Callable
9
9
  from pathlib import Path
10
- from typing import TypeVar
10
+ from typing import TYPE_CHECKING, TypeVar
11
11
 
12
12
  import typer as _typer
13
13
 
14
- from .client import DaemonStartError
15
- from .protocol import DoctorCheckResult, IndexingProgress, ProjectStatusResponse, SearchResponse
14
+ if TYPE_CHECKING:
15
+ from .protocol import (
16
+ DoctorCheckResult,
17
+ IndexingProgress,
18
+ ProjectStatusResponse,
19
+ SearchResponse,
20
+ )
21
+
16
22
  from .settings import (
17
23
  DEFAULT_ST_MODEL,
18
24
  EmbeddingSettings,
@@ -104,6 +110,8 @@ def _catch_daemon_start_error(func: _F) -> _F:
104
110
 
105
111
  @functools.wraps(func)
106
112
  def wrapper(*args: object, **kwargs: object) -> object:
113
+ from .client import DaemonStartError
114
+
107
115
  try:
108
116
  return func(*args, **kwargs)
109
117
  except DaemonStartError as e:
@@ -204,7 +212,7 @@ def _run_index_with_progress(project_root: str) -> None:
204
212
  except RuntimeError as e:
205
213
  live.stop()
206
214
  # Let DaemonStartError propagate to the decorator for consistent handling.
207
- if isinstance(e, DaemonStartError):
215
+ if isinstance(e, _client.DaemonStartError):
208
216
  raise
209
217
  _typer.echo(f"Indexing failed: {e}", err=True)
210
218
  raise _typer.Exit(code=1)
@@ -397,6 +405,7 @@ def _run_init_model_check(settings_path: Path) -> None:
397
405
  from rich.spinner import Spinner as _Spinner
398
406
 
399
407
  from . import client as _client
408
+ from .protocol import DoctorCheckResult
400
409
 
401
410
  err_console = _Console(stderr=True)
402
411
  results: list[DoctorCheckResult] = []
@@ -694,6 +703,9 @@ def _print_doctor_result(result: DoctorCheckResult) -> None:
694
703
  _typer.echo(f" {line}")
695
704
  for err in result.errors:
696
705
  _typer.echo(_click.style(f" ERROR: {err}", fg="red"), err=True)
706
+ if result.traceback:
707
+ for line in result.traceback.splitlines():
708
+ _typer.echo(_click.style(f" {line}", fg="bright_black"), err=True)
697
709
 
698
710
 
699
711
  @app.command()
@@ -363,7 +363,10 @@ def doctor(
363
363
  raise RuntimeError("Connection to daemon lost during doctor checks")
364
364
  resp = decode_response(data)
365
365
  if isinstance(resp, ErrorResponse):
366
- raise RuntimeError(f"Daemon error: {resp.message}")
366
+ detail = f"Daemon error: {resp.message}"
367
+ if resp.traceback:
368
+ detail += f"\n{resp.traceback}"
369
+ raise RuntimeError(detail)
367
370
  if isinstance(resp, DoctorResponse):
368
371
  results.append(resp.result)
369
372
  if on_result is not None:
@@ -10,6 +10,7 @@ import signal
10
10
  import sys
11
11
  import threading
12
12
  import time
13
+ import traceback
13
14
  from collections.abc import AsyncIterator, Callable
14
15
  from multiprocessing.connection import Connection, Listener
15
16
  from pathlib import Path
@@ -250,7 +251,11 @@ async def handle_connection(
250
251
  conn.send_bytes(encode_response(resp))
251
252
  except Exception as exc:
252
253
  logger.exception("Error during streaming response")
253
- conn.send_bytes(encode_response(ErrorResponse(message=str(exc))))
254
+ conn.send_bytes(
255
+ encode_response(
256
+ ErrorResponse(message=str(exc), traceback=traceback.format_exc())
257
+ )
258
+ )
254
259
  else:
255
260
  conn.send_bytes(encode_response(result))
256
261
  except (EOFError, OSError, asyncio.CancelledError):
@@ -359,6 +364,7 @@ async def _check_model(
359
364
  ok=False,
360
365
  details=[params_detail],
361
366
  errors=[result.error],
367
+ traceback=result.traceback,
362
368
  )
363
369
 
364
370
 
@@ -154,6 +154,9 @@ class DoctorCheckResult(_msgspec.Struct):
154
154
  ok: bool
155
155
  details: list[str]
156
156
  errors: list[str]
157
+ # Full formatted traceback for a failed check, shown by `ccc doctor` to aid
158
+ # debugging of daemon-side exceptions (e.g. a failing model check).
159
+ traceback: str | None = None
157
160
 
158
161
 
159
162
  class DoctorResponse(_msgspec.Struct, tag="doctor"):
@@ -175,6 +178,9 @@ class DaemonEnvResponse(_msgspec.Struct, tag="daemon_env"):
175
178
 
176
179
  class ErrorResponse(_msgspec.Struct, tag="error"):
177
180
  message: str
181
+ # Full formatted traceback from the daemon, when the error originates from an
182
+ # unhandled exception. Surfaced by the CLI so daemon-side failures are debuggable.
183
+ traceback: str | None = None
178
184
 
179
185
 
180
186
  Response = (
@@ -5,10 +5,12 @@ from __future__ import annotations
5
5
  import os
6
6
  from dataclasses import dataclass, field
7
7
  from pathlib import Path
8
- from typing import Any
8
+ from typing import TYPE_CHECKING, Any
9
9
 
10
10
  import yaml as _yaml
11
- from pathspec import GitIgnoreSpec
11
+
12
+ if TYPE_CHECKING:
13
+ from pathspec import GitIgnoreSpec
12
14
 
13
15
  # ---------------------------------------------------------------------------
14
16
  # Default file patterns (moved from indexer.py)
@@ -391,6 +393,8 @@ def global_settings_mtime_us() -> int | None:
391
393
 
392
394
  def load_gitignore_spec(project_root: Path) -> GitIgnoreSpec | None:
393
395
  """Load a GitIgnoreSpec for the project's ``.gitignore`` if present."""
396
+ from pathspec import GitIgnoreSpec
397
+
394
398
  gitignore = project_root / ".gitignore"
395
399
  if not gitignore.is_file():
396
400
  return None
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import importlib.util
6
6
  import logging
7
7
  import pathlib
8
+ import traceback as _tb
8
9
  from dataclasses import dataclass
9
10
  from typing import TYPE_CHECKING, Annotated, Any, NamedTuple, Union
10
11
 
@@ -47,11 +48,14 @@ def is_sentence_transformers_installed() -> bool:
47
48
  class EmbeddingCheckResult(NamedTuple):
48
49
  """Outcome of a single embed-test call. See `check_embedding`.
49
50
 
50
- Exactly one of ``dim`` / ``error`` is set: ``error is None`` means success.
51
+ On success ``error is None`` and ``dim`` holds the embedding dimension. On
52
+ failure ``error`` holds a one-line summary and ``traceback`` the full
53
+ formatted traceback (for surfacing daemon-side stack traces in `ccc doctor`).
51
54
  """
52
55
 
53
56
  dim: int | None
54
57
  error: str | None
58
+ traceback: str | None = None
55
59
 
56
60
 
57
61
  async def check_embedding(
@@ -73,7 +77,7 @@ async def check_embedding(
73
77
  msg = " ".join(f"{type(e).__name__}: {e}".splitlines())
74
78
  if len(msg) > 500:
75
79
  msg = msg[:500] + "…"
76
- return EmbeddingCheckResult(dim=None, error=msg)
80
+ return EmbeddingCheckResult(dim=None, error=msg, traceback=_tb.format_exc())
77
81
 
78
82
 
79
83
  def create_embedder(
@@ -1,10 +0,0 @@
1
- """CocoIndex Code - MCP server for indexing and querying codebases."""
2
-
3
- import logging
4
-
5
- logging.basicConfig(level=logging.WARNING)
6
-
7
- from ._version import __version__ # noqa: E402
8
- from .server import main # noqa: E402
9
-
10
- __all__ = ["main", "__version__"]
File without changes