cocoindex-code 0.2.38__tar.gz → 0.2.39__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 (26) hide show
  1. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/PKG-INFO +1 -1
  2. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/_version.py +2 -2
  3. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/client.py +40 -3
  4. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/protocol.py +9 -1
  5. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/.gitignore +0 -0
  6. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/LICENSE +0 -0
  7. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/README.md +0 -0
  8. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/pyproject.toml +0 -0
  9. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/__init__.py +0 -0
  10. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/__main__.py +0 -0
  11. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/_daemon_paths.py +0 -0
  12. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/chunking.py +0 -0
  13. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/cli.py +0 -0
  14. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/daemon.py +0 -0
  15. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/embedder_defaults.py +0 -0
  16. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/embedder_params.py +0 -0
  17. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/file_walk.py +0 -0
  18. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/grep.py +0 -0
  19. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/indexer.py +0 -0
  20. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/litellm_embedder.py +0 -0
  21. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/project.py +0 -0
  22. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/query.py +0 -0
  23. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/schema.py +0 -0
  24. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/server.py +0 -0
  25. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/settings.py +0 -0
  26. {cocoindex_code-0.2.38 → cocoindex_code-0.2.39}/src/cocoindex_code/shared.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex-code
3
- Version: 0.2.38
3
+ Version: 0.2.39
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
@@ -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.38'
22
- __version_tuple__ = version_tuple = (0, 2, 38)
21
+ __version__ = version = '0.2.39'
22
+ __version_tuple__ = version_tuple = (0, 2, 39)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -18,6 +18,8 @@ from multiprocessing.connection import Client, Connection
18
18
  from pathlib import Path
19
19
  from typing import NamedTuple
20
20
 
21
+ import msgspec
22
+
21
23
  from ._daemon_paths import (
22
24
  connection_family,
23
25
  daemon_log_path,
@@ -158,6 +160,16 @@ def _connect_and_handshake() -> Connection:
158
160
  if _daemon_ensured and not e.resp.ok:
159
161
  raise
160
162
  stop_daemon()
163
+ except DaemonProtocolError:
164
+ # The reply didn't even decode — a daemon whose wire protocol
165
+ # drifted beyond what the version-mismatch path can express (e.g.
166
+ # still running a pre-upgrade binary). Same treatment as a version
167
+ # mismatch: restart it below; once a matching daemon was already
168
+ # ensured this cannot legitimately happen, so fail fast instead of
169
+ # looping on restarts.
170
+ if _daemon_ensured:
171
+ raise
172
+ stop_daemon()
161
173
  except (ConnectionRefusedError, OSError):
162
174
  # No daemon answered. Normal on the first call of this process (start
163
175
  # one below). If we had already ensured one, decide crash vs graceful
@@ -238,7 +250,15 @@ def _raw_connect_and_handshake() -> _HandshakeResult:
238
250
  conn.close()
239
251
  raise ConnectionRefusedError(f"Handshake failed: {e}") from e
240
252
 
241
- resp = decode_response(data)
253
+ try:
254
+ resp = decode_response(data)
255
+ except msgspec.DecodeError as e:
256
+ # The daemon speaks an incompatible wire protocol — e.g. a stale
257
+ # pre-upgrade daemon whose handshake reply no longer matches this
258
+ # client's schema. Must not escape as a raw decode error: the caller
259
+ # handles DaemonProtocolError by restarting the daemon (issue #237).
260
+ conn.close()
261
+ raise DaemonProtocolError(f"Undecodable handshake reply from daemon: {e}") from e
242
262
  if isinstance(resp, ErrorResponse):
243
263
  conn.close()
244
264
  raise RuntimeError(f"Daemon error: {resp.message}")
@@ -274,6 +294,19 @@ class DaemonVersionError(RuntimeError):
274
294
  super().__init__(message)
275
295
 
276
296
 
297
+ class DaemonProtocolError(RuntimeError):
298
+ """Raised when the daemon's handshake reply cannot be decoded at all.
299
+
300
+ A version-mismatched daemon normally reports itself via ``resp.ok`` being
301
+ False (→ ``DaemonVersionError``), but that requires its reply to decode
302
+ against this client's schema. When even decoding fails, the daemon is
303
+ from a version whose wire protocol drifted too far — handled the same
304
+ way: restart on first contact, fail fast once a matching daemon was
305
+ already ensured. Subclasses RuntimeError so broad daemon-failure handlers
306
+ (e.g. in ``stop_daemon``) cover it.
307
+ """
308
+
309
+
277
310
  class DaemonStartError(RuntimeError):
278
311
  """Raised when the daemon process fails to start.
279
312
 
@@ -427,7 +460,7 @@ def send_heartbeat() -> bool:
427
460
  """
428
461
  try:
429
462
  conn, _resp = _raw_connect_and_handshake()
430
- except (ConnectionRefusedError, DaemonVersionError, OSError):
463
+ except (ConnectionRefusedError, DaemonVersionError, DaemonProtocolError, OSError):
431
464
  return False
432
465
  try:
433
466
  conn.send_bytes(encode_request(HeartbeatRequest()))
@@ -608,7 +641,11 @@ def stop_daemon() -> None:
608
641
  conn.recv_bytes()
609
642
  finally:
610
643
  conn.close()
611
- except (ConnectionRefusedError, OSError, RuntimeError, DaemonVersionError):
644
+ except (ConnectionRefusedError, OSError, RuntimeError, DaemonVersionError, DaemonProtocolError):
645
+ # A version-mismatched or protocol-incompatible daemon refuses the
646
+ # handshake, so the graceful StopRequest is impossible — fall through
647
+ # to the SIGTERM escalation below, which must never be skipped just
648
+ # because the daemon speaks a different protocol (issue #237).
612
649
  pass
613
650
 
614
651
  if _wait_for_daemon_exit(timeout=3.0):
@@ -79,13 +79,21 @@ Request = (
79
79
 
80
80
 
81
81
  class HandshakeResponse(_msgspec.Struct, tag="handshake"):
82
+ # The handshake is the one message exchanged between *mismatched*
83
+ # client/daemon versions — it is how a mismatch gets detected in the
84
+ # first place. Every field added after a release MUST have a default:
85
+ # a required field makes an older daemon's reply undecodable, which
86
+ # breaks the restart-on-mismatch path and bricks every command
87
+ # (issue #237).
82
88
  ok: bool
83
89
  daemon_version: str
84
90
  # The daemon's process id. The client remembers it so that, when the
85
91
  # daemon later vanishes, the graceful-exit marker (written on shutdown
86
92
  # with the same pid) can be matched race-free against the exact process
87
93
  # the client was talking to — distinguishing a graceful exit from a crash.
88
- pid: int
94
+ # None only when decoding the reply of a pre-0.2.38 daemon, whose
95
+ # handshake never satisfies ``ok`` and version checks anyway.
96
+ pid: int | None = None
89
97
  global_settings_mtime_us: int | None = None
90
98
  # Non-fatal daemon-side warnings surfaced to the client on every handshake.
91
99
  # The client dedupes and prints them to stderr (see client._print_handshake_warnings).
File without changes