cocoindex-code 0.2.35__tar.gz → 0.2.37__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.35/README.md → cocoindex_code-0.2.37/PKG-INFO +140 -4
  2. cocoindex_code-0.2.35/PKG-INFO → cocoindex_code-0.2.37/README.md +96 -48
  3. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/pyproject.toml +5 -5
  4. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/__init__.py +0 -3
  5. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/_version.py +2 -2
  6. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/cli.py +75 -0
  7. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/daemon.py +3 -10
  8. cocoindex_code-0.2.35/src/cocoindex_code/indexer.py → cocoindex_code-0.2.37/src/cocoindex_code/file_walk.py +63 -118
  9. cocoindex_code-0.2.37/src/cocoindex_code/grep.py +411 -0
  10. cocoindex_code-0.2.37/src/cocoindex_code/indexer.py +123 -0
  11. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/.gitignore +0 -0
  12. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/LICENSE +0 -0
  13. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/__main__.py +0 -0
  14. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/_daemon_paths.py +0 -0
  15. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/chunking.py +0 -0
  16. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/client.py +0 -0
  17. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/embedder_defaults.py +0 -0
  18. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/embedder_params.py +0 -0
  19. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/litellm_embedder.py +0 -0
  20. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/project.py +0 -0
  21. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/protocol.py +0 -0
  22. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/query.py +0 -0
  23. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/schema.py +0 -0
  24. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/server.py +0 -0
  25. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/settings.py +0 -0
  26. {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/shared.py +0 -0
@@ -1,3 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: cocoindex-code
3
+ Version: 0.2.37
4
+ Summary: MCP server for indexing and querying codebases using CocoIndex
5
+ Project-URL: Homepage, https://github.com/cocoindex-io/cocoindex-code
6
+ Project-URL: Repository, https://github.com/cocoindex-io/cocoindex-code
7
+ Project-URL: Issues, https://github.com/cocoindex-io/cocoindex-code/issues
8
+ License-Expression: Apache-2.0
9
+ License-File: LICENSE
10
+ Keywords: cocoindex,codebase,indexing,mcp,vector-search
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: cocoindex[litellm]<1.1.0,>=1.0.13
21
+ Requires-Dist: einops>=0.8.2
22
+ Requires-Dist: mcp>=1.0.0
23
+ Requires-Dist: msgspec>=0.19.0
24
+ Requires-Dist: numpy>=1.24.0
25
+ Requires-Dist: pathspec>=0.12.1
26
+ Requires-Dist: pydantic>=2.0.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: questionary>=2.0.0
29
+ Requires-Dist: sqlite-vec>=0.1.0
30
+ Requires-Dist: typer>=0.9.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.13; extra == 'dev'
33
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
+ Requires-Dist: prek>=0.1.0; extra == 'dev'
35
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
36
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
37
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
38
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
39
+ Provides-Extra: embeddings-local
40
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.13; extra == 'embeddings-local'
41
+ Provides-Extra: full
42
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.13; extra == 'full'
43
+ Description-Content-Type: text/markdown
44
+
1
45
  <p align="center">
2
46
  <img width="2428" alt="cocoindex code" src="https://github.com/user-attachments/assets/d05961b4-0b7b-42ea-834a-59c3c01717ca" />
3
47
  </p>
@@ -77,6 +121,17 @@ The agent uses semantic search automatically when it would be helpful. You can a
77
121
 
78
122
  Works with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and other skill-compatible agents.
79
123
 
124
+ #### Claude Code plugin marketplace
125
+
126
+ For Claude Code users, this repository is also a [plugin marketplace](https://code.claude.com/docs/en/plugin-marketplaces). Install the skill from inside Claude Code with:
127
+
128
+ ```text
129
+ /plugin marketplace add Roxabi/cocoindex-code
130
+ /plugin install cocoindex-code@cocoindex-code
131
+ ```
132
+
133
+ This bundles the same `ccc` skill, with version pinning and `/plugin marketplace update` for updates.
134
+
80
135
  ### MCP Server
81
136
 
82
137
  Alternatively, use `ccc mcp` to run as an MCP server:
@@ -169,6 +224,7 @@ The background daemon starts automatically on first use.
169
224
  | `ccc init` | Initialize a project — creates settings files, adds `.cocoindex_code/` to `.gitignore` |
170
225
  | `ccc index` | Build or update the index (auto-inits if needed). Shows streaming progress. |
171
226
  | `ccc search <query>` | Semantic search across the codebase |
227
+ | `ccc grep <pattern> [path]` | Structural code search by example (no index needed) |
172
228
  | `ccc status` | Show index stats (chunk count, file count, language breakdown) |
173
229
  | `ccc mcp` | Run as MCP server in stdio mode |
174
230
  | `ccc doctor` | Run diagnostics — checks settings, daemon, model, file matching, and index health |
@@ -189,6 +245,36 @@ ccc search --refresh database schema # update index first, then
189
245
 
190
246
  By default, `ccc search` scopes results to your current working directory (relative to the project root). Use `--path` to override.
191
247
 
248
+ ### Structural Search (`ccc grep`)
249
+
250
+ `ccc grep` finds code by **structure**, not text — you write a by-example pattern
251
+ and it matches the syntax tree (via cocoindex's `code_match`), so formatting,
252
+ whitespace, and intervening tokens don't matter. It runs entirely locally: no
253
+ index, daemon, or embeddings required.
254
+
255
+ ```bash
256
+ ccc grep 'def \NAME(\(ARGS*\)):' # every Python function def under the cwd
257
+ ccc grep 'foo(\(ARGS*\))' src/ # calls to foo(...) anywhere under src/
258
+ ccc grep 'fn \NAME(\(A*\))' --lang rust # restrict to one language
259
+ ccc grep 'class \NAME:' --path 'tests/**' # restrict to a path glob
260
+ ccc grep 'TODO(\(A*\))' path/to/file.py # a single file
261
+ ```
262
+
263
+ Metavariables use the `\` sigil: `\NAME` captures one node, `\(NAME*\)` a run of
264
+ siblings, `\_`/`\*` match anonymously. The pattern is matched per language, so a
265
+ single invocation scans every supported source file (others are skipped). Inside
266
+ an initialized project, `ccc grep` honors the project's include/exclude patterns
267
+ and `.gitignore`; otherwise it scans all supported source files under the path.
268
+
269
+ Results stream to the terminal file-by-file as each match is found (in completion
270
+ order, since files are matched in parallel) rather than all at once at the end.
271
+ Each matching file shows its matched line range; under a TTY the path is colored,
272
+ line numbers are dimmed, and the unmatched context around a match is dimmed so the
273
+ match stands out.
274
+
275
+ > **Note:** `ccc grep` relies on cocoindex's structural `code_match` feature.
276
+ > Until it ships in a released cocoindex, run against a local cocoindex build.
277
+
192
278
  ## Docker
193
279
 
194
280
  A Docker image is available for teams who want a reproducible, dependency-free
@@ -380,6 +466,8 @@ docker build -t cocoindex-code:local -f docker/Dockerfile .
380
466
 
381
467
  ## Configuration
382
468
 
469
+ For a detailed guide on choosing and configuring embedding models, see [EMBEDDINGS.md](EMBEDDINGS.md).
470
+
383
471
  Configuration lives in two YAML files, both created automatically by `ccc init`.
384
472
 
385
473
  ### User Settings (`~/.cocoindex_code/global_settings.yml`)
@@ -737,6 +825,33 @@ Using uv (install or upgrade):
737
825
  uv tool install --upgrade cocoindex-code
738
826
  ```
739
827
 
828
+ ### `MDB_MAP_FULL: Environment mapsize limit reached`
829
+
830
+ The index is stored in an LMDB database whose maximum size is fixed when the daemon starts. The default ceiling is **4 GiB**, which is plenty for most projects but can be exhausted by very large codebases (tens of thousands of files), especially with high-dimensional embedding models like `nomic-ai/CodeRankEmbed`.
831
+
832
+ Raise the ceiling with the `COCOINDEX_LMDB_MAP_SIZE` environment variable (value in **bytes**). LMDB only grows the file as data is written, so a high limit doesn't pre-allocate disk — it's safe to set it generously:
833
+
834
+ ```yaml
835
+ # ~/.cocoindex_code/global_settings.yml
836
+ envs:
837
+ COCOINDEX_LMDB_MAP_SIZE: "34359738368" # 32 GiB (= 32 * 1024^3)
838
+ ```
839
+
840
+ Or, if you prefer to set it in your shell environment (the daemon inherits it):
841
+
842
+ ```bash
843
+ export COCOINDEX_LMDB_MAP_SIZE=$((32 * 1024 * 1024 * 1024)) # 32 GiB
844
+ ```
845
+
846
+ The map size is read when the daemon starts, so restart it to pick up the change, then re-index:
847
+
848
+ ```bash
849
+ ccc daemon restart
850
+ ccc index
851
+ ```
852
+
853
+ > This manual step is temporary. Once [cocoindex#2108](https://github.com/cocoindex-io/cocoindex/issues/2108) lands, the map size grows automatically when needed and `COCOINDEX_LMDB_MAP_SIZE` won't be necessary.
854
+
740
855
  ## Legacy: Environment Variables
741
856
 
742
857
  If you previously configured `cocoindex-code` via environment variables, the `cocoindex-code` MCP command still reads them and auto-migrates to YAML settings on first run. We recommend switching to the YAML settings for new setups.
@@ -764,18 +879,39 @@ export COCOINDEX_DISABLE_USAGE_TRACKING=1
764
879
  ## Large codebase / Enterprise
765
880
  [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.
766
881
 
882
+ > Indexing a very large codebase and hitting `MDB_MAP_FULL`? Raise the LMDB map size — see [`MDB_MAP_FULL: Environment mapsize limit reached`](#mdb_map_full-environment-mapsize-limit-reached) under Troubleshooting.
883
+
767
884
  If you need help with remote setup, please email our maintainer linghua@cocoindex.io, happy to help!
768
885
 
769
886
  ## Contributing
770
887
 
771
- We welcome contributions! Before you start, please install the [pre-commit](https://pre-commit.com/) hooks so that linting, formatting, type checking, and tests run automatically before each commit:
888
+ We welcome contributions! This project uses [uv](https://docs.astral.sh/uv/getting-started/installation/) for development, and every PR is gated on the same lint, format, type-check, and test suite in CI. **Please run these checks locally before opening a PR** — failing pre-commit checks are the most common cause of red CI on incoming PRs.
889
+
890
+ ### 1. Install the dev dependencies
891
+
892
+ After installing [uv](https://docs.astral.sh/uv/getting-started/installation/), sync the project. This installs everything the checks need — including [prek](https://github.com/j178/prek), a fast pre-commit runner, plus Ruff, mypy, and pytest:
893
+
894
+ ```bash
895
+ uv sync
896
+ ```
897
+
898
+ ### 2. Run all checks before every PR
899
+
900
+ Run the full hook suite across all files — this is exactly what CI runs:
772
901
 
773
902
  ```bash
774
- pip install pre-commit
775
- pre-commit install
903
+ uv run prek run --all-files
776
904
  ```
777
905
 
778
- This catches common issues — trailing whitespace, lint errors (Ruff), type errors (mypy), and test failures — before they reach CI.
906
+ It runs trailing-whitespace/end-of-file fixes, Ruff lint (`--fix`) and format, `uv.lock` validation, mypy type checking, and the pytest suite. Fix anything it reports (Ruff auto-fixes most lint/format issues for you), re-run until it passes, then push.
907
+
908
+ ### 3. (Optional) Run automatically on each commit
909
+
910
+ To have the same checks run on every `git commit`, install the git hook once:
911
+
912
+ ```bash
913
+ uv run prek install
914
+ ```
779
915
 
780
916
  For more details, see our [contributing guide](https://cocoindex.io/docs/contributing/guide).
781
917
 
@@ -1,47 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: cocoindex-code
3
- Version: 0.2.35
4
- Summary: MCP server for indexing and querying codebases using CocoIndex
5
- Project-URL: Homepage, https://github.com/cocoindex-io/cocoindex-code
6
- Project-URL: Repository, https://github.com/cocoindex-io/cocoindex-code
7
- Project-URL: Issues, https://github.com/cocoindex-io/cocoindex-code/issues
8
- License-Expression: Apache-2.0
9
- License-File: LICENSE
10
- Keywords: cocoindex,codebase,indexing,mcp,vector-search
11
- Classifier: Development Status :: 3 - Alpha
12
- Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: Apache Software License
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.11
16
- Classifier: Programming Language :: Python :: 3.12
17
- Classifier: Programming Language :: Python :: 3.13
18
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
- Requires-Python: >=3.11
20
- Requires-Dist: cocoindex[litellm]<1.1.0,>=1.0.6
21
- Requires-Dist: einops>=0.8.2
22
- Requires-Dist: mcp>=1.0.0
23
- Requires-Dist: msgspec>=0.19.0
24
- Requires-Dist: numpy>=1.24.0
25
- Requires-Dist: pathspec>=0.12.1
26
- Requires-Dist: pydantic>=2.0.0
27
- Requires-Dist: pyyaml>=6.0
28
- Requires-Dist: questionary>=2.0.0
29
- Requires-Dist: sqlite-vec>=0.1.0
30
- Requires-Dist: typer>=0.9.0
31
- Provides-Extra: dev
32
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'dev'
33
- Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
- Requires-Dist: prek>=0.1.0; extra == 'dev'
35
- Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
36
- Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
37
- Requires-Dist: pytest>=7.0.0; extra == 'dev'
38
- Requires-Dist: ruff>=0.1.0; extra == 'dev'
39
- Provides-Extra: embeddings-local
40
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'embeddings-local'
41
- Provides-Extra: full
42
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'full'
43
- Description-Content-Type: text/markdown
44
-
45
1
  <p align="center">
46
2
  <img width="2428" alt="cocoindex code" src="https://github.com/user-attachments/assets/d05961b4-0b7b-42ea-834a-59c3c01717ca" />
47
3
  </p>
@@ -121,6 +77,17 @@ The agent uses semantic search automatically when it would be helpful. You can a
121
77
 
122
78
  Works with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and other skill-compatible agents.
123
79
 
80
+ #### Claude Code plugin marketplace
81
+
82
+ For Claude Code users, this repository is also a [plugin marketplace](https://code.claude.com/docs/en/plugin-marketplaces). Install the skill from inside Claude Code with:
83
+
84
+ ```text
85
+ /plugin marketplace add Roxabi/cocoindex-code
86
+ /plugin install cocoindex-code@cocoindex-code
87
+ ```
88
+
89
+ This bundles the same `ccc` skill, with version pinning and `/plugin marketplace update` for updates.
90
+
124
91
  ### MCP Server
125
92
 
126
93
  Alternatively, use `ccc mcp` to run as an MCP server:
@@ -213,6 +180,7 @@ The background daemon starts automatically on first use.
213
180
  | `ccc init` | Initialize a project — creates settings files, adds `.cocoindex_code/` to `.gitignore` |
214
181
  | `ccc index` | Build or update the index (auto-inits if needed). Shows streaming progress. |
215
182
  | `ccc search <query>` | Semantic search across the codebase |
183
+ | `ccc grep <pattern> [path]` | Structural code search by example (no index needed) |
216
184
  | `ccc status` | Show index stats (chunk count, file count, language breakdown) |
217
185
  | `ccc mcp` | Run as MCP server in stdio mode |
218
186
  | `ccc doctor` | Run diagnostics — checks settings, daemon, model, file matching, and index health |
@@ -233,6 +201,36 @@ ccc search --refresh database schema # update index first, then
233
201
 
234
202
  By default, `ccc search` scopes results to your current working directory (relative to the project root). Use `--path` to override.
235
203
 
204
+ ### Structural Search (`ccc grep`)
205
+
206
+ `ccc grep` finds code by **structure**, not text — you write a by-example pattern
207
+ and it matches the syntax tree (via cocoindex's `code_match`), so formatting,
208
+ whitespace, and intervening tokens don't matter. It runs entirely locally: no
209
+ index, daemon, or embeddings required.
210
+
211
+ ```bash
212
+ ccc grep 'def \NAME(\(ARGS*\)):' # every Python function def under the cwd
213
+ ccc grep 'foo(\(ARGS*\))' src/ # calls to foo(...) anywhere under src/
214
+ ccc grep 'fn \NAME(\(A*\))' --lang rust # restrict to one language
215
+ ccc grep 'class \NAME:' --path 'tests/**' # restrict to a path glob
216
+ ccc grep 'TODO(\(A*\))' path/to/file.py # a single file
217
+ ```
218
+
219
+ Metavariables use the `\` sigil: `\NAME` captures one node, `\(NAME*\)` a run of
220
+ siblings, `\_`/`\*` match anonymously. The pattern is matched per language, so a
221
+ single invocation scans every supported source file (others are skipped). Inside
222
+ an initialized project, `ccc grep` honors the project's include/exclude patterns
223
+ and `.gitignore`; otherwise it scans all supported source files under the path.
224
+
225
+ Results stream to the terminal file-by-file as each match is found (in completion
226
+ order, since files are matched in parallel) rather than all at once at the end.
227
+ Each matching file shows its matched line range; under a TTY the path is colored,
228
+ line numbers are dimmed, and the unmatched context around a match is dimmed so the
229
+ match stands out.
230
+
231
+ > **Note:** `ccc grep` relies on cocoindex's structural `code_match` feature.
232
+ > Until it ships in a released cocoindex, run against a local cocoindex build.
233
+
236
234
  ## Docker
237
235
 
238
236
  A Docker image is available for teams who want a reproducible, dependency-free
@@ -424,6 +422,8 @@ docker build -t cocoindex-code:local -f docker/Dockerfile .
424
422
 
425
423
  ## Configuration
426
424
 
425
+ For a detailed guide on choosing and configuring embedding models, see [EMBEDDINGS.md](EMBEDDINGS.md).
426
+
427
427
  Configuration lives in two YAML files, both created automatically by `ccc init`.
428
428
 
429
429
  ### User Settings (`~/.cocoindex_code/global_settings.yml`)
@@ -781,6 +781,33 @@ Using uv (install or upgrade):
781
781
  uv tool install --upgrade cocoindex-code
782
782
  ```
783
783
 
784
+ ### `MDB_MAP_FULL: Environment mapsize limit reached`
785
+
786
+ The index is stored in an LMDB database whose maximum size is fixed when the daemon starts. The default ceiling is **4 GiB**, which is plenty for most projects but can be exhausted by very large codebases (tens of thousands of files), especially with high-dimensional embedding models like `nomic-ai/CodeRankEmbed`.
787
+
788
+ Raise the ceiling with the `COCOINDEX_LMDB_MAP_SIZE` environment variable (value in **bytes**). LMDB only grows the file as data is written, so a high limit doesn't pre-allocate disk — it's safe to set it generously:
789
+
790
+ ```yaml
791
+ # ~/.cocoindex_code/global_settings.yml
792
+ envs:
793
+ COCOINDEX_LMDB_MAP_SIZE: "34359738368" # 32 GiB (= 32 * 1024^3)
794
+ ```
795
+
796
+ Or, if you prefer to set it in your shell environment (the daemon inherits it):
797
+
798
+ ```bash
799
+ export COCOINDEX_LMDB_MAP_SIZE=$((32 * 1024 * 1024 * 1024)) # 32 GiB
800
+ ```
801
+
802
+ The map size is read when the daemon starts, so restart it to pick up the change, then re-index:
803
+
804
+ ```bash
805
+ ccc daemon restart
806
+ ccc index
807
+ ```
808
+
809
+ > This manual step is temporary. Once [cocoindex#2108](https://github.com/cocoindex-io/cocoindex/issues/2108) lands, the map size grows automatically when needed and `COCOINDEX_LMDB_MAP_SIZE` won't be necessary.
810
+
784
811
  ## Legacy: Environment Variables
785
812
 
786
813
  If you previously configured `cocoindex-code` via environment variables, the `cocoindex-code` MCP command still reads them and auto-migrates to YAML settings on first run. We recommend switching to the YAML settings for new setups.
@@ -808,18 +835,39 @@ export COCOINDEX_DISABLE_USAGE_TRACKING=1
808
835
  ## Large codebase / Enterprise
809
836
  [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.
810
837
 
838
+ > Indexing a very large codebase and hitting `MDB_MAP_FULL`? Raise the LMDB map size — see [`MDB_MAP_FULL: Environment mapsize limit reached`](#mdb_map_full-environment-mapsize-limit-reached) under Troubleshooting.
839
+
811
840
  If you need help with remote setup, please email our maintainer linghua@cocoindex.io, happy to help!
812
841
 
813
842
  ## Contributing
814
843
 
815
- We welcome contributions! Before you start, please install the [pre-commit](https://pre-commit.com/) hooks so that linting, formatting, type checking, and tests run automatically before each commit:
844
+ We welcome contributions! This project uses [uv](https://docs.astral.sh/uv/getting-started/installation/) for development, and every PR is gated on the same lint, format, type-check, and test suite in CI. **Please run these checks locally before opening a PR** — failing pre-commit checks are the most common cause of red CI on incoming PRs.
845
+
846
+ ### 1. Install the dev dependencies
847
+
848
+ After installing [uv](https://docs.astral.sh/uv/getting-started/installation/), sync the project. This installs everything the checks need — including [prek](https://github.com/j178/prek), a fast pre-commit runner, plus Ruff, mypy, and pytest:
849
+
850
+ ```bash
851
+ uv sync
852
+ ```
853
+
854
+ ### 2. Run all checks before every PR
855
+
856
+ Run the full hook suite across all files — this is exactly what CI runs:
816
857
 
817
858
  ```bash
818
- pip install pre-commit
819
- pre-commit install
859
+ uv run prek run --all-files
820
860
  ```
821
861
 
822
- This catches common issues — trailing whitespace, lint errors (Ruff), type errors (mypy), and test failures — before they reach CI.
862
+ It runs trailing-whitespace/end-of-file fixes, Ruff lint (`--fix`) and format, `uv.lock` validation, mypy type checking, and the pytest suite. Fix anything it reports (Ruff auto-fixes most lint/format issues for you), re-run until it passes, then push.
863
+
864
+ ### 3. (Optional) Run automatically on each commit
865
+
866
+ To have the same checks run on every `git commit`, install the git hook once:
867
+
868
+ ```bash
869
+ uv run prek install
870
+ ```
823
871
 
824
872
  For more details, see our [contributing guide](https://cocoindex.io/docs/contributing/guide).
825
873
 
@@ -23,7 +23,7 @@ classifiers = [
23
23
 
24
24
  dependencies = [
25
25
  "mcp>=1.0.0",
26
- "cocoindex[litellm]>=1.0.6,<1.1.0",
26
+ "cocoindex[litellm]>=1.0.13,<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.6,<1.1.0"]
42
+ embeddings-local = ["cocoindex[sentence-transformers]>=1.0.13,<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.6,<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.6,<1.1.0"]
50
+ full = ["cocoindex[sentence-transformers]>=1.0.13,<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.6,<1.1.0",
58
+ "cocoindex[sentence-transformers]>=1.0.13,<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.7,<1.1.0",
92
+ "cocoindex[sentence-transformers]>=1.0.13,<1.1.0",
93
93
  ]
94
94
 
95
95
  [tool.ruff]
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import logging
6
5
  import os
7
6
  from typing import TYPE_CHECKING, Any
8
7
 
@@ -11,8 +10,6 @@ from typing import TYPE_CHECKING, Any
11
10
  # init time). See cocoindex-io/cocoindex#1992.
12
11
  os.environ.setdefault("COCOINDEX_APPLICATION_FOR_TRACKING", "cocoindex-code")
13
12
 
14
- logging.basicConfig(level=logging.WARNING)
15
-
16
13
  from ._version import __version__ # noqa: E402
17
14
 
18
15
  if TYPE_CHECKING:
@@ -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.35'
22
- __version_tuple__ = version_tuple = (0, 2, 35)
21
+ __version__ = version = '0.2.37'
22
+ __version_tuple__ = version_tuple = (0, 2, 37)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import functools
6
6
  import os
7
7
  import sys
8
+ import threading
8
9
  from collections.abc import Callable
9
10
  from pathlib import Path
10
11
  from typing import TYPE_CHECKING, TypeVar
@@ -12,6 +13,7 @@ from typing import TYPE_CHECKING, TypeVar
12
13
  import typer as _typer
13
14
 
14
15
  if TYPE_CHECKING:
16
+ from .grep import FileMatches, GrepWarning
15
17
  from .protocol import (
16
18
  DoctorCheckResult,
17
19
  IndexingProgress,
@@ -657,6 +659,79 @@ def search(
657
659
  print_search_results(resp)
658
660
 
659
661
 
662
+ @app.command()
663
+ def grep(
664
+ pattern: str = _typer.Argument(
665
+ ...,
666
+ help=r"By-example structural pattern; use \ for metavariables, "
667
+ r"e.g. 'def \NAME(\(ARGS*\)):' or 'foo(\(ARGS*\))'.",
668
+ ),
669
+ path: str = _typer.Argument(
670
+ ".", help="File or directory to search (default: current directory)."
671
+ ),
672
+ lang: list[str] = _typer.Option(
673
+ [], "--lang", help="Only match files of these languages (e.g. python, rust, cpp)."
674
+ ),
675
+ path_glob: str | None = _typer.Option(
676
+ None, "--path", help="Only match files whose path matches this glob (globset syntax)."
677
+ ),
678
+ no_color: bool = _typer.Option(False, "--no-color", help="Disable colored output."),
679
+ ) -> None:
680
+ r"""Structurally grep code by example (no index or daemon required).
681
+
682
+ Compiles the pattern per language and matches every supported source file
683
+ under PATH in parallel. Inside an initialized project it honors the project's
684
+ include/exclude and .gitignore rules; otherwise it scans all supported source
685
+ files.
686
+ """
687
+ from . import grep as _grep
688
+
689
+ target = Path(path)
690
+ if not target.exists():
691
+ _typer.echo(f"Error: path not found: {path}", err=True)
692
+ raise _typer.Exit(code=1)
693
+
694
+ req = _grep.GrepRequest(
695
+ pattern=pattern,
696
+ root=target,
697
+ languages=frozenset(lang_name.lower() for lang_name in lang) or None,
698
+ path_glob=path_glob,
699
+ )
700
+ use_color = not no_color and sys.stdout.isatty() and not os.environ.get("NO_COLOR")
701
+ grep_run = _grep.Grep(req)
702
+ matched = 0
703
+ # `run` calls `_emit` from several worker threads at once; the lock keeps one
704
+ # file's output (and the `matched` bookkeeping) from interleaving with another's.
705
+ output_lock = threading.Lock()
706
+
707
+ def _emit(item: FileMatches | GrepWarning) -> None:
708
+ nonlocal matched
709
+ if isinstance(item, _grep.GrepWarning):
710
+ with output_lock:
711
+ _typer.echo(f"warning: {item.message}", err=True)
712
+ return
713
+ block = _grep.render_file(item, color=use_color) # render outside the lock
714
+ with output_lock:
715
+ if matched:
716
+ _typer.echo() # blank line between files
717
+ _typer.echo(block)
718
+ matched += 1
719
+
720
+ grep_run.run(_emit)
721
+
722
+ # The "unusable everywhere" verdict needs the whole walk, so it's known only
723
+ # once the run is done — report it before exiting.
724
+ if grep_run.unusable:
725
+ langs = ", ".join(grep_run.failed_languages)
726
+ _typer.echo(
727
+ f"Error: the pattern did not compile for any of the languages found ({langs}).",
728
+ err=True,
729
+ )
730
+ raise _typer.Exit(code=1)
731
+ if matched == 0:
732
+ _typer.echo("No matches found.")
733
+
734
+
660
735
  @app.command()
661
736
  @_catch_daemon_start_error
662
737
  def status() -> None:
@@ -372,10 +372,8 @@ async def _check_file_walk(project_root_str: str) -> DoctorCheckResult:
372
372
  """Walk project files and report counts + gitignore paths."""
373
373
  from pathlib import PurePath
374
374
 
375
- from cocoindex.resources.file import PatternFilePathMatcher
376
-
377
- from .indexer import GitignoreAwareMatcher
378
- from .settings import load_gitignore_spec, load_project_settings
375
+ from .file_walk import build_matcher
376
+ from .settings import load_project_settings
379
377
 
380
378
  project_root = Path(project_root_str)
381
379
  try:
@@ -383,12 +381,7 @@ async def _check_file_walk(project_root_str: str) -> DoctorCheckResult:
383
381
  except FileNotFoundError as e:
384
382
  return DoctorCheckResult(name="File Walk", ok=False, details=[], errors=[str(e)])
385
383
 
386
- gitignore_spec = load_gitignore_spec(project_root)
387
- base_matcher = PatternFilePathMatcher(
388
- included_patterns=ps.include_patterns,
389
- excluded_patterns=ps.exclude_patterns,
390
- )
391
- matcher = GitignoreAwareMatcher(base_matcher, gitignore_spec, project_root)
384
+ matcher = build_matcher(project_root, ps.include_patterns, ps.exclude_patterns)
392
385
 
393
386
  counts_by_ext: dict[str, int] = {}
394
387
  gitignore_dirs: list[str] = []