carto-md 2.0.1 → 2.0.3

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.
@@ -0,0 +1,34 @@
1
+ # Carto V2 Benchmark Results
2
+
3
+ Generated: 2026-05-28T17:58:28.019Z
4
+ Platform: Node v20.20.1 · 8 CPUs · 8192.0 MB RAM · darwin arm64
5
+
6
+ | Repo | Source Files | Indexed | First Run | Second Run | DB Size | Routes | Import Edges |
7
+ |------|-------------|---------|-----------|------------|---------|--------|--------------|
8
+ | prisma | 3303 | 3303 | 1.6s | 178ms | 2.2 MB | 10 | 3590 |
9
+ | supabase | 6818 | 6746 | 4.9s | 725ms | 4.3 MB | 90 | 5754 |
10
+ | vscode | 10565 | 10565 | 9.7s | 1.2s | 10.6 MB | 11 | 19769 |
11
+ | zed | 1837 | 1837 | 2.7s | 83ms | 4.7 MB | 12 | 2176 |
12
+
13
+ ## Domains Detected
14
+
15
+ **prisma:** DATABASE(1044) · CORE(752) · EVENTS(36) · AUTH(8)
16
+ **supabase:** CORE(4243) · AUTH(412) · DATABASE(387) · PAYMENTS(51) · EVENTS(17) · NOTIFICATIONS(12) · TRPC(3)
17
+ **vscode:** CORE(5330) · AUTH(850) · EVENTS(446) · DATABASE(419) · NOTIFICATIONS(5)
18
+ **zed:** CORE(1424) · DATABASE(110) · AUTH(75) · EVENTS(55) · PAYMENTS(53) · NOTIFICATIONS(10) · TRPC(2)
19
+
20
+ ## MCP Query Latency
21
+
22
+ | Repo | get_structure | get_routes | get_domains_list |
23
+ |------|--------------|------------|-----------------|
24
+ | prisma | 0ms | 0ms | 1ms |
25
+ | supabase | 1ms | 0ms | 3ms |
26
+ | vscode | 1ms | 0ms | 3ms |
27
+ | zed | 0ms | 0ms | 1ms |
28
+
29
+ ## Target Assessment
30
+
31
+ - **prisma**: ✅ All targets met
32
+ - **supabase**: ✅ All targets met
33
+ - **vscode**: ✅ All targets met
34
+ - **zed**: ✅ All targets met
package/CONTRIBUTING.md CHANGED
@@ -215,13 +215,39 @@ 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 (30 tests)
218
+ npm test # run test suite (35 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
  ```
222
222
 
223
223
  ---
224
224
 
225
+ ## CI
226
+
227
+ Every push and PR runs the test suite on a 3 OS × 3 Node matrix (macOS, Linux, Windows × Node 18, 20, 22) via `.github/workflows/test.yml`. A red cell blocks merge; one cell failing does not cancel the others, so you see the full picture.
228
+
229
+ There are three workflows:
230
+
231
+ | Workflow | Trigger | What it does |
232
+ |----------|---------|-------------|
233
+ | `test.yml` | push to `main`, PRs to `main` | `npm ci` + `npm test` on 9 cells |
234
+ | `bench.yml` | Sundays 04:00 UTC + manual | Self-bench (`test/bench-ci.js`) on `ubuntu-22.04`, compared against `test/bench-baseline.json` |
235
+ | `release-smoke.yml` | tags `v*`, PRs touching `package.json` / `package-lock.json` / `.npmignore` | `npm pack` + install tarball into a fresh dir + `carto --help` smoke on 3 OS × 2 Node |
236
+
237
+ **Local equivalents** before pushing:
238
+
239
+ ```bash
240
+ npm test # main suite (matches what test.yml runs)
241
+ npm run test:correctness # correctness suite — needs tmp-bench/<name> clones, NOT run in CI
242
+ npm run test:bench-ci # self-bench (matches what bench.yml runs)
243
+ ```
244
+
245
+ **If a cell goes red:** click the failing job's "Details" link in the PR check section. Test failures show test names; install failures usually mean `package-lock.json` drifted from `package.json` — re-run `npm install` locally and commit the lockfile change.
246
+
247
+ **If `bench.yml` reports a regression:** the failure includes which metric exceeded its tolerance and by how much. The artifact `bench-output-<run-id>` keeps the raw output for 90 days. If the regression is intentional (e.g., you traded perf for correctness), update the baseline value in `test/bench-baseline.json` in the same PR and link the bench run id in the PR description.
248
+
249
+ ---
250
+
225
251
  ## PR checklist
226
252
 
227
253
  - [ ] Tested on at least 2-3 real open-source projects
@@ -232,7 +258,7 @@ node test/benchmark.js # run benchmarks against real repos
232
258
  - [ ] Extension added to `CODE_EXTS` and `detectLanguage()` in `sync-v2.js`
233
259
  - [ ] No changes to merger logic (unless explicitly fixing a merger bug)
234
260
  - [ ] No network calls added
235
- - [ ] `npm test` passes (30/30)
261
+ - [ ] `npm test` passes (35/35)
236
262
  - [ ] `node test/correctness.js` passes (31/31)
237
263
 
238
264
  ---
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # carto
2
2
 
3
+ [![CI](https://github.com/theanshsonkar/carto/actions/workflows/test.yml/badge.svg)](https://github.com/theanshsonkar/carto/actions/workflows/test.yml)
3
4
  [![npm version](https://img.shields.io/npm/v/carto-md)](https://www.npmjs.com/package/carto-md)
4
5
  [![MIT License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
5
6
  [![npm downloads](https://img.shields.io/npm/dm/carto-md)](https://www.npmjs.com/package/carto-md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carto-md",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
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"
@@ -9,7 +9,8 @@
9
9
  "scripts": {
10
10
  "test": "node test/test.js",
11
11
  "test:correctness": "node test/correctness.js",
12
- "test:benchmark": "node test/benchmark.js"
12
+ "test:benchmark": "node test/benchmark.js",
13
+ "test:bench-ci": "node test/bench-ci.js"
13
14
  },
14
15
  "dependencies": {
15
16
  "@agentclientprotocol/sdk": "^0.22.1",
@@ -16,6 +16,9 @@ function formatSections({ routes, models, frontend, structure, warnings, fileMap
16
16
  sections.push(`- ${icon} ${entry.name}${suffix}`);
17
17
  }
18
18
  } else {
19
+ if (process.env.CARTO_DEBUG) {
20
+ console.warn('[CARTO] Warning: structure data was empty when formatting AGENTS.md');
21
+ }
19
22
  sections.push('_No structure data available._');
20
23
  }
21
24
 
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+
5
+ /**
6
+ * IGNORE_DIRS — names skipped at the top level when listing project structure.
7
+ *
8
+ * This is intentionally a *small* set tuned for the "Project Structure (auto)"
9
+ * block in AGENTS.md. It is NOT the same as the recursive file-discovery
10
+ * ignore lists (e.g. JS_IGNORE / PYTHON_IGNORE in src/detector/files.js or
11
+ * IGNORE_DIRS in src/store/sync-v2.js) — those filter what gets indexed.
12
+ *
13
+ * Top-level structure should still surface things like `dist/`, `build/`,
14
+ * `coverage/` (so users see what their project actually contains), but it
15
+ * should hide noise (`node_modules`, `.git`, `.carto`, etc.) and the file
16
+ * the structure block is about to be merged into (`AGENTS.md`).
17
+ *
18
+ * Anchored on the original V1 set in src/sync.js so existing AGENTS.md
19
+ * outputs do not drift after the V1 → V2 cleanup.
20
+ */
21
+ const IGNORE_DIRS = new Set([
22
+ 'node_modules',
23
+ '.git',
24
+ '__pycache__',
25
+ '.venv',
26
+ 'venv',
27
+ '.idea',
28
+ '.vscode',
29
+ '.carto',
30
+ 'AGENTS.md'
31
+ ]);
32
+
33
+ /**
34
+ * scanStructure(basePath) → Array<{ name: string, type: 'dir' | 'file' }>
35
+ *
36
+ * Lists the immediate children of `basePath` (one level deep, no recursion).
37
+ * Filters out IGNORE_DIRS. Sorts: directories before files; alphabetical
38
+ * within each group.
39
+ *
40
+ * Symlinks are reported by Dirent as neither dir nor file → treated as 'file'.
41
+ * Failures (missing dir, EACCES, etc.) return an empty array silently — the
42
+ * formatter handles the empty case.
43
+ */
44
+ async function scanStructure(basePath) {
45
+ const entries = [];
46
+ let items;
47
+ try {
48
+ items = await fs.promises.readdir(basePath, { withFileTypes: true });
49
+ } catch {
50
+ return entries;
51
+ }
52
+
53
+ for (const item of items) {
54
+ if (IGNORE_DIRS.has(item.name)) continue;
55
+ entries.push({
56
+ name: item.name,
57
+ type: item.isDirectory() ? 'dir' : 'file'
58
+ });
59
+ }
60
+
61
+ entries.sort((a, b) => {
62
+ if (a.type !== b.type) return a.type === 'dir' ? -1 : 1;
63
+ return a.name.localeCompare(b.name);
64
+ });
65
+
66
+ return entries;
67
+ }
68
+
69
+ module.exports = { scanStructure, IGNORE_DIRS };