codecortex 0.9.0__tar.gz → 0.11.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.9.0/src/codecortex.egg-info → codecortex-0.11.0}/PKG-INFO +22 -14
- {codecortex-0.9.0 → codecortex-0.11.0}/README.md +21 -13
- {codecortex-0.9.0 → codecortex-0.11.0}/pyproject.toml +4 -0
- {codecortex-0.9.0 → codecortex-0.11.0/src/codecortex.egg-info}/PKG-INFO +22 -14
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codecortex.egg-info/SOURCES.txt +4 -0
- codecortex-0.11.0/src/codeintel/__init__.py +1 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/__main__.py +40 -4
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/doctor.py +17 -4
- codecortex-0.11.0/src/codeintel/grapher.py +115 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/onboarding.py +76 -12
- codecortex-0.11.0/src/codeintel/viewer/__init__.py +1 -0
- codecortex-0.11.0/src/codeintel/viewer/graph_template.html +490 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_doctor.py +18 -0
- codecortex-0.11.0/tests/test_grapher.py +127 -0
- codecortex-0.11.0/tests/test_onboarding.py +160 -0
- codecortex-0.9.0/src/codeintel/__init__.py +0 -1
- codecortex-0.9.0/tests/test_onboarding.py +0 -78
- {codecortex-0.9.0 → codecortex-0.11.0}/LICENSE +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/setup.cfg +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codecortex.egg-info/dependency_links.txt +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codecortex.egg-info/entry_points.txt +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codecortex.egg-info/requires.txt +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codecortex.egg-info/top_level.txt +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/auth.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/cache.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/config.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/gateway.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/http_server.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/indexer.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/injector.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/installer.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/logconfig.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/mapper.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/metrics.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/policy.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/provider.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/providers/__init__.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/providers/graph.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/providers/lsp.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/providers/none.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/providers/semantic.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/reindexer.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/reset.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/searcher.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/semantic_db.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/server.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/src/codeintel/term.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_cache.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_chunking.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_config.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_e2e.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_enterprise.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_gateway.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_graph_provider.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_graph_real.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_graph_stdin.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_hardening.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_http_auth.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_http_server.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_installer.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_integration.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_lsp_provider.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_lsp_real.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_mapper.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_mcp_server.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_model_dimension.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_never_raise.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_rbac.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_reindexer.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_rerank.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_reset.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_semantic_provider.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.0}/tests/test_term.py +0 -0
- {codecortex-0.9.0 → codecortex-0.11.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.11.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
|
|
@@ -60,10 +60,13 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
60
60
|
| Who calls this? | `callers` | graph | caller symbols + files |
|
|
61
61
|
| What does this call? | `callees` | graph | callee symbols + files |
|
|
62
62
|
| Blast radius of a change | `impact` | graph | callers **and** callees together |
|
|
63
|
-
| Trace a call chain up/downstream | `chain` | graph | ordered hops |
|
|
63
|
+
| Trace a call chain up/downstream | `chain` | graph | ordered, risk-labeled hops |
|
|
64
64
|
| Find symbols by pattern | `pattern` | graph | matching nodes + locations |
|
|
65
65
|
| Project shape at a glance | `overview` | graph → lsp | modules, node/edge counts, languages |
|
|
66
66
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
67
|
+
| **Impact of your uncommitted edits** | `changed` | graph | changed files → impacted symbols |
|
|
68
|
+
| Refactor-risk hotspots | `hotspots` | graph | highest complexity / fan-in symbols |
|
|
69
|
+
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers |
|
|
67
70
|
|
|
68
71
|
Pin one engine with `--engine graph│lsp│semantic`, or fan out with `--engine both` / `all` to merge results.
|
|
69
72
|
|
|
@@ -99,11 +102,21 @@ The agent hands `result` straight to the model. If the graph backend isn't insta
|
|
|
99
102
|
pip install codecortex
|
|
100
103
|
```
|
|
101
104
|
|
|
102
|
-
This installs the `codeintel` CLI; the **semantic** engine works out of the box.
|
|
103
|
-
and **LSP** engines use external backends (`codebase-memory-mcp`, and serena via `uvx`) —
|
|
104
|
-
run `codeintel doctor` to see what's available and how to enable the rest. (On PyPI the
|
|
105
|
+
This installs the `codeintel` CLI; the **semantic** engine works out of the box. (On PyPI the
|
|
105
106
|
distribution is `codecortex` because `codeintel` was taken; the CLI and import stay `codeintel`.)
|
|
106
107
|
|
|
108
|
+
**One command prepares the rest and indexes your repo:**
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
codeintel setup --all /path/to/your/project
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This installs `uv` (for the LSP engine), warms serena, downloads the embedding model, indexes the
|
|
115
|
+
repo, and prints a health report ending in a **Next:** list — exactly what's ready and the one
|
|
116
|
+
remaining step. It's idempotent, so re-running is safe. The **graph** engine (`codebase-memory-mcp`)
|
|
117
|
+
is an *optional* external binary that adds who-calls / impact / hotspots / `changed`; codeintel is
|
|
118
|
+
fully usable without it.
|
|
119
|
+
|
|
107
120
|
Or from source:
|
|
108
121
|
|
|
109
122
|
```bash
|
|
@@ -112,17 +125,10 @@ cd codeintel
|
|
|
112
125
|
pip install -e .
|
|
113
126
|
```
|
|
114
127
|
|
|
115
|
-
Register with your AI agent(s):
|
|
128
|
+
Register with your AI agent(s), then query:
|
|
116
129
|
|
|
117
130
|
```bash
|
|
118
131
|
codeintel install # registers with Claude, Codex, Gemini, Zed
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Index a project, check what's ready, and run your first query:
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
codeintel index /path/to/your/project
|
|
125
|
-
codeintel doctor /path/to/your/project # which engines are ready + how to fix the rest
|
|
126
132
|
codeintel query --op search --target "authentication middleware"
|
|
127
133
|
```
|
|
128
134
|
|
|
@@ -174,6 +180,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
174
180
|
- **[Architecture](docs/architecture.md)** — layers, the `CodeProvider` protocol, the safe-null contract, caching, freshness (ASCII + Mermaid).
|
|
175
181
|
- **[Query flow](docs/query-flow.md)** — request lifecycle, engine selection, fan-out & merge, and why it never throws.
|
|
176
182
|
- **[Map file](docs/map-file.md)** — the static `CODE_INTEL.md` orientation layer for hosts with no MCP support.
|
|
183
|
+
- **[Benchmarks](docs/benchmarks.md)** — real numbers at scale: 25 k chunks indexed in ~8 min, ~235 ms warm queries, 60 MB index.
|
|
177
184
|
- Engine references: **[graph](docs/graph.md)** · **[lsp](docs/lsp.md)** · **[semantic](docs/semantic.md)**.
|
|
178
185
|
|
|
179
186
|
## CLI reference
|
|
@@ -181,7 +188,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
181
188
|
| Command | Purpose |
|
|
182
189
|
|---|---|
|
|
183
190
|
| `codeintel install [--agent claude\|codex\|gemini\|zed\|all]` | Register codeintel with AI agent(s) |
|
|
184
|
-
| `codeintel setup [project_root] [--index] [--warm] [--install-uv]` |
|
|
191
|
+
| `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 |
|
|
185
192
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
186
193
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
187
194
|
| `codeintel serve-http [--host HOST] [--port 8766] [--allow-remote] [--token TOKEN]` | Start the HTTP transport (loopback-only unless `--allow-remote`; `--token` requires a bearer token on every request) |
|
|
@@ -189,6 +196,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
189
196
|
| `codeintel status [project_root]` | Show engine availability and index age |
|
|
190
197
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
191
198
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
199
|
+
| `codeintel graph [project_root] [--html] [--out FILE] [--limit N]` | Emit the call graph as `{nodes,edges}` JSON, or `--html` a self-contained interactive viewer — see [docs/graph-viewer.md](docs/graph-viewer.md) |
|
|
192
200
|
| `codeintel reset [project_root] [--all] [--yes]` | Clear the semantic index (this repo, or `--all`) to recover from a corrupt/stale DB |
|
|
193
201
|
| `codeintel gen-token` | Print a secure random bearer token (for `serve-http` / RBAC `auth.toml`) |
|
|
194
202
|
|
|
@@ -26,10 +26,13 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
26
26
|
| Who calls this? | `callers` | graph | caller symbols + files |
|
|
27
27
|
| What does this call? | `callees` | graph | callee symbols + files |
|
|
28
28
|
| Blast radius of a change | `impact` | graph | callers **and** callees together |
|
|
29
|
-
| Trace a call chain up/downstream | `chain` | graph | ordered hops |
|
|
29
|
+
| Trace a call chain up/downstream | `chain` | graph | ordered, risk-labeled hops |
|
|
30
30
|
| Find symbols by pattern | `pattern` | graph | matching nodes + locations |
|
|
31
31
|
| Project shape at a glance | `overview` | graph → lsp | modules, node/edge counts, languages |
|
|
32
32
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
33
|
+
| **Impact of your uncommitted edits** | `changed` | graph | changed files → impacted symbols |
|
|
34
|
+
| Refactor-risk hotspots | `hotspots` | graph | highest complexity / fan-in symbols |
|
|
35
|
+
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers |
|
|
33
36
|
|
|
34
37
|
Pin one engine with `--engine graph│lsp│semantic`, or fan out with `--engine both` / `all` to merge results.
|
|
35
38
|
|
|
@@ -65,11 +68,21 @@ The agent hands `result` straight to the model. If the graph backend isn't insta
|
|
|
65
68
|
pip install codecortex
|
|
66
69
|
```
|
|
67
70
|
|
|
68
|
-
This installs the `codeintel` CLI; the **semantic** engine works out of the box.
|
|
69
|
-
and **LSP** engines use external backends (`codebase-memory-mcp`, and serena via `uvx`) —
|
|
70
|
-
run `codeintel doctor` to see what's available and how to enable the rest. (On PyPI the
|
|
71
|
+
This installs the `codeintel` CLI; the **semantic** engine works out of the box. (On PyPI the
|
|
71
72
|
distribution is `codecortex` because `codeintel` was taken; the CLI and import stay `codeintel`.)
|
|
72
73
|
|
|
74
|
+
**One command prepares the rest and indexes your repo:**
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
codeintel setup --all /path/to/your/project
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This installs `uv` (for the LSP engine), warms serena, downloads the embedding model, indexes the
|
|
81
|
+
repo, and prints a health report ending in a **Next:** list — exactly what's ready and the one
|
|
82
|
+
remaining step. It's idempotent, so re-running is safe. The **graph** engine (`codebase-memory-mcp`)
|
|
83
|
+
is an *optional* external binary that adds who-calls / impact / hotspots / `changed`; codeintel is
|
|
84
|
+
fully usable without it.
|
|
85
|
+
|
|
73
86
|
Or from source:
|
|
74
87
|
|
|
75
88
|
```bash
|
|
@@ -78,17 +91,10 @@ cd codeintel
|
|
|
78
91
|
pip install -e .
|
|
79
92
|
```
|
|
80
93
|
|
|
81
|
-
Register with your AI agent(s):
|
|
94
|
+
Register with your AI agent(s), then query:
|
|
82
95
|
|
|
83
96
|
```bash
|
|
84
97
|
codeintel install # registers with Claude, Codex, Gemini, Zed
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Index a project, check what's ready, and run your first query:
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
codeintel index /path/to/your/project
|
|
91
|
-
codeintel doctor /path/to/your/project # which engines are ready + how to fix the rest
|
|
92
98
|
codeintel query --op search --target "authentication middleware"
|
|
93
99
|
```
|
|
94
100
|
|
|
@@ -140,6 +146,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
140
146
|
- **[Architecture](docs/architecture.md)** — layers, the `CodeProvider` protocol, the safe-null contract, caching, freshness (ASCII + Mermaid).
|
|
141
147
|
- **[Query flow](docs/query-flow.md)** — request lifecycle, engine selection, fan-out & merge, and why it never throws.
|
|
142
148
|
- **[Map file](docs/map-file.md)** — the static `CODE_INTEL.md` orientation layer for hosts with no MCP support.
|
|
149
|
+
- **[Benchmarks](docs/benchmarks.md)** — real numbers at scale: 25 k chunks indexed in ~8 min, ~235 ms warm queries, 60 MB index.
|
|
143
150
|
- Engine references: **[graph](docs/graph.md)** · **[lsp](docs/lsp.md)** · **[semantic](docs/semantic.md)**.
|
|
144
151
|
|
|
145
152
|
## CLI reference
|
|
@@ -147,7 +154,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
147
154
|
| Command | Purpose |
|
|
148
155
|
|---|---|
|
|
149
156
|
| `codeintel install [--agent claude\|codex\|gemini\|zed\|all]` | Register codeintel with AI agent(s) |
|
|
150
|
-
| `codeintel setup [project_root] [--index] [--warm] [--install-uv]` |
|
|
157
|
+
| `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 |
|
|
151
158
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
152
159
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
153
160
|
| `codeintel serve-http [--host HOST] [--port 8766] [--allow-remote] [--token TOKEN]` | Start the HTTP transport (loopback-only unless `--allow-remote`; `--token` requires a bearer token on every request) |
|
|
@@ -155,6 +162,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
155
162
|
| `codeintel status [project_root]` | Show engine availability and index age |
|
|
156
163
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
157
164
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
165
|
+
| `codeintel graph [project_root] [--html] [--out FILE] [--limit N]` | Emit the call graph as `{nodes,edges}` JSON, or `--html` a self-contained interactive viewer — see [docs/graph-viewer.md](docs/graph-viewer.md) |
|
|
158
166
|
| `codeintel reset [project_root] [--all] [--yes]` | Clear the semantic index (this repo, or `--all`) to recover from a corrupt/stale DB |
|
|
159
167
|
| `codeintel gen-token` | Print a secure random bearer token (for `serve-http` / RBAC `auth.toml`) |
|
|
160
168
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.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
|
|
@@ -60,10 +60,13 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
60
60
|
| Who calls this? | `callers` | graph | caller symbols + files |
|
|
61
61
|
| What does this call? | `callees` | graph | callee symbols + files |
|
|
62
62
|
| Blast radius of a change | `impact` | graph | callers **and** callees together |
|
|
63
|
-
| Trace a call chain up/downstream | `chain` | graph | ordered hops |
|
|
63
|
+
| Trace a call chain up/downstream | `chain` | graph | ordered, risk-labeled hops |
|
|
64
64
|
| Find symbols by pattern | `pattern` | graph | matching nodes + locations |
|
|
65
65
|
| Project shape at a glance | `overview` | graph → lsp | modules, node/edge counts, languages |
|
|
66
66
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
67
|
+
| **Impact of your uncommitted edits** | `changed` | graph | changed files → impacted symbols |
|
|
68
|
+
| Refactor-risk hotspots | `hotspots` | graph | highest complexity / fan-in symbols |
|
|
69
|
+
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers |
|
|
67
70
|
|
|
68
71
|
Pin one engine with `--engine graph│lsp│semantic`, or fan out with `--engine both` / `all` to merge results.
|
|
69
72
|
|
|
@@ -99,11 +102,21 @@ The agent hands `result` straight to the model. If the graph backend isn't insta
|
|
|
99
102
|
pip install codecortex
|
|
100
103
|
```
|
|
101
104
|
|
|
102
|
-
This installs the `codeintel` CLI; the **semantic** engine works out of the box.
|
|
103
|
-
and **LSP** engines use external backends (`codebase-memory-mcp`, and serena via `uvx`) —
|
|
104
|
-
run `codeintel doctor` to see what's available and how to enable the rest. (On PyPI the
|
|
105
|
+
This installs the `codeintel` CLI; the **semantic** engine works out of the box. (On PyPI the
|
|
105
106
|
distribution is `codecortex` because `codeintel` was taken; the CLI and import stay `codeintel`.)
|
|
106
107
|
|
|
108
|
+
**One command prepares the rest and indexes your repo:**
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
codeintel setup --all /path/to/your/project
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This installs `uv` (for the LSP engine), warms serena, downloads the embedding model, indexes the
|
|
115
|
+
repo, and prints a health report ending in a **Next:** list — exactly what's ready and the one
|
|
116
|
+
remaining step. It's idempotent, so re-running is safe. The **graph** engine (`codebase-memory-mcp`)
|
|
117
|
+
is an *optional* external binary that adds who-calls / impact / hotspots / `changed`; codeintel is
|
|
118
|
+
fully usable without it.
|
|
119
|
+
|
|
107
120
|
Or from source:
|
|
108
121
|
|
|
109
122
|
```bash
|
|
@@ -112,17 +125,10 @@ cd codeintel
|
|
|
112
125
|
pip install -e .
|
|
113
126
|
```
|
|
114
127
|
|
|
115
|
-
Register with your AI agent(s):
|
|
128
|
+
Register with your AI agent(s), then query:
|
|
116
129
|
|
|
117
130
|
```bash
|
|
118
131
|
codeintel install # registers with Claude, Codex, Gemini, Zed
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Index a project, check what's ready, and run your first query:
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
codeintel index /path/to/your/project
|
|
125
|
-
codeintel doctor /path/to/your/project # which engines are ready + how to fix the rest
|
|
126
132
|
codeintel query --op search --target "authentication middleware"
|
|
127
133
|
```
|
|
128
134
|
|
|
@@ -174,6 +180,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
174
180
|
- **[Architecture](docs/architecture.md)** — layers, the `CodeProvider` protocol, the safe-null contract, caching, freshness (ASCII + Mermaid).
|
|
175
181
|
- **[Query flow](docs/query-flow.md)** — request lifecycle, engine selection, fan-out & merge, and why it never throws.
|
|
176
182
|
- **[Map file](docs/map-file.md)** — the static `CODE_INTEL.md` orientation layer for hosts with no MCP support.
|
|
183
|
+
- **[Benchmarks](docs/benchmarks.md)** — real numbers at scale: 25 k chunks indexed in ~8 min, ~235 ms warm queries, 60 MB index.
|
|
177
184
|
- Engine references: **[graph](docs/graph.md)** · **[lsp](docs/lsp.md)** · **[semantic](docs/semantic.md)**.
|
|
178
185
|
|
|
179
186
|
## CLI reference
|
|
@@ -181,7 +188,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
181
188
|
| Command | Purpose |
|
|
182
189
|
|---|---|
|
|
183
190
|
| `codeintel install [--agent claude\|codex\|gemini\|zed\|all]` | Register codeintel with AI agent(s) |
|
|
184
|
-
| `codeintel setup [project_root] [--index] [--warm] [--install-uv]` |
|
|
191
|
+
| `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 |
|
|
185
192
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
186
193
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
187
194
|
| `codeintel serve-http [--host HOST] [--port 8766] [--allow-remote] [--token TOKEN]` | Start the HTTP transport (loopback-only unless `--allow-remote`; `--token` requires a bearer token on every request) |
|
|
@@ -189,6 +196,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
189
196
|
| `codeintel status [project_root]` | Show engine availability and index age |
|
|
190
197
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
191
198
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
199
|
+
| `codeintel graph [project_root] [--html] [--out FILE] [--limit N]` | Emit the call graph as `{nodes,edges}` JSON, or `--html` a self-contained interactive viewer — see [docs/graph-viewer.md](docs/graph-viewer.md) |
|
|
192
200
|
| `codeintel reset [project_root] [--all] [--yes]` | Clear the semantic index (this repo, or `--all`) to recover from a corrupt/stale DB |
|
|
193
201
|
| `codeintel gen-token` | Print a secure random bearer token (for `serve-http` / RBAC `auth.toml`) |
|
|
194
202
|
|
|
@@ -14,6 +14,7 @@ src/codeintel/cache.py
|
|
|
14
14
|
src/codeintel/config.py
|
|
15
15
|
src/codeintel/doctor.py
|
|
16
16
|
src/codeintel/gateway.py
|
|
17
|
+
src/codeintel/grapher.py
|
|
17
18
|
src/codeintel/http_server.py
|
|
18
19
|
src/codeintel/indexer.py
|
|
19
20
|
src/codeintel/injector.py
|
|
@@ -35,6 +36,8 @@ src/codeintel/providers/graph.py
|
|
|
35
36
|
src/codeintel/providers/lsp.py
|
|
36
37
|
src/codeintel/providers/none.py
|
|
37
38
|
src/codeintel/providers/semantic.py
|
|
39
|
+
src/codeintel/viewer/__init__.py
|
|
40
|
+
src/codeintel/viewer/graph_template.html
|
|
38
41
|
tests/test_cache.py
|
|
39
42
|
tests/test_chunking.py
|
|
40
43
|
tests/test_config.py
|
|
@@ -45,6 +48,7 @@ tests/test_gateway.py
|
|
|
45
48
|
tests/test_graph_provider.py
|
|
46
49
|
tests/test_graph_real.py
|
|
47
50
|
tests/test_graph_stdin.py
|
|
51
|
+
tests/test_grapher.py
|
|
48
52
|
tests/test_hardening.py
|
|
49
53
|
tests/test_http_auth.py
|
|
50
54
|
tests/test_http_server.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.11.0"
|
|
@@ -68,6 +68,13 @@ def main() -> None:
|
|
|
68
68
|
map_parser.add_argument("--inject", action="store_true", help="Inject reference block into CLAUDE.md/AGENTS.md")
|
|
69
69
|
map_parser.add_argument("--budget", type=int, default=32768, help="Byte budget for CODE_INTEL.md (default: 32768)")
|
|
70
70
|
|
|
71
|
+
# graph subcommand — interactive call-graph view (HTML) or the raw {nodes,edges} JSON
|
|
72
|
+
graph_parser = subparsers.add_parser("graph", help="Build an interactive call-graph view (--html) or emit the graph as JSON — works on any indexed repo")
|
|
73
|
+
graph_parser.add_argument("project_root", nargs="?", default=None, help="Project root (default: cwd)")
|
|
74
|
+
graph_parser.add_argument("--html", action="store_true", help="Write a self-contained interactive HTML viewer (default: print JSON)")
|
|
75
|
+
graph_parser.add_argument("--out", default=None, help="Output path for --html (default: codeintel-graph.html)")
|
|
76
|
+
graph_parser.add_argument("--limit", type=int, default=220, help="Max call edges to include (default: 220)")
|
|
77
|
+
|
|
71
78
|
# doctor subcommand
|
|
72
79
|
doctor_parser = subparsers.add_parser("doctor", parents=[color_parent], help="Diagnose engine health + index status for a repo")
|
|
73
80
|
doctor_parser.add_argument("project_root", nargs="?", default=None, help="Project root (default: cwd)")
|
|
@@ -77,6 +84,9 @@ def main() -> None:
|
|
|
77
84
|
# setup subcommand
|
|
78
85
|
setup_parser = subparsers.add_parser("setup", parents=[color_parent], help="Prepare backends and optionally index this repo")
|
|
79
86
|
setup_parser.add_argument("project_root", nargs="?", default=None, help="Project root (default: cwd)")
|
|
87
|
+
setup_parser.add_argument("--all", action="store_true", dest="all_steps",
|
|
88
|
+
help="One-command setup: do everything automatable (uv + deps + index + "
|
|
89
|
+
"warm serena). Idempotent — skips what's already installed.")
|
|
80
90
|
setup_parser.add_argument("--install-uv", action="store_true", help="Run `pip install uv` (provides uvx for the LSP engine)")
|
|
81
91
|
setup_parser.add_argument("--install-deps", action="store_true", help="Run `pip install -e .` (semantic engine deps)")
|
|
82
92
|
setup_parser.add_argument("--index", action="store_true", help="Index this repo now (first run downloads the ~50MB model)")
|
|
@@ -187,6 +197,31 @@ def main() -> None:
|
|
|
187
197
|
print(f"map failed: {exc}")
|
|
188
198
|
sys.exit(0)
|
|
189
199
|
|
|
200
|
+
elif args.command == "graph":
|
|
201
|
+
from codeintel import grapher
|
|
202
|
+
project_root = args.project_root or os.getcwd()
|
|
203
|
+
try:
|
|
204
|
+
payload = grapher.build_graph_payload(project_root, limit=args.limit)
|
|
205
|
+
n, e = len(payload.get("nodes", [])), len(payload.get("edges", []))
|
|
206
|
+
if args.html:
|
|
207
|
+
out = args.out or "codeintel-graph.html"
|
|
208
|
+
with open(out, "w", encoding="utf-8") as f:
|
|
209
|
+
f.write(grapher.render_html(payload))
|
|
210
|
+
print(f"Wrote {out} ({n} nodes, {e} edges) — open it in any browser")
|
|
211
|
+
if not n:
|
|
212
|
+
reason = payload.get("reason")
|
|
213
|
+
if reason:
|
|
214
|
+
print(f" (graph empty: {reason} — run `codeintel doctor` to check the "
|
|
215
|
+
f"graph backend + index)")
|
|
216
|
+
else:
|
|
217
|
+
print(" (no internal call edges found for this repo)")
|
|
218
|
+
else:
|
|
219
|
+
import json as _json
|
|
220
|
+
print(_json.dumps(payload, indent=2))
|
|
221
|
+
except Exception as exc:
|
|
222
|
+
print(f"graph failed: {exc}")
|
|
223
|
+
sys.exit(0)
|
|
224
|
+
|
|
190
225
|
elif args.command == "query":
|
|
191
226
|
try:
|
|
192
227
|
import time
|
|
@@ -284,12 +319,13 @@ def main() -> None:
|
|
|
284
319
|
from codeintel import onboarding
|
|
285
320
|
|
|
286
321
|
project_root = args.project_root or os.getcwd()
|
|
322
|
+
all_steps = getattr(args, "all_steps", False) # --all implies every automatable step
|
|
287
323
|
report = onboarding.run_setup(
|
|
288
324
|
project_root,
|
|
289
|
-
install_uv=args.install_uv,
|
|
290
|
-
install_deps=args.install_deps,
|
|
291
|
-
do_index=args.index,
|
|
292
|
-
warm_lsp=args.warm,
|
|
325
|
+
install_uv=args.install_uv or all_steps,
|
|
326
|
+
install_deps=args.install_deps or all_steps,
|
|
327
|
+
do_index=args.index or all_steps,
|
|
328
|
+
warm_lsp=args.warm or all_steps,
|
|
293
329
|
)
|
|
294
330
|
if args.json:
|
|
295
331
|
import json as _json
|
|
@@ -11,6 +11,9 @@ import os
|
|
|
11
11
|
from typing import Any, Callable, Optional
|
|
12
12
|
|
|
13
13
|
_ENGINES = ("graph", "lsp", "semantic")
|
|
14
|
+
# Graph needs an external native binary (codebase-memory-mcp) codeintel can't auto-install, so a
|
|
15
|
+
# missing graph engine does NOT make a repo "unhealthy" — the tool is fully usable on semantic + lsp.
|
|
16
|
+
_OPTIONAL_ENGINES = frozenset({"graph"})
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
def _status_for(report: dict) -> str:
|
|
@@ -112,13 +115,17 @@ def run_doctor(
|
|
|
112
115
|
treesitter = False
|
|
113
116
|
|
|
114
117
|
ready = sum(1 for e in engines.values() if e.get("status") != "fail")
|
|
118
|
+
# "healthy" ignores OPTIONAL engines (graph): a repo with semantic + lsp ready is healthy even
|
|
119
|
+
# without the external graph binary. `ready`/`total` stay literal (all three) for transparency.
|
|
120
|
+
healthy = all(
|
|
121
|
+
e.get("status") != "fail" for n, e in engines.items() if n not in _OPTIONAL_ENGINES
|
|
122
|
+
)
|
|
115
123
|
return {
|
|
116
124
|
"ok": True,
|
|
117
125
|
"project_root": root,
|
|
118
126
|
"deep": bool(deep),
|
|
119
127
|
"treesitter": treesitter,
|
|
120
|
-
"summary": {"ready": ready, "total": len(engines),
|
|
121
|
-
"healthy": all(e.get("status") != "fail" for e in engines.values())},
|
|
128
|
+
"summary": {"ready": ready, "total": len(engines), "healthy": healthy},
|
|
122
129
|
"engines": engines,
|
|
123
130
|
}
|
|
124
131
|
|
|
@@ -168,10 +175,16 @@ def render_doctor_text(report: dict) -> str:
|
|
|
168
175
|
tail = "" if report.get("deep") else c.dim(" (run with --deep to boot-check serena)")
|
|
169
176
|
out.append("")
|
|
170
177
|
out.append(f" {count} engines ready for this repo.{tail}")
|
|
178
|
+
opt_down = [n for n in _ENGINES
|
|
179
|
+
if n in _OPTIONAL_ENGINES and (engines.get(n) or {}).get("status") == "fail"]
|
|
180
|
+
if opt_down:
|
|
181
|
+
out.append(" " + c.dim(
|
|
182
|
+
f"({', '.join(opt_down)} optional — an external backend; codeintel works without it)"
|
|
183
|
+
))
|
|
171
184
|
if healthy is False:
|
|
172
185
|
out.append(" " + c.dim(
|
|
173
|
-
"tip: `codeintel setup --
|
|
174
|
-
"
|
|
186
|
+
"tip: `codeintel setup --all` installs + indexes everything automatable in one command; "
|
|
187
|
+
"each fix: line above has the per-engine command."
|
|
175
188
|
))
|
|
176
189
|
if report.get("treesitter") is False:
|
|
177
190
|
out.append(" " + c.dim(
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Build an interactive view of a project's call graph from the graph engine.
|
|
2
|
+
|
|
3
|
+
Headless-first, in board-differ's data→renderer spirit: `build_graph_payload` returns a plain
|
|
4
|
+
``{project, nodes, edges}`` dict (the machine-readable `--format json` shape); `render_html` wraps
|
|
5
|
+
that payload in the self-contained interactive viewer (``viewer/graph_template.html``). The engine
|
|
6
|
+
produces the *data*; the template is the *renderer*. Both never raise.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from codeintel.provider import log_swallowed
|
|
15
|
+
|
|
16
|
+
_EMPTY = {"project": "", "engine": "graph", "op": "callgraph", "nodes": [], "edges": []}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def build_graph_payload(project_root: Any, *, limit: int = 220, timeout_ms: int = 8000) -> dict:
|
|
20
|
+
"""Query the graph engine for a project's internal call graph → ``{project, nodes, edges}``.
|
|
21
|
+
|
|
22
|
+
Nodes are the symbols that participate in an internal call edge, enriched with the same
|
|
23
|
+
complexity metrics the ``hotspots`` op surfaces; edges are ``CALLS``/``USAGE`` relations.
|
|
24
|
+
Builtins/synthetic nodes are excluded. Returns an empty payload with a ``reason`` on any
|
|
25
|
+
failure — never raises (mirrors the safe-null contract)."""
|
|
26
|
+
try:
|
|
27
|
+
try:
|
|
28
|
+
limit = max(1, min(2000, int(limit)))
|
|
29
|
+
except Exception:
|
|
30
|
+
limit = 220
|
|
31
|
+
try:
|
|
32
|
+
timeout_ms = int(timeout_ms)
|
|
33
|
+
except Exception:
|
|
34
|
+
timeout_ms = 8000
|
|
35
|
+
from codeintel.providers.graph import GraphProvider
|
|
36
|
+
p = GraphProvider()
|
|
37
|
+
if not getattr(p, "available", False):
|
|
38
|
+
return {**_EMPTY, "reason": "engine-unavailable"}
|
|
39
|
+
project = p._resolve_project(str(project_root or ""))
|
|
40
|
+
if not project:
|
|
41
|
+
return {**_EMPTY, "reason": "project-not-indexed"}
|
|
42
|
+
|
|
43
|
+
# per-symbol metrics (same search_graph the `hotspots` op uses)
|
|
44
|
+
metrics: dict[str, dict] = {}
|
|
45
|
+
for r in (p._search_symbols({"label": "Function", "min_degree": 1, "limit": 600}, project, timeout_ms) or []):
|
|
46
|
+
qn = str(r.get("qualified_name") or "")
|
|
47
|
+
if qn:
|
|
48
|
+
metrics[qn] = r
|
|
49
|
+
|
|
50
|
+
# internal call edges — fetch generously and filter builtins/synthetic ('<...>') nodes
|
|
51
|
+
# CLIENT-SIDE (robust across Cypher dialects; mirrors how the hotspots op drops them).
|
|
52
|
+
cypher = (
|
|
53
|
+
"MATCH (a)-[c:CALLS|USAGE]->(b) "
|
|
54
|
+
"RETURN a.qualified_name, a.name, a.file_path, b.qualified_name, b.name, b.file_path, type(c) "
|
|
55
|
+
"LIMIT " + str(min(max(limit * 3, 400), 1500))
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def _synth(fp: str) -> bool:
|
|
59
|
+
return (not fp) or fp.startswith("<")
|
|
60
|
+
|
|
61
|
+
nodes_by_id: dict[str, dict] = {}
|
|
62
|
+
edges: list[dict] = []
|
|
63
|
+
seen: set = set()
|
|
64
|
+
|
|
65
|
+
def _add(qn: str, name: str, fp: str) -> None:
|
|
66
|
+
if qn and qn not in nodes_by_id:
|
|
67
|
+
m = metrics.get(qn, {})
|
|
68
|
+
nodes_by_id[qn] = {
|
|
69
|
+
"id": qn, "label": name or qn.rsplit(".", 1)[-1], "file": str(fp or ""),
|
|
70
|
+
"complexity": m.get("complexity") or 0, "cognitive": m.get("cognitive") or 0,
|
|
71
|
+
"in_degree": m.get("in_degree") or 0, "out_degree": m.get("out_degree") or 0,
|
|
72
|
+
"lines": m.get("lines") or 0,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for e in (p._query_rows(cypher, project, timeout_ms) or []):
|
|
76
|
+
if len(edges) >= limit:
|
|
77
|
+
break
|
|
78
|
+
aq, bq = str(e.get("a.qualified_name") or ""), str(e.get("b.qualified_name") or "")
|
|
79
|
+
af, bf = str(e.get("a.file_path") or ""), str(e.get("b.file_path") or "")
|
|
80
|
+
if not aq or not bq or aq == bq or _synth(af) or _synth(bf):
|
|
81
|
+
continue
|
|
82
|
+
_add(aq, str(e.get("a.name") or ""), af)
|
|
83
|
+
_add(bq, str(e.get("b.name") or ""), bf)
|
|
84
|
+
if (aq, bq) not in seen:
|
|
85
|
+
seen.add((aq, bq))
|
|
86
|
+
edges.append({"from": aq, "to": bq, "type": str(e.get("type(c)") or "")})
|
|
87
|
+
|
|
88
|
+
nodes = list(nodes_by_id.values())
|
|
89
|
+
return {"project": project, "engine": "graph", "op": "callgraph", "nodes": nodes, "edges": edges}
|
|
90
|
+
except Exception as exc:
|
|
91
|
+
log_swallowed("grapher.build_graph_payload", exc)
|
|
92
|
+
return {**_EMPTY, "reason": "error"}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _template_path() -> str:
|
|
96
|
+
return os.path.join(os.path.dirname(__file__), "viewer", "graph_template.html")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def render_html(payload: dict) -> str:
|
|
100
|
+
"""Wrap a graph payload in the self-contained interactive viewer template. Never raises."""
|
|
101
|
+
try:
|
|
102
|
+
# default=str → serialization can't raise on an unexpected value; "</" escape keeps the
|
|
103
|
+
# JSON inside the <script> element (the template's viewer JS re-emits every string via
|
|
104
|
+
# textContent, so there is no innerHTML/XSS sink downstream).
|
|
105
|
+
data = json.dumps(payload, default=str).replace("</", "<\\/")
|
|
106
|
+
with open(_template_path(), encoding="utf-8") as f:
|
|
107
|
+
return f.read().replace("__DATA__", data)
|
|
108
|
+
except Exception as exc:
|
|
109
|
+
log_swallowed("grapher.render_html", exc)
|
|
110
|
+
try:
|
|
111
|
+
body = json.dumps(payload, indent=2, default=str).replace("&", "&").replace("<", "<")
|
|
112
|
+
except Exception:
|
|
113
|
+
body = "(graph payload unavailable)"
|
|
114
|
+
return ("<!doctype html><meta charset=utf-8><title>codeintel graph</title>"
|
|
115
|
+
"<pre style='font:13px ui-monospace,monospace;padding:16px'>" + body + "</pre>")
|