carto-md 2.0.5 → 2.0.7

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.
package/CONTRIBUTING.md CHANGED
@@ -44,9 +44,9 @@ Framework-specific route and model extraction lives inside the language plugins.
44
44
 
45
45
  ---
46
46
 
47
- ## How to add a language (V2 pattern — tree-sitter based)
47
+ ## How to add a language (tree-sitter based)
48
48
 
49
- V2 uses tree-sitter for import and symbol extraction. Babel is only used for deep JS/TS route/model extraction on API handler files.
49
+ Carto uses tree-sitter for import and symbol extraction. Babel is only used for deep JS/TS route/model extraction on API handler files.
50
50
 
51
51
  ### Step 1: Install the grammar
52
52
 
@@ -177,7 +177,7 @@ Test on at least 2 real open-source projects using the framework.
177
177
 
178
178
  ---
179
179
 
180
- ## How domain clustering works (V2)
180
+ ## How domain clustering works
181
181
 
182
182
  Domain detection uses **Leiden+CPM graph clustering** (`src/agents/leiden.js`). Files that import each other heavily cluster together. Domain names are inferred from path tokens, with keyword hints for well-known patterns.
183
183
 
@@ -215,7 +215,7 @@ cd carto
215
215
  npm install
216
216
  node src/cli/index.js init # test in any project
217
217
  node src/cli/index.js serve # test MCP server
218
- npm test # run test suite (35 tests)
218
+ npm test # run test suite (62 tests)
219
219
  node test/correctness.js # run correctness tests (31 tests)
220
220
  node test/benchmark.js # run benchmarks against real repos
221
221
  ```
@@ -258,7 +258,7 @@ npm run test:bench-ci # self-bench (matches what bench.yml runs)
258
258
  - [ ] Extension added to `CODE_EXTS` and `detectLanguage()` in `sync-v2.js`
259
259
  - [ ] No changes to merger logic (unless explicitly fixing a merger bug)
260
260
  - [ ] No network calls added
261
- - [ ] `npm test` passes (35/35)
261
+ - [ ] `npm test` passes (62/62)
262
262
  - [ ] `node test/correctness.js` passes (31/31)
263
263
 
264
264
  ---
package/README.md CHANGED
@@ -7,93 +7,104 @@
7
7
 
8
8
  **The structural intelligence layer for AI coding tools.**
9
9
 
10
+ Your AI coding tool sees files. Carto sees architecture — domains, blast radius, import graph, routes. Every AI tool you use stops guessing about your codebase and starts knowing it.
11
+
10
12
  ```bash
11
13
  npm install -g carto-md
12
14
  cd your-project
13
15
  carto init
14
16
  ```
15
17
 
16
- Carto indexes your codebase routes, models, import graph, blast radius, domain clusters and keeps it live via SQLite. Every AI tool you use gets accurate structural facts about your project instead of guessing.
18
+ That's it. Carto auto-wires itself into every AI tool you have installed. Restart your AI tool and it now knows your codebase architecturally.
19
+
20
+ **Works with:** Cursor · Claude Code · Kiro · Claude Desktop · Windsurf · VS Code Copilot · JetBrains · Zed
17
21
 
18
22
  ---
19
23
 
20
- ## Benchmarks
24
+ ## Use it with your AI tool
21
25
 
22
- Measured on real open-source repos. Apple M-series, 8 CPUs, 8GB RAM.
26
+ `carto init` auto-wires the MCP server into every AI tool it detects. If yours wasn't detected, here's the manual config — **one block, copy-paste, done.**
23
27
 
24
- | Repo | Language | Source Files | Indexed | First Run | Second Run | DB Size | Import Edges |
25
- |------|----------|-------------|---------|-----------|------------|---------|--------------|
26
- | [prisma/prisma](https://github.com/prisma/prisma) | TypeScript | 3,303 | 3,303 | **1.6s** | **178ms** | 2.2 MB | 3,590 |
27
- | [supabase/supabase](https://github.com/supabase/supabase) | TypeScript | 6,818 | 6,746 | **4.9s** | **725ms** | 4.3 MB | 5,754 |
28
- | [microsoft/vscode](https://github.com/microsoft/vscode) | TypeScript | 10,565 | 10,565 | **9.7s** | **1.2s** | 10.6 MB | 19,769 |
29
- | [zed-industries/zed](https://github.com/zed-industries/zed) | Rust | 1,837 | 1,837 | **2.7s** | **83ms** | 4.7 MB | 2,176 |
28
+ ### Cursor
30
29
 
31
- **Second run** = only changed files re-parsed. mtime+size checked before reading content — if nothing changed, nothing is re-parsed.
30
+ `carto init` writes this for you. Manual: `~/.cursor/mcp.json`
31
+ ```json
32
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
33
+ ```
32
34
 
33
- **All MCP queries** (blast radius, routes, structure, domains): **<5ms** on all repos.
35
+ ### Claude Code (CLI)
34
36
 
35
- ### Domains detected
37
+ One command from your project root:
38
+ ```bash
39
+ claude mcp add carto -- carto serve
40
+ ```
41
+ Or create `.mcp.json` at the project root:
42
+ ```json
43
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"] } } }
44
+ ```
36
45
 
37
- | Repo | Domains |
38
- |------|---------|
39
- | prisma | DATABASE · CORE · EVENTS · AUTH |
40
- | supabase | CORE · AUTH · DATABASE · PAYMENTS · EVENTS · NOTIFICATIONS · TRPC |
41
- | vscode | CORE · AUTH · EVENTS · DATABASE · NOTIFICATIONS |
42
- | zed (Rust) | CORE · DATABASE · AUTH · EVENTS · PAYMENTS · NOTIFICATIONS |
46
+ ### Kiro
43
47
 
44
- vscode at 10,565 files in under 10 seconds. Rust import graph working on zed (2,176 edges from `mod` declarations and `use crate::` paths).
48
+ `carto init` writes this for you. Manual: `~/.kiro/settings/mcp.json`
49
+ ```json
50
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
51
+ ```
45
52
 
46
- ---
53
+ ### Claude Desktop
54
+
55
+ `carto init` writes this for you. Manual: `~/Library/Application Support/Claude/claude_desktop_config.json`
56
+ ```json
57
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
58
+ ```
47
59
 
48
- ## What it does
60
+ ### VS Code Copilot
49
61
 
62
+ `.vscode/mcp.json` in your project root, or Command Palette → `MCP: Add Server`
63
+ ```json
64
+ { "servers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
50
65
  ```
51
- carto init / carto sync
52
-
53
- Discovers all files (no cap — SQLite handles the volume)
54
- mtime+size check → skip unchanged files
55
- tree-sitter parse → imports + symbols (0.05–0.2ms/file)
56
- Babel deep parse routes + models (API handler files only)
57
- Leiden+CPM graph clustering → auto-detects domains
58
- Computes reverse deps → blast radius for every file
59
- Writes AGENTS.md + .carto/context/*.md (lazy, on-demand)
60
- Auto-wires MCP into Kiro, Cursor, Claude Desktop
61
-
62
- carto watch
63
-
64
- File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
66
+
67
+ ### Windsurf
68
+
69
+ `~/.windsurf/mcp.json`
70
+ ```json
71
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
65
72
  ```
66
73
 
74
+ ### Zed / JetBrains / VS Code (full agent mode)
75
+
76
+ Carto also runs as a full **ACP agent** — not just a passive MCP server, but an active coding agent with architectural awareness. See [ACP Agent](#acp-agent-zed--jetbrains--vs-code) below.
77
+
67
78
  ---
68
79
 
69
- ## 16 MCP tools
80
+ ## What changes for your AI
70
81
 
71
- `carto serve` exposes a local MCP server. Kiro, Cursor, and Claude query it mid-task.
82
+ Without carto, your AI greps text and guesses. With carto, it queries structural facts:
72
83
 
73
- | Tool | What it returns |
74
- |------|----------------|
75
- | `get_architecture()` | 500-word project overview: domains, entry points, stack, key patterns. **Use this first.** |
76
- | `get_blast_radius(file)` | All files affected by changing a given file, with hop distance |
77
- | `get_context(file)` | Everything about a file: domain, blast radius, neighbors, routes, models |
78
- | `get_change_plan(intent)` | Given "add rate limiting to /api/users" → files to touch, domains affected, blast radius, similar patterns |
79
- | `get_file_summary(file)` | What a file does, its role, key deps and dependents |
80
- | `get_similar_patterns(file)` | Files with same domain, same route shape, or shared dependencies — find conventions before writing new code |
81
- | `get_routes()` | All API endpoints with file mapping |
82
- | `get_structure()` | Import graph, entry points, high-impact files, tech stack |
83
- | `get_domain(name)` | All routes, models, functions for a domain. Lazily regenerated when stale. |
84
- | `get_neighbors(file, hops)` | Import graph neighbors: nodes and edges |
85
- | `get_cross_domain()` | Import edges that cross domain boundaries |
86
- | `search_routes(query)` | Search API routes by path or method |
87
- | `get_models(domain?)` | All data models, optionally filtered by domain |
88
- | `get_high_impact_files(n)` | Top N files by blast radius |
89
- | `get_env_vars(domain?)` | All env vars with domain mapping |
90
- | `get_domains_list()` | All detected domains with file, route, model counts |
84
+ > *"Add rate limiting to /api/users"*
85
+
86
+ **Without carto:** AI grep-searches your codebase, finds 12 files mentioning "users", picks 3 at random, hopes for the best.
87
+
88
+ **With carto:** AI calls `get_change_plan("add rate limiting to /api/users")` and gets back:
89
+ - The exact route handler file
90
+ - All 7 files that import it (blast radius)
91
+ - The AUTH domain it lives in
92
+ - Similar middleware patterns already in the codebase
93
+ - Cross-domain dependencies that could break
94
+
95
+ Your AI's response goes from "here's a guess" to "here's the right change with the architectural context."
96
+
97
+ ### In the wild
98
+
99
+ ![Claude Code reviewing the supabase repo through carto's MCP server](docs/screenshots/claude-code-supabase.png)
100
+
101
+ *Claude Code analyzing the [supabase](https://github.com/supabase/supabase) repo via carto. Real session, no editing — 5,974 files indexed in ~780ms, 86 routes, 4,839 import edges, 7 domains. The agent's own verdict at the bottom: "useful, especially for a large codebase like supabase. The blast radius + cross-domain tools are the most valuable."*
91
102
 
92
103
  ---
93
104
 
94
105
  ## Languages and frameworks
95
106
 
96
- ### Import graph + symbols (tree-sitter — works on any repo)
107
+ ### Import graph + symbols (any repo)
97
108
 
98
109
  | Language | Extensions |
99
110
  |----------|-----------|
@@ -106,16 +117,16 @@ File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
106
117
  | C# | `.cs` |
107
118
  | Ruby | `.rb` |
108
119
 
109
- ### Route extraction (framework-specific)
120
+ ### Route extraction (framework-aware)
110
121
 
111
122
  | Framework | Language |
112
123
  |-----------|---------|
113
- | Express, Next.js (App + Pages Router), tRPC, React Router | TypeScript / JavaScript |
124
+ | Express, Next.js (App + Pages), tRPC, React Router | TypeScript / JavaScript |
114
125
  | FastAPI, Flask, Django | Python |
115
126
  | Gin, Echo, Chi, net/http | Go |
116
127
  | Actix-web, Axum, Rocket | Rust |
117
128
  | Spring MVC / Boot, JAX-RS | Java |
118
- | ASP.NET Core (attribute routing + minimal API) | C# |
129
+ | ASP.NET Core | C# |
119
130
  | Rails, Sinatra | Ruby |
120
131
 
121
132
  ### Model extraction
@@ -127,52 +138,18 @@ File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
127
138
  | Go structs | Go |
128
139
  | Rust structs | Rust |
129
140
  | JPA `@Entity`, Java records | Java |
130
- | EF Core classes, C# records | C# |
141
+ | EF Core, C# records | C# |
131
142
  | ActiveRecord | Ruby |
132
143
 
133
144
  ### TypeScript path aliases
134
145
 
135
- Reads `tsconfig.json` / `jsconfig.json` for `paths` config. `@/components/Button` resolves to the actual file in the import graph — blast radius works correctly for Next.js and Vite projects.
136
-
137
- ---
138
-
139
- ## Domain detection
140
-
141
- V2 uses **Leiden+CPM graph clustering** — files that import each other heavily cluster together. Domain names are inferred from path tokens, with keyword hints for well-known patterns (AUTH, PAYMENTS, DATABASE, etc.).
142
-
143
- Works on any repo — not just SaaS apps. vscode gets AUTH/EVENTS/DATABASE. zed (Rust) gets DATABASE/AUTH/EVENTS. A game engine would get RENDERER/PHYSICS/AUDIO.
144
-
145
- Custom domains via `carto.config.json`:
146
-
147
- ```json
148
- {
149
- "domains": {
150
- "EDITOR": ["editor", "monaco", "text"],
151
- "WORKBENCH": ["workbench", "layout", "panel"]
152
- }
153
- }
154
- ```
155
-
156
- ---
157
-
158
- ## Commands
159
-
160
- | Command | What it does |
161
- |---------|-------------|
162
- | `carto init` | Detect project, index codebase, generate AGENTS.md, wire MCP |
163
- | `carto sync` | Full re-index (skips unchanged files via mtime+size cache) |
164
- | `carto watch` | Incremental live re-index on every file save (<50ms) |
165
- | `carto serve` | Start MCP server for Kiro / Cursor / Claude |
166
- | `carto agent` | Start ACP agent mode (for Zed / JetBrains / VS Code) |
167
- | `carto impact <file>` | Blast radius: risk level, affected files, routes at risk |
168
- | `carto check` | Cross-domain violations, high-risk uncommitted changes, domain health |
169
- | `carto remove` | Remove AGENTS.md and .carto/ from project |
146
+ Reads `tsconfig.json` / `jsconfig.json` `paths` config. `@/components/Button` resolves to the actual file in the import graph — blast radius works correctly for Next.js and Vite projects.
170
147
 
171
148
  ---
172
149
 
173
150
  ## ACP Agent (Zed / JetBrains / VS Code)
174
151
 
175
- Carto works as a full **ACP agent** — not just a passive tool server, but an active coding agent with architectural awareness.
152
+ Beyond MCP, Carto runs as a full **ACP agent** — an active coding agent with built-in architectural awareness.
176
153
 
177
154
  ```
178
155
  User: "Add rate limiting to /api/users"
@@ -189,20 +166,16 @@ Sends to LLM (your API key) → streams answer + diffs back to editor
189
166
 
190
167
  ### Setup in Zed
191
168
 
192
- Add to `~/.config/zed/settings.json`:
193
-
169
+ `~/.config/zed/settings.json`:
194
170
  ```json
195
171
  {
196
172
  "agent_servers": {
197
- "Carto": {
198
- "command": "carto",
199
- "args": ["agent"]
200
- }
173
+ "Carto": { "command": "carto", "args": ["agent"] }
201
174
  }
202
175
  }
203
176
  ```
204
177
 
205
- ### BYOK (Bring Your Own Key)
178
+ ### Bring Your Own Key
206
179
 
207
180
  Carto supports any LLM provider — configure in your editor:
208
181
 
@@ -217,60 +190,123 @@ Carto supports any LLM provider — configure in your editor:
217
190
  | Together AI | Open-source models |
218
191
  | Azure OpenAI | Enterprise deployments |
219
192
 
220
- ### What makes it different
221
-
222
- Other agents are smart but blind. Carto sees the architecture:
223
- - Auto-indexes your project on first session (1-10s depending on size)
224
- - Injects structural context into every LLM call (blast radius, domains, routes)
225
- - 12 internal tools the LLM can call during reasoning
226
- - Zero cost to you beyond your own API key
227
-
228
193
  ---
229
194
 
230
- ## V1 V2 migration
195
+ ## The 16 MCP tools
231
196
 
232
- Run `carto sync` it auto-migrates your existing `graph-cache.json` and `map.json` into SQLite and renames them to `.bak`. No manual steps.
197
+ Once carto is wired in, your AI tool can call any of these mid-task. You don't need to memorize them your AI will pick the right ones.
233
198
 
234
- What changed under the hood:
199
+ | Tool | What it returns |
200
+ |------|----------------|
201
+ | `get_architecture()` | 500-word project overview: domains, entry points, stack, key patterns. **Use this first.** |
202
+ | `get_change_plan(intent)` | Given "add rate limiting to /api/users" → files to touch, domains affected, blast radius, similar patterns |
203
+ | `get_blast_radius(file)` | All files affected by changing a given file, with hop distance |
204
+ | `get_context(file)` | Everything about a file: domain, blast radius, neighbors, routes, models |
205
+ | `get_file_summary(file)` | What a file does, its role, key deps and dependents |
206
+ | `get_similar_patterns(file)` | Files with same domain, route shape, or shared deps — find conventions before writing new code |
207
+ | `get_routes()` | All API endpoints with file mapping |
208
+ | `get_structure()` | Import graph, entry points, high-impact files, tech stack |
209
+ | `get_domain(name)` | All routes, models, functions for a domain. Lazily regenerated when stale. |
210
+ | `get_neighbors(file, hops)` | Import graph neighbors: nodes and edges |
211
+ | `get_cross_domain()` | Import edges that cross domain boundaries |
212
+ | `search_routes(query)` | Search API routes by path or method |
213
+ | `get_models(domain?)` | All data models, optionally filtered by domain |
214
+ | `get_high_impact_files(n)` | Top N files by blast radius |
215
+ | `get_env_vars(domain?)` | All env vars with domain mapping |
216
+ | `get_domains_list()` | All detected domains with file, route, model counts |
235
217
 
236
- | | V1 | V2 |
237
- |---|---|---|
238
- | Storage | JSON blobs | SQLite (WAL mode, indexed queries) |
239
- | Parsing | Babel-only | tree-sitter for all languages, Babel only for deep route/model extraction |
240
- | File limit | 300 cap | Unlimited |
241
- | Languages | JS/TS/Python/Go/R | + Rust/Java/C++/C#/Ruby |
242
- | Domain detection | Hardcoded keywords | Leiden+CPM graph clustering |
243
- | Watcher | Per-file chokidar | Single recursive directory watch (<20 file descriptors) |
244
- | MCP startup | Re-indexes on start | Opens SQLite instantly (<10ms) |
245
- | Path aliases | Not resolved | `@/`, `~/` resolved via tsconfig |
218
+ **All MCP queries:** **<5ms** on every benchmarked repo.
246
219
 
247
220
  ---
248
221
 
249
- ## MCP config (if auto-wire missed your IDE)
222
+ ## Domain detection
250
223
 
251
- **Kiro** — `~/.kiro/settings/mcp.json`
252
- ```json
253
- { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
254
- ```
224
+ Carto uses **Leiden+CPM graph clustering** — files that import each other heavily cluster together. Domain names are inferred from path tokens, with keyword hints for well-known patterns (AUTH, PAYMENTS, DATABASE, etc.).
225
+
226
+ Works on any repo not just SaaS apps. vscode gets AUTH/EVENTS/DATABASE. zed (Rust) gets DATABASE/AUTH/EVENTS. A game engine would get RENDERER/PHYSICS/AUDIO.
255
227
 
256
- **Cursor** `~/.cursor/mcp.json`
228
+ Custom domains via `carto.config.json`:
257
229
  ```json
258
- { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
230
+ {
231
+ "domains": {
232
+ "EDITOR": ["editor", "monaco", "text"],
233
+ "WORKBENCH": ["workbench", "layout", "panel"]
234
+ }
235
+ }
259
236
  ```
260
237
 
261
- **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
262
- ```json
263
- { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
238
+ ---
239
+
240
+ ## CLI commands
241
+
242
+ | Command | What it does |
243
+ |---------|-------------|
244
+ | `carto init` | Detect project, index codebase, generate AGENTS.md, auto-wire MCP into every AI tool found |
245
+ | `carto sync` | Full re-index (skips unchanged files via mtime+size cache) |
246
+ | `carto watch` | Incremental live re-index on every file save (<50ms) |
247
+ | `carto serve` | Start MCP server (called by your AI tool — usually you don't run this directly) |
248
+ | `carto agent` | Start ACP agent mode (for Zed / JetBrains / VS Code) |
249
+ | `carto impact <file>` | Blast radius: risk level, affected files, routes at risk |
250
+ | `carto check` | Cross-domain violations, high-risk uncommitted changes, domain health |
251
+ | `carto remove` | Remove AGENTS.md and .carto/ from project |
252
+
253
+ ---
254
+
255
+ ## Benchmarks
256
+
257
+ Measured on real open-source repos. Apple M-series, 8 CPUs, 8GB RAM. SHAs pinned in `~/carto-test-repos`.
258
+
259
+ | Repo | Language | Indexed Files | First Run | Second Run | DB Size | Import Edges |
260
+ |------|----------|---------------|-----------|------------|---------|--------------|
261
+ | [prisma/prisma](https://github.com/prisma/prisma) | TypeScript | 961 | **649ms** | **110ms** | 0.7 MB | 1,387 |
262
+ | [supabase/supabase](https://github.com/supabase/supabase) | TypeScript | 6,259 | **4.8s** | **751ms** | 4.0 MB | 5,321 |
263
+ | [microsoft/vscode](https://github.com/microsoft/vscode) | TypeScript | 7,567 | **7.8s** | **387ms** | 6.7 MB | 13,420 |
264
+ | [zed-industries/zed](https://github.com/zed-industries/zed) | Rust | 1,752 | **3.0s** | **182ms** | 4.4 MB | 2,113 |
265
+
266
+ **Indexed Files** counts what Carto actually parses — `.ts/.js/.py/.go/.rs/...` after excluding `node_modules`, build output, and per-file `*.test.*` / `*.spec.*` / `*.stories.*` / `test_*.py` patterns. The on-disk file count of the repo is larger.
267
+
268
+ **Second run** = only changed files re-parsed. mtime+size checked before reading content — if nothing changed, nothing is re-parsed.
269
+
270
+ ### Domains detected
271
+
272
+ | Repo | Domains |
273
+ |------|---------|
274
+ | prisma | CORE · DATABASE · EVENTS · AUTH |
275
+ | supabase | CORE · AUTH · DATABASE · PAYMENTS · EVENTS · NOTIFICATIONS · TRPC |
276
+ | vscode | CORE · DATABASE · AUTH · EVENTS · NOTIFICATIONS |
277
+ | zed (Rust) | CORE · DATABASE · AUTH · EVENTS · PAYMENTS · NOTIFICATIONS · TRPC |
278
+
279
+ vscode at 7,567 indexed files in under 8 seconds. Rust import graph working on zed (2,113 edges from `mod` declarations and `use crate::` paths).
280
+
281
+ ---
282
+
283
+ ## How it works
284
+
285
+ ```
286
+ carto init / carto sync
287
+
288
+ Discovers all files (no cap — SQLite handles the volume)
289
+ mtime+size check → skip unchanged files
290
+ tree-sitter parse → imports + symbols (0.05–0.2ms/file)
291
+ Babel deep parse → routes + models (API handler files only)
292
+ Leiden+CPM graph clustering → auto-detects domains
293
+ Computes reverse deps → blast radius for every file
294
+ Writes AGENTS.md + .carto/context/*.md (lazy, on-demand)
295
+ Auto-wires MCP into every AI tool found
296
+
297
+ carto watch (optional)
298
+
299
+ File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
264
300
  ```
265
301
 
266
302
  ---
267
303
 
268
304
  ## What Carto never does
269
305
 
270
- - Sends your code anywhere. Local only. SQLite on disk.
271
- - Writes secrets into AGENTS.md. `.cartoignore` blocks `.env` and credential files by default.
272
- - Touches your manual notes. Writes only between `<!-- CARTO:AUTO:START -->` and `<!-- CARTO:AUTO:END -->`.
273
- - Costs money. MIT license. Free forever.
306
+ - **Sends your code anywhere.** Local only. SQLite on disk.
307
+ - **Writes secrets into AGENTS.md.** `.cartoignore` blocks `.env` and credential files by default.
308
+ - **Touches your manual notes.** Writes only between `<!-- CARTO:AUTO:START -->` and `<!-- CARTO:AUTO:END -->`.
309
+ - **Costs money.** MIT license. Free forever.
274
310
 
275
311
  ---
276
312
 
package/index.js CHANGED
@@ -4,17 +4,27 @@
4
4
  * carto-md — public module API
5
5
  *
6
6
  * Usage:
7
- * const { Carto } = require('carto-md');
8
- * const carto = new Carto();
7
+ * const { StoreAdapter } = require('carto-md');
8
+ * const carto = new StoreAdapter();
9
9
  * await carto.index('/path/to/project');
10
10
  *
11
- * // Get everything Kepler needs for a file
11
+ * // Get everything an editor agent needs for a file
12
12
  * const ctx = carto.getContextForFile('src/auth/auth.service.ts');
13
13
  *
14
- * // Listen for live updates
15
- * carto.on('updated', ({ file, blastRadius }) => { ... });
14
+ * // Read structural facts
15
+ * const routes = carto.getRoutes();
16
+ * const radius = carto.getBlastRadius('src/auth/auth.service.ts');
17
+ * carto.close();
18
+ *
19
+ * Back-compat: `Carto` is exported as an alias for `StoreAdapter`.
20
+ * Existing programs that did `const { Carto } = require('carto-md')`
21
+ * continue to work without changes. The alias (and the `terminate()`
22
+ * method on StoreAdapter) will be removed in 3.0.0.
16
23
  */
17
24
 
18
- const { Carto } = require('./src/engine/carto');
25
+ const { StoreAdapter } = require('./src/store/store-adapter');
19
26
 
20
- module.exports = { Carto };
27
+ module.exports = {
28
+ StoreAdapter,
29
+ Carto: StoreAdapter, // deprecated alias, removed in 3.0.0
30
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carto-md",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Structural intelligence layer for AI coding tools. Indexes your codebase into SQLite — routes, models, import graph, blast radius, domains — and exposes 16 MCP tools for Kiro, Cursor, and Claude.",
5
5
  "bin": {
6
6
  "carto": "src/cli/index.js"
@@ -29,7 +29,7 @@
29
29
  "tree-sitter-typescript": "0.23.2"
30
30
  },
31
31
  "engines": {
32
- "node": ">=18.0.0"
32
+ "node": ">=18.0.0 <26.0.0"
33
33
  },
34
34
  "author": {
35
35
  "name": "Ansh Sonkar",
package/src/acp/agent.js CHANGED
@@ -70,19 +70,12 @@ class CartoAgent {
70
70
  }
71
71
 
72
72
  // Provider methods
73
- async unstable_listProviders(_params) {
74
- return { providers: this.providers.list() };
75
- }
76
-
77
- async unstable_setProvider(params) {
78
- this.providers.set(params);
79
- return {};
80
- }
81
-
82
- async unstable_disableProvider(_params) {
83
- this.providers.disable();
84
- return {};
85
- }
73
+ // The custom `unstable_*` provider-management methods (list / set / disable)
74
+ // were removed in 2.0.7 (Spec 7 Bug 3). The ACP SDK only dispatches the
75
+ // methods declared in its AGENT_METHODS constant, so those custom routes
76
+ // returned -32601 "Method not found" anyway. Provider config flows
77
+ // through env vars / editor settings; ProviderRegistry remains as the
78
+ // internal configuration carrier.
86
79
 
87
80
  // Session list/load stubs
88
81
  async listSessions(_params) { return { sessions: [] }; }
@@ -30,20 +30,12 @@ class ProviderRegistry {
30
30
  this._config = null;
31
31
  }
32
32
 
33
- /**
34
- * list() Returns supported providers for ACP providers/list.
35
- */
36
- list() {
37
- return SUPPORTED_PROVIDERS.map(p => ({
38
- id: p.id,
39
- name: p.name,
40
- defaultModel: p.defaultModel,
41
- models: p.models,
42
- }));
43
- }
33
+ // list() was removed in 2.0.7 (Spec 7 Bug 3). It was only called by the
34
+ // dropped custom provider-list ACP method, which the SDK never dispatched.
35
+ // SUPPORTED_PROVIDERS is still exported for external callers / tests.
44
36
 
45
37
  /**
46
- * set(params) — Configures the active provider from ACP providers/set.
38
+ * set(params) — Configures the active provider.
47
39
  * params: { providerId, apiKey, baseUrl?, model? }
48
40
  */
49
41
  set(params) {
@@ -3,7 +3,7 @@
3
3
  const crypto = require('crypto');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
- const { Carto } = require('../engine/carto');
6
+ const { StoreAdapter } = require('../store/store-adapter');
7
7
 
8
8
  class Session {
9
9
  constructor(id, workingDir) {
@@ -23,20 +23,16 @@ class Session {
23
23
  if (this._indexed) return null;
24
24
 
25
25
  const dbPath = path.join(this.workingDir, '.carto', 'carto.db');
26
- this.carto = new Carto();
26
+ const wasIndexed = fs.existsSync(dbPath);
27
27
 
28
- if (fs.existsSync(dbPath)) {
29
- // DB exists — just load the index (fast path, <10ms)
30
- await this.carto.index(this.workingDir);
31
- this._indexed = true;
32
- return null;
33
- }
34
-
35
- // No DB — run full indexing
28
+ this.carto = new StoreAdapter();
36
29
  const start = Date.now();
37
- await this.carto.index(this.workingDir, { useWorkers: true });
30
+ await this.carto.index(this.workingDir, { writeOutputs: false });
38
31
  this._indexed = true;
39
32
 
33
+ if (wasIndexed) return null;
34
+
35
+ // Fresh index — surface status message
40
36
  const meta = this.carto.getMeta();
41
37
  const duration = ((Date.now() - start) / 1000).toFixed(1);
42
38
  const domains = this.carto.getDomainsList();
@@ -64,6 +60,8 @@ class SessionManager {
64
60
  }
65
61
 
66
62
  delete(id) {
63
+ const s = this._sessions.get(id);
64
+ if (s && s.carto) s.carto.close();
67
65
  this._sessions.delete(id);
68
66
  }
69
67
  }
package/src/cli/impact.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const path = require('path');
4
- const { Carto } = require('../../index.js');
3
+ const { StoreAdapter } = require('../store/store-adapter');
4
+ const { normalizeFileArg } = require('../store/path-utils');
5
5
  const { checkForUpdate } = require('./update-check');
6
6
 
7
7
  async function run(projectRoot, fileArg) {
@@ -11,17 +11,22 @@ async function run(projectRoot, fileArg) {
11
11
  process.exit(1);
12
12
  }
13
13
 
14
- const carto = new Carto();
14
+ // Normalize so `./lib/x.js`, absolute paths, and Windows separators
15
+ // all resolve to the same `files.path` value stored in SQLite.
16
+ const file = normalizeFileArg(projectRoot, fileArg);
17
+
18
+ const carto = new StoreAdapter();
15
19
  try {
16
- await carto.index(projectRoot, { useWorkers: false });
20
+ await carto.index(projectRoot);
17
21
  } catch (err) {
18
22
  console.error(`[CARTO] Error loading index: ${err.message}`);
19
23
  process.exit(1);
20
24
  }
21
25
 
22
- const br = carto.getBlastRadius(fileArg);
26
+ const br = carto.getBlastRadius(file);
23
27
  if (!br) {
24
28
  console.error(`[CARTO] File not found in project graph: ${fileArg}`);
29
+ carto.close();
25
30
  process.exit(1);
26
31
  }
27
32
 
@@ -55,7 +60,7 @@ async function run(projectRoot, fileArg) {
55
60
  }
56
61
 
57
62
  console.log('');
58
- carto.terminate();
63
+ carto.close();
59
64
  }
60
65
 
61
66
  module.exports = { run };