codetree-claude 1.5.8 → 1.6.0
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 +633 -140
- package/dist/indexer/indexer.d.ts +38 -1
- package/dist/indexer/indexer.d.ts.map +1 -1
- package/dist/indexer/indexer.js +77 -5
- package/dist/indexer/indexer.js.map +1 -1
- package/dist/server/ipc.d.ts +41 -0
- package/dist/server/ipc.d.ts.map +1 -1
- package/dist/server/ipc.js +191 -31
- package/dist/server/ipc.js.map +1 -1
- package/dist/server/tools/codetree-read.d.ts.map +1 -1
- package/dist/server/tools/codetree-read.js +7 -0
- package/dist/server/tools/codetree-read.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,229 +1,722 @@
|
|
|
1
|
-
# CodeTree
|
|
1
|
+
# CodeTree
|
|
2
2
|
|
|
3
|
-
**Persistent codebase index + MCP
|
|
3
|
+
> **Persistent codebase index + Model Context Protocol (MCP) server for AI coding assistants.**
|
|
4
|
+
> Cuts redundant **Read / Grep / Glob** token usage by routing AI tool calls through a **cached SQLite index** with **symbol-aware** APIs.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
[](https://www.npmjs.com/package/codetree-claude)
|
|
7
|
+
[](https://marketplace.visualstudio.com/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://nodejs.org/)
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
CodeTree works with **Anthropic Claude Code**, **Cursor**, **OpenAI Codex**, **Google Antigravity / Gemini**, and any **MCP-compatible** editor or CLI. A single `codetree init` wires the same MCP server into every tool's config format.
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
---
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|--------|---------------------------|---------------------|
|
|
13
|
-
| **Claude Code** (Anthropic) | Root `.mcp.json`, `.claude/settings.json` **hooks**, `CLAUDE.md`, `.claude/rules` | **Hooks** can redirect native Read/Grep/Glob/Edit/Write to `codetree_*` when safe |
|
|
14
|
-
| **Cursor** | `.cursor/mcp.json`, `.cursor/rules/codetree.mdc` | MCP tools + rules steer the agent toward CodeTree |
|
|
15
|
-
| **OpenAI Codex** | `.codex/config.toml` `[mcp_servers.codetree]`, `AGENTS.md` | MCP tools + agent instructions (merge-safe TOML) |
|
|
16
|
-
| **Google Antigravity** | `.antigravity/mcp.json`, **`AGENTS.md`**, **`GEMINI.md`** | MCP + portable docs (Gemini / Antigravity steering) |
|
|
17
|
-
| **VS Code** | Marketplace extension **“CodeTree — Cache for Claude Code”** | Helps activate / discover setup in the editor |
|
|
18
|
-
| **Any MCP host** | Same `node …/mcp-server.js` entry as above | Register **Model Context Protocol** server manually if your stack reads custom paths |
|
|
15
|
+
## Table of Contents
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
1. [Why CodeTree](#why-codetree)
|
|
18
|
+
2. [Features](#features)
|
|
19
|
+
3. [Quick Start](#quick-start)
|
|
20
|
+
4. [Supported AI Tools](#supported-ai-tools-multi-ide)
|
|
21
|
+
5. [Architecture](#architecture)
|
|
22
|
+
6. [Component Design](#component-design)
|
|
23
|
+
7. [Data Flow Diagrams](#data-flow-diagrams)
|
|
24
|
+
8. [MCP Tools Reference](#mcp-tools-reference)
|
|
25
|
+
9. [CLI Commands](#cli-commands)
|
|
26
|
+
10. [Configuration](#configuration)
|
|
27
|
+
11. [Repository Layout](#repository-layout)
|
|
28
|
+
12. [How `codetree init` Wires Each IDE](#how-codetree-init-wires-each-ide)
|
|
29
|
+
13. [Reliability & Cross-Platform Notes](#reliability--cross-platform-notes)
|
|
30
|
+
14. [Development](#development)
|
|
31
|
+
15. [Testing](#testing)
|
|
32
|
+
16. [Contributing](#contributing)
|
|
33
|
+
17. [License](#license)
|
|
21
34
|
|
|
22
|
-
|
|
35
|
+
---
|
|
23
36
|
|
|
24
|
-
##
|
|
37
|
+
## Why CodeTree
|
|
25
38
|
|
|
26
|
-
Teams using
|
|
39
|
+
Teams using AI coding assistants spend a large fraction of their **context window / tokens** on **re-reading** the same files. Every chat re-runs `Glob`, `Grep`, and `Read`, and the model sees the same source again and again.
|
|
27
40
|
|
|
28
|
-
|
|
41
|
+
CodeTree solves this by maintaining a **local, persistent SQLite index** of your repo and serving requests through **MCP tools** that return:
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
- **Cached file content** (mtime-validated, never silently stale)
|
|
44
|
+
- **Compact diffs** when the file is mostly unchanged
|
|
45
|
+
- **Symbol outlines** instead of full bodies
|
|
46
|
+
- **Symbol-aware search** that bypasses raw text grep
|
|
47
|
+
- **Token-efficient project tree** instead of `Glob "**/*"`
|
|
31
48
|
|
|
32
|
-
|
|
49
|
+
For **Claude Code**, CodeTree additionally installs **PreToolUse hooks** that intercept native `Read`/`Grep`/`Glob` calls and redirect them to the cache. For **Cursor / Codex / Antigravity**, the model is steered to the same MCP tools via project rules and `AGENTS.md` / `GEMINI.md`.
|
|
33
50
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
├── Read("src/api/auth.ts")
|
|
38
|
-
│ └── Hook (Claude Code) → cached? YES → codetree_read
|
|
39
|
-
│ └── Cached content + symbol metadata
|
|
40
|
-
│
|
|
41
|
-
├── Grep("handleAuth")
|
|
42
|
-
│ └── Hook → indexed? YES → codetree_search
|
|
43
|
-
│
|
|
44
|
-
└── Glob("src/**/*.ts")
|
|
45
|
-
└── Hook → tree indexed? YES → codetree_structure
|
|
46
|
-
```
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Features
|
|
47
54
|
|
|
48
|
-
|
|
55
|
+
- **Persistent SQLite index** — survives restarts; cold start uses cached postings
|
|
56
|
+
- **In-memory LRU + compressed SQLite content cache** — two-tier read path
|
|
57
|
+
- **Symbol extraction** for JS/TS/JSX/TSX, Python, Java/Kotlin/C#, Go, Rust, Ruby
|
|
58
|
+
- **Token-postings index** for fast multi-token content scans (avoids full-corpus grep)
|
|
59
|
+
- **mtime-validated reads** — branch switches, external edits, merges all reflected
|
|
60
|
+
- **File watcher** (chokidar) + **safety-net rescan** every 10 min for missed events
|
|
61
|
+
- **Singleton IPC server** — deterministic per-project port; duplicates exit cleanly
|
|
62
|
+
- **Hooks for Claude Code** — `PreToolUse`, `PostToolUse`, `SessionStart`, `Pre/PostCompact`
|
|
63
|
+
- **Multi-IDE setup** — one `codetree init` configures Claude, Cursor, Codex, Antigravity
|
|
64
|
+
- **VS Code extension** — sidebar with token savings, indexed files, symbols, dashboard
|
|
65
|
+
- **Cross-platform** — Windows `\r\n` safe, forward-slash paths in MCP configs
|
|
66
|
+
- **Per-tool telemetry** — read/search/glob hits, misses, tokens saved, scan-cache hit rate
|
|
49
67
|
|
|
50
|
-
|
|
68
|
+
---
|
|
51
69
|
|
|
52
|
-
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
### Option 1 — npm global
|
|
53
73
|
|
|
54
74
|
```bash
|
|
55
75
|
npm install -g codetree-claude
|
|
56
|
-
|
|
76
|
+
cd your-project
|
|
57
77
|
codetree init
|
|
58
78
|
```
|
|
59
79
|
|
|
60
|
-
### Option 2
|
|
61
|
-
|
|
62
|
-
Install **“CodeTree — Cache for Claude Code”** from the VS Code Marketplace. It helps you use CodeTree when the project is open in VS Code.
|
|
63
|
-
|
|
64
|
-
### Option 3: Per-project dev dependency
|
|
80
|
+
### Option 2 — per-project dev dependency
|
|
65
81
|
|
|
66
82
|
```bash
|
|
67
83
|
npm install --save-dev codetree-claude
|
|
68
84
|
npx codetree init
|
|
69
85
|
```
|
|
70
86
|
|
|
71
|
-
|
|
87
|
+
### Option 3 — VS Code extension
|
|
88
|
+
|
|
89
|
+
Install **"CodeTree — Cache for Claude Code"** from the VS Code Marketplace. The extension activates CodeTree in the editor and shows the live dashboard.
|
|
90
|
+
|
|
91
|
+
After `codetree init`, **reload your editor** (Cursor / VS Code: `Cmd/Ctrl+Shift+P → Developer: Reload Window`). The MCP server starts automatically per project on the next AI session.
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Supported AI Tools (multi-IDE)
|
|
96
|
+
|
|
97
|
+
| Product | What CodeTree configures | How tokens are saved |
|
|
98
|
+
|---------|--------------------------|----------------------|
|
|
99
|
+
| **Claude Code** (Anthropic) | Root `.mcp.json`, `.claude/settings.json` hooks, `CLAUDE.md`, `.claude/rules/codetree.md` | **Hooks** redirect native `Read`/`Grep`/`Glob`/`Edit`/`Write` to `codetree_*` when the cache can serve |
|
|
100
|
+
| **Cursor** | `.cursor/mcp.json`, `.cursor/rules/codetree.mdc` | MCP tools + `alwaysApply` rules steer the agent |
|
|
101
|
+
| **OpenAI Codex** | `.codex/config.toml` `[mcp_servers.codetree]`, `AGENTS.md` | MCP tools + agent instructions (merge-safe TOML) |
|
|
102
|
+
| **Google Antigravity / Gemini** | `.antigravity/mcp.json`, `AGENTS.md`, `GEMINI.md` | MCP + portable docs |
|
|
103
|
+
| **VS Code** | Marketplace extension *"CodeTree — Cache for Claude Code"* | Sidebar dashboard + auto-mirroring MCP into `.cursor/mcp.json` |
|
|
104
|
+
| **Any MCP host** | Same `node …/dist/server/mcp-server.js` entry | Register the **MCP** server manually if your tool uses a custom config path |
|
|
105
|
+
|
|
106
|
+
> **Note:** Token-saving **hooks** (PreToolUse interception) are a Claude Code feature. Cursor / Codex / Antigravity rely on **MCP + project rules** — the model is steered to call `codetree_read`, `codetree_search`, etc., instead of native tools. The **indexer, cache, and MCP tool surface** are identical for all hosts.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Architecture
|
|
111
|
+
|
|
112
|
+
CodeTree is composed of **six layered subsystems**, each with a single responsibility. The whole stack is one Node process per project, started on demand by the MCP host.
|
|
74
113
|
|
|
75
114
|
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
AGENTS.md
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
115
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
116
|
+
│ AI client │
|
|
117
|
+
│ (Claude Code / Cursor / Codex / Antigravity / any MCP host) │
|
|
118
|
+
│ │
|
|
119
|
+
│ ┌────────────────────────────────────────────────────────────────┐ │
|
|
120
|
+
│ │ Steering layer │ │
|
|
121
|
+
│ │ - Claude Code: PreToolUse hooks + .claude/rules │ │
|
|
122
|
+
│ │ - Cursor: .cursor/rules/codetree.mdc (alwaysApply) │ │
|
|
123
|
+
│ │ - Codex: AGENTS.md + .codex/config.toml │ │
|
|
124
|
+
│ │ - Antigravity: AGENTS.md + GEMINI.md + .antigravity/mcp.json │ │
|
|
125
|
+
│ └────────────────────────────┬───────────────────────────────────┘ │
|
|
126
|
+
└───────────────────────────────┼──────────────────────────────────────┘
|
|
127
|
+
│ MCP / stdio
|
|
128
|
+
┌───────────────────────────────▼──────────────────────────────────────┐
|
|
129
|
+
│ MCP Server (src/server/mcp-server.ts) │
|
|
130
|
+
│ - Registers 10 tools, dispatches CallToolRequest │
|
|
131
|
+
│ - Routes telemetry through HTTP IPC │
|
|
132
|
+
└──────────┬──────────────────────────────────┬────────────────────────┘
|
|
133
|
+
│ │
|
|
134
|
+
┌──────────▼──────────────┐ ┌──────────▼────────────────────────┐
|
|
135
|
+
│ Tool Handlers │ │ IPC Server (singleton, HTTP) │
|
|
136
|
+
│ src/server/tools/*.ts │ │ src/server/ipc.ts │
|
|
137
|
+
│ - codetree_read │ │ - Deterministic per-project port │
|
|
138
|
+
│ - codetree_search │ │ - /check, /check-search, │
|
|
139
|
+
│ - codetree_structure │ │ /check-glob (hook decisions) │
|
|
140
|
+
│ - codetree_outline │ │ - /stats, /status, /mcp-call │
|
|
141
|
+
│ - codetree_probe │ │ - Owner / shared mode coordination│
|
|
142
|
+
│ - codetree_find_refs │ └──────────┬────────────────────────┘
|
|
143
|
+
│ - codetree_summary │ │
|
|
144
|
+
│ - codetree_memory │ │ same process
|
|
145
|
+
│ - codetree_edit │ │
|
|
146
|
+
│ - codetree_write │ │
|
|
147
|
+
└──────────┬──────────────┘ │
|
|
148
|
+
│ │
|
|
149
|
+
┌──────────▼──────────────────────────────────▼────────────────────────┐
|
|
150
|
+
│ Indexer (src/indexer/indexer.ts) │
|
|
151
|
+
│ - fullScan / indexFile / safetyNetRescan │
|
|
152
|
+
│ - In-memory token postings (Map<token, Set<relPath>>) │
|
|
153
|
+
│ - readCached / readForScan (mtime revalidation, disk fallback) │
|
|
154
|
+
│ - looksBinary heuristic, file size cap │
|
|
155
|
+
│ - Uses ExtractorRegistry to pull symbols + dependencies │
|
|
156
|
+
└──────────┬──────────────────────┬────────────────┬───────────────────┘
|
|
157
|
+
│ │ │
|
|
158
|
+
┌──────────▼──────────┐ ┌────────▼──────────┐ ┌──▼──────────────────┐
|
|
159
|
+
│ Storage │ │ ContentCache LRU │ │ FileWatcher │
|
|
160
|
+
│ src/storage/ │ │ (in-memory) │ │ src/indexer/ │
|
|
161
|
+
│ database.ts │ │ cache.ts │ │ watcher.ts │
|
|
162
|
+
│ - sql.js (WASM) │ │ - hash-keyed │ │ - chokidar │
|
|
163
|
+
│ - files, │ │ - mtime/size/ │ │ - debounce 300ms │
|
|
164
|
+
│ symbols, │ │ hash metadata │ │ - .git/HEAD watcher │
|
|
165
|
+
│ dependencies, │ │ │ │ → branch switch │
|
|
166
|
+
│ content_cache, │ │ │ │ cache invalidation│
|
|
167
|
+
│ token_postings, │ │ │ │ - error handler │
|
|
168
|
+
│ trigrams, │ │ │ │ (EMFILE/ENOSPC) │
|
|
169
|
+
│ previous_content │ │ │ │ │
|
|
170
|
+
│ - persistToDisk │ │ │ │ │
|
|
171
|
+
└─────────────────────┘ └───────────────────┘ └──────────────────────┘
|
|
91
172
|
```
|
|
92
173
|
|
|
93
|
-
|
|
174
|
+
### Layer Responsibilities
|
|
94
175
|
|
|
95
|
-
|
|
176
|
+
| Layer | File(s) | Responsibility |
|
|
177
|
+
|-------|---------|----------------|
|
|
178
|
+
| **Steering** | `templates/`, `setup/install.ts` | Idempotent install of MCP configs + rules into each IDE |
|
|
179
|
+
| **MCP Server** | `src/server/mcp-server.ts` | Stdio transport, tool registration, lifecycle management |
|
|
180
|
+
| **Tool Handlers** | `src/server/tools/*.ts` | One file per MCP tool; pure functions of `(config, indexer, db)` |
|
|
181
|
+
| **IPC Server** | `src/server/ipc.ts` | HTTP server on deterministic port; serves hook decisions + telemetry |
|
|
182
|
+
| **Indexer** | `src/indexer/indexer.ts` | The orchestrator — read / scan / extract / postings / token cache |
|
|
183
|
+
| **Storage** | `src/storage/database.ts`, `cache.ts` | SQLite (sql.js WASM) + in-memory LRU |
|
|
184
|
+
| **Watcher** | `src/indexer/watcher.ts` | chokidar + branch-switch detection + safety-net rescan |
|
|
185
|
+
| **Hooks (Claude only)** | `src/hook/*.ts` | Bundled standalone scripts invoked by Claude Code per tool call |
|
|
186
|
+
| **CLI** | `src/cli.ts` | `init`, `status`, `stats`, `reindex`, `doctor`, `help` |
|
|
96
187
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Component Design
|
|
191
|
+
|
|
192
|
+
### Indexer
|
|
193
|
+
|
|
194
|
+
The `Indexer` class (`src/indexer/indexer.ts`) is the heart of CodeTree.
|
|
195
|
+
|
|
196
|
+
- **`fullScan()`** — incremental scan of the project tree. Each file goes through `indexFile()`, which short-circuits on `(size, mtime)` match (the cheap path) and only re-extracts on real change.
|
|
197
|
+
- **`indexFile()`** — reads file, runs `looksBinary` heuristic (>5% unprintable bytes ⇒ skip), computes content hash, extracts symbols + dependencies via the language-specific extractor, writes to SQLite, populates LRU + content-cache, and updates the token-postings index.
|
|
198
|
+
- **`readCached(relPath)`** — two-tier read: in-memory LRU first (with periodic mtime revalidation), then SQLite content cache (with mtime check against disk). On mismatch, re-indexes and serves fresh.
|
|
199
|
+
- **`readForScan(relPath)`** — used by content-search loops. Like `readCached` but **never returns null for files that exist**: falls back to direct `readFileSync` and re-seats both caches. Counts hits/misses for scan telemetry.
|
|
200
|
+
- **`safetyNetRescan()`** — cheap incremental sweep (mostly statSync + short-circuit) run every 10 min as backup against missed chokidar events on Windows / OneDrive / network drives.
|
|
201
|
+
- **Token postings** (`Map<lowercase-token, Set<relPath>>`) — drives `codetree_search` content search, `codetree_find_refs`, and `codetree_probe`. Persisted to SQLite for instant cold start. Tokens are extracted with `/[A-Za-z_][A-Za-z0-9_]{2,}/` (≥3 chars, capped per-file at 4000).
|
|
202
|
+
|
|
203
|
+
### Storage
|
|
204
|
+
|
|
205
|
+
`src/storage/database.ts` — SQLite via [`sql.js`](https://github.com/sql-js/sql.js) (WASM, no native build). Tables:
|
|
206
|
+
|
|
207
|
+
| Table | Purpose |
|
|
208
|
+
|-------|---------|
|
|
209
|
+
| `files` | path, hash, size, mtime, language, line count, indexed-at |
|
|
210
|
+
| `symbols` | name, kind, line span, signature, exported flag — keyed by file path |
|
|
211
|
+
| `dependencies` | source path → target import specifier (resolved is null in current pass) |
|
|
212
|
+
| `content_cache` | zlib-deflated file content; capped by `cache.contentCacheMaxMB` |
|
|
213
|
+
| `token_postings` | per-file token list (for postings cold start) |
|
|
214
|
+
| `trigrams` | content trigrams (for fuzzy content search) |
|
|
215
|
+
| `previous_content` | older deflated content for diff-based reads (24h TTL, capped at 200 rows) |
|
|
103
216
|
|
|
104
|
-
|
|
217
|
+
`src/storage/cache.ts` — small in-memory LRU keyed by `relPath`. Stores raw text plus hash/mtime/size metadata. Hit/miss counters exposed on `/stats`.
|
|
105
218
|
|
|
106
|
-
|
|
219
|
+
### IPC Server
|
|
107
220
|
|
|
108
|
-
|
|
221
|
+
`src/server/ipc.ts` (~1000 lines, single class `IpcServer`) exposes an HTTP API on a deterministic per-project port. Two responsibilities:
|
|
222
|
+
|
|
223
|
+
1. **Hook decisions** — `/check`, `/check-search`, `/check-glob` answer Claude Code hooks in <50 ms.
|
|
224
|
+
2. **Telemetry** — `/stats`, `/status`, `/clear-cache`, `/mcp-call`. Per-tool counters: `readHits`, `searchHits`, `globHits`, `mcpCalls`, `tokensSaved`, `scanCacheHits`, `scanHitRate`.
|
|
225
|
+
|
|
226
|
+
The IPC server is a **singleton per project**: it picks a deterministic port from the project root path. If another instance is already bound, it retries with backoff (200/400/800/1200 ms). On failure the duplicate process exits cleanly so two instances never race on the same SQLite write lock.
|
|
227
|
+
|
|
228
|
+
### Hooks (Claude Code only)
|
|
229
|
+
|
|
230
|
+
Bundled into `dist/hook/*.js` (esbuild standalone scripts) and invoked by Claude Code via `.claude/settings.json`:
|
|
231
|
+
|
|
232
|
+
| Hook | When it fires | What it does |
|
|
233
|
+
|------|---------------|--------------|
|
|
234
|
+
| `pre-tool-use` | Before every `Read`/`Grep`/`Glob` | Asks IPC `/check*`; on cache hit, exits 2 with redirect message → Claude calls `codetree_*` instead |
|
|
235
|
+
| `post-tool-use` | After every tool call | Updates session memory |
|
|
236
|
+
| `session-start` | New chat session | Injects compact project summary (capped at 2 KB) |
|
|
237
|
+
| `pre-compact` | Before context compaction | Saves current insights for recall |
|
|
238
|
+
| `post-compact` | After compaction | Restores compact session context |
|
|
239
|
+
|
|
240
|
+
All hooks must complete in **<50 ms** and **fail open** (any error ⇒ exit 0, native tool runs).
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Data Flow Diagrams
|
|
245
|
+
|
|
246
|
+
### Flow 1 — AI agent reads a file (Claude Code)
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
Agent: Read("src/api/auth.ts")
|
|
250
|
+
│
|
|
251
|
+
▼
|
|
252
|
+
Claude Code ──── PreToolUse hook ────► pre-tool-use.js
|
|
253
|
+
│
|
|
254
|
+
▼
|
|
255
|
+
IpcServer /check?path=…
|
|
256
|
+
│
|
|
257
|
+
┌───────────────┴───────────────┐
|
|
258
|
+
│ │
|
|
259
|
+
cached not cached
|
|
260
|
+
│ │
|
|
261
|
+
▼ ▼
|
|
262
|
+
exit 2 + stderr message exit 0 (allow)
|
|
263
|
+
"Use codetree_read …" │
|
|
264
|
+
│ │
|
|
265
|
+
▼ ▼
|
|
266
|
+
Agent calls codetree_read Native Read runs
|
|
267
|
+
│ │
|
|
268
|
+
▼ ▼
|
|
269
|
+
Indexer.readCached → LRU/SQLite Disk read
|
|
270
|
+
│
|
|
271
|
+
▼
|
|
272
|
+
JSON: { content, hash, lineCount,
|
|
273
|
+
symbols, language,
|
|
274
|
+
unchanged_since_last_read? }
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Flow 2 — AI agent reads a file (Cursor / Codex / Antigravity)
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
Agent (steered by .cursor/rules/codetree.mdc or AGENTS.md)
|
|
281
|
+
│
|
|
282
|
+
▼ (decides to call codetree_read directly)
|
|
283
|
+
MCP Server ──► CallToolRequest("codetree_read", {file_path, session_id?})
|
|
284
|
+
│
|
|
285
|
+
▼
|
|
286
|
+
Tool handler (src/server/tools/codetree-read.ts)
|
|
287
|
+
│
|
|
288
|
+
├── session+hash short-circuit? → unchanged_since_last_read: true (no body)
|
|
289
|
+
├── expected_hash match? → unchanged: true (no body)
|
|
290
|
+
├── outline_only or auto-fallback → symbols + metadata only (no body)
|
|
291
|
+
└── focus_symbol set? → return only symbol body + context
|
|
292
|
+
│
|
|
293
|
+
▼
|
|
294
|
+
Indexer.readCached(relPath)
|
|
295
|
+
│
|
|
296
|
+
├── LRU hit? → mtime revalidate periodically → return content
|
|
297
|
+
├── SQLite content_cache hit? → mtime check vs disk → re-index if stale
|
|
298
|
+
└── miss → null (handler falls back to direct disk read for non-scan paths)
|
|
299
|
+
│
|
|
300
|
+
▼
|
|
301
|
+
Response → MCP Server → JSON over stdio → Agent
|
|
302
|
+
│
|
|
303
|
+
└── (in parallel) IPC /mcp-call?tool=codetree_read&tokens=N updates telemetry
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Flow 3 — Indexer lifecycle (server startup)
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
MCP host spawns: node dist/server/mcp-server.js
|
|
310
|
+
│
|
|
311
|
+
▼
|
|
312
|
+
loadConfig() ──► Database.init() (sql.js loads .codetree/index.db)
|
|
313
|
+
│
|
|
314
|
+
▼
|
|
315
|
+
ContentCache(memoryLimitMB) ──► Indexer.init() (load token postings from SQLite)
|
|
316
|
+
│
|
|
317
|
+
▼
|
|
318
|
+
IpcServer.start() ──► bind deterministic port
|
|
319
|
+
│
|
|
320
|
+
├── port owned by another live codetree → retry (200/400/800/1200ms) → exit if duplicate
|
|
321
|
+
├── port acquired → owner mode
|
|
322
|
+
└── port already ours → shared mode (skip scan + watcher)
|
|
323
|
+
│
|
|
324
|
+
▼ (owner mode only)
|
|
325
|
+
indexer.fullScan() ──► walk project, indexFile() per file (incremental)
|
|
326
|
+
│
|
|
327
|
+
▼
|
|
328
|
+
FileWatcher.start() ──► chokidar + .git/HEAD watcher + safetyNetRescan timer
|
|
329
|
+
│
|
|
330
|
+
▼
|
|
331
|
+
Server.connect(StdioServerTransport()) ──► ready for AI host requests
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Flow 4 — File change → index update
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
Editor saves file → chokidar 'change' event → debounce 300ms
|
|
338
|
+
│
|
|
339
|
+
▼
|
|
340
|
+
Indexer.indexFile(absPath)
|
|
341
|
+
│
|
|
342
|
+
┌────────────────────────┴────────────────────────┐
|
|
343
|
+
│ │
|
|
344
|
+
size+mtime same size or mtime changed
|
|
345
|
+
│ │
|
|
346
|
+
▼ ▼
|
|
347
|
+
short-circuit: skip extract read file → looksBinary?
|
|
348
|
+
(reseat content_cache if evicted) │
|
|
349
|
+
┌────────────────────┴────────────────────┐
|
|
350
|
+
│ │
|
|
351
|
+
binary text
|
|
352
|
+
│ │
|
|
353
|
+
▼ ▼
|
|
354
|
+
delete from index hash → ExtractorRegistry
|
|
355
|
+
│
|
|
356
|
+
▼
|
|
357
|
+
upsert files / symbols / deps
|
|
358
|
+
save trigrams + token postings
|
|
359
|
+
save previous content (for diffs)
|
|
360
|
+
update LRU + content_cache
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Flow 5 — `codetree init` setup
|
|
364
|
+
|
|
365
|
+
```
|
|
366
|
+
codetree init
|
|
367
|
+
│
|
|
368
|
+
▼
|
|
369
|
+
findGitRepos(cwd) ──► for each repo:
|
|
370
|
+
1. createDefaultConfig → .codetreerc.json
|
|
371
|
+
2. updateGitignore → adds .codetree/
|
|
372
|
+
3. installHook → .claude/settings.json
|
|
373
|
+
4. installMcpServer → .mcp.json (Claude)
|
|
374
|
+
5. installClaudeMd → CLAUDE.md
|
|
375
|
+
6. installClaudeRules → .claude/rules/codetree.md
|
|
376
|
+
7. installCursorMcp → .cursor/mcp.json
|
|
377
|
+
8. installCursorRules → .cursor/rules/codetree.mdc
|
|
378
|
+
9. installAntigravityMcp → .antigravity/mcp.json
|
|
379
|
+
10. installCodexMcp → .codex/config.toml
|
|
380
|
+
11. installAgentsMd → AGENTS.md (block)
|
|
381
|
+
12. installGeminiMd → GEMINI.md
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
All install steps are **idempotent** — re-running `codetree init` only refreshes generated blocks.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## MCP Tools Reference
|
|
389
|
+
|
|
390
|
+
All ten tools are available on every MCP host (Claude Code, Cursor, Codex, Antigravity, …).
|
|
391
|
+
|
|
392
|
+
| Tool | Replaces / complements | What it does |
|
|
393
|
+
|------|------------------------|--------------|
|
|
394
|
+
| `codetree_read` | `Read` | Cached read; supports `outline_only`, `expected_hash` (returns diff or "unchanged"), `session_id` short-circuit, `focus_symbol` narrowing, `offset`/`limit` pagination. Mtime-validated. |
|
|
395
|
+
| `codetree_outline` | `Read` (lite) | File metadata + exported symbols + imports. **No body.** Cheapest browse primitive. |
|
|
396
|
+
| `codetree_probe` | `Grep` (lite) | Returns only `{ file_path, line_numbers[] }` per match. **No snippets.** Use for "does X mention Y?" triage. |
|
|
397
|
+
| `codetree_search` | `Grep` | Symbol-name search + optional content search via token postings. Pagination via `next_cursor`. `file_pattern` narrows before scanning. |
|
|
398
|
+
| `codetree_find_refs` | — | Cross-file references for a symbol; uses postings to narrow candidates. |
|
|
399
|
+
| `codetree_structure` | `Glob` | Project file tree. `format='text'` ≈ 40% fewer tokens than JSON. `path`/`depth`/`pattern` narrow. Auto-collapses huge repos. |
|
|
400
|
+
| `codetree_summary` | — | Whole-project overview: language breakdown, top files by symbol count, total estimated tokens. Use at session start. |
|
|
401
|
+
| `codetree_memory` | — | Save / recall insights across sessions. `get_context` is aggressively trimmed. |
|
|
402
|
+
| `codetree_edit` | `Edit` | Edit without prior `Read`. `\r\n`-safe on Windows. Updates index in place. |
|
|
403
|
+
| `codetree_write` | `Write` | Write file without prior `Read`. Creates parent dirs. Updates index. |
|
|
404
|
+
|
|
405
|
+
### Token-saving knobs (selected)
|
|
406
|
+
|
|
407
|
+
| Tool | Knob | Default | Effect |
|
|
408
|
+
|------|------|---------|--------|
|
|
409
|
+
| `codetree_read` | `outline_only` | `false` | Symbols + metadata only |
|
|
410
|
+
| `codetree_read` | `exported_symbols_only` | `true` | Drop private symbols |
|
|
411
|
+
| `codetree_read` | `expected_hash` | — | Unchanged ⇒ no body; changed ⇒ compact diff |
|
|
412
|
+
| `codetree_read` | `session_id` | — | "Already-read this session" short-circuit |
|
|
413
|
+
| `codetree_read` | `focus_symbol` | — | Return only the named function / class body + context |
|
|
414
|
+
| `codetree_search` | `file_pattern` | — | Narrow candidate pool **before** the scan cap |
|
|
415
|
+
| `codetree_structure` | `format='text'` | `'json'` | Compact indented tree |
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## CLI Commands
|
|
109
420
|
|
|
110
421
|
```bash
|
|
111
|
-
codetree init #
|
|
112
|
-
codetree status #
|
|
113
|
-
codetree stats #
|
|
114
|
-
codetree reindex #
|
|
115
|
-
codetree doctor # Verify MCP paths, hook scripts, IPC (after Node/npm changes)
|
|
422
|
+
codetree init # Configure CodeTree + Claude + Cursor + Antigravity + Codex in every git repo under cwd
|
|
423
|
+
codetree status # Per-project: running? indexed file count? ready?
|
|
424
|
+
codetree stats # Aggregated cache hit rates + estimated tokens / cost saved
|
|
425
|
+
codetree reindex # Drop .codetree/index.db (rebuilds on next session)
|
|
426
|
+
codetree doctor # Verify MCP paths, hook scripts, IPC port (run after Node/npm changes)
|
|
116
427
|
codetree help # Show help
|
|
117
428
|
```
|
|
118
429
|
|
|
119
|
-
|
|
430
|
+
`codetree init` discovers all `.git` directories under the current working directory and configures each one independently.
|
|
120
431
|
|
|
121
|
-
|
|
122
|
-
- The **indexer** skips **`node_modules`** for speed. To hack on **CodeTree source**, open a **git clone** of this repo as the project root.
|
|
123
|
-
- After **`nvm use`**, switching Node, or changing **npm prefix**, run **`codetree doctor`** and **`codetree init`** again if paths are wrong.
|
|
432
|
+
---
|
|
124
433
|
|
|
125
434
|
## Configuration
|
|
126
435
|
|
|
127
|
-
Edit `.codetreerc.json` in your project root:
|
|
436
|
+
Edit `.codetreerc.json` in your project root (a default is created by `codetree init`):
|
|
128
437
|
|
|
129
438
|
```json
|
|
130
439
|
{
|
|
131
|
-
"
|
|
440
|
+
"projectRoot": ".",
|
|
441
|
+
"ignore": [".git", "node_modules", "dist", "build", "coverage", ".next", "__pycache__", ".cache", ".turbo", ".vercel", ".output"],
|
|
442
|
+
"ignoreBinary": true,
|
|
132
443
|
"maxFileSize": 1048576,
|
|
133
444
|
"cache": {
|
|
134
445
|
"memoryLimitMB": 256,
|
|
446
|
+
"dbPath": ".codetree/index.db",
|
|
135
447
|
"contentCacheMaxMB": 512
|
|
136
448
|
},
|
|
449
|
+
"ipc": { "port": 0, "host": "127.0.0.1" },
|
|
450
|
+
"watch": { "enabled": true, "debounceMs": 300, "usePolling": false },
|
|
137
451
|
"symbols": {
|
|
138
452
|
"enabled": true,
|
|
139
|
-
"languages": ["javascript", "typescript", "python", "java", "go"]
|
|
453
|
+
"languages": ["javascript", "typescript", "python", "java", "go", "rust", "ruby", "csharp"]
|
|
454
|
+
},
|
|
455
|
+
"telemetry": { "enabled": true, "statsFile": ".codetree/stats.json" },
|
|
456
|
+
"tokenSave": {
|
|
457
|
+
"read": {
|
|
458
|
+
"includeSymbolsByDefault": true,
|
|
459
|
+
"maxSymbols": 40,
|
|
460
|
+
"exportedSymbolsOnlyByDefault": true,
|
|
461
|
+
"unchangedShortCircuit": true,
|
|
462
|
+
"outlineFallbackBytes": 81920
|
|
463
|
+
},
|
|
464
|
+
"search": { "defaultLimit": 20, "snippetMaxChars": 120 },
|
|
465
|
+
"structure": { "compactText": false },
|
|
466
|
+
"sessionStart": { "maxBytes": 2048 }
|
|
140
467
|
}
|
|
141
468
|
}
|
|
142
469
|
```
|
|
143
470
|
|
|
144
|
-
|
|
471
|
+
The schema is enforced via `zod` in `src/config.ts` — invalid values fall back to defaults rather than crashing the server.
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Repository Layout
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
codetree/
|
|
479
|
+
├── src/
|
|
480
|
+
│ ├── cli.ts # `codetree` CLI entry point
|
|
481
|
+
│ ├── config.ts # zod schema + project-root discovery
|
|
482
|
+
│ ├── doctor.ts # `codetree doctor` checks
|
|
483
|
+
│ ├── diff.ts # compact diff format for codetree_read
|
|
484
|
+
│ ├── index.ts # programmatic API exports
|
|
485
|
+
│ ├── utils.ts # findGitRepos, findIpcPort, formatNumber
|
|
486
|
+
│ │
|
|
487
|
+
│ ├── server/
|
|
488
|
+
│ │ ├── mcp-server.ts # MCP stdio entry; lifecycle + shutdown
|
|
489
|
+
│ │ ├── ipc.ts # HTTP IPC server (singleton per project)
|
|
490
|
+
│ │ └── tools/
|
|
491
|
+
│ │ ├── codetree-read.ts
|
|
492
|
+
│ │ ├── codetree-outline.ts
|
|
493
|
+
│ │ ├── codetree-probe.ts
|
|
494
|
+
│ │ ├── codetree-search.ts
|
|
495
|
+
│ │ ├── codetree-find-refs.ts
|
|
496
|
+
│ │ ├── codetree-structure.ts
|
|
497
|
+
│ │ ├── codetree-summary.ts
|
|
498
|
+
│ │ ├── codetree-memory.ts
|
|
499
|
+
│ │ ├── codetree-edit.ts
|
|
500
|
+
│ │ └── codetree-write.ts
|
|
501
|
+
│ │
|
|
502
|
+
│ ├── indexer/
|
|
503
|
+
│ │ ├── indexer.ts # the orchestrator
|
|
504
|
+
│ │ ├── watcher.ts # chokidar + .git/HEAD + safety-net rescan
|
|
505
|
+
│ │ ├── hasher.ts # xxhash content + quick (size,mtime) hash
|
|
506
|
+
│ │ ├── ignore.ts # gitignore-compatible ignore filter
|
|
507
|
+
│ │ ├── extractor-registry.ts # routes file → language extractor
|
|
508
|
+
│ │ └── extractors/ # JS/TS, Python, Java, Go, Rust, Ruby, C#, generic
|
|
509
|
+
│ │
|
|
510
|
+
│ ├── storage/
|
|
511
|
+
│ │ ├── database.ts # sql.js wrapper + schema + migrations
|
|
512
|
+
│ │ ├── cache.ts # in-memory LRU
|
|
513
|
+
│ │ └── disk-manager.ts # disk-budget management
|
|
514
|
+
│ │
|
|
515
|
+
│ ├── hook/
|
|
516
|
+
│ │ ├── pre-tool-use.ts # bundled standalone (esbuild)
|
|
517
|
+
│ │ ├── post-tool-use.ts
|
|
518
|
+
│ │ ├── session-start.ts
|
|
519
|
+
│ │ ├── pre-compact.ts
|
|
520
|
+
│ │ ├── post-compact.ts
|
|
521
|
+
│ │ └── hook-client.ts # tiny HTTP client → IPC server
|
|
522
|
+
│ │
|
|
523
|
+
│ └── setup/
|
|
524
|
+
│ ├── install.ts # all install* functions used by `codetree init`
|
|
525
|
+
│ └── template-load.ts # reads templates/ and copies into project
|
|
526
|
+
│
|
|
527
|
+
├── templates/ # bundled with npm package; copied by init
|
|
528
|
+
│ ├── claude-md-codetree.snippet.md
|
|
529
|
+
│ ├── claude-rules-codetree.md
|
|
530
|
+
│ ├── cursor-codetree.mdc
|
|
531
|
+
│ ├── agents-codetree.snippet.md
|
|
532
|
+
│ ├── gemini-codetree.snippet.md
|
|
533
|
+
│ └── README.md
|
|
534
|
+
│
|
|
535
|
+
├── vscode-extension/ # standalone published extension
|
|
536
|
+
│ ├── src/
|
|
537
|
+
│ │ ├── extension.ts # activation, commands, MCP mirror
|
|
538
|
+
│ │ ├── dashboard.ts # webview dashboard (live token savings)
|
|
539
|
+
│ │ └── tree-views.ts # sidebar trees (stats / files / symbols)
|
|
540
|
+
│ ├── media/ # icons
|
|
541
|
+
│ └── package.json # publisher: rishuni30
|
|
542
|
+
│
|
|
543
|
+
├── scripts/
|
|
544
|
+
│ ├── bundle-hook.js # esbuild bundle for hook/*.ts
|
|
545
|
+
│ └── postinstall.js
|
|
546
|
+
│
|
|
547
|
+
├── docs/
|
|
548
|
+
│ ├── INSTALL_PATH_AND_IGNORE_ISSUES.md
|
|
549
|
+
│ └── INTEGRATION_CURSOR_ANTIGRAVITY_CODEX.md
|
|
550
|
+
│
|
|
551
|
+
├── test/
|
|
552
|
+
│ ├── diff.test.ts
|
|
553
|
+
│ ├── extractors.test.ts
|
|
554
|
+
│ ├── utils.test.ts
|
|
555
|
+
│ └── integration.mjs # end-to-end against a live server
|
|
556
|
+
│
|
|
557
|
+
├── dist/ # build output (gitignored — but shipped on npm)
|
|
558
|
+
├── .codetree/ # local index DB + stats (gitignored)
|
|
559
|
+
├── .codetreerc.json # project config
|
|
560
|
+
├── .codetreerc.default.json # template default
|
|
561
|
+
├── .mcp.json # Claude Code MCP entry for THIS repo
|
|
562
|
+
├── .gitignore # node_modules/, dist/, .codetree/, *.tsbuildinfo
|
|
563
|
+
├── package.json # name: codetree-claude
|
|
564
|
+
├── tsconfig.json
|
|
565
|
+
├── CHANGELOG.md
|
|
566
|
+
├── LICENSE # MIT
|
|
567
|
+
└── README.md # this file
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## How `codetree init` Wires Each IDE
|
|
573
|
+
|
|
574
|
+
| IDE | MCP config | Rules / instructions |
|
|
575
|
+
|-----|------------|----------------------|
|
|
576
|
+
| **Claude Code** | Root `.mcp.json` | `CLAUDE.md` + `.claude/rules/codetree.md` + hooks in `.claude/settings.json` |
|
|
577
|
+
| **Cursor** | `.cursor/mcp.json` | `.cursor/rules/codetree.mdc` (alwaysApply) |
|
|
578
|
+
| **OpenAI Codex** | `.codex/config.toml` (`[mcp_servers.codetree]`) | `AGENTS.md` (also: trust the project in Codex if required) |
|
|
579
|
+
| **Google Antigravity** | `.antigravity/mcp.json` | `AGENTS.md` (full table) + `GEMINI.md` (Gemini pointer) |
|
|
580
|
+
|
|
581
|
+
All written files are **safe to commit** (the team setup) except `.codetree/` itself which is gitignored. Re-running `codetree init` only refreshes the CodeTree-managed blocks.
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Reliability & Cross-Platform Notes
|
|
145
586
|
|
|
146
587
|
### Never stale
|
|
147
|
-
- **External edits** — mtime
|
|
148
|
-
- **
|
|
149
|
-
- **
|
|
588
|
+
- **External edits** — periodic mtime revalidation on read; immediate re-index on mismatch
|
|
589
|
+
- **Branch switches** — `.git/HEAD` watcher invalidates relevant cache
|
|
590
|
+
- **Missed watcher events** — safety-net rescan every 10 min (1 min after startup)
|
|
150
591
|
|
|
151
592
|
### Cross-platform
|
|
152
|
-
- **Windows `\r\n`** — `codetree_edit` normalizes for matching
|
|
153
|
-
- **Paths** — forward slashes in MCP JSON
|
|
593
|
+
- **Windows `\r\n`** — `codetree_edit` normalizes for matching, preserves style on write
|
|
594
|
+
- **Paths** — forward slashes in MCP JSON for portability across OSs
|
|
595
|
+
- **Shutdown** — `SIGINT`/`SIGTERM`/`SIGHUP` + `transport.onclose` + `stdin.end`/`stdin.close` (Windows doesn't reliably deliver SIGTERM to Node child processes)
|
|
154
596
|
|
|
155
597
|
### Safe at scale
|
|
156
|
-
- **Large files** —
|
|
157
|
-
- **Large repos** — structure view
|
|
158
|
-
- **Hooks (Claude)** — redirect only when CodeTree can serve; otherwise native tools run
|
|
159
|
-
- **Graceful degradation** — non-critical failures wrapped so core reads do not break
|
|
598
|
+
- **Large files** — `outlineFallbackBytes` (default 80 KB) auto-degrades to outline mode rather than truncating mid-byte; per-call slice capped at 5000 lines
|
|
599
|
+
- **Large repos** — structure view paginates via `next_cursor`; auto-collapses on huge trees
|
|
600
|
+
- **Hooks (Claude)** — redirect only when CodeTree can serve; otherwise native tools run
|
|
601
|
+
- **Graceful degradation** — non-critical failures wrapped so core reads do not break
|
|
602
|
+
- **Single owner** — duplicate processes detect via deterministic IPC port and exit cleanly to avoid SQLite write-lock contention
|
|
603
|
+
|
|
604
|
+
### Telemetry
|
|
605
|
+
Per-tool counters available on `IPC /stats`:
|
|
160
606
|
|
|
161
|
-
|
|
162
|
-
|
|
607
|
+
```
|
|
608
|
+
readHits / readMisses searchHits / searchMisses globHits / globMisses
|
|
609
|
+
readTokensSaved searchTokensSaved globTokensSaved
|
|
610
|
+
sessionTokensSaved mcpTokensSaved mcpCalls
|
|
611
|
+
scanCacheHits / scanCacheMisses scanHitRate scanDiskReadBytes
|
|
612
|
+
hitRate (= cacheHits / (cacheHits + cacheMisses)) avgTokensPerHit
|
|
613
|
+
```
|
|
163
614
|
|
|
164
|
-
|
|
615
|
+
A persistently low `scanHitRate` on a large repo is a clear signal that `cache.contentCacheMaxMB` is too small.
|
|
165
616
|
|
|
166
|
-
|
|
617
|
+
---
|
|
167
618
|
|
|
168
|
-
|
|
169
|
-
|------|------------------------|--------------|
|
|
170
|
-
| `codetree_read` | Read | Cached read + symbols; mtime-validated. |
|
|
171
|
-
| `codetree_edit` | Edit | Edit without prior Read; `\r\n`-safe on Windows. |
|
|
172
|
-
| `codetree_write` | Write | Write without prior Read; creates parent dirs. |
|
|
173
|
-
| `codetree_search` | Grep | Symbol index + optional content search. |
|
|
174
|
-
| `codetree_structure` | Glob | Project tree; auto-collapse on huge repos. |
|
|
175
|
-
| `codetree_find_refs` | — | Cross-file references. |
|
|
176
|
-
| `codetree_summary` | — | Project overview for session start. |
|
|
177
|
-
| `codetree_memory` | — | Save / recall insights across sessions. |
|
|
619
|
+
## Development
|
|
178
620
|
|
|
179
|
-
|
|
621
|
+
### Prerequisites
|
|
622
|
+
- **Node.js ≥ 20**
|
|
623
|
+
- **npm** (or pnpm / yarn — npm is what CI uses)
|
|
180
624
|
|
|
181
|
-
|
|
625
|
+
### Setup
|
|
182
626
|
|
|
183
|
-
|
|
627
|
+
```bash
|
|
628
|
+
git clone <your-repo-url> codetree
|
|
629
|
+
cd codetree
|
|
630
|
+
npm install
|
|
631
|
+
npm run build
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
`npm run build` runs `tsc` and then `scripts/bundle-hook.js` (esbuild) to produce standalone bundles for `dist/hook/*.js`.
|
|
184
635
|
|
|
185
|
-
|
|
636
|
+
### Useful scripts
|
|
186
637
|
|
|
638
|
+
| Script | What it does |
|
|
639
|
+
|--------|--------------|
|
|
640
|
+
| `npm run build` | Full build: TypeScript compile + hook bundling |
|
|
641
|
+
| `npm run build:hook` | Re-bundle hook scripts only |
|
|
642
|
+
| `npm run dev` | `tsc --watch` |
|
|
643
|
+
| `npm run lint` | `tsc --noEmit` (no separate ESLint dependency) |
|
|
644
|
+
| `npm test` | Vitest run |
|
|
645
|
+
| `npm run test:watch` | Vitest watch mode |
|
|
646
|
+
| `npm start` | Run the MCP server directly (`node dist/server/mcp-server.js`) |
|
|
647
|
+
|
|
648
|
+
### Local install for testing
|
|
649
|
+
|
|
650
|
+
```bash
|
|
651
|
+
npm pack
|
|
652
|
+
npm install -g ./codetree-claude-*.tgz
|
|
653
|
+
cd /path/to/test-project
|
|
654
|
+
codetree init
|
|
655
|
+
codetree doctor
|
|
187
656
|
```
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
│ └───────────────────────────┬───────────────────────────┘ │
|
|
198
|
-
│ │ │
|
|
199
|
-
│ ┌───────────────────────────▼───────────────────────────┐ │
|
|
200
|
-
│ │ Indexer + cache (SQLite, LRU, watcher, git HEAD, …) │ │
|
|
201
|
-
│ └─────────────────────────────────────────────────────────┘ │
|
|
202
|
-
└─────────────────────────────────────────────────────────────┘
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
660
|
+
## Testing
|
|
661
|
+
|
|
662
|
+
### Unit tests (Vitest)
|
|
663
|
+
|
|
664
|
+
```bash
|
|
665
|
+
npm test
|
|
203
666
|
```
|
|
204
667
|
|
|
205
|
-
|
|
668
|
+
Covers:
|
|
669
|
+
- `test/diff.test.ts` — diff formatter
|
|
670
|
+
- `test/extractors.test.ts` — symbol + import extraction per language
|
|
671
|
+
- `test/utils.test.ts` — utility helpers
|
|
206
672
|
|
|
207
|
-
|
|
208
|
-
2. Commit `.codetreerc.json`, `.mcp.json`, `.cursor/`, `.antigravity/`, `.codex/`, `AGENTS.md`, `GEMINI.md` as policy allows.
|
|
209
|
-
3. Add `.codetree/` to `.gitignore` (init does this).
|
|
210
|
-
4. Each developer runs `npx codetree init` once (or uses the VS Code extension).
|
|
673
|
+
### Integration tests
|
|
211
674
|
|
|
212
|
-
|
|
675
|
+
```bash
|
|
676
|
+
node test/integration.mjs
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
Spins up a real MCP server against a test fixture and asserts:
|
|
680
|
+
- `/stats` shape and arithmetic invariants (`cacheHits == readHits + searchHits + globHits`)
|
|
681
|
+
- Phantom-hit regression (a `/check` against a path with no DB record correctly counts as a miss)
|
|
682
|
+
- `/check-search` and `/check-glob` token-saving credits
|
|
683
|
+
- Cold-cache disk fallback for multi-word queries
|
|
684
|
+
- `scanStats` reachability
|
|
685
|
+
- File-pattern narrowing on probe and content search
|
|
213
686
|
|
|
214
|
-
|
|
687
|
+
---
|
|
215
688
|
|
|
216
|
-
|
|
689
|
+
## Contributing
|
|
217
690
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
691
|
+
1. **Fork** and create a feature branch off `main`.
|
|
692
|
+
2. **Install** dependencies (`npm install`) and **build** (`npm run build`).
|
|
693
|
+
3. **Add tests** under `test/` for any behavior change.
|
|
694
|
+
4. **Run** `npm run lint && npm test && node test/integration.mjs`.
|
|
695
|
+
5. **Update** `CHANGELOG.md` under a new `## [x.y.z] - YYYY-MM-DD` entry.
|
|
696
|
+
6. **Open a PR** with a clear description of the user-visible change and a reference to the symptom you observed (CHANGELOG entries on this project lead with the symptom — see `CHANGELOG.md` for examples).
|
|
222
697
|
|
|
223
|
-
|
|
698
|
+
### Coding conventions
|
|
699
|
+
- TypeScript strict mode; no `any` casts in committed code
|
|
700
|
+
- Forward-slash paths in any string written to disk
|
|
701
|
+
- Tool handlers are pure functions of `(config, indexer, db)` — easy to unit-test
|
|
702
|
+
- Failures in non-critical paths are wrapped (`try { … } catch { /* non-critical */ }`) so a corrupted index row never breaks the whole server
|
|
224
703
|
|
|
225
|
-
|
|
704
|
+
---
|
|
226
705
|
|
|
227
706
|
## License
|
|
228
707
|
|
|
229
|
-
MIT
|
|
708
|
+
[MIT](LICENSE) © CodeTree contributors
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## Acknowledgements
|
|
713
|
+
|
|
714
|
+
Built on top of:
|
|
715
|
+
- [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) — MCP transport
|
|
716
|
+
- [`sql.js`](https://github.com/sql-js/sql.js) — SQLite in WebAssembly (no native build)
|
|
717
|
+
- [`chokidar`](https://github.com/paulmillr/chokidar) — cross-platform file watching
|
|
718
|
+
- [`xxhash-wasm`](https://github.com/jungomi/xxhash-wasm) — fast content hashing
|
|
719
|
+
- [`zod`](https://github.com/colinhacks/zod) — config schema
|
|
720
|
+
- [`lru-cache`](https://github.com/isaacs/node-lru-cache) — in-memory cache
|
|
721
|
+
- [`esbuild`](https://esbuild.github.io/) — hook bundling
|
|
722
|
+
- [`vitest`](https://vitest.dev/) — tests
|