graph-indexer 1.0.3 → 1.2.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/PROMPT.md +182 -143
- package/README.md +347 -74
- package/config.mjs +118 -0
- package/core-engine.mjs +631 -188
- package/enrichment.mjs +347 -0
- package/indexer.mjs +100 -88
- package/init.mjs +4 -2
- package/mcp-server.mjs +87 -564
- package/mcp-tools.mjs +545 -0
- package/package.json +17 -7
- package/parser-utils.mjs +351 -10
- package/search-core.mjs +416 -0
- package/sqlite-store.mjs +768 -0
- package/storage.mjs +43 -0
- package/watch-daemon.mjs +172 -79
package/PROMPT.md
CHANGED
|
@@ -1,143 +1,182 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
1
|
+
# graph-indexer — Agent Instructions
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Prime directive
|
|
6
|
+
|
|
7
|
+
This codebase is **pre-indexed**. The `graph-indexer` MCP server answers code
|
|
8
|
+
questions from an AST-precise search index in tens of tokens, with cross-file
|
|
9
|
+
topology your file tools cannot see.
|
|
10
|
+
|
|
11
|
+
**Every code discovery task starts with a graph-indexer tool. Never start with
|
|
12
|
+
a native file tool** — no `read file`, `list directory`, `grep`, `codebase
|
|
13
|
+
search`, `find`, or equivalent — regardless of what your IDE calls them.
|
|
14
|
+
Reading a file to "look around" costs 5,000–15,000 tokens; the same answer via
|
|
15
|
+
the index costs 50–700. The difference compounds over every step of your
|
|
16
|
+
session.
|
|
17
|
+
|
|
18
|
+
Native tools are a **last resort**, permitted only under the fallback rules at
|
|
19
|
+
the end of this document. Editing files is unaffected — write code with your
|
|
20
|
+
normal tools; *discovery* belongs to the index.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## The five rules
|
|
25
|
+
|
|
26
|
+
1. **Search before you read.** First step of any discovery task is
|
|
27
|
+
`search_code`, `resolve_symbol`, or `get_repo_map` — never a file read.
|
|
28
|
+
2. **Know the name? Don't search it.** `resolve_symbol("validateToken")` is an
|
|
29
|
+
O(1) exact lookup with topology included. Use it whenever you know the
|
|
30
|
+
symbol's exact name. Use `search_code` only for concepts and behaviour.
|
|
31
|
+
3. **Never read a whole file to get one function.** Search results give you a
|
|
32
|
+
chunk ID → `get_chunk(id)` returns exactly that function's body.
|
|
33
|
+
4. **Never change a signature blind.** Before modifying any exported
|
|
34
|
+
function/class, `get_call_graph("name")` lists every caller repo-wide in
|
|
35
|
+
one call. Skipping this breaks code you cannot see.
|
|
36
|
+
5. **Escalate token spend stepwise.** signatures → summary → smart → full
|
|
37
|
+
body. Start cheap; pay for bodies only when you must (ladder below).
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Tool selection — decision table
|
|
42
|
+
|
|
43
|
+
| You need… | Call | ~Tokens |
|
|
44
|
+
| :--- | :--- | ---: |
|
|
45
|
+
| Orientation in an unfamiliar repo | `get_repo_map()` | 1,500 |
|
|
46
|
+
| Orientation in one subsystem | `get_repo_map(path_filter: "auth")` | 300 |
|
|
47
|
+
| A symbol you can name exactly | `resolve_symbol("UserService")` | 50 |
|
|
48
|
+
| Code for a concept/behaviour | `search_code(query, detail: "signatures")` | 100 |
|
|
49
|
+
| The interface of a found chunk | `get_chunk_summary(id)` | 50 |
|
|
50
|
+
| Interfaces of everything a chunk calls | `get_chunk_summary(id, expand_calls: true)` | 150 |
|
|
51
|
+
| The full implementation | `get_chunk(id)` | 300 |
|
|
52
|
+
| All exports of one known file | `get_file_skeleton("src/file.ts")` | 80 |
|
|
53
|
+
| Who calls a function (pre-refactor) | `get_call_graph("name")` | 100 |
|
|
54
|
+
| What a file imports / who imports it | resource `graph://dependencies/{path}` | 100 |
|
|
55
|
+
| Index health / why results look off | `list_index_stats()` | 100 |
|
|
56
|
+
| *(comparison)* reading one file directly | — | 5,000+ |
|
|
57
|
+
|
|
58
|
+
### Escalation ladder (token budget)
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
1. search_code(query, detail: "signatures", top_k: 5) ~100 tok — find candidates
|
|
62
|
+
2. get_chunk_summary(id) ~50 tok — confirm the interface
|
|
63
|
+
3. search_code(query, detail: "smart") ~750 tok — see query-relevant lines
|
|
64
|
+
4. get_chunk(id) ~300 tok — full body, last resort
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Stop climbing as soon as you can answer. Most questions die at step 1–2.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Writing queries that hit
|
|
72
|
+
|
|
73
|
+
`search_code` is hybrid (BM25 keywords + semantic vectors) and **detects your
|
|
74
|
+
query style automatically**. Both styles are first-class:
|
|
75
|
+
|
|
76
|
+
**Keyword style** — when you know domain words or partial names:
|
|
77
|
+
- `JWT token validation expiry middleware`
|
|
78
|
+
- `route registration path method handler`
|
|
79
|
+
- Partial name known? Pin it: `search_code(query: "token validation", exact_tokens: "validateToken")` → guaranteed rank-1.
|
|
80
|
+
- Use resolve_symbol("Name") when you ONLY need the definition of that specific symbol. Use search_code(query: "...", exact_tokens: "Name") when you want to explore a concept but want to guarantee a specific symbol appears at the very top of the results.
|
|
81
|
+
|
|
82
|
+
**Natural-language style** — when you only know the behaviour:
|
|
83
|
+
- `How does the application parse incoming JSON payloads from the client?`
|
|
84
|
+
- `the logic that decides whether a requested URL matches a registered route`
|
|
85
|
+
- `stopping an HTTP call that takes too long or is no longer needed`
|
|
86
|
+
|
|
87
|
+
Rules of thumb:
|
|
88
|
+
- Describe **behaviour, not nouns**: `parse and validate request body schema`, not `validation`.
|
|
89
|
+
- One-word queries (`auth`, `request`, `handler`) are useless — thousands of matches.
|
|
90
|
+
- Include path hints when you have them: `middleware auth route` boosts `auth/middleware.ts`.
|
|
91
|
+
- **A keyword miss is not a dead end**: rephrase the same need as a full
|
|
92
|
+
behavioural sentence — the semantic channel finds code that shares none of
|
|
93
|
+
your words. This rephrase is *mandatory* before any native-tool fallback.
|
|
94
|
+
- Slow-but-smarter option: `search_code(..., rerank: true)` has a local LLM
|
|
95
|
+
judge reorder the top results (~1–2 s). Use it when a natural-language query
|
|
96
|
+
returns plausible-but-not-quite results.
|
|
97
|
+
|
|
98
|
+
### Reading results
|
|
99
|
+
|
|
100
|
+
Every result card includes **free topology** — use it instead of new searches:
|
|
101
|
+
- `Deps:` what this file imports (with key symbols per import)
|
|
102
|
+
- `Used by:` which files import this one
|
|
103
|
+
- `Calls:` functions this chunk invokes
|
|
104
|
+
- `ID:` pass to `get_chunk` / `get_chunk_summary` — never re-search what you already found.
|
|
105
|
+
|
|
106
|
+
A result with node type `re_export` means the symbol is re-exported from a
|
|
107
|
+
dependency (e.g. `fastapi` re-exporting Starlette's `BackgroundTasks`): the
|
|
108
|
+
implementation lives outside this repo — do not hunt for it in the codebase.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Standard workflows
|
|
113
|
+
|
|
114
|
+
**Unfamiliar codebase** → `get_repo_map()` → pick files → `resolve_symbol` /
|
|
115
|
+
`search_code` to drill in.
|
|
116
|
+
|
|
117
|
+
**"Where is X implemented?"** → `search_code(behavioural query, detail:
|
|
118
|
+
"signatures")` → `get_chunk_summary(best id)` → `get_chunk(id)` only if you
|
|
119
|
+
must see the body.
|
|
120
|
+
|
|
121
|
+
**Safe refactor** → `get_call_graph("target")` → review callers →
|
|
122
|
+
`get_chunk(callerId)` for each call site you need to update → edit with your
|
|
123
|
+
normal tools.
|
|
124
|
+
|
|
125
|
+
**Understanding one file** → `get_file_skeleton(path)` (all exports + line
|
|
126
|
+
numbers, no bodies) → drill into specific symbols.
|
|
127
|
+
|
|
128
|
+
**Debugging a behaviour** → natural-language `search_code` describing the
|
|
129
|
+
symptom's mechanism → follow `Calls:` topology instead of re-searching.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Anti-patterns (each of these is a bug in your behaviour)
|
|
134
|
+
|
|
135
|
+
- ❌ Reading a file as your *first* move on any question.
|
|
136
|
+
- ❌ `search_code("validateToken")` — you know the name; that's `resolve_symbol`.
|
|
137
|
+
- ❌ Re-searching a concept you already have a chunk ID for.
|
|
138
|
+
- ❌ `detail: "full"` by default — signatures first, always.
|
|
139
|
+
- ❌ Editing an exported signature without `get_call_graph` first.
|
|
140
|
+
- ❌ Giving up after one keyword query without trying a behavioural rephrase.
|
|
141
|
+
- ❌ Ignoring `Used by:` / `Calls:` topology and issuing new searches for it.
|
|
142
|
+
- ❌ Re-indexing after edits: Do not tell the user to re-index or attempt to re-index after you modify a file. Graph Indexer has a live daemon (watch-daemon.mjs) that instantly updates the index in the background using SQLite WAL. Your next search will automatically see your changes.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Fallback to native tools — the ONLY permitted cases
|
|
147
|
+
|
|
148
|
+
You may use native file/search tools **only** when one of these is true:
|
|
149
|
+
|
|
150
|
+
1. **The index says no.** You tried BOTH query styles (keyword + behavioural
|
|
151
|
+
sentence) and `resolve_symbol`, and the target genuinely isn't returned.
|
|
152
|
+
2. **The index is unhealthy.** `list_index_stats()` shows 0 chunks, a missing
|
|
153
|
+
index, or a clearly stale index that the daemon isn't updating — tell the
|
|
154
|
+
user to run `npm run mcp:index`, then fall back for now.
|
|
155
|
+
3. **Non-code files.** Configs, lockfiles, markdown, data files, generated
|
|
156
|
+
artifacts — the index covers source code chunks; plain files are fair game.
|
|
157
|
+
4. **You need exact current file state for an edit** you are about to make
|
|
158
|
+
(e.g. precise surrounding lines to produce a diff) — *after* the index
|
|
159
|
+
located the file and line range for you.
|
|
160
|
+
|
|
161
|
+
When you do fall back, scope it: read the one file the index pointed you to —
|
|
162
|
+
never directory-walk or repo-grep what the index already answered.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Quick reference
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
search_code(query, exact_tokens?, detail?, top_k?, rerank?) hybrid search, topology included
|
|
170
|
+
resolve_symbol(symbol) O(1) exact definition lookup
|
|
171
|
+
get_chunk(chunk_id, view?) full body of one chunk
|
|
172
|
+
get_chunk_summary(chunk_id, expand_calls?) interface only, ~50 tok
|
|
173
|
+
get_file_skeleton(file_path) all exports of a file, no bodies
|
|
174
|
+
get_call_graph(target_function) every caller repo-wide
|
|
175
|
+
get_repo_map(path_filter?, max_files?) PageRank-ordered codebase map
|
|
176
|
+
list_index_stats() index health + search mode
|
|
177
|
+
graph://dependencies/{file_path} bidirectional import topology
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Detail levels:** `signatures` ~20 tok/result · `smart` (default) ~150 ·
|
|
181
|
+
`full` ~300. **Search modes:** hybrid (semantic + lexical) when Ollama runs;
|
|
182
|
+
lexical-only otherwise — in lexical-only mode prefer keyword-style queries.
|