codecortex 0.11.1__tar.gz → 0.12.0__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.
- {codecortex-0.11.1/src/codecortex.egg-info → codecortex-0.12.0}/PKG-INFO +98 -6
- {codecortex-0.11.1 → codecortex-0.12.0}/README.md +97 -5
- {codecortex-0.11.1 → codecortex-0.12.0/src/codecortex.egg-info}/PKG-INFO +98 -6
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codecortex.egg-info/SOURCES.txt +6 -1
- codecortex-0.12.0/src/codeintel/__init__.py +1 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/__main__.py +68 -13
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/cache.py +7 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/doctor.py +172 -5
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/gateway.py +40 -0
- codecortex-0.12.0/src/codeintel/installer.py +369 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/providers/lsp.py +35 -11
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/server.py +114 -43
- codecortex-0.12.0/src/codeintel/verify.py +316 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/viewer/graph_template.html +54 -6
- codecortex-0.12.0/tests/test_engine_adoption.py +206 -0
- codecortex-0.12.0/tests/test_installer.py +516 -0
- codecortex-0.12.0/tests/test_mcp_handshake.py +215 -0
- codecortex-0.12.0/tests/test_verify.py +172 -0
- codecortex-0.12.0/tests/test_verify_call.py +141 -0
- codecortex-0.11.1/src/codeintel/__init__.py +0 -1
- codecortex-0.11.1/src/codeintel/installer.py +0 -120
- codecortex-0.11.1/tests/test_installer.py +0 -97
- {codecortex-0.11.1 → codecortex-0.12.0}/LICENSE +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/pyproject.toml +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/setup.cfg +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codecortex.egg-info/dependency_links.txt +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codecortex.egg-info/entry_points.txt +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codecortex.egg-info/requires.txt +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codecortex.egg-info/top_level.txt +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/auth.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/config.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/grapher.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/http_server.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/indexer.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/injector.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/logconfig.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/mapper.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/metrics.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/onboarding.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/policy.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/provider.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/providers/__init__.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/providers/graph.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/providers/none.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/providers/semantic.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/reindexer.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/reset.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/searcher.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/semantic_db.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/term.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/src/codeintel/viewer/__init__.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_cache.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_chunking.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_config.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_doctor.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_e2e.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_enterprise.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_gateway.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_graph_provider.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_graph_real.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_graph_stdin.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_grapher.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_hardening.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_http_auth.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_http_server.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_integration.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_lsp_provider.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_lsp_real.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_mapper.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_mcp_server.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_model_dimension.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_never_raise.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_onboarding.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_rbac.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_reindexer.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_rerank.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_reset.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_semantic_provider.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_term.py +0 -0
- {codecortex-0.11.1 → codecortex-0.12.0}/tests/test_treesitter.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Local-first, MCP-native code-intelligence server — graph, LSP, and semantic search behind one safe code.query tool for coding agents.
|
|
5
5
|
Author: Shammai Hamilton
|
|
6
6
|
License-Expression: MIT
|
|
@@ -110,7 +110,7 @@ The agent hands `result` straight to the model. If the graph backend isn't insta
|
|
|
110
110
|
- **Degrades instead of breaking.** No graph backend installed? That engine returns `null` and the agent falls back to grep. The semantic engine needs nothing external, so codeintel is useful the moment it's installed and only gets sharper as you add backends.
|
|
111
111
|
- **Fast on repeat, never stale.** A content-hash cache returns instantly for unchanged code and self-invalidates when a background reindex advances the index — answers stay both quick *and* fresh. The cache is bounded (LRU), so a long-running server holds steady memory.
|
|
112
112
|
- **Concurrency-safe.** The HTTP transport handles requests on threads, so one slow query (an LSP session warming, a first-time index) can't block every other agent.
|
|
113
|
-
- **Honest about its own health.** `codeintel doctor`
|
|
113
|
+
- **Honest about its own health.** `codeintel doctor` answers three separate questions per engine — *installed?* *runnable?* *is this repo indexed?* — with the single command to fix each gap, so "installed" is never mistaken for "working". And a readiness claim is one a query can actually honor: install a missing backend mid-session and the running server picks it up on the next call, rather than reporting the engine healthy while quietly routing around it until you restart the host.
|
|
114
114
|
|
|
115
115
|
## Quickstart
|
|
116
116
|
|
|
@@ -144,10 +144,91 @@ pip install -e .
|
|
|
144
144
|
Register with your AI agent(s), then query:
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
|
-
codeintel install # registers with
|
|
147
|
+
codeintel install # registers with the agents you actually have installed
|
|
148
148
|
codeintel query --op search --target "authentication middleware"
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
### Enable native Codex integration
|
|
152
|
+
|
|
153
|
+
`codeintel` is an MCP server, so Codex can call its tools directly rather than invoking the CLI.
|
|
154
|
+
After installing the package, explicitly register it with Codex:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
codeintel install --agent codex
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
This safely adds a `[mcp_servers.codeintel]` entry to `~/.codex/config.toml` (or `$CODEX_HOME/config.toml`
|
|
161
|
+
when that is set) without changing your other Codex settings. Registration is deliberately opt-in:
|
|
162
|
+
installing a Python package should not silently modify an agent's configuration. Start a new Codex
|
|
163
|
+
task (or restart Codex) after registration; the refreshed task will have native `code.query`,
|
|
164
|
+
`code.status`, `code.doctor`, and `code.map` MCP tools available.
|
|
165
|
+
|
|
166
|
+
For a fully prepared local setup, run:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
codeintel setup --all /path/to/your/project && codeintel install --agent codex
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Enable native Claude Code integration
|
|
173
|
+
|
|
174
|
+
After installing the package, explicitly register it with Claude Code:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
codeintel install --agent claude
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
This adds the `codeintel` MCP server to `~/.claude.json` (or `$CLAUDE_CONFIG_DIR/.claude.json`)
|
|
181
|
+
while preserving your existing configuration — that is the file Claude Code reads for user-scope
|
|
182
|
+
MCP servers, and you can confirm the entry with `claude mcp list`. Start a new Claude Code session
|
|
183
|
+
after registration so it can load the native `code.query`, `code.status`, `code.doctor`, and
|
|
184
|
+
`code.map` MCP tools.
|
|
185
|
+
|
|
186
|
+
> **Upgrading from ≤ 0.11.1?** Earlier versions wrote this block to `~/.claude/settings.json`,
|
|
187
|
+
> which Claude Code ignores for MCP registration — so codeintel never actually loaded. Re-run
|
|
188
|
+
> `codeintel install --agent claude`; it registers in the right place and points out the stale
|
|
189
|
+
> entry so you can delete it.
|
|
190
|
+
|
|
191
|
+
For a fully prepared local setup, run:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
codeintel setup --all /path/to/your/project && codeintel install --agent claude
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Registration is verified, not assumed
|
|
198
|
+
|
|
199
|
+
**It only touches agents you have.** `codeintel install` defaults to `--agent auto`: it registers
|
|
200
|
+
the hosts whose config root already exists on this machine and *names the ones it skipped*.
|
|
201
|
+
Installing a Python package should not create `~/.gemini/` and `~/.config/zed/` for someone who has
|
|
202
|
+
neither. Force a specific host with `--agent claude|codex|gemini|zed`, or every supported host with
|
|
203
|
+
`--agent all`.
|
|
204
|
+
|
|
205
|
+
**It registers an absolute path.** The bare name `codeintel` is resolved by the *host*, not by the
|
|
206
|
+
shell you ran `install` in — and a GUI-launched desktop agent does not source your shell profile, so
|
|
207
|
+
a command your terminal finds is routinely invisible to the app. That is the one failure a handshake
|
|
208
|
+
run in your terminal cannot catch, because it inherits the PATH that works. Pass
|
|
209
|
+
`--relative-command` for the bare name. If a later upgrade moves the binary, re-running
|
|
210
|
+
`codeintel install` repairs the stale path in place, leaving the rest of your config untouched.
|
|
211
|
+
|
|
212
|
+
Then it launches the exact command it registered and drives a real MCP handshake —
|
|
213
|
+
`initialize` → `tools/list` — and reports what came back:
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
v claude: registered at /Users/you/.claude.json
|
|
217
|
+
|
|
218
|
+
v verified: codeintel 0.11.2 — 4 tools (code.query, code.status, code.doctor, code.map)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
If the command is not on `PATH`, or the server fails to start, install says so and exits non-zero
|
|
222
|
+
instead of reporting a success your agent cannot use. Pass `--no-verify` to skip the handshake.
|
|
223
|
+
|
|
224
|
+
The same principle gates releases. Because every result is a safe envelope with `ok: true` and the
|
|
225
|
+
CLI never throws, an exit-code smoke test passes against a build that boots cleanly and answers
|
|
226
|
+
nothing — so **[`scripts/release_canary.py`](scripts/release_canary.py)** runs before every publish
|
|
227
|
+
against the built wheel in a clean environment: it registers Codex and Claude Code into a throwaway
|
|
228
|
+
`HOME`, launches the command those config files name, and asserts on the **answer text** of a real
|
|
229
|
+
`code.query` over a fixture repo. A release that writes a config no host reads, or that returns
|
|
230
|
+
`ok: true` with nothing in it, fails there instead of on your machine.
|
|
231
|
+
|
|
151
232
|
## How it works
|
|
152
233
|
|
|
153
234
|
A `Gateway` receives every query and dispatches it to one of three providers — graph (structural relationships), LSP (precise symbol resolution), or semantic (embedding-based search) — based on the operation type. Each provider is fully isolated: if it is unavailable or raises an exception, the gateway catches it and returns a safe-null envelope. The caller always gets a well-formed response with no exception to catch.
|
|
@@ -203,7 +284,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
203
284
|
|
|
204
285
|
| Command | Purpose |
|
|
205
286
|
|---|---|
|
|
206
|
-
| `codeintel install [--agent claude\|codex\|gemini\|zed\|all]` | Register codeintel with
|
|
287
|
+
| `codeintel install [--agent auto\|claude\|codex\|gemini\|zed\|all] [--no-verify] [--relative-command]` | Register codeintel with the agents installed on this machine (`auto`, the default), then prove it by completing a real MCP handshake against the registered command |
|
|
207
288
|
| `codeintel setup [project_root] [--all] [--index] [--warm] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
208
289
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
209
290
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
@@ -271,7 +352,7 @@ Register codeintel as an MCP server (`codeintel install`) and the agent gets fou
|
|
|
271
352
|
| MCP tool | HTTP equivalent | Purpose |
|
|
272
353
|
|---|---|---|
|
|
273
354
|
| `code.query` | `POST /code/query` | The main call — search, trace, understand (the `op` table above) |
|
|
274
|
-
| `code.status` | `GET /code/status` |
|
|
355
|
+
| `code.status` | `GET /code/status` | Per-engine `installed` / `runnable` / `repo_indexed`, probed against the live engines a query actually hits |
|
|
275
356
|
| `code.doctor` | `POST /code/doctor` | Per-engine health + repo index status, with a fix for each gap |
|
|
276
357
|
| `code.map` | — | Generate/refresh `CODE_INTEL.md`, a static orientation file for hosts without MCP |
|
|
277
358
|
|
|
@@ -328,5 +409,16 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
328
409
|
git clone https://github.com/hamilton-sky/codeintel.git
|
|
329
410
|
cd codeintel
|
|
330
411
|
pip install -e .[dev]
|
|
331
|
-
pytest tests/ -q #
|
|
412
|
+
pytest tests/ -q # ~390 tests, ~35s (live graph/LSP backend tests skip when absent)
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Release gate.** The unit suite runs against the source tree, so it cannot see a packaging break, a
|
|
416
|
+
missing entry point, a host config written where nobody reads it, or a server that boots and answers
|
|
417
|
+
nothing. Run the canary against the built wheel in a clean environment — the same check CI runs
|
|
418
|
+
before publishing:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
python -m build && python -m venv /tmp/canary && /tmp/canary/bin/python -m pip install dist/*.whl && /tmp/canary/bin/python scripts/release_canary.py
|
|
332
422
|
```
|
|
423
|
+
|
|
424
|
+
It exits non-zero on the first failed check and cleans up the temporary `HOME` it installs into.
|
|
@@ -76,7 +76,7 @@ The agent hands `result` straight to the model. If the graph backend isn't insta
|
|
|
76
76
|
- **Degrades instead of breaking.** No graph backend installed? That engine returns `null` and the agent falls back to grep. The semantic engine needs nothing external, so codeintel is useful the moment it's installed and only gets sharper as you add backends.
|
|
77
77
|
- **Fast on repeat, never stale.** A content-hash cache returns instantly for unchanged code and self-invalidates when a background reindex advances the index — answers stay both quick *and* fresh. The cache is bounded (LRU), so a long-running server holds steady memory.
|
|
78
78
|
- **Concurrency-safe.** The HTTP transport handles requests on threads, so one slow query (an LSP session warming, a first-time index) can't block every other agent.
|
|
79
|
-
- **Honest about its own health.** `codeintel doctor`
|
|
79
|
+
- **Honest about its own health.** `codeintel doctor` answers three separate questions per engine — *installed?* *runnable?* *is this repo indexed?* — with the single command to fix each gap, so "installed" is never mistaken for "working". And a readiness claim is one a query can actually honor: install a missing backend mid-session and the running server picks it up on the next call, rather than reporting the engine healthy while quietly routing around it until you restart the host.
|
|
80
80
|
|
|
81
81
|
## Quickstart
|
|
82
82
|
|
|
@@ -110,10 +110,91 @@ pip install -e .
|
|
|
110
110
|
Register with your AI agent(s), then query:
|
|
111
111
|
|
|
112
112
|
```bash
|
|
113
|
-
codeintel install # registers with
|
|
113
|
+
codeintel install # registers with the agents you actually have installed
|
|
114
114
|
codeintel query --op search --target "authentication middleware"
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
+
### Enable native Codex integration
|
|
118
|
+
|
|
119
|
+
`codeintel` is an MCP server, so Codex can call its tools directly rather than invoking the CLI.
|
|
120
|
+
After installing the package, explicitly register it with Codex:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
codeintel install --agent codex
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This safely adds a `[mcp_servers.codeintel]` entry to `~/.codex/config.toml` (or `$CODEX_HOME/config.toml`
|
|
127
|
+
when that is set) without changing your other Codex settings. Registration is deliberately opt-in:
|
|
128
|
+
installing a Python package should not silently modify an agent's configuration. Start a new Codex
|
|
129
|
+
task (or restart Codex) after registration; the refreshed task will have native `code.query`,
|
|
130
|
+
`code.status`, `code.doctor`, and `code.map` MCP tools available.
|
|
131
|
+
|
|
132
|
+
For a fully prepared local setup, run:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
codeintel setup --all /path/to/your/project && codeintel install --agent codex
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Enable native Claude Code integration
|
|
139
|
+
|
|
140
|
+
After installing the package, explicitly register it with Claude Code:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
codeintel install --agent claude
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This adds the `codeintel` MCP server to `~/.claude.json` (or `$CLAUDE_CONFIG_DIR/.claude.json`)
|
|
147
|
+
while preserving your existing configuration — that is the file Claude Code reads for user-scope
|
|
148
|
+
MCP servers, and you can confirm the entry with `claude mcp list`. Start a new Claude Code session
|
|
149
|
+
after registration so it can load the native `code.query`, `code.status`, `code.doctor`, and
|
|
150
|
+
`code.map` MCP tools.
|
|
151
|
+
|
|
152
|
+
> **Upgrading from ≤ 0.11.1?** Earlier versions wrote this block to `~/.claude/settings.json`,
|
|
153
|
+
> which Claude Code ignores for MCP registration — so codeintel never actually loaded. Re-run
|
|
154
|
+
> `codeintel install --agent claude`; it registers in the right place and points out the stale
|
|
155
|
+
> entry so you can delete it.
|
|
156
|
+
|
|
157
|
+
For a fully prepared local setup, run:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
codeintel setup --all /path/to/your/project && codeintel install --agent claude
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Registration is verified, not assumed
|
|
164
|
+
|
|
165
|
+
**It only touches agents you have.** `codeintel install` defaults to `--agent auto`: it registers
|
|
166
|
+
the hosts whose config root already exists on this machine and *names the ones it skipped*.
|
|
167
|
+
Installing a Python package should not create `~/.gemini/` and `~/.config/zed/` for someone who has
|
|
168
|
+
neither. Force a specific host with `--agent claude|codex|gemini|zed`, or every supported host with
|
|
169
|
+
`--agent all`.
|
|
170
|
+
|
|
171
|
+
**It registers an absolute path.** The bare name `codeintel` is resolved by the *host*, not by the
|
|
172
|
+
shell you ran `install` in — and a GUI-launched desktop agent does not source your shell profile, so
|
|
173
|
+
a command your terminal finds is routinely invisible to the app. That is the one failure a handshake
|
|
174
|
+
run in your terminal cannot catch, because it inherits the PATH that works. Pass
|
|
175
|
+
`--relative-command` for the bare name. If a later upgrade moves the binary, re-running
|
|
176
|
+
`codeintel install` repairs the stale path in place, leaving the rest of your config untouched.
|
|
177
|
+
|
|
178
|
+
Then it launches the exact command it registered and drives a real MCP handshake —
|
|
179
|
+
`initialize` → `tools/list` — and reports what came back:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
v claude: registered at /Users/you/.claude.json
|
|
183
|
+
|
|
184
|
+
v verified: codeintel 0.11.2 — 4 tools (code.query, code.status, code.doctor, code.map)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
If the command is not on `PATH`, or the server fails to start, install says so and exits non-zero
|
|
188
|
+
instead of reporting a success your agent cannot use. Pass `--no-verify` to skip the handshake.
|
|
189
|
+
|
|
190
|
+
The same principle gates releases. Because every result is a safe envelope with `ok: true` and the
|
|
191
|
+
CLI never throws, an exit-code smoke test passes against a build that boots cleanly and answers
|
|
192
|
+
nothing — so **[`scripts/release_canary.py`](scripts/release_canary.py)** runs before every publish
|
|
193
|
+
against the built wheel in a clean environment: it registers Codex and Claude Code into a throwaway
|
|
194
|
+
`HOME`, launches the command those config files name, and asserts on the **answer text** of a real
|
|
195
|
+
`code.query` over a fixture repo. A release that writes a config no host reads, or that returns
|
|
196
|
+
`ok: true` with nothing in it, fails there instead of on your machine.
|
|
197
|
+
|
|
117
198
|
## How it works
|
|
118
199
|
|
|
119
200
|
A `Gateway` receives every query and dispatches it to one of three providers — graph (structural relationships), LSP (precise symbol resolution), or semantic (embedding-based search) — based on the operation type. Each provider is fully isolated: if it is unavailable or raises an exception, the gateway catches it and returns a safe-null envelope. The caller always gets a well-formed response with no exception to catch.
|
|
@@ -169,7 +250,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
169
250
|
|
|
170
251
|
| Command | Purpose |
|
|
171
252
|
|---|---|
|
|
172
|
-
| `codeintel install [--agent claude\|codex\|gemini\|zed\|all]` | Register codeintel with
|
|
253
|
+
| `codeintel install [--agent auto\|claude\|codex\|gemini\|zed\|all] [--no-verify] [--relative-command]` | Register codeintel with the agents installed on this machine (`auto`, the default), then prove it by completing a real MCP handshake against the registered command |
|
|
173
254
|
| `codeintel setup [project_root] [--all] [--index] [--warm] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
174
255
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
175
256
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
@@ -237,7 +318,7 @@ Register codeintel as an MCP server (`codeintel install`) and the agent gets fou
|
|
|
237
318
|
| MCP tool | HTTP equivalent | Purpose |
|
|
238
319
|
|---|---|---|
|
|
239
320
|
| `code.query` | `POST /code/query` | The main call — search, trace, understand (the `op` table above) |
|
|
240
|
-
| `code.status` | `GET /code/status` |
|
|
321
|
+
| `code.status` | `GET /code/status` | Per-engine `installed` / `runnable` / `repo_indexed`, probed against the live engines a query actually hits |
|
|
241
322
|
| `code.doctor` | `POST /code/doctor` | Per-engine health + repo index status, with a fix for each gap |
|
|
242
323
|
| `code.map` | — | Generate/refresh `CODE_INTEL.md`, a static orientation file for hosts without MCP |
|
|
243
324
|
|
|
@@ -294,5 +375,16 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
294
375
|
git clone https://github.com/hamilton-sky/codeintel.git
|
|
295
376
|
cd codeintel
|
|
296
377
|
pip install -e .[dev]
|
|
297
|
-
pytest tests/ -q #
|
|
378
|
+
pytest tests/ -q # ~390 tests, ~35s (live graph/LSP backend tests skip when absent)
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Release gate.** The unit suite runs against the source tree, so it cannot see a packaging break, a
|
|
382
|
+
missing entry point, a host config written where nobody reads it, or a server that boots and answers
|
|
383
|
+
nothing. Run the canary against the built wheel in a clean environment — the same check CI runs
|
|
384
|
+
before publishing:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
python -m build && python -m venv /tmp/canary && /tmp/canary/bin/python -m pip install dist/*.whl && /tmp/canary/bin/python scripts/release_canary.py
|
|
298
388
|
```
|
|
389
|
+
|
|
390
|
+
It exits non-zero on the first failed check and cleans up the temporary `HOME` it installs into.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Local-first, MCP-native code-intelligence server — graph, LSP, and semantic search behind one safe code.query tool for coding agents.
|
|
5
5
|
Author: Shammai Hamilton
|
|
6
6
|
License-Expression: MIT
|
|
@@ -110,7 +110,7 @@ The agent hands `result` straight to the model. If the graph backend isn't insta
|
|
|
110
110
|
- **Degrades instead of breaking.** No graph backend installed? That engine returns `null` and the agent falls back to grep. The semantic engine needs nothing external, so codeintel is useful the moment it's installed and only gets sharper as you add backends.
|
|
111
111
|
- **Fast on repeat, never stale.** A content-hash cache returns instantly for unchanged code and self-invalidates when a background reindex advances the index — answers stay both quick *and* fresh. The cache is bounded (LRU), so a long-running server holds steady memory.
|
|
112
112
|
- **Concurrency-safe.** The HTTP transport handles requests on threads, so one slow query (an LSP session warming, a first-time index) can't block every other agent.
|
|
113
|
-
- **Honest about its own health.** `codeintel doctor`
|
|
113
|
+
- **Honest about its own health.** `codeintel doctor` answers three separate questions per engine — *installed?* *runnable?* *is this repo indexed?* — with the single command to fix each gap, so "installed" is never mistaken for "working". And a readiness claim is one a query can actually honor: install a missing backend mid-session and the running server picks it up on the next call, rather than reporting the engine healthy while quietly routing around it until you restart the host.
|
|
114
114
|
|
|
115
115
|
## Quickstart
|
|
116
116
|
|
|
@@ -144,10 +144,91 @@ pip install -e .
|
|
|
144
144
|
Register with your AI agent(s), then query:
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
|
-
codeintel install # registers with
|
|
147
|
+
codeintel install # registers with the agents you actually have installed
|
|
148
148
|
codeintel query --op search --target "authentication middleware"
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
### Enable native Codex integration
|
|
152
|
+
|
|
153
|
+
`codeintel` is an MCP server, so Codex can call its tools directly rather than invoking the CLI.
|
|
154
|
+
After installing the package, explicitly register it with Codex:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
codeintel install --agent codex
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
This safely adds a `[mcp_servers.codeintel]` entry to `~/.codex/config.toml` (or `$CODEX_HOME/config.toml`
|
|
161
|
+
when that is set) without changing your other Codex settings. Registration is deliberately opt-in:
|
|
162
|
+
installing a Python package should not silently modify an agent's configuration. Start a new Codex
|
|
163
|
+
task (or restart Codex) after registration; the refreshed task will have native `code.query`,
|
|
164
|
+
`code.status`, `code.doctor`, and `code.map` MCP tools available.
|
|
165
|
+
|
|
166
|
+
For a fully prepared local setup, run:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
codeintel setup --all /path/to/your/project && codeintel install --agent codex
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Enable native Claude Code integration
|
|
173
|
+
|
|
174
|
+
After installing the package, explicitly register it with Claude Code:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
codeintel install --agent claude
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
This adds the `codeintel` MCP server to `~/.claude.json` (or `$CLAUDE_CONFIG_DIR/.claude.json`)
|
|
181
|
+
while preserving your existing configuration — that is the file Claude Code reads for user-scope
|
|
182
|
+
MCP servers, and you can confirm the entry with `claude mcp list`. Start a new Claude Code session
|
|
183
|
+
after registration so it can load the native `code.query`, `code.status`, `code.doctor`, and
|
|
184
|
+
`code.map` MCP tools.
|
|
185
|
+
|
|
186
|
+
> **Upgrading from ≤ 0.11.1?** Earlier versions wrote this block to `~/.claude/settings.json`,
|
|
187
|
+
> which Claude Code ignores for MCP registration — so codeintel never actually loaded. Re-run
|
|
188
|
+
> `codeintel install --agent claude`; it registers in the right place and points out the stale
|
|
189
|
+
> entry so you can delete it.
|
|
190
|
+
|
|
191
|
+
For a fully prepared local setup, run:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
codeintel setup --all /path/to/your/project && codeintel install --agent claude
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Registration is verified, not assumed
|
|
198
|
+
|
|
199
|
+
**It only touches agents you have.** `codeintel install` defaults to `--agent auto`: it registers
|
|
200
|
+
the hosts whose config root already exists on this machine and *names the ones it skipped*.
|
|
201
|
+
Installing a Python package should not create `~/.gemini/` and `~/.config/zed/` for someone who has
|
|
202
|
+
neither. Force a specific host with `--agent claude|codex|gemini|zed`, or every supported host with
|
|
203
|
+
`--agent all`.
|
|
204
|
+
|
|
205
|
+
**It registers an absolute path.** The bare name `codeintel` is resolved by the *host*, not by the
|
|
206
|
+
shell you ran `install` in — and a GUI-launched desktop agent does not source your shell profile, so
|
|
207
|
+
a command your terminal finds is routinely invisible to the app. That is the one failure a handshake
|
|
208
|
+
run in your terminal cannot catch, because it inherits the PATH that works. Pass
|
|
209
|
+
`--relative-command` for the bare name. If a later upgrade moves the binary, re-running
|
|
210
|
+
`codeintel install` repairs the stale path in place, leaving the rest of your config untouched.
|
|
211
|
+
|
|
212
|
+
Then it launches the exact command it registered and drives a real MCP handshake —
|
|
213
|
+
`initialize` → `tools/list` — and reports what came back:
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
v claude: registered at /Users/you/.claude.json
|
|
217
|
+
|
|
218
|
+
v verified: codeintel 0.11.2 — 4 tools (code.query, code.status, code.doctor, code.map)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
If the command is not on `PATH`, or the server fails to start, install says so and exits non-zero
|
|
222
|
+
instead of reporting a success your agent cannot use. Pass `--no-verify` to skip the handshake.
|
|
223
|
+
|
|
224
|
+
The same principle gates releases. Because every result is a safe envelope with `ok: true` and the
|
|
225
|
+
CLI never throws, an exit-code smoke test passes against a build that boots cleanly and answers
|
|
226
|
+
nothing — so **[`scripts/release_canary.py`](scripts/release_canary.py)** runs before every publish
|
|
227
|
+
against the built wheel in a clean environment: it registers Codex and Claude Code into a throwaway
|
|
228
|
+
`HOME`, launches the command those config files name, and asserts on the **answer text** of a real
|
|
229
|
+
`code.query` over a fixture repo. A release that writes a config no host reads, or that returns
|
|
230
|
+
`ok: true` with nothing in it, fails there instead of on your machine.
|
|
231
|
+
|
|
151
232
|
## How it works
|
|
152
233
|
|
|
153
234
|
A `Gateway` receives every query and dispatches it to one of three providers — graph (structural relationships), LSP (precise symbol resolution), or semantic (embedding-based search) — based on the operation type. Each provider is fully isolated: if it is unavailable or raises an exception, the gateway catches it and returns a safe-null envelope. The caller always gets a well-formed response with no exception to catch.
|
|
@@ -203,7 +284,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
203
284
|
|
|
204
285
|
| Command | Purpose |
|
|
205
286
|
|---|---|
|
|
206
|
-
| `codeintel install [--agent claude\|codex\|gemini\|zed\|all]` | Register codeintel with
|
|
287
|
+
| `codeintel install [--agent auto\|claude\|codex\|gemini\|zed\|all] [--no-verify] [--relative-command]` | Register codeintel with the agents installed on this machine (`auto`, the default), then prove it by completing a real MCP handshake against the registered command |
|
|
207
288
|
| `codeintel setup [project_root] [--all] [--index] [--warm] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
208
289
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
209
290
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
@@ -271,7 +352,7 @@ Register codeintel as an MCP server (`codeintel install`) and the agent gets fou
|
|
|
271
352
|
| MCP tool | HTTP equivalent | Purpose |
|
|
272
353
|
|---|---|---|
|
|
273
354
|
| `code.query` | `POST /code/query` | The main call — search, trace, understand (the `op` table above) |
|
|
274
|
-
| `code.status` | `GET /code/status` |
|
|
355
|
+
| `code.status` | `GET /code/status` | Per-engine `installed` / `runnable` / `repo_indexed`, probed against the live engines a query actually hits |
|
|
275
356
|
| `code.doctor` | `POST /code/doctor` | Per-engine health + repo index status, with a fix for each gap |
|
|
276
357
|
| `code.map` | — | Generate/refresh `CODE_INTEL.md`, a static orientation file for hosts without MCP |
|
|
277
358
|
|
|
@@ -328,5 +409,16 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
328
409
|
git clone https://github.com/hamilton-sky/codeintel.git
|
|
329
410
|
cd codeintel
|
|
330
411
|
pip install -e .[dev]
|
|
331
|
-
pytest tests/ -q #
|
|
412
|
+
pytest tests/ -q # ~390 tests, ~35s (live graph/LSP backend tests skip when absent)
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Release gate.** The unit suite runs against the source tree, so it cannot see a packaging break, a
|
|
416
|
+
missing entry point, a host config written where nobody reads it, or a server that boots and answers
|
|
417
|
+
nothing. Run the canary against the built wheel in a clean environment — the same check CI runs
|
|
418
|
+
before publishing:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
python -m build && python -m venv /tmp/canary && /tmp/canary/bin/python -m pip install dist/*.whl && /tmp/canary/bin/python scripts/release_canary.py
|
|
332
422
|
```
|
|
423
|
+
|
|
424
|
+
It exits non-zero on the first failed check and cleans up the temporary `HOME` it installs into.
|
|
@@ -31,6 +31,7 @@ src/codeintel/searcher.py
|
|
|
31
31
|
src/codeintel/semantic_db.py
|
|
32
32
|
src/codeintel/server.py
|
|
33
33
|
src/codeintel/term.py
|
|
34
|
+
src/codeintel/verify.py
|
|
34
35
|
src/codeintel/providers/__init__.py
|
|
35
36
|
src/codeintel/providers/graph.py
|
|
36
37
|
src/codeintel/providers/lsp.py
|
|
@@ -43,6 +44,7 @@ tests/test_chunking.py
|
|
|
43
44
|
tests/test_config.py
|
|
44
45
|
tests/test_doctor.py
|
|
45
46
|
tests/test_e2e.py
|
|
47
|
+
tests/test_engine_adoption.py
|
|
46
48
|
tests/test_enterprise.py
|
|
47
49
|
tests/test_gateway.py
|
|
48
50
|
tests/test_graph_provider.py
|
|
@@ -57,6 +59,7 @@ tests/test_integration.py
|
|
|
57
59
|
tests/test_lsp_provider.py
|
|
58
60
|
tests/test_lsp_real.py
|
|
59
61
|
tests/test_mapper.py
|
|
62
|
+
tests/test_mcp_handshake.py
|
|
60
63
|
tests/test_mcp_server.py
|
|
61
64
|
tests/test_model_dimension.py
|
|
62
65
|
tests/test_never_raise.py
|
|
@@ -67,4 +70,6 @@ tests/test_rerank.py
|
|
|
67
70
|
tests/test_reset.py
|
|
68
71
|
tests/test_semantic_provider.py
|
|
69
72
|
tests/test_term.py
|
|
70
|
-
tests/test_treesitter.py
|
|
73
|
+
tests/test_treesitter.py
|
|
74
|
+
tests/test_verify.py
|
|
75
|
+
tests/test_verify_call.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.12.0"
|
|
@@ -57,9 +57,21 @@ def main() -> None:
|
|
|
57
57
|
install_parser = subparsers.add_parser("install", help="Register codeintel with AI agents")
|
|
58
58
|
install_parser.add_argument(
|
|
59
59
|
"--agent",
|
|
60
|
-
choices=["claude", "codex", "gemini", "zed", "all"],
|
|
61
|
-
default="
|
|
62
|
-
help="Agent to register with (default:
|
|
60
|
+
choices=["auto", "claude", "codex", "gemini", "zed", "all"],
|
|
61
|
+
default="auto",
|
|
62
|
+
help="Agent to register with (default: auto — only agents installed on this machine; "
|
|
63
|
+
"`all` forces every supported agent)",
|
|
64
|
+
)
|
|
65
|
+
install_parser.add_argument(
|
|
66
|
+
"--no-verify",
|
|
67
|
+
action="store_true",
|
|
68
|
+
help="Skip the post-registration MCP handshake (verification is on by default)",
|
|
69
|
+
)
|
|
70
|
+
install_parser.add_argument(
|
|
71
|
+
"--relative-command",
|
|
72
|
+
action="store_true",
|
|
73
|
+
help="Register the bare `codeintel` name instead of its absolute path (the absolute path "
|
|
74
|
+
"is the default because a GUI-launched agent does not inherit your shell's PATH)",
|
|
63
75
|
)
|
|
64
76
|
|
|
65
77
|
# map subcommand
|
|
@@ -275,11 +287,18 @@ def main() -> None:
|
|
|
275
287
|
project_root = args.project_root or os.getcwd()
|
|
276
288
|
status = server.code_status_handler({"project_root": project_root})
|
|
277
289
|
|
|
290
|
+
# "available" alone was the misleading word: it meant "a binary is on PATH", which is
|
|
291
|
+
# not the same as runnable, and not the same as usable on THIS repo. Say which.
|
|
292
|
+
_READY = {"ok": "ready", "warn": "installed (not verified)", "fail": "unavailable"}
|
|
293
|
+
readiness = status.get("readiness") or {}
|
|
278
294
|
print("Engine status:")
|
|
279
295
|
for engine in ["graph", "lsp", "semantic"]:
|
|
280
|
-
|
|
281
|
-
state = "
|
|
282
|
-
|
|
296
|
+
entry = readiness.get(engine) or {}
|
|
297
|
+
state = _READY.get(entry.get("status"), "unavailable")
|
|
298
|
+
detail = entry.get("detail") or ""
|
|
299
|
+
print(f" {engine:<10} {state:<26} {detail}")
|
|
300
|
+
if status.get("healthy") is False:
|
|
301
|
+
print("\n run `codeintel doctor` for the fix for each gap")
|
|
283
302
|
|
|
284
303
|
from codeintel.config import load_config
|
|
285
304
|
from codeintel.semantic_db import default_db_path
|
|
@@ -382,16 +401,27 @@ def main() -> None:
|
|
|
382
401
|
from codeintel.installer import Installer
|
|
383
402
|
|
|
384
403
|
installer = Installer()
|
|
385
|
-
|
|
386
|
-
|
|
404
|
+
do_verify = not args.no_verify
|
|
405
|
+
absolute = not args.relative_command
|
|
406
|
+
skipped: list[str] = []
|
|
407
|
+
if args.agent == "auto":
|
|
408
|
+
results, skipped = installer.register_detected(verify=do_verify, absolute=absolute)
|
|
409
|
+
if not results:
|
|
410
|
+
print("No supported agent found on this machine "
|
|
411
|
+
f"(looked for: {', '.join(skipped)}).")
|
|
412
|
+
print(" Install one, or force registration with "
|
|
413
|
+
"`codeintel install --agent <name>`.")
|
|
414
|
+
sys.exit(1)
|
|
415
|
+
elif args.agent == "all":
|
|
416
|
+
results = installer.register_all(verify=do_verify, absolute=absolute)
|
|
387
417
|
else:
|
|
388
|
-
results =
|
|
418
|
+
results = installer.register_many([args.agent], verify=do_verify, absolute=absolute)
|
|
389
419
|
|
|
390
420
|
any_ok = False
|
|
421
|
+
legacy_paths: list[str] = []
|
|
422
|
+
verdict = None
|
|
391
423
|
for r in results:
|
|
392
|
-
agent = r["agent"]
|
|
393
|
-
path = r["path"]
|
|
394
|
-
action = r["action"]
|
|
424
|
+
agent, path, action = r["agent"], r["path"], r["action"]
|
|
395
425
|
if action == "registered":
|
|
396
426
|
print(f"v {agent}: registered at {path}")
|
|
397
427
|
any_ok = True
|
|
@@ -400,7 +430,32 @@ def main() -> None:
|
|
|
400
430
|
any_ok = True
|
|
401
431
|
else:
|
|
402
432
|
print(f"x {agent}: failed — {r['reason']}")
|
|
403
|
-
|
|
433
|
+
if r.get("legacy"):
|
|
434
|
+
legacy_paths.append(r["legacy"])
|
|
435
|
+
verdict = r.get("verified") or verdict
|
|
436
|
+
|
|
437
|
+
# A written config file proves nothing about whether the host can launch the server —
|
|
438
|
+
# so say what the handshake actually found, and fail loudly when it did not happen.
|
|
439
|
+
if verdict is not None:
|
|
440
|
+
if verdict.get("ok"):
|
|
441
|
+
print(f"\nv verified: {verdict.get('detail', '')}")
|
|
442
|
+
else:
|
|
443
|
+
print(f"\nx NOT verified: {verdict.get('detail', '')}")
|
|
444
|
+
print(" The config was written, but your agent will not be able to use it "
|
|
445
|
+
"until this is resolved.")
|
|
446
|
+
any_ok = False
|
|
447
|
+
|
|
448
|
+
for legacy in dict.fromkeys(legacy_paths):
|
|
449
|
+
print(f"\n! stale entry: {legacy} has an `mcpServers.codeintel` block that this host "
|
|
450
|
+
f"does NOT read (an older codeintel wrote it). Safe to delete by hand.")
|
|
451
|
+
|
|
452
|
+
# Name what was skipped: silence about an untouched host reads as "unsupported" rather
|
|
453
|
+
# than "you don't have it installed".
|
|
454
|
+
if skipped:
|
|
455
|
+
print(f"\n- skipped (not installed here): {', '.join(skipped)}"
|
|
456
|
+
f"\n register anyway with `codeintel install --agent <name>`")
|
|
457
|
+
|
|
458
|
+
print("\n Start a new agent session to pick up the tools.")
|
|
404
459
|
sys.exit(0 if any_ok else 1)
|
|
405
460
|
|
|
406
461
|
elif args.command == "gen-token":
|
|
@@ -77,3 +77,10 @@ class ContentHashCache:
|
|
|
77
77
|
self._store.move_to_end(key) # most-recently-used
|
|
78
78
|
while len(self._store) > self._max_entries:
|
|
79
79
|
self._store.popitem(last=False) # evict least-recently-used
|
|
80
|
+
|
|
81
|
+
def clear(self) -> None:
|
|
82
|
+
"""Drop every entry. For events that change what an engine *can* answer rather than what
|
|
83
|
+
the content says — the freshness token and the content hash can't see those. Currently:
|
|
84
|
+
a new engine being attached to the gateway mid-process (see ``Gateway.adopt_provider``)."""
|
|
85
|
+
with self._lock:
|
|
86
|
+
self._store.clear()
|