@stupidloud/codegraph 0.7.15 → 0.8.1
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/README.md +82 -58
- package/dist/bin/codegraph.js +127 -24
- package/dist/bin/codegraph.js.map +1 -1
- package/dist/bin/node-version-check.d.ts +3 -0
- package/dist/bin/node-version-check.d.ts.map +1 -1
- package/dist/bin/node-version-check.js +5 -2
- package/dist/bin/node-version-check.js.map +1 -1
- package/dist/bin/uninstall.d.ts +7 -7
- package/dist/bin/uninstall.d.ts.map +1 -1
- package/dist/bin/uninstall.js +23 -135
- package/dist/bin/uninstall.js.map +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +4 -2
- package/dist/context/index.js.map +1 -1
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +7 -1
- package/dist/db/queries.js.map +1 -1
- package/dist/extraction/index.d.ts +1 -1
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +63 -37
- package/dist/extraction/index.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/installer/claude-md-template.d.ts +10 -6
- package/dist/installer/claude-md-template.d.ts.map +1 -1
- package/dist/installer/claude-md-template.js +15 -40
- package/dist/installer/claude-md-template.js.map +1 -1
- package/dist/installer/config-writer.d.ts +17 -24
- package/dist/installer/config-writer.d.ts.map +1 -1
- package/dist/installer/config-writer.js +46 -239
- package/dist/installer/config-writer.js.map +1 -1
- package/dist/installer/index.d.ts +57 -4
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +286 -81
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/instructions-template.d.ts +28 -0
- package/dist/installer/instructions-template.d.ts.map +1 -0
- package/dist/installer/instructions-template.js +65 -0
- package/dist/installer/instructions-template.js.map +1 -0
- package/dist/installer/targets/claude.d.ts +31 -0
- package/dist/installer/targets/claude.d.ts.map +1 -0
- package/dist/installer/targets/claude.js +308 -0
- package/dist/installer/targets/claude.js.map +1 -0
- package/dist/installer/targets/codex.d.ts +18 -0
- package/dist/installer/targets/codex.d.ts.map +1 -0
- package/dist/installer/targets/codex.js +185 -0
- package/dist/installer/targets/codex.js.map +1 -0
- package/dist/installer/targets/cursor.d.ts +35 -0
- package/dist/installer/targets/cursor.d.ts.map +1 -0
- package/dist/installer/targets/cursor.js +229 -0
- package/dist/installer/targets/cursor.js.map +1 -0
- package/dist/installer/targets/opencode.d.ts +30 -0
- package/dist/installer/targets/opencode.d.ts.map +1 -0
- package/dist/installer/targets/opencode.js +235 -0
- package/dist/installer/targets/opencode.js.map +1 -0
- package/dist/installer/targets/registry.d.ts +35 -0
- package/dist/installer/targets/registry.d.ts.map +1 -0
- package/dist/installer/targets/registry.js +83 -0
- package/dist/installer/targets/registry.js.map +1 -0
- package/dist/installer/targets/shared.d.ts +77 -0
- package/dist/installer/targets/shared.d.ts.map +1 -0
- package/dist/installer/targets/shared.js +246 -0
- package/dist/installer/targets/shared.js.map +1 -0
- package/dist/installer/targets/toml.d.ts +52 -0
- package/dist/installer/targets/toml.d.ts.map +1 -0
- package/dist/installer/targets/toml.js +147 -0
- package/dist/installer/targets/toml.js.map +1 -0
- package/dist/installer/targets/types.d.ts +116 -0
- package/dist/installer/targets/types.d.ts.map +1 -0
- package/dist/installer/targets/types.js +16 -0
- package/dist/installer/targets/types.js.map +1 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +143 -20
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +20 -5
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/tools.d.ts +75 -5
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +472 -89
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/transport.d.ts +17 -0
- package/dist/mcp/transport.d.ts.map +1 -1
- package/dist/mcp/transport.js +63 -0
- package/dist/mcp/transport.js.map +1 -1
- package/dist/resolution/frameworks/index.d.ts +1 -0
- package/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/dist/resolution/frameworks/index.js +5 -1
- package/dist/resolution/frameworks/index.js.map +1 -1
- package/dist/resolution/frameworks/nestjs.d.ts +26 -0
- package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
- package/dist/resolution/frameworks/nestjs.js +374 -0
- package/dist/resolution/frameworks/nestjs.js.map +1 -0
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +29 -26
- package/dist/search/query-utils.js.map +1 -1
- package/dist/sync/git-hooks.d.ts +45 -0
- package/dist/sync/git-hooks.d.ts.map +1 -0
- package/dist/sync/git-hooks.js +223 -0
- package/dist/sync/git-hooks.js.map +1 -0
- package/dist/sync/index.d.ts +4 -0
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +12 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/watch-policy.d.ts +48 -0
- package/dist/sync/watch-policy.d.ts.map +1 -0
- package/dist/sync/watch-policy.js +124 -0
- package/dist/sync/watch-policy.js.map +1 -0
- package/dist/sync/watcher.d.ts.map +1 -1
- package/dist/sync/watcher.js +10 -0
- package/dist/sync/watcher.js.map +1 -1
- package/dist/ui/glyphs.d.ts +42 -0
- package/dist/ui/glyphs.d.ts.map +1 -0
- package/dist/ui/glyphs.js +78 -0
- package/dist/ui/glyphs.js.map +1 -0
- package/dist/ui/shimmer-progress.d.ts +1 -0
- package/dist/ui/shimmer-progress.d.ts.map +1 -1
- package/dist/ui/shimmer-progress.js +7 -0
- package/dist/ui/shimmer-progress.js.map +1 -1
- package/dist/ui/shimmer-worker.js +20 -11
- package/dist/ui/shimmer-worker.js.map +1 -1
- package/dist/ui/types.d.ts +1 -0
- package/dist/ui/types.d.ts.map +1 -1
- package/dist/vectors/embedder.d.ts +11 -1
- package/dist/vectors/embedder.d.ts.map +1 -1
- package/dist/vectors/embedder.js +48 -18
- package/dist/vectors/embedder.js.map +1 -1
- package/dist/vectors/index.d.ts +1 -1
- package/dist/vectors/index.d.ts.map +1 -1
- package/dist/vectors/index.js.map +1 -1
- package/dist/vectors/manager.d.ts +5 -0
- package/dist/vectors/manager.d.ts.map +1 -1
- package/dist/vectors/manager.js +44 -23
- package/dist/vectors/manager.js.map +1 -1
- package/package.json +4 -3
- package/scripts/agent-eval/audit.sh +68 -0
- package/scripts/agent-eval/itrun.sh +107 -0
- package/scripts/agent-eval/parse-run.mjs +45 -0
- package/scripts/agent-eval/parse-session.mjs +93 -0
- package/scripts/agent-eval/run-agent.sh +34 -0
- package/scripts/agent-eval/run-all.sh +67 -0
- package/scripts/extract-release-notes.mjs +130 -0
- package/scripts/local-install.sh +41 -0
- package/scripts/release.sh +68 -0
package/README.md
CHANGED
|
@@ -2,17 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
# CodeGraph
|
|
4
4
|
|
|
5
|
-
### Supercharge Claude Code with Semantic Code Intelligence
|
|
5
|
+
### Supercharge Claude Code, Cursor, Codex, and OpenCode with Semantic Code Intelligence
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**~35% cheaper · ~70% fewer tool calls · 100% local**
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@stupidloud/codegraph)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
11
|
-
[](https://nodejs.org/)
|
|
12
12
|
|
|
13
13
|
[](#)
|
|
14
14
|
[](#)
|
|
15
15
|
[](#)
|
|
16
|
+
[](#)
|
|
17
|
+
[](#)
|
|
18
|
+
[](#)
|
|
19
|
+
[](#)
|
|
16
20
|
|
|
17
21
|
[English](./README.md) · [简体中文](./README.zh-CN.md)
|
|
18
22
|
|
|
@@ -24,7 +28,7 @@
|
|
|
24
28
|
npx @stupidloud/codegraph
|
|
25
29
|
```
|
|
26
30
|
|
|
27
|
-
<sub>Interactive installer configures Claude Code
|
|
31
|
+
<sub>Interactive installer auto-configures your agent(s) — Claude Code, Cursor, Codex CLI, opencode</sub>
|
|
28
32
|
|
|
29
33
|
#### Initialize Projects
|
|
30
34
|
|
|
@@ -47,61 +51,50 @@ When Claude Code explores a codebase, it spawns **Explore agents** that scan fil
|
|
|
47
51
|
|
|
48
52
|
### Benchmark Results
|
|
49
53
|
|
|
50
|
-
Tested across
|
|
54
|
+
Tested across **7 real-world open-source codebases** spanning 7 languages, comparing an agent (Claude Code, headless) answering one architecture question **with** and **without** CodeGraph. Each cell is the savings at the **median of 4 runs per arm**.
|
|
51
55
|
|
|
52
|
-
> **Average:
|
|
56
|
+
> **Average: 35% cheaper · 59% fewer tokens · 49% faster · 70% fewer tool calls**
|
|
53
57
|
|
|
54
|
-
| Codebase |
|
|
55
|
-
|
|
56
|
-
| **VS Code**
|
|
57
|
-
| **Excalidraw**
|
|
58
|
-
| **
|
|
59
|
-
| **
|
|
60
|
-
| **
|
|
61
|
-
| **
|
|
58
|
+
| Codebase | Language | Cost | Tokens | Time | Tool calls |
|
|
59
|
+
|----------|----------|------|--------|------|------------|
|
|
60
|
+
| **VS Code** | TypeScript · ~10k files | 35% cheaper | 73% fewer | 41% faster | 72% fewer |
|
|
61
|
+
| **Excalidraw** | TypeScript · ~600 | 47% cheaper | 73% fewer | 60% faster | 86% fewer |
|
|
62
|
+
| **Django** | Python · ~2.7k | 34% cheaper | 64% fewer | 59% faster | 81% fewer |
|
|
63
|
+
| **Tokio** | Rust · ~700 | 52% cheaper | 81% fewer | 63% faster | 89% fewer |
|
|
64
|
+
| **OkHttp** | Java · ~640 | 17% cheaper | 41% fewer | 36% faster | 64% fewer |
|
|
65
|
+
| **Gin** | Go · ~150 | 22% cheaper | 23% fewer | 34% faster | 19% fewer |
|
|
66
|
+
| **Alamofire** | Swift · ~100 | 38% cheaper | 59% fewer | 51% faster | 77% fewer |
|
|
67
|
+
|
|
68
|
+
The gains scale with codebase size: on large repos the agent answers from the index in a handful of calls with **zero file reads**, while the no-CodeGraph agent fans out across grep/find/Read (and the sub-agents it spawns). On a small repo like Gin (~150 files) native search is already cheap, so the margin narrows.
|
|
62
69
|
|
|
63
70
|
<details>
|
|
64
71
|
<summary><strong>Full benchmark details</strong></summary>
|
|
65
72
|
|
|
66
|
-
|
|
73
|
+
**Methodology.** Each arm is `claude -p` (Claude Opus 4.7, Claude Code v2.1.145) run headlessly against the repo with `--strict-mcp-config`: **WITH** = CodeGraph's MCP server enabled, **WITHOUT** = an empty MCP config. Built-in Read/Grep/Bash stay available to both. Same question per repo, **4 runs per arm, median reported**. Cost = the run's `total_cost_usd`; Tokens = total tokens processed (input incl. cached + output); Time = wall-clock; Tool calls = every tool invocation, including those inside any sub-agents the model spawns. Repos cloned at `--depth 1` and indexed by the same CodeGraph build that served them.
|
|
67
74
|
|
|
68
|
-
**Queries
|
|
75
|
+
**Queries:**
|
|
69
76
|
| Codebase | Query |
|
|
70
77
|
|----------|-------|
|
|
71
78
|
| VS Code | "How does the extension host communicate with the main process?" |
|
|
72
|
-
| Excalidraw | "How does
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
| VS Code (TypeScript) | 52 | 89.4k | 1m 37s | ~15 |
|
|
92
|
-
| Excalidraw (TypeScript) | 47 | 77.9k | 1m 45s | ~20 |
|
|
93
|
-
| Claude Code (Python+Rust) | 40 | 69.3k | 1m 8s | ~15 |
|
|
94
|
-
| Claude Code (Java) | 26 | 73.3k | 1m 22s | ~15 |
|
|
95
|
-
| Alamofire (Swift) | 32 | 52.4k | 1m 39s | ~10 |
|
|
96
|
-
| Swift Compiler (Swift/C++) | 37 | 99.1k | 2m 8s | ~20 |
|
|
97
|
-
|
|
98
|
-
**Key observations:**
|
|
99
|
-
- With CodeGraph, the agent **never fell back to reading files** — it trusted the codegraph_explore results completely
|
|
100
|
-
- Without CodeGraph, agents spent most of their time on discovery (find, ls, grep) before they could even start reading relevant code
|
|
101
|
-
- The Java codebase needed only **1 codegraph_explore call** to answer the entire question
|
|
102
|
-
- Cross-language queries (Python+Rust) worked seamlessly — CodeGraph's graph traversal found connections across language boundaries
|
|
103
|
-
- The Swift benchmark (Alamofire) traced a **9-step call chain** from `Session.request()` to `URLSession.dataTask()` — CodeGraph's graph traversal at depth 3 captured the full chain in one explore call
|
|
104
|
-
- The **Swift Compiler** benchmark is the largest codebase tested (**25,874 files, 272,898 nodes**) — CodeGraph indexed it in under 4 minutes and the agent answered a complex cross-cutting question with **6 explore calls and zero file reads** in 35 seconds
|
|
79
|
+
| Excalidraw | "How does Excalidraw render and update canvas elements?" |
|
|
80
|
+
| Django | "How does Django's ORM build and execute a query from a QuerySet?" |
|
|
81
|
+
| Tokio | "How does tokio schedule and run async tasks on its runtime?" |
|
|
82
|
+
| OkHttp | "How does OkHttp process a request through its interceptor chain?" |
|
|
83
|
+
| Gin | "How does gin route requests through its middleware chain?" |
|
|
84
|
+
| Alamofire | "How does Alamofire build, send, and validate a request?" |
|
|
85
|
+
|
|
86
|
+
**Raw medians — WITH → WITHOUT:**
|
|
87
|
+
| Codebase | Cost | Tokens | Time | Tool calls |
|
|
88
|
+
|----------|------|--------|------|------------|
|
|
89
|
+
| VS Code | $0.42 → $0.64 | 393k → 1.4M | 1m 0s → 1m 43s | 7 → 23 |
|
|
90
|
+
| Excalidraw | $0.54 → $1.02 | 851k → 3.2M | 1m 17s → 3m 14s | 12 → 83 |
|
|
91
|
+
| Django | $0.41 → $0.62 | 499k → 1.4M | 1m 0s → 2m 25s | 9 → 48 |
|
|
92
|
+
| Tokio | $0.50 → $1.04 | 657k → 3.4M | 1m 5s → 2m 56s | 9 → 75 |
|
|
93
|
+
| OkHttp | $0.36 → $0.44 | 352k → 596k | 45s → 1m 11s | 5 → 14 |
|
|
94
|
+
| Gin | $0.36 → $0.46 | 431k → 562k | 47s → 1m 11s | 7 → 8 |
|
|
95
|
+
| Alamofire | $0.61 → $0.99 | 1.1M → 2.6M | 1m 19s → 2m 41s | 15 → 64 |
|
|
96
|
+
|
|
97
|
+
**Why CodeGraph wins:** with the index available, the agent answers directly — `codegraph_context` to map the area, then one `codegraph_explore` for the relevant source — and stops, usually with zero file reads. Without it, the agent (and the Explore sub-agents it spawns) spends most of its budget on discovery (find/ls/grep) before reading the right code. CodeGraph only helps when queried *directly*, so its instructions steer agents to answer directly rather than delegate exploration to file-reading sub-agents — otherwise a sub-agent reads files regardless and CodeGraph becomes overhead.
|
|
105
98
|
|
|
106
99
|
</details>
|
|
107
100
|
|
|
@@ -131,6 +124,7 @@ CodeGraph detects web-framework routing files and emits `route` nodes linked by
|
|
|
131
124
|
| **Flask** | `@app.route('/path', methods=[...])`, blueprint routes |
|
|
132
125
|
| **FastAPI** | `@app.get(...)`, `@router.post(...)`, all standard methods |
|
|
133
126
|
| **Express** | `app.get(...)`, `router.post(...)` with middleware chains |
|
|
127
|
+
| **NestJS** | `@Controller` + `@Get/@Post/...`, GraphQL `@Resolver` + `@Query/@Mutation`, `@MessagePattern`/`@EventPattern`, `@SubscribeMessage` |
|
|
134
128
|
| **Laravel** | `Route::get()`, `Route::resource()`, `Controller@action`, tuple syntax |
|
|
135
129
|
| **Rails** | `get '/x', to: 'users#index'`, hash-rocket `=>` syntax |
|
|
136
130
|
| **Spring** | `@GetMapping`, `@PostMapping`, `@RequestMapping` on methods |
|
|
@@ -151,15 +145,33 @@ npx @stupidloud/codegraph
|
|
|
151
145
|
```
|
|
152
146
|
|
|
153
147
|
The installer will:
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
148
|
+
- Ask which agent(s) to configure — auto-detects installed ones from: **Claude Code**, **Cursor**, **Codex CLI**, **opencode**
|
|
149
|
+
- Prompt to install `codegraph` on your PATH (so agents can launch the MCP server)
|
|
150
|
+
- Ask whether configs apply to all your projects or just this one
|
|
151
|
+
- Write each chosen agent's MCP server config + an instructions file (e.g. `CLAUDE.md`, `.cursor/rules/codegraph.mdc`, `~/.codex/AGENTS.md`)
|
|
152
|
+
- Set up auto-allow permissions when Claude Code is one of the targets
|
|
153
|
+
- Initialize your current project (local installs only)
|
|
154
|
+
|
|
155
|
+
**Non-interactive (scripting / CI):**
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
codegraph install --yes # auto-detect agents, install global
|
|
159
|
+
codegraph install --target=cursor,claude --yes # explicit target list
|
|
160
|
+
codegraph install --target=auto --location=local # detected agents, project-local
|
|
161
|
+
codegraph install --print-config codex # print snippet, no file writes
|
|
162
|
+
```
|
|
159
163
|
|
|
160
|
-
|
|
164
|
+
| Flag | Values | Default |
|
|
165
|
+
|---|---|---|
|
|
166
|
+
| `--target` | `auto`, `all`, `none`, or csv (`claude,cursor,...`) | prompt |
|
|
167
|
+
| `--location` | `global`, `local` | prompt |
|
|
168
|
+
| `--yes` | (boolean) | prompt every step |
|
|
169
|
+
| `--no-permissions` | (boolean) skip Claude auto-allow list | permissions on |
|
|
170
|
+
| `--print-config <id>` | dump snippet for one agent and exit | — |
|
|
161
171
|
|
|
162
|
-
|
|
172
|
+
### 2. Restart Your Agent
|
|
173
|
+
|
|
174
|
+
Restart your agent (Claude Code / Cursor / Codex CLI / opencode) for the MCP server to load.
|
|
163
175
|
|
|
164
176
|
### 3. Initialize Projects
|
|
165
177
|
|
|
@@ -168,7 +180,9 @@ cd your-project
|
|
|
168
180
|
codegraph init -i
|
|
169
181
|
```
|
|
170
182
|
|
|
171
|
-
|
|
183
|
+
Builds the per-project knowledge graph index. Also wires up any project-local agent surfaces (e.g. Cursor's `.cursor/rules/codegraph.mdc`) so a single global `codegraph install` works in every project you open — no need to re-run the installer per project.
|
|
184
|
+
|
|
185
|
+
That's it — your agent will use CodeGraph tools automatically when a `.codegraph/` directory exists.
|
|
172
186
|
|
|
173
187
|
<details>
|
|
174
188
|
<summary><strong>Manual Setup (Alternative)</strong></summary>
|
|
@@ -469,6 +483,16 @@ The `.codegraph/config.json` file controls indexing:
|
|
|
469
483
|
|
|
470
484
|
**Missing symbols** — The MCP server auto-syncs on save (wait a couple seconds). Run `codegraph sync` manually if needed. Check that the file's language is supported and isn't excluded by config patterns.
|
|
471
485
|
|
|
486
|
+
## Star History
|
|
487
|
+
|
|
488
|
+
<a href="https://www.star-history.com/?repos=colbymchenry%2Fcodegraph&type=date&legend=top-left">
|
|
489
|
+
<picture>
|
|
490
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=colbymchenry/codegraph&type=date&theme=dark&legend=top-left" />
|
|
491
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=colbymchenry/codegraph&type=date&legend=top-left" />
|
|
492
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=colbymchenry/codegraph&type=date&legend=top-left" />
|
|
493
|
+
</picture>
|
|
494
|
+
</a>
|
|
495
|
+
|
|
472
496
|
## License
|
|
473
497
|
|
|
474
498
|
MIT
|
|
@@ -477,7 +501,7 @@ MIT
|
|
|
477
501
|
|
|
478
502
|
<div align="center">
|
|
479
503
|
|
|
480
|
-
**Made for
|
|
504
|
+
**Made for AI coding agents — Claude Code, Cursor, Codex CLI, and opencode**
|
|
481
505
|
|
|
482
506
|
[Report Bug](https://github.com/colbymchenry/codegraph/issues) · [Request Feature](https://github.com/colbymchenry/codegraph/issues)
|
|
483
507
|
|
package/dist/bin/codegraph.js
CHANGED
|
@@ -58,6 +58,7 @@ const fs = __importStar(require("fs"));
|
|
|
58
58
|
const child_process_1 = require("child_process");
|
|
59
59
|
const directory_1 = require("../directory");
|
|
60
60
|
const shimmer_progress_1 = require("../ui/shimmer-progress");
|
|
61
|
+
const glyphs_1 = require("../ui/glyphs");
|
|
61
62
|
const node_version_check_1 = require("./node-version-check");
|
|
62
63
|
// Lazy-load heavy modules (CodeGraph, runInstaller) to keep CLI startup fast.
|
|
63
64
|
async function loadCodeGraph() {
|
|
@@ -66,7 +67,7 @@ async function loadCodeGraph() {
|
|
|
66
67
|
}
|
|
67
68
|
catch (err) {
|
|
68
69
|
const msg = err instanceof Error ? err.message : String(err);
|
|
69
|
-
console.error(
|
|
70
|
+
console.error(`\x1b[31m${(0, glyphs_1.getGlyphs)().err}\x1b[0m Failed to load CodeGraph modules.`);
|
|
70
71
|
console.error(`\n Node: ${process.version} Platform: ${process.platform} ${process.arch}`);
|
|
71
72
|
console.error(`\n Error: ${msg}`);
|
|
72
73
|
console.error('\n Try reinstalling with: npm install -g @stupidloud/codegraph\n');
|
|
@@ -204,12 +205,14 @@ function main() {
|
|
|
204
205
|
function createVerboseProgress() {
|
|
205
206
|
let lastPhase = '';
|
|
206
207
|
let lastPct = -1;
|
|
208
|
+
let lastDetail = '';
|
|
207
209
|
const startTime = Date.now();
|
|
208
210
|
return (progress) => {
|
|
209
211
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
210
212
|
if (progress.phase !== lastPhase) {
|
|
211
213
|
lastPhase = progress.phase;
|
|
212
214
|
lastPct = -1;
|
|
215
|
+
lastDetail = '';
|
|
213
216
|
console.log(`[${elapsed}s] Phase: ${progress.phase}`);
|
|
214
217
|
}
|
|
215
218
|
if (progress.total > 0) {
|
|
@@ -217,7 +220,13 @@ function main() {
|
|
|
217
220
|
// Log every 5% to keep output manageable
|
|
218
221
|
if (pct >= lastPct + 5 || progress.current === progress.total) {
|
|
219
222
|
lastPct = pct;
|
|
220
|
-
console.log(`[${elapsed}s] ${progress.current}/${progress.total} (${pct}%)${progress.currentFile ? `
|
|
223
|
+
console.log(`[${elapsed}s] ${progress.current}/${progress.total} (${pct}%)${progress.currentFile ? ` ${(0, glyphs_1.getGlyphs)().dash} ${progress.currentFile}` : ''}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else if (progress.currentFile) {
|
|
227
|
+
if (progress.currentFile !== lastDetail) {
|
|
228
|
+
lastDetail = progress.currentFile;
|
|
229
|
+
console.log(`[${elapsed}s] ${progress.currentFile}`);
|
|
221
230
|
}
|
|
222
231
|
}
|
|
223
232
|
else if (progress.current > 0) {
|
|
@@ -232,25 +241,25 @@ function main() {
|
|
|
232
241
|
* Print success message
|
|
233
242
|
*/
|
|
234
243
|
function success(message) {
|
|
235
|
-
console.log(chalk.green(
|
|
244
|
+
console.log(chalk.green((0, glyphs_1.getGlyphs)().ok) + ' ' + message);
|
|
236
245
|
}
|
|
237
246
|
/**
|
|
238
247
|
* Print error message
|
|
239
248
|
*/
|
|
240
249
|
function error(message) {
|
|
241
|
-
console.error(chalk.red(
|
|
250
|
+
console.error(chalk.red((0, glyphs_1.getGlyphs)().err) + ' ' + message);
|
|
242
251
|
}
|
|
243
252
|
/**
|
|
244
253
|
* Print info message
|
|
245
254
|
*/
|
|
246
255
|
function info(message) {
|
|
247
|
-
console.log(chalk.blue(
|
|
256
|
+
console.log(chalk.blue((0, glyphs_1.getGlyphs)().info) + ' ' + message);
|
|
248
257
|
}
|
|
249
258
|
/**
|
|
250
259
|
* Print warning message
|
|
251
260
|
*/
|
|
252
261
|
function warn(message) {
|
|
253
|
-
console.log(chalk.yellow(
|
|
262
|
+
console.log(chalk.yellow((0, glyphs_1.getGlyphs)().warn) + ' ' + message);
|
|
254
263
|
}
|
|
255
264
|
/**
|
|
256
265
|
* Print indexing results using clack log methods
|
|
@@ -270,7 +279,7 @@ function main() {
|
|
|
270
279
|
// continuing to the misleading "No files found" branch or throwing.
|
|
271
280
|
if (!result.success && !hasErrors && result.filesIndexed === 0) {
|
|
272
281
|
const generic = result.errors.find((e) => e.severity === 'error');
|
|
273
|
-
clack.log.error(generic?.message ??
|
|
282
|
+
clack.log.error(generic?.message ?? `Indexing failed ${(0, glyphs_1.getGlyphs)().dash} no further details available`);
|
|
274
283
|
return;
|
|
275
284
|
}
|
|
276
285
|
if (result.filesIndexed > 0) {
|
|
@@ -283,7 +292,7 @@ function main() {
|
|
|
283
292
|
clack.log.info(`${formatNumber(result.nodesCreated)} nodes, ${formatNumber(result.edgesCreated)} edges in ${formatDuration(result.durationMs)}`);
|
|
284
293
|
}
|
|
285
294
|
else if (hasErrors) {
|
|
286
|
-
clack.log.error(`Indexing failed
|
|
295
|
+
clack.log.error(`Indexing failed ${(0, glyphs_1.getGlyphs)().dash} all ${formatNumber(result.filesErrored)} files had errors`);
|
|
287
296
|
}
|
|
288
297
|
else {
|
|
289
298
|
clack.log.warn('No files found to index');
|
|
@@ -313,7 +322,7 @@ function main() {
|
|
|
313
322
|
clack.log.info('See .codegraph/errors.log for details');
|
|
314
323
|
}
|
|
315
324
|
if (result.filesIndexed > 0) {
|
|
316
|
-
clack.log.info(
|
|
325
|
+
clack.log.info(`The index is fully usable ${(0, glyphs_1.getGlyphs)().dash} only the failed files are missing.`);
|
|
317
326
|
}
|
|
318
327
|
}
|
|
319
328
|
else if (projectPath) {
|
|
@@ -350,7 +359,7 @@ function main() {
|
|
|
350
359
|
}
|
|
351
360
|
}
|
|
352
361
|
const lines = [
|
|
353
|
-
`CodeGraph Error Log
|
|
362
|
+
`CodeGraph Error Log - ${new Date().toISOString()}`,
|
|
354
363
|
`${errorsByFile.size} files with errors`,
|
|
355
364
|
'',
|
|
356
365
|
];
|
|
@@ -383,6 +392,21 @@ function main() {
|
|
|
383
392
|
if ((0, directory_1.isInitialized)(projectPath)) {
|
|
384
393
|
clack.log.warn(`Already initialized in ${projectPath}`);
|
|
385
394
|
clack.log.info('Use "codegraph index" to re-index or "codegraph sync" to update');
|
|
395
|
+
// Re-run agent surface wiring so re-running `init` is the
|
|
396
|
+
// documented way to recover a project that's missing its
|
|
397
|
+
// Cursor rules file (or future per-agent project surfaces).
|
|
398
|
+
try {
|
|
399
|
+
const { wireProjectSurfacesForGlobalAgents } = await Promise.resolve().then(() => __importStar(require('../installer')));
|
|
400
|
+
for (const { target, file } of wireProjectSurfacesForGlobalAgents()) {
|
|
401
|
+
clack.log.success(`${target.displayName}: ${file.action} ${file.path}`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
catch { /* non-fatal */ }
|
|
405
|
+
try {
|
|
406
|
+
const { offerWatchFallback } = await Promise.resolve().then(() => __importStar(require('../installer')));
|
|
407
|
+
await offerWatchFallback(clack, projectPath);
|
|
408
|
+
}
|
|
409
|
+
catch { /* non-fatal */ }
|
|
386
410
|
clack.outro('');
|
|
387
411
|
return;
|
|
388
412
|
}
|
|
@@ -394,6 +418,20 @@ function main() {
|
|
|
394
418
|
config: semanticConfig,
|
|
395
419
|
});
|
|
396
420
|
clack.log.success(`Initialized in ${projectPath}`);
|
|
421
|
+
// Bootstrap project-local surfaces for any agent that's
|
|
422
|
+
// configured globally (Cursor needs ./.cursor/rules/codegraph.mdc
|
|
423
|
+
// to actually prefer codegraph over native grep). Silent when
|
|
424
|
+
// there's nothing to write.
|
|
425
|
+
try {
|
|
426
|
+
const { wireProjectSurfacesForGlobalAgents } = await Promise.resolve().then(() => __importStar(require('../installer')));
|
|
427
|
+
for (const { target, file } of wireProjectSurfacesForGlobalAgents()) {
|
|
428
|
+
clack.log.success(`${target.displayName}: ${file.action} ${file.path}`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
catch (err) {
|
|
432
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
433
|
+
clack.log.warn(`Skipped wiring project-local agent surfaces: ${msg}`);
|
|
434
|
+
}
|
|
397
435
|
if (options.index) {
|
|
398
436
|
let result;
|
|
399
437
|
if (options.verbose) {
|
|
@@ -403,7 +441,7 @@ function main() {
|
|
|
403
441
|
});
|
|
404
442
|
}
|
|
405
443
|
else {
|
|
406
|
-
process.stdout.write(`${colors.dim}
|
|
444
|
+
process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
|
|
407
445
|
const progress = (0, shimmer_progress_1.createShimmerProgress)();
|
|
408
446
|
result = await cg.indexAll({
|
|
409
447
|
onProgress: progress.onProgress,
|
|
@@ -415,6 +453,11 @@ function main() {
|
|
|
415
453
|
else {
|
|
416
454
|
clack.log.info('Run "codegraph index" to index the project');
|
|
417
455
|
}
|
|
456
|
+
try {
|
|
457
|
+
const { offerWatchFallback } = await Promise.resolve().then(() => __importStar(require('../installer')));
|
|
458
|
+
await offerWatchFallback(clack, projectPath);
|
|
459
|
+
}
|
|
460
|
+
catch { /* non-fatal */ }
|
|
418
461
|
clack.outro('Done');
|
|
419
462
|
cg.destroy();
|
|
420
463
|
}
|
|
@@ -442,7 +485,7 @@ function main() {
|
|
|
442
485
|
const readline = await Promise.resolve().then(() => __importStar(require('readline')));
|
|
443
486
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
444
487
|
const answer = await new Promise((resolve) => {
|
|
445
|
-
rl.question(chalk.yellow(
|
|
488
|
+
rl.question(chalk.yellow(`${(0, glyphs_1.getGlyphs)().warn} This will permanently delete all CodeGraph data. Continue? (y/N) `), resolve);
|
|
446
489
|
});
|
|
447
490
|
rl.close();
|
|
448
491
|
if (answer.toLowerCase() !== 'y') {
|
|
@@ -453,6 +496,15 @@ function main() {
|
|
|
453
496
|
const { default: CodeGraph } = await loadCodeGraph();
|
|
454
497
|
const cg = CodeGraph.openSync(projectPath);
|
|
455
498
|
cg.uninitialize();
|
|
499
|
+
// Clean up any git sync hooks we installed (no-op if none / not a repo).
|
|
500
|
+
try {
|
|
501
|
+
const { removeGitSyncHook } = await Promise.resolve().then(() => __importStar(require('../sync/git-hooks')));
|
|
502
|
+
const removed = removeGitSyncHook(projectPath);
|
|
503
|
+
if (removed.installed.length > 0) {
|
|
504
|
+
info(`Removed git ${removed.installed.join(', ')} sync hook${removed.installed.length > 1 ? 's' : ''}`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
catch { /* non-fatal */ }
|
|
456
508
|
success(`Removed CodeGraph from ${projectPath}`);
|
|
457
509
|
}
|
|
458
510
|
catch (err) {
|
|
@@ -503,7 +555,7 @@ function main() {
|
|
|
503
555
|
});
|
|
504
556
|
}
|
|
505
557
|
else {
|
|
506
|
-
process.stdout.write(`${colors.dim}
|
|
558
|
+
process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
|
|
507
559
|
const progress = (0, shimmer_progress_1.createShimmerProgress)();
|
|
508
560
|
result = await cg.indexAll({
|
|
509
561
|
onProgress: progress.onProgress,
|
|
@@ -547,7 +599,7 @@ function main() {
|
|
|
547
599
|
}
|
|
548
600
|
const clack = await importESM('@clack/prompts');
|
|
549
601
|
clack.intro('Syncing CodeGraph');
|
|
550
|
-
process.stdout.write(`${colors.dim}
|
|
602
|
+
process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
|
|
551
603
|
const progress = (0, shimmer_progress_1.createShimmerProgress)();
|
|
552
604
|
const result = await cg.sync({
|
|
553
605
|
onProgress: progress.onProgress,
|
|
@@ -566,7 +618,7 @@ function main() {
|
|
|
566
618
|
details.push(`Modified: ${result.filesModified}`);
|
|
567
619
|
if (result.filesRemoved > 0)
|
|
568
620
|
details.push(`Removed: ${result.filesRemoved}`);
|
|
569
|
-
clack.log.info(`${details.join(', ')}
|
|
621
|
+
clack.log.info(`${details.join(', ')} ${(0, glyphs_1.getGlyphs)().dash} ${formatNumber(result.nodesUpdated)} nodes in ${formatDuration(result.durationMs)}`);
|
|
570
622
|
}
|
|
571
623
|
clack.outro('Done');
|
|
572
624
|
cg.destroy();
|
|
@@ -641,7 +693,7 @@ function main() {
|
|
|
641
693
|
// when the native build fails.
|
|
642
694
|
const backendLabel = backend === 'native'
|
|
643
695
|
? chalk.green('native')
|
|
644
|
-
: chalk.yellow(
|
|
696
|
+
: chalk.yellow(`wasm ${(0, glyphs_1.getGlyphs)().dash} slower fallback; run \`npm rebuild better-sqlite3\``);
|
|
645
697
|
console.log(` Backend: ${backendLabel}`);
|
|
646
698
|
console.log();
|
|
647
699
|
// Node breakdown
|
|
@@ -886,8 +938,9 @@ function main() {
|
|
|
886
938
|
const renderNode = (node, prefix, isLast, depth) => {
|
|
887
939
|
if (maxDepth !== undefined && depth > maxDepth)
|
|
888
940
|
return;
|
|
889
|
-
const
|
|
890
|
-
const
|
|
941
|
+
const glyphs = (0, glyphs_1.getGlyphs)();
|
|
942
|
+
const connector = isLast ? glyphs.treeLast : glyphs.treeBranch;
|
|
943
|
+
const childPrefix = isLast ? ' ' : glyphs.treePipe;
|
|
891
944
|
if (node.name) {
|
|
892
945
|
let line = prefix + connector + node.name;
|
|
893
946
|
if (node.file && includeMetadata) {
|
|
@@ -954,8 +1007,14 @@ function main() {
|
|
|
954
1007
|
.description('Start CodeGraph as an MCP server for AI assistants')
|
|
955
1008
|
.option('-p, --path <path>', 'Project path (optional for MCP mode, uses rootUri from client)')
|
|
956
1009
|
.option('--mcp', 'Run as MCP server (stdio transport)')
|
|
1010
|
+
.option('--no-watch', 'Disable the file watcher (no auto-sync; useful on slow filesystems like WSL2 /mnt drives)')
|
|
957
1011
|
.action(async (options) => {
|
|
958
1012
|
const projectPath = options.path ? resolveProjectPath(options.path) : undefined;
|
|
1013
|
+
// Commander sets watch=false when --no-watch is passed. Route it through
|
|
1014
|
+
// the same env-var chokepoint the watcher and MCP server already honor.
|
|
1015
|
+
if (options.watch === false) {
|
|
1016
|
+
process.env.CODEGRAPH_NO_WATCH = '1';
|
|
1017
|
+
}
|
|
959
1018
|
try {
|
|
960
1019
|
if (options.mcp) {
|
|
961
1020
|
// Start MCP server - it handles initialization lazily based on rootUri from client
|
|
@@ -968,7 +1027,7 @@ function main() {
|
|
|
968
1027
|
// Default: show info about MCP mode.
|
|
969
1028
|
// Use stderr so stdout stays clean for any piped/stdio usage.
|
|
970
1029
|
console.error(chalk.bold('\nCodeGraph MCP Server\n'));
|
|
971
|
-
console.error(chalk.blue(
|
|
1030
|
+
console.error(chalk.blue((0, glyphs_1.getGlyphs)().info) + ' Use --mcp flag to start the MCP server');
|
|
972
1031
|
console.error('\nTo use with Claude Code, add to your MCP configuration:');
|
|
973
1032
|
console.error(chalk.dim(`
|
|
974
1033
|
{
|
|
@@ -1144,7 +1203,7 @@ function main() {
|
|
|
1144
1203
|
}
|
|
1145
1204
|
const lockPath = path.join((0, directory_1.getCodeGraphDir)(projectPath), 'codegraph.lock');
|
|
1146
1205
|
if (!fs.existsSync(lockPath)) {
|
|
1147
|
-
info(
|
|
1206
|
+
info(`No lock file found ${(0, glyphs_1.getGlyphs)().dash} nothing to do`);
|
|
1148
1207
|
return;
|
|
1149
1208
|
}
|
|
1150
1209
|
fs.unlinkSync(lockPath);
|
|
@@ -1290,10 +1349,54 @@ function main() {
|
|
|
1290
1349
|
*/
|
|
1291
1350
|
program
|
|
1292
1351
|
.command('install')
|
|
1293
|
-
.description('
|
|
1294
|
-
.
|
|
1295
|
-
|
|
1296
|
-
|
|
1352
|
+
.description('Install codegraph MCP server into one or more agents (Claude Code, Cursor, Codex CLI, opencode)')
|
|
1353
|
+
.option('-t, --target <ids>', 'Target agent(s): comma-separated ids, or "auto"|"all"|"none". Default: prompt')
|
|
1354
|
+
.option('-l, --location <where>', 'Install location: "global" or "local". Default: prompt')
|
|
1355
|
+
.option('-y, --yes', 'Non-interactive: defaults to --location=global --target=auto, auto-allow on')
|
|
1356
|
+
.option('--no-permissions', 'Skip writing the auto-allow permissions list (Claude Code only)')
|
|
1357
|
+
.option('--print-config <id>', 'Print MCP config snippet for the named agent and exit (no file writes)')
|
|
1358
|
+
.action(async (opts) => {
|
|
1359
|
+
if (opts.printConfig) {
|
|
1360
|
+
const { getTarget, listTargetIds } = await Promise.resolve().then(() => __importStar(require('../installer/targets/registry')));
|
|
1361
|
+
const target = getTarget(opts.printConfig);
|
|
1362
|
+
if (!target) {
|
|
1363
|
+
const known = listTargetIds().join(', ');
|
|
1364
|
+
error(`Unknown target "${opts.printConfig}". Known: ${known}.`);
|
|
1365
|
+
process.exit(1);
|
|
1366
|
+
}
|
|
1367
|
+
const loc = (opts.location === 'local' ? 'local' : 'global');
|
|
1368
|
+
process.stdout.write(target.printConfig(loc));
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
const { runInstallerWithOptions } = await Promise.resolve().then(() => __importStar(require('../installer')));
|
|
1372
|
+
if (opts.location && opts.location !== 'global' && opts.location !== 'local') {
|
|
1373
|
+
error(`--location must be "global" or "local" (got "${opts.location}").`);
|
|
1374
|
+
process.exit(1);
|
|
1375
|
+
}
|
|
1376
|
+
try {
|
|
1377
|
+
// Commander's `--no-permissions` makes `opts.permissions === false`;
|
|
1378
|
+
// omitting the flag leaves it `true` (the positive-form default).
|
|
1379
|
+
// We MUST treat the default-true as "user did not override — let
|
|
1380
|
+
// the orchestrator prompt" and only forward an explicit `false`
|
|
1381
|
+
// (or `true` when --yes implies it). Otherwise the auto-allow
|
|
1382
|
+
// prompt is silently skipped on every interactive run.
|
|
1383
|
+
const explicitNoPermissions = opts.permissions === false;
|
|
1384
|
+
const autoAllow = explicitNoPermissions
|
|
1385
|
+
? false
|
|
1386
|
+
: opts.yes
|
|
1387
|
+
? true
|
|
1388
|
+
: undefined;
|
|
1389
|
+
await runInstallerWithOptions({
|
|
1390
|
+
target: opts.target,
|
|
1391
|
+
location: opts.location,
|
|
1392
|
+
autoAllow,
|
|
1393
|
+
yes: opts.yes,
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
catch (err) {
|
|
1397
|
+
error(err instanceof Error ? err.message : String(err));
|
|
1398
|
+
process.exit(1);
|
|
1399
|
+
}
|
|
1297
1400
|
});
|
|
1298
1401
|
// Parse and run
|
|
1299
1402
|
program.parse();
|