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 +5 -5
- package/README.md +174 -138
- package/docs/screenshots/claude-code-supabase.png +0 -0
- package/index.js +17 -7
- package/package.json +2 -2
- package/src/acp/agent.js +6 -13
- package/src/acp/providers/index.js +4 -12
- package/src/acp/session.js +9 -11
- package/src/cli/impact.js +11 -6
- package/src/cli/init.js +16 -19
- package/src/cli/serve.js +11 -12
- package/src/cli/sync.js +2 -14
- package/src/extractors/imports.js +5 -1
- package/src/mcp/server-v2.js +51 -5
- package/src/security/ignore.js +56 -1
- package/src/store/path-utils.js +50 -0
- package/src/store/sqlite-store.js +66 -11
- package/src/store/store-adapter.js +169 -0
- package/src/store/sync-v2.js +37 -4
- package/src/cache/file-hash.js +0 -84
- package/src/cache/graph-cache.js +0 -77
- package/src/detector/files.js +0 -289
- package/src/engine/carto.js +0 -606
- package/src/engine/incremental.js +0 -149
- package/src/mcp/server.js +0 -431
- package/src/sync.js +0 -317
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 (
|
|
47
|
+
## How to add a language (tree-sitter based)
|
|
48
48
|
|
|
49
|
-
|
|
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
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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
|
-
##
|
|
24
|
+
## Use it with your AI tool
|
|
21
25
|
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
+
### Claude Code (CLI)
|
|
34
36
|
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
##
|
|
80
|
+
## What changes for your AI
|
|
70
81
|
|
|
71
|
-
|
|
82
|
+
Without carto, your AI greps text and guesses. With carto, it queries structural facts:
|
|
72
83
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+

|
|
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 (
|
|
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-
|
|
120
|
+
### Route extraction (framework-aware)
|
|
110
121
|
|
|
111
122
|
| Framework | Language |
|
|
112
123
|
|-----------|---------|
|
|
113
|
-
| Express, Next.js (App + Pages
|
|
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
|
|
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
|
|
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`
|
|
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
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
##
|
|
195
|
+
## The 16 MCP tools
|
|
231
196
|
|
|
232
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
##
|
|
222
|
+
## Domain detection
|
|
250
223
|
|
|
251
|
-
**
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
228
|
+
Custom domains via `carto.config.json`:
|
|
257
229
|
```json
|
|
258
|
-
{
|
|
230
|
+
{
|
|
231
|
+
"domains": {
|
|
232
|
+
"EDITOR": ["editor", "monaco", "text"],
|
|
233
|
+
"WORKBENCH": ["workbench", "layout", "panel"]
|
|
234
|
+
}
|
|
235
|
+
}
|
|
259
236
|
```
|
|
260
237
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
|
271
|
-
- Writes secrets into AGENTS.md
|
|
272
|
-
- Touches your manual notes
|
|
273
|
-
- Costs money
|
|
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
|
|
|
Binary file
|
package/index.js
CHANGED
|
@@ -4,17 +4,27 @@
|
|
|
4
4
|
* carto-md — public module API
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* const {
|
|
8
|
-
* const carto = new
|
|
7
|
+
* const { StoreAdapter } = require('carto-md');
|
|
8
|
+
* const carto = new StoreAdapter();
|
|
9
9
|
* await carto.index('/path/to/project');
|
|
10
10
|
*
|
|
11
|
-
* // Get everything
|
|
11
|
+
* // Get everything an editor agent needs for a file
|
|
12
12
|
* const ctx = carto.getContextForFile('src/auth/auth.service.ts');
|
|
13
13
|
*
|
|
14
|
-
* //
|
|
15
|
-
* carto.
|
|
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 {
|
|
25
|
+
const { StoreAdapter } = require('./src/store/store-adapter');
|
|
19
26
|
|
|
20
|
-
module.exports = {
|
|
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.
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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
|
|
38
|
+
* set(params) — Configures the active provider.
|
|
47
39
|
* params: { providerId, apiKey, baseUrl?, model? }
|
|
48
40
|
*/
|
|
49
41
|
set(params) {
|
package/src/acp/session.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const crypto = require('crypto');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
-
const {
|
|
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
|
-
|
|
26
|
+
const wasIndexed = fs.existsSync(dbPath);
|
|
27
27
|
|
|
28
|
-
|
|
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, {
|
|
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
|
|
4
|
-
const {
|
|
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
|
-
|
|
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
|
|
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(
|
|
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.
|
|
63
|
+
carto.close();
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
module.exports = { run };
|