carto-md 1.0.9 → 1.0.10
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 +108 -0
- package/README.md +267 -0
- package/package.json +1 -1
- package/src/sync.js +1 -35
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Contributing to Carto
|
|
2
|
+
|
|
3
|
+
Carto is free, open source, and community-maintained. The core team owns the merger logic, AST engine, and CLI. The community owns language and framework extractors.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What to contribute
|
|
8
|
+
|
|
9
|
+
### Tier 1 — Languages (safe to add, easy to review)
|
|
10
|
+
|
|
11
|
+
New language support lives in `src/ast/languages/`. Each language is an isolated module.
|
|
12
|
+
|
|
13
|
+
Currently supported: JavaScript/TypeScript, Python.
|
|
14
|
+
|
|
15
|
+
Wanted: Go, Rust, Ruby, Java, PHP, C#.
|
|
16
|
+
|
|
17
|
+
### Tier 2 — Framework extractors (safe to add, easy to review)
|
|
18
|
+
|
|
19
|
+
Framework-specific route and model extraction lives in `src/extractors/`. Each framework is an isolated module.
|
|
20
|
+
|
|
21
|
+
Currently supported: FastAPI, Express, Next.js App Router, Prisma, HTML fetch().
|
|
22
|
+
|
|
23
|
+
Wanted: Django, Rails, Laravel, NestJS, Hono, Gin, Spring.
|
|
24
|
+
|
|
25
|
+
### Tier 3 — Core (review carefully before merging)
|
|
26
|
+
|
|
27
|
+
- `src/agents/merger.js` — merger logic. One bad merge = developer loses manual notes = project dies. Changes here need strong justification and full test coverage.
|
|
28
|
+
- `src/ast/` — AST engine. Wrong extraction = wrong AGENTS.md = AI gets confident with wrong facts. Worse than no AGENTS.md.
|
|
29
|
+
- `src/detector/` — framework detection logic.
|
|
30
|
+
- `src/cli/` — CLI commands.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## How to add a language
|
|
35
|
+
|
|
36
|
+
1. Create `src/ast/languages/yourlanguage.js`
|
|
37
|
+
2. Export a single function: `extractFromFile(filePath, fileContent)`
|
|
38
|
+
3. Return:
|
|
39
|
+
```js
|
|
40
|
+
{
|
|
41
|
+
functions: [{ name, params, returns }],
|
|
42
|
+
classes: [{ name, fields }],
|
|
43
|
+
imports: [{ from, symbols }],
|
|
44
|
+
exports: [{ name }]
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
4. Add it to `src/ast/parser.js` language map
|
|
48
|
+
5. Test on at least 3 real open-source projects
|
|
49
|
+
6. Open a PR with before/after AGENTS.md examples
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## How to add a framework extractor
|
|
54
|
+
|
|
55
|
+
1. Create `src/extractors/yourframework.js`
|
|
56
|
+
2. Export:
|
|
57
|
+
```js
|
|
58
|
+
{
|
|
59
|
+
detect(projectRoot, files) → boolean,
|
|
60
|
+
extractRoutes(filePath, fileContent) → [{ method, path, functionName }],
|
|
61
|
+
extractModels(filePath, fileContent) → [{ name, fields: [{ name, type }] }]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
3. Add detection logic to `src/detector/framework.js`
|
|
65
|
+
4. Test on at least 2 real projects using that framework
|
|
66
|
+
5. Open a PR with before/after AGENTS.md examples
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Ground rules
|
|
71
|
+
|
|
72
|
+
- **Never break the merger.** Manual sections in AGENTS.md are sacred. If your change could corrupt them, it needs a full merger test suite pass.
|
|
73
|
+
- **Wrong output is worse than no output.** If your extractor produces incorrect routes or models, AI gets confident with wrong facts. Only ship when accurate on real projects.
|
|
74
|
+
- **Test on unknown repos.** Don't just test on projects you wrote. Find a real open-source repo using the framework and verify the output is correct.
|
|
75
|
+
- **No cloud, no telemetry, no tracking.** Carto is local only. Forever. Don't add any network calls.
|
|
76
|
+
- **No paid features.** Free forever. MIT. Don't propose monetization.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Development setup
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
git clone https://github.com/anshsonkar/carto-ansh
|
|
84
|
+
cd carto-ansh
|
|
85
|
+
npm install
|
|
86
|
+
node src/cli/index.js init # test in any project
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## PR checklist
|
|
92
|
+
|
|
93
|
+
- [ ] Tested on at least 2-3 real open-source projects
|
|
94
|
+
- [ ] Before/after AGENTS.md included in PR description
|
|
95
|
+
- [ ] No changes to merger logic (unless explicitly fixing a merger bug)
|
|
96
|
+
- [ ] No network calls added
|
|
97
|
+
- [ ] `carto --version` still works
|
|
98
|
+
- [ ] Existing tests pass
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Issues
|
|
103
|
+
|
|
104
|
+
- **Bug**: Open an issue with the project type, command run, and what AGENTS.md produced vs what you expected.
|
|
105
|
+
- **Language request**: Open an issue titled "Language: [name]" — someone from the community will pick it up.
|
|
106
|
+
- **Framework request**: Open an issue titled "Framework: [name]".
|
|
107
|
+
|
|
108
|
+
All issues acknowledged within 24 hours.
|
package/README.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# carto
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/carto-md)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/carto-md)
|
|
6
|
+
|
|
7
|
+
**Your code changes. AGENTS.md updates. Every AI always knows.**
|
|
8
|
+
|
|
9
|
+
Carto auto-generates and auto-maintains your `AGENTS.md` file. Every time you save, your routes, models, functions, and dependencies are extracted and written into the standard file every AI coding tool already reads.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Origin
|
|
14
|
+
|
|
15
|
+
I was building [Emfirge](https://emfirge.com) — a cloud security advisor for AWS.
|
|
16
|
+
|
|
17
|
+
To make the AI inside Emfirge understand infrastructure, I wrote a module called `cartography.py`. It scanned AWS resources, built a graph of how they connected, and wrote it into a structured map. The AI stopped hallucinating. It worked with accurate facts about the actual infrastructure — not guesses.
|
|
18
|
+
|
|
19
|
+
Halfway through, I switched AI tools. Opened a new session. Had to explain everything again from scratch.
|
|
20
|
+
|
|
21
|
+
I thought: *I just built a cartography system so AI can understand infrastructure. Why doesn't this exist for codebases?*
|
|
22
|
+
|
|
23
|
+
Carto is that thing. Same insight, different domain. Map your codebase once. Every AI session starts with accurate facts. You never explain your project again.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## The problem
|
|
28
|
+
|
|
29
|
+
AI coding tools are blind to your actual project. Every session starts from zero.
|
|
30
|
+
|
|
31
|
+
- Claude hallucinates your schema
|
|
32
|
+
- Copilot suggests the wrong field names
|
|
33
|
+
- Kiro asks what framework you're using
|
|
34
|
+
- You rebuild context manually, every time
|
|
35
|
+
|
|
36
|
+
`AGENTS.md` is the standard that fixes this — a file in your project root that every AI tool reads for project context. But it's static. You write it manually. It gets stale the moment your code changes.
|
|
37
|
+
|
|
38
|
+
**Carto makes it live.**
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Why not just paste your code?
|
|
43
|
+
|
|
44
|
+
Context windows are large now. But pasting code means:
|
|
45
|
+
|
|
46
|
+
- You decide what's relevant — you're often wrong
|
|
47
|
+
- AI sees a snapshot, not your live state
|
|
48
|
+
- Bigger context ≠ better context
|
|
49
|
+
|
|
50
|
+
Carto gives AI the map. You give AI the problem. Different jobs.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## How it works
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
You save a file
|
|
58
|
+
↓
|
|
59
|
+
Carto extracts routes, models, functions, env vars
|
|
60
|
+
↓
|
|
61
|
+
AGENTS.md updated in 300ms
|
|
62
|
+
↓
|
|
63
|
+
Cursor, Copilot, Kiro, Codex, Claude — all read current truth
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Install
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm install -g carto-md
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Or run without installing:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npx carto-md init
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Usage
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# 1. Go to your project
|
|
86
|
+
cd your-project
|
|
87
|
+
|
|
88
|
+
# 2. Generate AGENTS.md (run once)
|
|
89
|
+
carto init
|
|
90
|
+
|
|
91
|
+
# 3. Keep it live while you work
|
|
92
|
+
carto watch
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Leave `carto watch` running in a background terminal. Every file save updates AGENTS.md automatically.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Commands
|
|
100
|
+
|
|
101
|
+
| Command | What it does |
|
|
102
|
+
|---------|-------------|
|
|
103
|
+
| `carto init` | Detect stack, generate AGENTS.md, install git hook |
|
|
104
|
+
| `carto watch` | Watch files, update AGENTS.md on every save |
|
|
105
|
+
| `carto sync` | One-time refresh, no watcher |
|
|
106
|
+
| `carto impact <file>` | Show blast radius before touching a file |
|
|
107
|
+
| `carto --version` | Show version |
|
|
108
|
+
|
|
109
|
+
**When to use each:**
|
|
110
|
+
- `init` — once, when you add Carto to a project
|
|
111
|
+
- `watch` — every work session, leave it running
|
|
112
|
+
- `sync` — if you skipped watch and just want a fresh snapshot
|
|
113
|
+
- `impact` — before editing anything critical
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## What gets extracted automatically
|
|
118
|
+
|
|
119
|
+
- API routes — FastAPI, Express, Next.js App Router
|
|
120
|
+
- Data models — Pydantic, Prisma
|
|
121
|
+
- Function signatures — across all files
|
|
122
|
+
- Dependencies — from `package.json` / `requirements.txt`
|
|
123
|
+
- Environment variable names — never values
|
|
124
|
+
- Frontend API calls — from `fetch()` patterns
|
|
125
|
+
- Import graph — which files depend on which
|
|
126
|
+
- Database tables
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## What Carto never touches
|
|
131
|
+
|
|
132
|
+
The manual sections you write directly into `AGENTS.md` — architecture decisions, active bugs, business rules, coding conventions — stay yours forever. Carto only rewrites content between its own markers:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
<!-- CARTO:AUTO:START -->
|
|
136
|
+
... auto-generated content ...
|
|
137
|
+
<!-- CARTO:AUTO:END -->
|
|
138
|
+
|
|
139
|
+
Your manual notes here. Never touched.
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## carto impact
|
|
145
|
+
|
|
146
|
+
Before touching any file, know the blast radius:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
carto impact app/models.py
|
|
150
|
+
|
|
151
|
+
# Impact analysis: app/models.py
|
|
152
|
+
#
|
|
153
|
+
# Imported by:
|
|
154
|
+
# → app/main.py
|
|
155
|
+
# → app/rules.py
|
|
156
|
+
# → app/scoring.py
|
|
157
|
+
# → app/aws_collector.py
|
|
158
|
+
# → tests/conftest.py
|
|
159
|
+
#
|
|
160
|
+
# Routes affected:
|
|
161
|
+
# → POST /analyze
|
|
162
|
+
# → GET /history
|
|
163
|
+
# → POST /simulate
|
|
164
|
+
# → ... 12 more
|
|
165
|
+
#
|
|
166
|
+
# Risk: HIGH — 5 files depend on this
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Most production bugs aren't logic errors. They're *"I didn't know X depended on Y."* Carto makes that invisible knowledge visible before you break something.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## What Carto fixes
|
|
174
|
+
|
|
175
|
+
Carto fixes **factual hallucination about your own project**:
|
|
176
|
+
|
|
177
|
+
- AI guessing wrong routes → fixed
|
|
178
|
+
- AI guessing wrong field names → fixed
|
|
179
|
+
- AI assuming wrong framework → fixed
|
|
180
|
+
- AI guessing wrong DB schema → fixed
|
|
181
|
+
|
|
182
|
+
What Carto does not fix: AI reasoning badly, wrong implementation logic, misunderstanding what you want. Carto makes AI **accurate** about your project. Not smarter. Accurate. Different thing.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Real test — cal.com (800k lines)
|
|
187
|
+
|
|
188
|
+
We ran the same task in two Claude sessions: *"Add a `notes` field to the booking model."*
|
|
189
|
+
|
|
190
|
+
**Without AGENTS.md:**
|
|
191
|
+
- Wrong API route: suggested `POST /api/bookings` → actual is `POST /v2/bookings`
|
|
192
|
+
- Wrong handler: suggested `handleNewBooking.ts` → not the creation path
|
|
193
|
+
- Wrong file paths: pointed to v1 API (`apps/api/v1/...`) → v1 is legacy
|
|
194
|
+
- Wrong tRPC file: `bookings.tsx` → actual is `bookings/_router.tsx`
|
|
195
|
+
- Field list: ~15 fields guessed → missing 20+ real fields
|
|
196
|
+
- Couldn't proceed without follow-up: *"Want me to write the exact diffs once you confirm the codebase location?"*
|
|
197
|
+
|
|
198
|
+
**With AGENTS.md (generated by Carto):**
|
|
199
|
+
- Correct API route: `POST /v2/bookings` ✅
|
|
200
|
+
- Correct controller path ✅
|
|
201
|
+
- Correct tRPC file ✅
|
|
202
|
+
- All 35+ booking fields returned accurately ✅
|
|
203
|
+
- Answered in one shot. No follow-up needed.
|
|
204
|
+
|
|
205
|
+
**4 wrong file paths → 0. 20 missing fields → 0. Zero follow-up clarifications.**
|
|
206
|
+
|
|
207
|
+
This is what Carto does. Not smarter AI. The same AI with accurate facts.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## AI tools that read AGENTS.md
|
|
212
|
+
|
|
213
|
+
Drop the file in your project root. Each tool picks it up via its own context config:
|
|
214
|
+
|
|
215
|
+
- **Cursor** — via context rules
|
|
216
|
+
- **GitHub Copilot** — via workspace instructions
|
|
217
|
+
- **Kiro** — natively
|
|
218
|
+
- **Codex** — natively
|
|
219
|
+
- **VS Code** — via workspace context
|
|
220
|
+
- **Gemini CLI** — natively
|
|
221
|
+
- **Devin** — natively
|
|
222
|
+
- **Jules** — natively
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Tested on
|
|
227
|
+
|
|
228
|
+
- FastAPI + Python projects
|
|
229
|
+
- Next.js App Router
|
|
230
|
+
- Next.js + Prisma
|
|
231
|
+
- React + FastAPI monorepos
|
|
232
|
+
- Large monorepos (5000+ files — tested on Supabase and cal.com for stability, caps at 50 most important files on projects this scale)
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## What it does NOT do
|
|
237
|
+
|
|
238
|
+
- No cloud. No servers. No telemetry. No tracking.
|
|
239
|
+
- Your code never leaves your machine.
|
|
240
|
+
- No paid tiers. Free forever. MIT license.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Security
|
|
245
|
+
|
|
246
|
+
Carto never writes secrets into AGENTS.md. `.cartoignore` blocks `.env` files, secret files, key files, and credential files by default. The sanitizer strips API key patterns from extracted code.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Contributing
|
|
251
|
+
|
|
252
|
+
Python and JS/TS are supported today. Community adds more.
|
|
253
|
+
|
|
254
|
+
- **Add a language**: `src/ast/languages/`
|
|
255
|
+
- **Add a framework**: `src/extractors/`
|
|
256
|
+
|
|
257
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
MIT — free forever.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
*Built because AGENTS.md won. Someone had to keep it alive.*
|
package/package.json
CHANGED
package/src/sync.js
CHANGED
|
@@ -62,25 +62,15 @@ async function runFullSync(config) {
|
|
|
62
62
|
const allModelFiles = config.watch.modelFiles || [];
|
|
63
63
|
const allFrontendFiles = config.watch.frontendFiles || [];
|
|
64
64
|
|
|
65
|
-
// Aggregate data
|
|
66
65
|
let allRoutes = [];
|
|
67
66
|
let allModels = [];
|
|
68
67
|
let allFetches = [];
|
|
69
68
|
let allStorageKeys = [];
|
|
70
|
-
|
|
71
|
-
// Functions: { filename: [{ name, params, returnType }] }
|
|
72
69
|
const functionsMap = {};
|
|
73
|
-
// Routes per file for file map
|
|
74
70
|
const routeCountMap = {};
|
|
75
|
-
// Env vars: { varName: Set([filename, ...]) }
|
|
76
71
|
const envVarMap = new Map();
|
|
77
|
-
// DB tables: [{ tableName, modelName, file }]
|
|
78
72
|
const dbTableList = [];
|
|
79
|
-
|
|
80
|
-
// Deduplicate files
|
|
81
73
|
const processedFiles = new Set();
|
|
82
|
-
|
|
83
|
-
// Process all code files (route + model files, deduplicated)
|
|
84
74
|
const allCodeFiles = [...new Set([...allRouteFiles, ...allModelFiles])];
|
|
85
75
|
|
|
86
76
|
for (const filePath of allCodeFiles) {
|
|
@@ -94,42 +84,32 @@ async function runFullSync(config) {
|
|
|
94
84
|
const relPath = path.relative(projectRoot, filePath);
|
|
95
85
|
const plugin = getPluginForFile(plugins, filePath);
|
|
96
86
|
|
|
97
|
-
if (!plugin)
|
|
98
|
-
// No plugin for this file type — skip silently
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
87
|
+
if (!plugin) continue;
|
|
101
88
|
|
|
102
89
|
const result = plugin.extract(content, relPath);
|
|
103
90
|
|
|
104
|
-
// Routes
|
|
105
91
|
allRoutes = allRoutes.concat(result.routes);
|
|
106
92
|
routeCountMap[filePath] = result.routes.length;
|
|
107
93
|
|
|
108
|
-
// Models
|
|
109
94
|
allModels = allModels.concat(result.models);
|
|
110
95
|
|
|
111
|
-
// Functions
|
|
112
96
|
if (result.functions.length > 0 && basename !== '__init__.py') {
|
|
113
97
|
functionsMap[basename] = result.functions;
|
|
114
98
|
}
|
|
115
99
|
|
|
116
|
-
// Env vars
|
|
117
100
|
for (const varName of result.envVars) {
|
|
118
101
|
if (!envVarMap.has(varName)) envVarMap.set(varName, new Set());
|
|
119
102
|
envVarMap.get(varName).add(basename);
|
|
120
103
|
}
|
|
121
104
|
|
|
122
|
-
// DB tables
|
|
123
105
|
for (const t of result.dbTables) {
|
|
124
106
|
dbTableList.push({ tableName: t.tableName, modelName: t.modelName, file: basename });
|
|
125
107
|
}
|
|
126
108
|
|
|
127
|
-
// Fetches and storage keys (from JS/HTML plugins)
|
|
128
109
|
allFetches = allFetches.concat(result.fetches);
|
|
129
110
|
allStorageKeys = allStorageKeys.concat(result.storageKeys);
|
|
130
111
|
}
|
|
131
112
|
|
|
132
|
-
// Process frontend files separately (may overlap with code files)
|
|
133
113
|
for (const filePath of allFrontendFiles) {
|
|
134
114
|
if (processedFiles.has(filePath)) continue;
|
|
135
115
|
processedFiles.add(filePath);
|
|
@@ -147,12 +127,10 @@ async function runFullSync(config) {
|
|
|
147
127
|
allStorageKeys = allStorageKeys.concat(result.storageKeys);
|
|
148
128
|
}
|
|
149
129
|
|
|
150
|
-
// Global dedup: collapse dynamic fetches across all files into one summary row
|
|
151
130
|
const staticFetches = allFetches.filter(f => f.url !== '[dynamic]' && !f.url.startsWith('dynamic calls detected'));
|
|
152
131
|
let totalDynamic = 0;
|
|
153
132
|
for (const f of allFetches) {
|
|
154
133
|
if (f.url === '[dynamic]') totalDynamic++;
|
|
155
|
-
// Also count already-collapsed per-file rows
|
|
156
134
|
const m = f.url.match(/^dynamic calls detected \((\d+) unresolved\)$/);
|
|
157
135
|
if (m) totalDynamic += parseInt(m[1], 10);
|
|
158
136
|
}
|
|
@@ -161,7 +139,6 @@ async function runFullSync(config) {
|
|
|
161
139
|
}
|
|
162
140
|
allFetches = staticFetches;
|
|
163
141
|
|
|
164
|
-
// Global dedup: storage keys across all files
|
|
165
142
|
const skSeen = new Set();
|
|
166
143
|
allStorageKeys = allStorageKeys.filter(({ operation, key }) => {
|
|
167
144
|
const id = `${operation}::${key}`;
|
|
@@ -170,10 +147,8 @@ async function runFullSync(config) {
|
|
|
170
147
|
return true;
|
|
171
148
|
});
|
|
172
149
|
|
|
173
|
-
// Build import graph from all processed files
|
|
174
150
|
const fileContentsForImports = [];
|
|
175
151
|
const allProcessedPaths = [...new Set([...allCodeFiles, ...allFrontendFiles])];
|
|
176
|
-
// Re-read is avoided — collect during processing. Use a second pass for simplicity.
|
|
177
152
|
for (const filePath of allProcessedPaths) {
|
|
178
153
|
try {
|
|
179
154
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
@@ -184,19 +159,15 @@ async function runFullSync(config) {
|
|
|
184
159
|
}
|
|
185
160
|
const importGraph = buildImportGraph(fileContentsForImports, projectRoot);
|
|
186
161
|
|
|
187
|
-
// Detect tech stack from watched files + manifests
|
|
188
162
|
const stackItems = buildStackLine(fileContentsForImports, projectRoot);
|
|
189
163
|
|
|
190
|
-
// Compute entry points and high impact files from import graph
|
|
191
164
|
const allValues = new Set();
|
|
192
165
|
for (const deps of Object.values(importGraph)) {
|
|
193
166
|
for (const dep of deps) allValues.add(dep);
|
|
194
167
|
}
|
|
195
|
-
// Entry points: files that import 3+ others but nothing imports them
|
|
196
168
|
const entryPoints = Object.keys(importGraph)
|
|
197
169
|
.filter(f => !allValues.has(f) && importGraph[f].length >= 3)
|
|
198
170
|
.sort();
|
|
199
|
-
// High impact: files imported by 3+ others, sorted descending by count
|
|
200
171
|
const depCount = {};
|
|
201
172
|
for (const deps of Object.values(importGraph)) {
|
|
202
173
|
for (const dep of deps) {
|
|
@@ -208,7 +179,6 @@ async function runFullSync(config) {
|
|
|
208
179
|
.sort((a, b) => b[1] - a[1])
|
|
209
180
|
.map(([file, count]) => ({ file, count }));
|
|
210
181
|
|
|
211
|
-
// Build file map
|
|
212
182
|
const fileMap = [];
|
|
213
183
|
for (const filePath of allCodeFiles) {
|
|
214
184
|
const basename = path.basename(filePath);
|
|
@@ -221,15 +191,12 @@ async function runFullSync(config) {
|
|
|
221
191
|
}
|
|
222
192
|
}
|
|
223
193
|
|
|
224
|
-
// Aggregate env vars into sorted array
|
|
225
194
|
const envVars = [...envVarMap.keys()]
|
|
226
195
|
.sort()
|
|
227
196
|
.map(name => ({ name, files: [...envVarMap.get(name)].sort() }));
|
|
228
197
|
|
|
229
|
-
// Scan project structure
|
|
230
198
|
const structure = await scanStructure(projectRoot);
|
|
231
199
|
|
|
232
|
-
// Validate extracted data — drop anything malformed
|
|
233
200
|
const validated = validateExtracted({
|
|
234
201
|
routes: allRoutes,
|
|
235
202
|
models: allModels,
|
|
@@ -256,7 +223,6 @@ async function runFullSync(config) {
|
|
|
256
223
|
|
|
257
224
|
mergeIntoAgentsMd(config.output, autoContent);
|
|
258
225
|
|
|
259
|
-
// Save graph to .carto/map.json (atomic write)
|
|
260
226
|
const cartoDir = path.join(projectRoot, '.carto');
|
|
261
227
|
const mapData = {
|
|
262
228
|
version: '1',
|