codecortex 0.12.0__tar.gz → 0.13.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.12.0/src/codecortex.egg-info → codecortex-0.13.0}/PKG-INFO +23 -3
- {codecortex-0.12.0 → codecortex-0.13.0}/README.md +18 -1
- codecortex-0.13.0/pyproject.toml +139 -0
- {codecortex-0.12.0 → codecortex-0.13.0/src/codecortex.egg-info}/PKG-INFO +23 -3
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codecortex.egg-info/SOURCES.txt +17 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codecortex.egg-info/requires.txt +3 -0
- codecortex-0.13.0/src/codeintel/__init__.py +1 -0
- codecortex-0.13.0/src/codeintel/__main__.py +273 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/auth.py +10 -9
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/cache.py +7 -8
- codecortex-0.13.0/src/codeintel/commands/__init__.py +6 -0
- codecortex-0.13.0/src/codeintel/commands/_common.py +46 -0
- codecortex-0.13.0/src/codeintel/commands/doctor.py +15 -0
- codecortex-0.13.0/src/codeintel/commands/gen_token.py +9 -0
- codecortex-0.13.0/src/codeintel/commands/graph.py +31 -0
- codecortex-0.13.0/src/codeintel/commands/index.py +63 -0
- codecortex-0.13.0/src/codeintel/commands/install.py +77 -0
- codecortex-0.13.0/src/codeintel/commands/map.py +36 -0
- codecortex-0.13.0/src/codeintel/commands/query.py +55 -0
- codecortex-0.13.0/src/codeintel/commands/reset.py +27 -0
- codecortex-0.13.0/src/codeintel/commands/serve.py +10 -0
- codecortex-0.13.0/src/codeintel/commands/serve_http.py +20 -0
- codecortex-0.13.0/src/codeintel/commands/setup.py +21 -0
- codecortex-0.13.0/src/codeintel/commands/status.py +42 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/config.py +2 -12
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/doctor.py +8 -7
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/gateway.py +4 -5
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/http_server.py +13 -2
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/indexer.py +6 -7
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/installer.py +4 -5
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/mapper.py +10 -10
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/metrics.py +3 -4
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/onboarding.py +6 -4
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/policy.py +2 -4
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/provider.py +5 -4
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/providers/graph.py +27 -25
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/providers/lsp.py +27 -29
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/providers/semantic.py +3 -4
- codecortex-0.13.0/src/codeintel/py.typed +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/searcher.py +1 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/server.py +10 -6
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/term.py +3 -4
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/verify.py +23 -21
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_chunking.py +3 -2
- codecortex-0.13.0/tests/test_cli_commands.py +773 -0
- codecortex-0.13.0/tests/test_cli_help.py +136 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_doctor.py +1 -3
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_gateway.py +0 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_hardening.py +0 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_http_auth.py +3 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_http_server.py +1 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_lsp_real.py +2 -2
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_mapper.py +2 -4
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_mcp_handshake.py +21 -24
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_mcp_server.py +36 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_never_raise.py +4 -8
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_rbac.py +10 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_reindexer.py +1 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_rerank.py +4 -4
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_semantic_provider.py +2 -10
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_treesitter.py +1 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_verify.py +0 -1
- codecortex-0.12.0/pyproject.toml +0 -62
- codecortex-0.12.0/src/codeintel/__init__.py +0 -1
- codecortex-0.12.0/src/codeintel/__main__.py +0 -472
- {codecortex-0.12.0 → codecortex-0.13.0}/LICENSE +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/setup.cfg +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codecortex.egg-info/dependency_links.txt +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codecortex.egg-info/entry_points.txt +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codecortex.egg-info/top_level.txt +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/grapher.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/injector.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/logconfig.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/providers/__init__.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/providers/none.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/reindexer.py +1 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/reset.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/semantic_db.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/viewer/__init__.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/src/codeintel/viewer/graph_template.html +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_cache.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_config.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_e2e.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_engine_adoption.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_enterprise.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_graph_provider.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_graph_real.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_graph_stdin.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_grapher.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_installer.py +1 -1
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_integration.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_lsp_provider.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_model_dimension.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_onboarding.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_reset.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_term.py +0 -0
- {codecortex-0.12.0 → codecortex-0.13.0}/tests/test_verify_call.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.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
|
|
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/hamilton-sky/codeintel
|
|
|
9
9
|
Project-URL: Issues, https://github.com/hamilton-sky/codeintel/issues
|
|
10
10
|
Project-URL: Changelog, https://github.com/hamilton-sky/codeintel/blob/main/CHANGELOG.md
|
|
11
11
|
Keywords: mcp,model-context-protocol,code-intelligence,code-search,llm,agents,lsp,semantic-search,knowledge-graph,static-analysis,developer-tools
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Environment :: Console
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
@@ -29,7 +29,10 @@ Requires-Dist: fastembed>=0.3
|
|
|
29
29
|
Requires-Dist: tree-sitter-language-pack>=1.0
|
|
30
30
|
Provides-Extra: dev
|
|
31
31
|
Requires-Dist: pytest>=8; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
32
33
|
Requires-Dist: numpy>=1.24; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff>=0.16; extra == "dev"
|
|
35
|
+
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
33
36
|
Dynamic: license-file
|
|
34
37
|
|
|
35
38
|
# codeintel
|
|
@@ -229,6 +232,9 @@ against the built wheel in a clean environment: it registers Codex and Claude Co
|
|
|
229
232
|
`code.query` over a fixture repo. A release that writes a config no host reads, or that returns
|
|
230
233
|
`ok: true` with nothing in it, fails there instead of on your machine.
|
|
231
234
|
|
|
235
|
+
> Full reference — what each host reads, the absolute-path rationale, and troubleshooting:
|
|
236
|
+
> **[docs/install.md](docs/install.md)**.
|
|
237
|
+
|
|
232
238
|
## How it works
|
|
233
239
|
|
|
234
240
|
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.
|
|
@@ -275,6 +281,7 @@ Pass `--engine auto` (the default) and codeintel chooses the best engine per ope
|
|
|
275
281
|
Full system docs live in [`docs/`](docs/) — start with the index:
|
|
276
282
|
|
|
277
283
|
- **[Architecture](docs/architecture.md)** — layers, the `CodeProvider` protocol, the safe-null contract, caching, freshness (ASCII + Mermaid).
|
|
284
|
+
- **[Install & registration](docs/install.md)** — what each agent host actually reads, why the registered command is an absolute path, and the three levels of proof that registration worked.
|
|
278
285
|
- **[Query flow](docs/query-flow.md)** — request lifecycle, engine selection, fan-out & merge, and why it never throws.
|
|
279
286
|
- **[Map file](docs/map-file.md)** — the static `CODE_INTEL.md` orientation layer for hosts with no MCP support.
|
|
280
287
|
- **[Benchmarks](docs/benchmarks.md)** — real numbers at scale: 25 k chunks indexed in ~8 min, ~235 ms warm queries, 60 MB index.
|
|
@@ -284,6 +291,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
284
291
|
|
|
285
292
|
| Command | Purpose |
|
|
286
293
|
|---|---|
|
|
294
|
+
| `codeintel help` | Every command grouped by task, with descriptions and examples (also the bare `codeintel`). A mistyped command suggests what you meant. |
|
|
287
295
|
| `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 |
|
|
288
296
|
| `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 |
|
|
289
297
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
@@ -409,7 +417,19 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
409
417
|
git clone https://github.com/hamilton-sky/codeintel.git
|
|
410
418
|
cd codeintel
|
|
411
419
|
pip install -e .[dev]
|
|
412
|
-
|
|
420
|
+
|
|
421
|
+
pytest tests/ -q # ~494 tests, ~35s; fails under 83% coverage
|
|
422
|
+
ruff check src tests # lint
|
|
423
|
+
mypy # types (src/ only)
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**Your local run is not CI's run.** A dev machine usually has `codebase-memory-mcp` and `uvx`
|
|
427
|
+
installed; CI has neither, so the live graph/LSP tests skip there *and* the never-raise envelopes
|
|
428
|
+
take different `reason`/`hint` paths. A bug reachable only on the no-backend path passes at your
|
|
429
|
+
desk and fails in CI. To see CI's shape before you push:
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
env PATH="$(dirname "$(which python)"):/usr/bin:/bin" pytest -q
|
|
413
433
|
```
|
|
414
434
|
|
|
415
435
|
**Release gate.** The unit suite runs against the source tree, so it cannot see a packaging break, a
|
|
@@ -195,6 +195,9 @@ against the built wheel in a clean environment: it registers Codex and Claude Co
|
|
|
195
195
|
`code.query` over a fixture repo. A release that writes a config no host reads, or that returns
|
|
196
196
|
`ok: true` with nothing in it, fails there instead of on your machine.
|
|
197
197
|
|
|
198
|
+
> Full reference — what each host reads, the absolute-path rationale, and troubleshooting:
|
|
199
|
+
> **[docs/install.md](docs/install.md)**.
|
|
200
|
+
|
|
198
201
|
## How it works
|
|
199
202
|
|
|
200
203
|
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.
|
|
@@ -241,6 +244,7 @@ Pass `--engine auto` (the default) and codeintel chooses the best engine per ope
|
|
|
241
244
|
Full system docs live in [`docs/`](docs/) — start with the index:
|
|
242
245
|
|
|
243
246
|
- **[Architecture](docs/architecture.md)** — layers, the `CodeProvider` protocol, the safe-null contract, caching, freshness (ASCII + Mermaid).
|
|
247
|
+
- **[Install & registration](docs/install.md)** — what each agent host actually reads, why the registered command is an absolute path, and the three levels of proof that registration worked.
|
|
244
248
|
- **[Query flow](docs/query-flow.md)** — request lifecycle, engine selection, fan-out & merge, and why it never throws.
|
|
245
249
|
- **[Map file](docs/map-file.md)** — the static `CODE_INTEL.md` orientation layer for hosts with no MCP support.
|
|
246
250
|
- **[Benchmarks](docs/benchmarks.md)** — real numbers at scale: 25 k chunks indexed in ~8 min, ~235 ms warm queries, 60 MB index.
|
|
@@ -250,6 +254,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
250
254
|
|
|
251
255
|
| Command | Purpose |
|
|
252
256
|
|---|---|
|
|
257
|
+
| `codeintel help` | Every command grouped by task, with descriptions and examples (also the bare `codeintel`). A mistyped command suggests what you meant. |
|
|
253
258
|
| `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 |
|
|
254
259
|
| `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 |
|
|
255
260
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
@@ -375,7 +380,19 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
375
380
|
git clone https://github.com/hamilton-sky/codeintel.git
|
|
376
381
|
cd codeintel
|
|
377
382
|
pip install -e .[dev]
|
|
378
|
-
|
|
383
|
+
|
|
384
|
+
pytest tests/ -q # ~494 tests, ~35s; fails under 83% coverage
|
|
385
|
+
ruff check src tests # lint
|
|
386
|
+
mypy # types (src/ only)
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Your local run is not CI's run.** A dev machine usually has `codebase-memory-mcp` and `uvx`
|
|
390
|
+
installed; CI has neither, so the live graph/LSP tests skip there *and* the never-raise envelopes
|
|
391
|
+
take different `reason`/`hint` paths. A bug reachable only on the no-backend path passes at your
|
|
392
|
+
desk and fails in CI. To see CI's shape before you push:
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
env PATH="$(dirname "$(which python)"):/usr/bin:/bin" pytest -q
|
|
379
396
|
```
|
|
380
397
|
|
|
381
398
|
**Release gate.** The unit suite runs against the source tree, so it cannot see a packaging break, a
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
# Distribution name is `codecortex` because `codeintel` is taken on PyPI and `codeintel-*` names
|
|
7
|
+
# are rejected as "too similar" to it. The import package and the CLI are still `codeintel`
|
|
8
|
+
# (i.e. `pip install codecortex` installs the `codeintel` command).
|
|
9
|
+
name = "codecortex"
|
|
10
|
+
dynamic = ["version"]
|
|
11
|
+
description = "Local-first, MCP-native code-intelligence server — graph, LSP, and semantic search behind one safe code.query tool for coding agents."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.11"
|
|
14
|
+
license = "MIT"
|
|
15
|
+
license-files = ["LICENSE"]
|
|
16
|
+
authors = [{ name = "Shammai Hamilton" }]
|
|
17
|
+
keywords = [
|
|
18
|
+
"mcp", "model-context-protocol", "code-intelligence", "code-search", "llm", "agents",
|
|
19
|
+
"lsp", "semantic-search", "knowledge-graph", "static-analysis", "developer-tools",
|
|
20
|
+
]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 5 - Production/Stable",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Environment :: Console",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
31
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
32
|
+
"Typing :: Typed",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"mcp>=1.0",
|
|
36
|
+
"sqlite-vec>=0.1",
|
|
37
|
+
"fastembed>=0.3",
|
|
38
|
+
"tree-sitter-language-pack>=1.0", # def-aligned chunking for non-Python languages (P3)
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/hamilton-sky/codeintel"
|
|
43
|
+
Repository = "https://github.com/hamilton-sky/codeintel"
|
|
44
|
+
Issues = "https://github.com/hamilton-sky/codeintel/issues"
|
|
45
|
+
Changelog = "https://github.com/hamilton-sky/codeintel/blob/main/CHANGELOG.md"
|
|
46
|
+
|
|
47
|
+
[project.scripts]
|
|
48
|
+
codeintel = "codeintel.__main__:main"
|
|
49
|
+
|
|
50
|
+
[project.optional-dependencies]
|
|
51
|
+
dev = ["pytest>=8", "pytest-cov>=5", "numpy>=1.24", "ruff>=0.16", "mypy>=1.11"]
|
|
52
|
+
|
|
53
|
+
# Single source of truth for the version: read from codeintel.__version__ (AST-parsed, no import).
|
|
54
|
+
[tool.setuptools.dynamic]
|
|
55
|
+
version = { attr = "codeintel.__version__" }
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.packages.find]
|
|
58
|
+
where = ["src"]
|
|
59
|
+
|
|
60
|
+
# Ship the self-contained interactive graph viewer template with the wheel, and the PEP 561 marker
|
|
61
|
+
# without which the `Typing :: Typed` classifier is a promise the installed package cannot keep —
|
|
62
|
+
# type checkers ignore an installed package's annotations entirely unless py.typed is present.
|
|
63
|
+
[tool.setuptools.package-data]
|
|
64
|
+
"codeintel.viewer" = ["*.html"]
|
|
65
|
+
"codeintel" = ["py.typed"]
|
|
66
|
+
|
|
67
|
+
[tool.ruff]
|
|
68
|
+
line-length = 120
|
|
69
|
+
target-version = "py311"
|
|
70
|
+
|
|
71
|
+
[tool.ruff.lint]
|
|
72
|
+
select = [
|
|
73
|
+
"E", "W", # pycodestyle
|
|
74
|
+
"F", # pyflakes
|
|
75
|
+
"I", # import sorting
|
|
76
|
+
"UP", # pyupgrade — this is a >=3.11 package, so modern syntax is always available
|
|
77
|
+
"B", # bugbear
|
|
78
|
+
"C4", # comprehensions
|
|
79
|
+
"SIM", # simplify
|
|
80
|
+
"PIE", "PERF", "RUF",
|
|
81
|
+
"S", # bandit — the HTTP transport is a real network surface
|
|
82
|
+
]
|
|
83
|
+
ignore = [
|
|
84
|
+
# The never-raise contract IS the architecture: providers and handlers degrade to a `reason`
|
|
85
|
+
# string rather than propagate, and the best-effort refresh paths (graph reindex, map rewrite)
|
|
86
|
+
# are deliberately allowed to fail silently. These three rules flag that design at ~190 sites,
|
|
87
|
+
# so enforcing them would mean 190 `noqa`s asserting the same thing the module docstrings say.
|
|
88
|
+
"S110", # try-except-pass
|
|
89
|
+
"S112", # try-except-continue
|
|
90
|
+
"SIM105", # "use contextlib.suppress" — see below
|
|
91
|
+
"S603", # subprocess call — every one is an explicit argv list, never a shell string
|
|
92
|
+
]
|
|
93
|
+
# On SIM105 specifically: the suppressed blocks carry their reason on the `pass` line itself
|
|
94
|
+
# (`pass # code_embeddings is created lazily at first embed — may not exist yet`), and
|
|
95
|
+
# contextlib.suppress has nowhere to put that. Losing 13 such explanations to gain a context
|
|
96
|
+
# manager is a bad trade in code whose whole contract is degrading quietly.
|
|
97
|
+
|
|
98
|
+
[tool.ruff.lint.per-file-ignores]
|
|
99
|
+
# Tests stand up fake servers on loopback, assert on hardcoded fixture tokens, and shell out to
|
|
100
|
+
# the CLI under test. Flagging that as a security finding is noise.
|
|
101
|
+
"tests/*" = [
|
|
102
|
+
"S101", "S104", "S105", "S106", "S108", "S404", "S607",
|
|
103
|
+
"S310", # urlopen against the loopback test server this same test just started
|
|
104
|
+
"E402", # a few modules import after a skip guard, so a missing backend skips, not errors
|
|
105
|
+
"E501", # fixture payloads (graph JSON, serena responses) are copied verbatim; rewrapping
|
|
106
|
+
# them would make them stop matching what the real backend returns
|
|
107
|
+
"E702", # `a = 1; b = 2` setup one-liners
|
|
108
|
+
"SIM115", # ad-hoc open() in assertions, inside tmp_path — nothing to leak
|
|
109
|
+
"UP031", # %-format is the readable choice for templating source into a fake server
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
[tool.mypy]
|
|
113
|
+
python_version = "3.11"
|
|
114
|
+
files = ["src/codeintel"]
|
|
115
|
+
# Deliberately not --strict: the provider seams cross into untyped third-party backends (mcp,
|
|
116
|
+
# fastembed, sqlite-vec, tree-sitter), where demanding annotations buys noise rather than safety.
|
|
117
|
+
# These flags catch the errors that actually bite — unreachable branches, bad returns, silent Any
|
|
118
|
+
# propagation out of our own typed code.
|
|
119
|
+
warn_redundant_casts = true
|
|
120
|
+
warn_unused_ignores = true
|
|
121
|
+
warn_unreachable = true
|
|
122
|
+
warn_no_return = true
|
|
123
|
+
no_implicit_optional = true
|
|
124
|
+
check_untyped_defs = true
|
|
125
|
+
|
|
126
|
+
[[tool.mypy.overrides]]
|
|
127
|
+
# Don't type-check the backends themselves, and don't follow into them: `python_version = "3.11"`
|
|
128
|
+
# makes mypy parse their stubs under 3.11 syntax rules, and numpy's (reached transitively through
|
|
129
|
+
# fastembed) use 3.12 `type` statements — an error in a dependency's own stubs, not in our code.
|
|
130
|
+
module = ["mcp.*", "fastembed.*", "sqlite_vec.*", "tree_sitter_language_pack.*", "numpy.*"]
|
|
131
|
+
ignore_missing_imports = true
|
|
132
|
+
follow_imports = "skip"
|
|
133
|
+
|
|
134
|
+
[tool.pytest.ini_options]
|
|
135
|
+
# The floor sits below the current number (85.3% with every backend present) on purpose: the live
|
|
136
|
+
# graph/LSP tests skip when codebase-memory-mcp and uvx/serena are absent, which is exactly the
|
|
137
|
+
# case in CI, and that costs ~0.4 points. A floor pinned to today's measurement would go red on a
|
|
138
|
+
# runner's toolchain rather than on a real coverage regression. Ratchet it up deliberately.
|
|
139
|
+
addopts = "--cov=codeintel --cov-report=term-missing:skip-covered --cov-fail-under=83"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.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
|
|
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/hamilton-sky/codeintel
|
|
|
9
9
|
Project-URL: Issues, https://github.com/hamilton-sky/codeintel/issues
|
|
10
10
|
Project-URL: Changelog, https://github.com/hamilton-sky/codeintel/blob/main/CHANGELOG.md
|
|
11
11
|
Keywords: mcp,model-context-protocol,code-intelligence,code-search,llm,agents,lsp,semantic-search,knowledge-graph,static-analysis,developer-tools
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Environment :: Console
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
@@ -29,7 +29,10 @@ Requires-Dist: fastembed>=0.3
|
|
|
29
29
|
Requires-Dist: tree-sitter-language-pack>=1.0
|
|
30
30
|
Provides-Extra: dev
|
|
31
31
|
Requires-Dist: pytest>=8; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
32
33
|
Requires-Dist: numpy>=1.24; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff>=0.16; extra == "dev"
|
|
35
|
+
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
33
36
|
Dynamic: license-file
|
|
34
37
|
|
|
35
38
|
# codeintel
|
|
@@ -229,6 +232,9 @@ against the built wheel in a clean environment: it registers Codex and Claude Co
|
|
|
229
232
|
`code.query` over a fixture repo. A release that writes a config no host reads, or that returns
|
|
230
233
|
`ok: true` with nothing in it, fails there instead of on your machine.
|
|
231
234
|
|
|
235
|
+
> Full reference — what each host reads, the absolute-path rationale, and troubleshooting:
|
|
236
|
+
> **[docs/install.md](docs/install.md)**.
|
|
237
|
+
|
|
232
238
|
## How it works
|
|
233
239
|
|
|
234
240
|
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.
|
|
@@ -275,6 +281,7 @@ Pass `--engine auto` (the default) and codeintel chooses the best engine per ope
|
|
|
275
281
|
Full system docs live in [`docs/`](docs/) — start with the index:
|
|
276
282
|
|
|
277
283
|
- **[Architecture](docs/architecture.md)** — layers, the `CodeProvider` protocol, the safe-null contract, caching, freshness (ASCII + Mermaid).
|
|
284
|
+
- **[Install & registration](docs/install.md)** — what each agent host actually reads, why the registered command is an absolute path, and the three levels of proof that registration worked.
|
|
278
285
|
- **[Query flow](docs/query-flow.md)** — request lifecycle, engine selection, fan-out & merge, and why it never throws.
|
|
279
286
|
- **[Map file](docs/map-file.md)** — the static `CODE_INTEL.md` orientation layer for hosts with no MCP support.
|
|
280
287
|
- **[Benchmarks](docs/benchmarks.md)** — real numbers at scale: 25 k chunks indexed in ~8 min, ~235 ms warm queries, 60 MB index.
|
|
@@ -284,6 +291,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
284
291
|
|
|
285
292
|
| Command | Purpose |
|
|
286
293
|
|---|---|
|
|
294
|
+
| `codeintel help` | Every command grouped by task, with descriptions and examples (also the bare `codeintel`). A mistyped command suggests what you meant. |
|
|
287
295
|
| `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 |
|
|
288
296
|
| `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 |
|
|
289
297
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
@@ -409,7 +417,19 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
409
417
|
git clone https://github.com/hamilton-sky/codeintel.git
|
|
410
418
|
cd codeintel
|
|
411
419
|
pip install -e .[dev]
|
|
412
|
-
|
|
420
|
+
|
|
421
|
+
pytest tests/ -q # ~494 tests, ~35s; fails under 83% coverage
|
|
422
|
+
ruff check src tests # lint
|
|
423
|
+
mypy # types (src/ only)
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**Your local run is not CI's run.** A dev machine usually has `codebase-memory-mcp` and `uvx`
|
|
427
|
+
installed; CI has neither, so the live graph/LSP tests skip there *and* the never-raise envelopes
|
|
428
|
+
take different `reason`/`hint` paths. A bug reachable only on the no-backend path passes at your
|
|
429
|
+
desk and fails in CI. To see CI's shape before you push:
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
env PATH="$(dirname "$(which python)"):/usr/bin:/bin" pytest -q
|
|
413
433
|
```
|
|
414
434
|
|
|
415
435
|
**Release gate.** The unit suite runs against the source tree, so it cannot see a packaging break, a
|
|
@@ -25,6 +25,7 @@ src/codeintel/metrics.py
|
|
|
25
25
|
src/codeintel/onboarding.py
|
|
26
26
|
src/codeintel/policy.py
|
|
27
27
|
src/codeintel/provider.py
|
|
28
|
+
src/codeintel/py.typed
|
|
28
29
|
src/codeintel/reindexer.py
|
|
29
30
|
src/codeintel/reset.py
|
|
30
31
|
src/codeintel/searcher.py
|
|
@@ -32,6 +33,20 @@ src/codeintel/semantic_db.py
|
|
|
32
33
|
src/codeintel/server.py
|
|
33
34
|
src/codeintel/term.py
|
|
34
35
|
src/codeintel/verify.py
|
|
36
|
+
src/codeintel/commands/__init__.py
|
|
37
|
+
src/codeintel/commands/_common.py
|
|
38
|
+
src/codeintel/commands/doctor.py
|
|
39
|
+
src/codeintel/commands/gen_token.py
|
|
40
|
+
src/codeintel/commands/graph.py
|
|
41
|
+
src/codeintel/commands/index.py
|
|
42
|
+
src/codeintel/commands/install.py
|
|
43
|
+
src/codeintel/commands/map.py
|
|
44
|
+
src/codeintel/commands/query.py
|
|
45
|
+
src/codeintel/commands/reset.py
|
|
46
|
+
src/codeintel/commands/serve.py
|
|
47
|
+
src/codeintel/commands/serve_http.py
|
|
48
|
+
src/codeintel/commands/setup.py
|
|
49
|
+
src/codeintel/commands/status.py
|
|
35
50
|
src/codeintel/providers/__init__.py
|
|
36
51
|
src/codeintel/providers/graph.py
|
|
37
52
|
src/codeintel/providers/lsp.py
|
|
@@ -41,6 +56,8 @@ src/codeintel/viewer/__init__.py
|
|
|
41
56
|
src/codeintel/viewer/graph_template.html
|
|
42
57
|
tests/test_cache.py
|
|
43
58
|
tests/test_chunking.py
|
|
59
|
+
tests/test_cli_commands.py
|
|
60
|
+
tests/test_cli_help.py
|
|
44
61
|
tests/test_config.py
|
|
45
62
|
tests/test_doctor.py
|
|
46
63
|
tests/test_e2e.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.13.0"
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import difflib
|
|
3
|
+
import sys
|
|
4
|
+
from importlib import import_module
|
|
5
|
+
|
|
6
|
+
from codeintel import __version__
|
|
7
|
+
|
|
8
|
+
# Commands grouped by what you are trying to DO. argparse lists them in declaration order with no
|
|
9
|
+
# grouping, which turns "what can this thing do?" into reading twelve lines to find the one verb you
|
|
10
|
+
# wanted. Each entry is (command, one-line description).
|
|
11
|
+
_COMMAND_GROUPS: list[tuple[str, list[tuple[str, str]]]] = [
|
|
12
|
+
("Understand your code", [
|
|
13
|
+
("query", "Ask one question — search, callers, callees, impact, chain, symbol, hotspots"),
|
|
14
|
+
("map", "Write CODE_INTEL.md — a committable architecture overview"),
|
|
15
|
+
("graph", "Interactive call-graph viewer (--html), or the graph as JSON"),
|
|
16
|
+
]),
|
|
17
|
+
("Set up", [
|
|
18
|
+
("setup", "Prepare backends + index this repo (--all does everything automatable)"),
|
|
19
|
+
("index", "Index a project for semantic search"),
|
|
20
|
+
("install", "Register codeintel with the AI agents installed on this machine"),
|
|
21
|
+
]),
|
|
22
|
+
("Check health", [
|
|
23
|
+
("doctor", "Per-engine health + index status, with the fix for each gap"),
|
|
24
|
+
("status", "Engine readiness and index age at a glance"),
|
|
25
|
+
("reset", "Clear the semantic index (recover from a corrupt or stale DB)"),
|
|
26
|
+
]),
|
|
27
|
+
("Run as a server", [
|
|
28
|
+
("serve", "Start the MCP server over stdio — what an agent host launches"),
|
|
29
|
+
("serve-http", "Start the HTTP transport (loopback only unless --allow-remote)"),
|
|
30
|
+
("gen-token", "Print a secure random bearer token for serve-http / RBAC"),
|
|
31
|
+
]),
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
_COMMANDS = [name for _group, items in _COMMAND_GROUPS for name, _desc in items]
|
|
35
|
+
|
|
36
|
+
# Each command's body lives in codeintel.commands.<module> as `run(args) -> int`. The mapping is
|
|
37
|
+
# spelled out rather than derived from the command name so the target of any command is greppable,
|
|
38
|
+
# and the import happens at dispatch time so `codeintel serve` never pays for the semantic
|
|
39
|
+
# engine's imports (nor serve-http for the graph's).
|
|
40
|
+
_MODULES = {
|
|
41
|
+
"query": "query",
|
|
42
|
+
"map": "map",
|
|
43
|
+
"graph": "graph",
|
|
44
|
+
"setup": "setup",
|
|
45
|
+
"index": "index",
|
|
46
|
+
"install": "install",
|
|
47
|
+
"doctor": "doctor",
|
|
48
|
+
"status": "status",
|
|
49
|
+
"reset": "reset",
|
|
50
|
+
"serve": "serve",
|
|
51
|
+
"serve-http": "serve_http",
|
|
52
|
+
"gen-token": "gen_token",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
_EXAMPLES = [
|
|
56
|
+
("codeintel setup --all .", "prepare backends and index this repo"),
|
|
57
|
+
("codeintel install", "register with the agents you have"),
|
|
58
|
+
("codeintel query --op callers --target my_function", "who calls it?"),
|
|
59
|
+
("codeintel doctor", "why is a query coming back empty?"),
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def render_help() -> str:
|
|
64
|
+
"""The `codeintel` / `codeintel help` screen: grouped, colored, with real examples.
|
|
65
|
+
|
|
66
|
+
Color comes from codeintel.term, so it auto-degrades on a pipe, under NO_COLOR, and on a dumb
|
|
67
|
+
terminal — same as every other human-facing command."""
|
|
68
|
+
from codeintel.term import c
|
|
69
|
+
|
|
70
|
+
width = max(len(name) for name in _COMMANDS)
|
|
71
|
+
out = [
|
|
72
|
+
c.bold("codeintel") + c.dim(f" {__version__}")
|
|
73
|
+
+ c.dim(" — code intelligence for AI agents: graph + LSP + semantic search"),
|
|
74
|
+
"",
|
|
75
|
+
c.dim("usage: ") + "codeintel <command> [options]",
|
|
76
|
+
]
|
|
77
|
+
for group, items in _COMMAND_GROUPS:
|
|
78
|
+
out.append("")
|
|
79
|
+
out.append(" " + c.bold(group))
|
|
80
|
+
for name, desc in items:
|
|
81
|
+
out.append(" " + c.cyan(name.ljust(width)) + " " + desc)
|
|
82
|
+
|
|
83
|
+
out.append("")
|
|
84
|
+
out.append(" " + c.bold("Examples"))
|
|
85
|
+
# Width from the content, not a guess — a hardcoded column silently loses its gutter the moment
|
|
86
|
+
# one example grows past it, and ljust() will not pad below the string's own length.
|
|
87
|
+
cmd_width = max(len(cmd) for cmd, _why in _EXAMPLES) + 2
|
|
88
|
+
for cmd, why in _EXAMPLES:
|
|
89
|
+
out.append(" " + cmd.ljust(cmd_width) + c.dim("# " + why))
|
|
90
|
+
|
|
91
|
+
out.append("")
|
|
92
|
+
out.append(" " + c.dim("codeintel <command> --help") + " full options for one command")
|
|
93
|
+
out.append(" " + c.dim("docs: https://github.com/hamilton-sky/codeintel"))
|
|
94
|
+
return "\n".join(out)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _suggest(unknown: str) -> list[str]:
|
|
98
|
+
"""Commands a typo probably meant. Close matches first, then prefix matches — `gragh` should
|
|
99
|
+
land on `graph`, and a bare `serv` on both `serve` and `serve-http`."""
|
|
100
|
+
close = difflib.get_close_matches(unknown, _COMMANDS, n=3, cutoff=0.5)
|
|
101
|
+
prefix = [cmd for cmd in _COMMANDS if cmd.startswith(unknown) and cmd not in close]
|
|
102
|
+
return (close + prefix)[:3]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _unknown_command(name: str) -> int:
|
|
106
|
+
"""Report an unrecognized command with a way forward. argparse's own error dumps the full list
|
|
107
|
+
of choices and stops there, which is a dead end for a one-character typo."""
|
|
108
|
+
from codeintel.term import c_err as e
|
|
109
|
+
|
|
110
|
+
print(e.red(f"unknown command: {name!r}"), file=sys.stderr)
|
|
111
|
+
matches = _suggest(name)
|
|
112
|
+
if matches:
|
|
113
|
+
joined = " or ".join(e.cyan(m) for m in matches)
|
|
114
|
+
print(f"\n did you mean {joined}?", file=sys.stderr)
|
|
115
|
+
print("\n " + e.dim("run `codeintel help` to see every command"), file=sys.stderr)
|
|
116
|
+
return 2
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def main() -> None:
|
|
120
|
+
parser = argparse.ArgumentParser(prog="codeintel")
|
|
121
|
+
parser.add_argument("--version", action="version", version=f"codeintel {__version__}")
|
|
122
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
123
|
+
|
|
124
|
+
# Shared flags for the human-facing (styled) commands.
|
|
125
|
+
color_parent = argparse.ArgumentParser(add_help=False)
|
|
126
|
+
color_parent.add_argument("--no-color", action="store_true", help="Disable ANSI color output")
|
|
127
|
+
color_parent.add_argument("--ascii", action="store_true", help="Use ASCII-only glyphs")
|
|
128
|
+
|
|
129
|
+
subparsers.add_parser("serve", help="Start the MCP server")
|
|
130
|
+
|
|
131
|
+
# index subcommand
|
|
132
|
+
index_parser = subparsers.add_parser("index", help="Index a project for semantic search")
|
|
133
|
+
index_parser.add_argument(
|
|
134
|
+
"project_root",
|
|
135
|
+
nargs="?",
|
|
136
|
+
default=None,
|
|
137
|
+
help="Project root directory (default: cwd)",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# query subcommand
|
|
141
|
+
query_parser = subparsers.add_parser("query", help="Query the code intelligence engine")
|
|
142
|
+
query_parser.add_argument("--op", required=True, help="Query operation (e.g. search, symbol)")
|
|
143
|
+
query_parser.add_argument("--target", required=True, help="Query target")
|
|
144
|
+
query_parser.add_argument("--engine", default="auto", help="Engine to use (default: auto)")
|
|
145
|
+
query_parser.add_argument(
|
|
146
|
+
"--project-root",
|
|
147
|
+
default=None,
|
|
148
|
+
help="Project root directory (default: cwd)",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# status subcommand
|
|
152
|
+
status_parser = subparsers.add_parser("status", help="Show code intelligence engine status")
|
|
153
|
+
status_parser.add_argument(
|
|
154
|
+
"project_root",
|
|
155
|
+
nargs="?",
|
|
156
|
+
default=None,
|
|
157
|
+
help="Project root directory (default: cwd)",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# serve-http subcommand
|
|
161
|
+
http_parser = subparsers.add_parser("serve-http", help="Start the HTTP transport server")
|
|
162
|
+
http_parser.add_argument("--port", type=int, default=8766, help="Port to listen on (default: 8766)")
|
|
163
|
+
http_parser.add_argument("--host", default="127.0.0.1", help="Host to bind to (default: 127.0.0.1)")
|
|
164
|
+
http_parser.add_argument("--allow-remote", action="store_true",
|
|
165
|
+
help="Permit binding a non-loopback host (use with --token, or the "
|
|
166
|
+
"endpoint is UNAUTHENTICATED)")
|
|
167
|
+
http_parser.add_argument("--token", default=None,
|
|
168
|
+
help="Require this bearer token on every request (or set "
|
|
169
|
+
"CODEINTEL_HTTP_TOKEN). Strongly recommended with --allow-remote.")
|
|
170
|
+
|
|
171
|
+
# install subcommand
|
|
172
|
+
install_parser = subparsers.add_parser("install", help="Register codeintel with AI agents")
|
|
173
|
+
install_parser.add_argument(
|
|
174
|
+
"--agent",
|
|
175
|
+
choices=["auto", "claude", "codex", "gemini", "zed", "all"],
|
|
176
|
+
default="auto",
|
|
177
|
+
help="Agent to register with (default: auto — only agents installed on this machine; "
|
|
178
|
+
"`all` forces every supported agent)",
|
|
179
|
+
)
|
|
180
|
+
install_parser.add_argument(
|
|
181
|
+
"--no-verify",
|
|
182
|
+
action="store_true",
|
|
183
|
+
help="Skip the post-registration MCP handshake (verification is on by default)",
|
|
184
|
+
)
|
|
185
|
+
install_parser.add_argument(
|
|
186
|
+
"--relative-command",
|
|
187
|
+
action="store_true",
|
|
188
|
+
help="Register the bare `codeintel` name instead of its absolute path (the absolute path "
|
|
189
|
+
"is the default because a GUI-launched agent does not inherit your shell's PATH)",
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# map subcommand
|
|
193
|
+
map_parser = subparsers.add_parser("map", help="Generate CODE_INTEL.md orientation file")
|
|
194
|
+
map_parser.add_argument("project_root", nargs="?", default=None)
|
|
195
|
+
map_parser.add_argument("--inject", action="store_true", help="Inject reference block into CLAUDE.md/AGENTS.md")
|
|
196
|
+
map_parser.add_argument("--budget", type=int, default=32768, help="Byte budget for CODE_INTEL.md (default: 32768)")
|
|
197
|
+
|
|
198
|
+
# graph subcommand — interactive call-graph view (HTML) or the raw {nodes,edges} JSON
|
|
199
|
+
graph_parser = subparsers.add_parser(
|
|
200
|
+
"graph", help="Build an interactive call-graph view (--html) or emit the graph as JSON — "
|
|
201
|
+
"works on any indexed repo")
|
|
202
|
+
graph_parser.add_argument("project_root", nargs="?", default=None, help="Project root (default: cwd)")
|
|
203
|
+
graph_parser.add_argument("--html", action="store_true",
|
|
204
|
+
help="Write a self-contained interactive HTML viewer (default: print JSON)")
|
|
205
|
+
graph_parser.add_argument("--out", default=None, help="Output path for --html (default: codeintel-graph.html)")
|
|
206
|
+
graph_parser.add_argument("--limit", type=int, default=220, help="Max call edges to include (default: 220)")
|
|
207
|
+
|
|
208
|
+
# doctor subcommand
|
|
209
|
+
doctor_parser = subparsers.add_parser("doctor", parents=[color_parent],
|
|
210
|
+
help="Diagnose engine health + index status for a repo")
|
|
211
|
+
doctor_parser.add_argument("project_root", nargs="?", default=None, help="Project root (default: cwd)")
|
|
212
|
+
doctor_parser.add_argument("--deep", action="store_true",
|
|
213
|
+
help="Also boot-check serena (slower; first boot pulls it via uvx)")
|
|
214
|
+
doctor_parser.add_argument("--json", action="store_true",
|
|
215
|
+
help="Emit the structured JSON report instead of the table")
|
|
216
|
+
|
|
217
|
+
# setup subcommand
|
|
218
|
+
setup_parser = subparsers.add_parser("setup", parents=[color_parent],
|
|
219
|
+
help="Prepare backends and optionally index this repo")
|
|
220
|
+
setup_parser.add_argument("project_root", nargs="?", default=None, help="Project root (default: cwd)")
|
|
221
|
+
setup_parser.add_argument("--all", action="store_true", dest="all_steps",
|
|
222
|
+
help="One-command setup: do everything automatable (uv + deps + index + "
|
|
223
|
+
"warm serena). Idempotent — skips what's already installed.")
|
|
224
|
+
setup_parser.add_argument("--install-uv", action="store_true",
|
|
225
|
+
help="Run `pip install uv` (provides uvx for the LSP engine)")
|
|
226
|
+
setup_parser.add_argument("--install-deps", action="store_true",
|
|
227
|
+
help="Run `pip install -e .` (semantic engine deps)")
|
|
228
|
+
setup_parser.add_argument("--index", action="store_true",
|
|
229
|
+
help="Index this repo now (first run downloads the ~50MB model)")
|
|
230
|
+
setup_parser.add_argument("--warm", action="store_true", help="Boot serena now (first run pulls it via uvx; slow)")
|
|
231
|
+
setup_parser.add_argument("--json", action="store_true", help="Emit the structured JSON report")
|
|
232
|
+
|
|
233
|
+
# reset subcommand
|
|
234
|
+
reset_parser = subparsers.add_parser("reset", parents=[color_parent],
|
|
235
|
+
help="Clear the semantic index (recover from a corrupt/stale DB)")
|
|
236
|
+
reset_parser.add_argument("project_root", nargs="?", default=None, help="Project root (default: cwd)")
|
|
237
|
+
reset_parser.add_argument("--all", action="store_true",
|
|
238
|
+
help="Clear the ENTIRE index (all projects), not just this repo")
|
|
239
|
+
reset_parser.add_argument("--yes", "-y", action="store_true", help="Skip the confirmation prompt")
|
|
240
|
+
reset_parser.add_argument("--json", action="store_true", help="Emit the structured JSON report")
|
|
241
|
+
|
|
242
|
+
subparsers.add_parser("gen-token", help="Print a secure random bearer token (for serve-http / RBAC auth.toml)")
|
|
243
|
+
subparsers.add_parser("help", help="Show every command, grouped, with examples")
|
|
244
|
+
|
|
245
|
+
# Intercept an unrecognized command BEFORE argparse, whose error prints the full choice list and
|
|
246
|
+
# stops — a dead end for a one-character typo. Only a bare word is claimed here; anything
|
|
247
|
+
# starting with `-` (--version, --help) still goes to argparse.
|
|
248
|
+
argv = sys.argv[1:]
|
|
249
|
+
if argv and not argv[0].startswith("-") and argv[0] not in [*_COMMANDS, "help"]:
|
|
250
|
+
sys.exit(_unknown_command(argv[0]))
|
|
251
|
+
if not argv or argv[0] == "help":
|
|
252
|
+
from codeintel import term
|
|
253
|
+
term.configure(no_color=False, ascii_mode=None)
|
|
254
|
+
print(render_help())
|
|
255
|
+
sys.exit(0)
|
|
256
|
+
|
|
257
|
+
args = parser.parse_args()
|
|
258
|
+
|
|
259
|
+
from codeintel import term
|
|
260
|
+
term.configure(
|
|
261
|
+
no_color=getattr(args, "no_color", False),
|
|
262
|
+
ascii_mode=(True if getattr(args, "ascii", False) else None),
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
module = _MODULES.get(args.command)
|
|
266
|
+
if module is None: # unreachable via argparse; a bare `codeintel` is handled above
|
|
267
|
+
print(render_help())
|
|
268
|
+
sys.exit(0)
|
|
269
|
+
sys.exit(import_module(f"codeintel.commands.{module}").run(args))
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
if __name__ == "__main__":
|
|
273
|
+
main()
|