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.
- cocoindex_code-0.2.35/README.md → cocoindex_code-0.2.37/PKG-INFO +140 -4
- cocoindex_code-0.2.35/PKG-INFO → cocoindex_code-0.2.37/README.md +96 -48
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/pyproject.toml +5 -5
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/__init__.py +0 -3
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/_version.py +2 -2
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/cli.py +75 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/daemon.py +3 -10
- cocoindex_code-0.2.35/src/cocoindex_code/indexer.py → cocoindex_code-0.2.37/src/cocoindex_code/file_walk.py +63 -118
- cocoindex_code-0.2.37/src/cocoindex_code/grep.py +411 -0
- cocoindex_code-0.2.37/src/cocoindex_code/indexer.py +123 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/.gitignore +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/LICENSE +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/__main__.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/_daemon_paths.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/chunking.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/client.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/embedder_defaults.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/embedder_params.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/litellm_embedder.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/project.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/protocol.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/query.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/schema.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/server.py +0 -0
- {cocoindex_code-0.2.35 → cocoindex_code-0.2.37}/src/cocoindex_code/settings.py +0 -0
- {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!
|
|
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
|
-
|
|
775
|
-
pre-commit install
|
|
903
|
+
uv run prek run --all-files
|
|
776
904
|
```
|
|
777
905
|
|
|
778
|
-
|
|
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!
|
|
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
|
-
|
|
819
|
-
pre-commit install
|
|
859
|
+
uv run prek run --all-files
|
|
820
860
|
```
|
|
821
861
|
|
|
822
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2,
|
|
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
|
|
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
|
-
|
|
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] = []
|