Skip to content

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 03 Mar 02:50
· 64 commits to main since this release

[0.2.0] - 2026-03-02

Added

  • Cross-process file locking — filelock serializes database access across concurrent MCP instances (e.g. Cursor + Claude Desktop sharing the same cache). Lock timeout produces a clear RuntimeError instead of cryptic SQLite crashes.
  • Atomic file writes — All write/edit/batch_edit operations use temp-file + rename to prevent data loss on crash or signal interruption.
  • Thread-safe connection pool — threading.Lock around pool counter prevents connection overflow under concurrent access.
  • Thread-safe tokenizer init — Double-checked locking prevents duplicate downloads when multiple threads call get_tokenizer() simultaneously. Download is now atomic (temp file + rename).
  • Thread-safe ZSTD compressor cache — Double-checked locking on lazy compressor/decompressor initialization.

Fixed

  • Directory filter bypass — search(directory=...) used startswith() which matched /project_evil when filtering for /project. Now uses Path.is_relative_to().
  • Special files passed to formatter — _format_file now rejects char devices, pipes, and /proc entries via stat.S_ISREG before spawning subprocess.
  • Startup crash on init failure — UnboundLocalError when SemanticCache() or warmup() raised during lifespan. cache is now initialized to None with proper guards.
  • Negative offset/limit silently wrapping — read tool now validates offset >= 1 and limit >= 1; max_size clamped to prevent unbounded reads.
  • executescript breaking transactions — clear() used executescript which auto-commits, defeating the connection pool's transaction management. Replaced with separate execute() calls.
  • O(N) eviction loading all metadata — Eviction now uses ORDER BY json_extract(...) LIMIT ? in SQL instead of loading all rows + JSON parsing in Python.
  • LRU cache memory bloat — Content hash cache now bypasses @lru_cache for files > 64KB, bounding worst-case retention to ~128MB instead of ~20GB.
  • k=0 / k<0 passing search guards — min(k, MAX) now wrapped with max(1, ...) for both search and similar.
  • compare_files crash on missing/binary files — Now validates file existence and catches UnicodeDecodeError with clean error messages.
  • assert used for control flow — Three assert statements in write.py replaced with TypeError raises (assertions are stripped by -O).
  • Symlink traversal in glob — glob_with_cache_status now skips symlinks that resolve outside the base directory.
  • SEMANTIC_CACHE_DIR env var not resolved — Now calls .expanduser().resolve() on the override path.
  • Operator precedence ambiguity — Added explicit parentheses in _summarize.py for or/and expression.
  • Redundant ORDER BY in find_similar — Removed wasted sort; similarity search already ranks results.
  • Double chunking pass in put() — Removed chunk counting loop that duplicated work done by storage layer.

Performance

  • Vectorized hamming distance — hamming_distance_batch now uses np.unpackbits on uint8 view of XOR results instead of Python-level popcount loops. Scalar hamming_distance uses Kernighan's bit-counting algorithm.
  • Vectorized SimHash bit packing — compute_simhash replaces Python loop with np.uint64 power-of-two dot product. compute_simhash_batch uses pre-allocated matrix instead of np.vstack.
  • O(N) top-K selection — np.argpartition replaces np.argsort in similarity ranking (2 call sites), reducing top-K from O(N log N) to O(N).
  • O(N) pruning threshold — np.partition replaces np.percentile for dimension pruning cutoff in cosine similarity.
  • Native binary quantization — np.packbits/np.unpackbits replaces Python bit-manipulation loops in quantize_binary/dequantize_binary.
  • Buffer protocol blob deserialization — Single b"".join() + np.frombuffer reshape replaces per-row struct.unpack loop in batch cosine similarity.
  • Pre-allocated matrices — np.empty + fill replaces np.vstack with list comprehension in 3 hot paths (LSH batch, cosine batch ×2).

Changed

  • Stdout redirect uses contextlib.redirect_stdout — Replaces manual sys.stdout swap for thread-safety and re-entrancy.
  • Explicit stderr logging handler — logging.StreamHandler(sys.stderr) instead of basicConfig() to guard against third-party reconfiguration.
  • Type annotations tightened: dict[str, Any] → dict[str, bool | int] in get_hash_stats, -> list → -> list[float] in cosine_similarity_batch, params: list → params: list[str] in find_similar.
  • README: added uvx vs uv tool install explanation, cross-platform cache paths, SEMANTIC_CACHE_DIR env var.