rho-graph 0.1.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.
Files changed (118) hide show
  1. package/README.md +277 -0
  2. package/bin/rho-graph.js +2 -0
  3. package/dist/cli/commands/index-cmd.d.ts +2 -0
  4. package/dist/cli/commands/index-cmd.js +45 -0
  5. package/dist/cli/commands/index-cmd.js.map +1 -0
  6. package/dist/cli/commands/init.d.ts +3 -0
  7. package/dist/cli/commands/init.js +55 -0
  8. package/dist/cli/commands/init.js.map +1 -0
  9. package/dist/cli/commands/install-hook.d.ts +3 -0
  10. package/dist/cli/commands/install-hook.js +37 -0
  11. package/dist/cli/commands/install-hook.js.map +1 -0
  12. package/dist/cli/commands/install-mcp.d.ts +3 -0
  13. package/dist/cli/commands/install-mcp.js +32 -0
  14. package/dist/cli/commands/install-mcp.js.map +1 -0
  15. package/dist/cli/commands/query.d.ts +2 -0
  16. package/dist/cli/commands/query.js +92 -0
  17. package/dist/cli/commands/query.js.map +1 -0
  18. package/dist/cli/commands/setup.d.ts +2 -0
  19. package/dist/cli/commands/setup.js +15 -0
  20. package/dist/cli/commands/setup.js.map +1 -0
  21. package/dist/cli/commands/status.d.ts +2 -0
  22. package/dist/cli/commands/status.js +40 -0
  23. package/dist/cli/commands/status.js.map +1 -0
  24. package/dist/cli/commands/visualize.d.ts +2 -0
  25. package/dist/cli/commands/visualize.js +45 -0
  26. package/dist/cli/commands/visualize.js.map +1 -0
  27. package/dist/cli/index.d.ts +1 -0
  28. package/dist/cli/index.js +32 -0
  29. package/dist/cli/index.js.map +1 -0
  30. package/dist/config.d.ts +22 -0
  31. package/dist/config.js +95 -0
  32. package/dist/config.js.map +1 -0
  33. package/dist/db/connection.d.ts +13 -0
  34. package/dist/db/connection.js +25 -0
  35. package/dist/db/connection.js.map +1 -0
  36. package/dist/db/queries.d.ts +106 -0
  37. package/dist/db/queries.js +247 -0
  38. package/dist/db/queries.js.map +1 -0
  39. package/dist/db/schema.d.ts +2 -0
  40. package/dist/db/schema.js +22 -0
  41. package/dist/db/schema.js.map +1 -0
  42. package/dist/docker/neo4j.d.ts +5 -0
  43. package/dist/docker/neo4j.js +85 -0
  44. package/dist/docker/neo4j.js.map +1 -0
  45. package/dist/indexer/batch-writer.d.ts +35 -0
  46. package/dist/indexer/batch-writer.js +202 -0
  47. package/dist/indexer/batch-writer.js.map +1 -0
  48. package/dist/indexer/extractor.d.ts +35 -0
  49. package/dist/indexer/extractor.js +141 -0
  50. package/dist/indexer/extractor.js.map +1 -0
  51. package/dist/indexer/graph-writer.d.ts +12 -0
  52. package/dist/indexer/graph-writer.js +75 -0
  53. package/dist/indexer/graph-writer.js.map +1 -0
  54. package/dist/indexer/import-resolver.d.ts +8 -0
  55. package/dist/indexer/import-resolver.js +80 -0
  56. package/dist/indexer/import-resolver.js.map +1 -0
  57. package/dist/indexer/index.d.ts +21 -0
  58. package/dist/indexer/index.js +262 -0
  59. package/dist/indexer/index.js.map +1 -0
  60. package/dist/indexer/language-map.json +101 -0
  61. package/dist/indexer/parallel-pipeline.d.ts +41 -0
  62. package/dist/indexer/parallel-pipeline.js +82 -0
  63. package/dist/indexer/parallel-pipeline.js.map +1 -0
  64. package/dist/indexer/parser.d.ts +9 -0
  65. package/dist/indexer/parser.js +85 -0
  66. package/dist/indexer/parser.js.map +1 -0
  67. package/dist/indexer/staleness.d.ts +12 -0
  68. package/dist/indexer/staleness.js +60 -0
  69. package/dist/indexer/staleness.js.map +1 -0
  70. package/dist/mcp/index.d.ts +1 -0
  71. package/dist/mcp/index.js +38 -0
  72. package/dist/mcp/index.js.map +1 -0
  73. package/dist/mcp/staleness-check.d.ts +7 -0
  74. package/dist/mcp/staleness-check.js +31 -0
  75. package/dist/mcp/staleness-check.js.map +1 -0
  76. package/dist/mcp/tools/get-callees.d.ts +3 -0
  77. package/dist/mcp/tools/get-callees.js +34 -0
  78. package/dist/mcp/tools/get-callees.js.map +1 -0
  79. package/dist/mcp/tools/get-callers.d.ts +3 -0
  80. package/dist/mcp/tools/get-callers.js +34 -0
  81. package/dist/mcp/tools/get-callers.js.map +1 -0
  82. package/dist/mcp/tools/get-class.d.ts +3 -0
  83. package/dist/mcp/tools/get-class.js +42 -0
  84. package/dist/mcp/tools/get-class.js.map +1 -0
  85. package/dist/mcp/tools/get-dependencies.d.ts +3 -0
  86. package/dist/mcp/tools/get-dependencies.js +26 -0
  87. package/dist/mcp/tools/get-dependencies.js.map +1 -0
  88. package/dist/mcp/tools/get-dependents.d.ts +3 -0
  89. package/dist/mcp/tools/get-dependents.js +26 -0
  90. package/dist/mcp/tools/get-dependents.js.map +1 -0
  91. package/dist/mcp/tools/get-file-structure.d.ts +3 -0
  92. package/dist/mcp/tools/get-file-structure.js +33 -0
  93. package/dist/mcp/tools/get-file-structure.js.map +1 -0
  94. package/dist/mcp/tools/get-function.d.ts +3 -0
  95. package/dist/mcp/tools/get-function.js +34 -0
  96. package/dist/mcp/tools/get-function.js.map +1 -0
  97. package/dist/mcp/tools/get-repo-structure.d.ts +3 -0
  98. package/dist/mcp/tools/get-repo-structure.js +39 -0
  99. package/dist/mcp/tools/get-repo-structure.js.map +1 -0
  100. package/dist/mcp/tools/reindex.d.ts +4 -0
  101. package/dist/mcp/tools/reindex.js +27 -0
  102. package/dist/mcp/tools/reindex.js.map +1 -0
  103. package/dist/mcp/tools/search-code.d.ts +3 -0
  104. package/dist/mcp/tools/search-code.js +43 -0
  105. package/dist/mcp/tools/search-code.js.map +1 -0
  106. package/dist/visualize/public/graph.js +445 -0
  107. package/dist/visualize/public/index.html +88 -0
  108. package/dist/visualize/queries.d.ts +14 -0
  109. package/dist/visualize/queries.js +84 -0
  110. package/dist/visualize/queries.js.map +1 -0
  111. package/dist/visualize/server.d.ts +19 -0
  112. package/dist/visualize/server.js +293 -0
  113. package/dist/visualize/server.js.map +1 -0
  114. package/docker-compose.yml +16 -0
  115. package/package.json +69 -0
  116. package/src/indexer/language-map.json +128 -0
  117. package/src/visualize/public/graph.js +445 -0
  118. package/src/visualize/public/index.html +88 -0
package/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # rho-graph
2
+
3
+ > Graph-RAG code indexer for AI agents — token-efficient code search via MCP tools backed by Neo4j
4
+
5
+ Parses your codebase into a knowledge graph (functions, classes, imports, call edges) and exposes it as MCP tools that Claude Code, Cursor, and other AI agents can use instead of reading raw files. A graph traversal to find callers of a function costs a handful of tokens; reading every file to find the same thing costs thousands.
6
+
7
+ ---
8
+
9
+ ## How it works
10
+
11
+ ```
12
+ Your code
13
+
14
+ ▼ tree-sitter (WASM, no native deps)
15
+ Parse AST
16
+
17
+ ▼ extractor
18
+ Functions · Classes · Imports · Call edges
19
+
20
+ ▼ graph-writer
21
+ Neo4j property graph
22
+
23
+ ▼ MCP server (stdio)
24
+ Claude Code / Cursor get 10 graph tools
25
+ ```
26
+
27
+ Files are parsed with [tree-sitter](https://tree-sitter.github.io/) via WASM bindings — no native compilation required. The resulting entities are written to Neo4j with uniqueness constraints and full-text indexes so queries are fast even on large repos.
28
+
29
+ Incremental indexing checks files against stored content hashes and mtimes so only changed files are re-parsed on subsequent runs.
30
+
31
+ ---
32
+
33
+ ## Supported languages
34
+
35
+ TypeScript · TSX · JavaScript · Python · Go · Java · Rust · C · C++ · Ruby · GraphQL · YAML · JSON · Markdown
36
+
37
+ ---
38
+
39
+ ## Quick start
40
+
41
+ ```bash
42
+ # Install globally
43
+ npm install -g rho-graph
44
+
45
+ # In your repo: start Neo4j, index, register MCP, install git hook
46
+ rho-graph setup
47
+ ```
48
+
49
+ That's it. Claude Code and Cursor will now have access to the graph tools for the current repo.
50
+
51
+ **Prerequisites:** Docker (for the managed Neo4j instance) and Node.js >= 18.
52
+
53
+ ---
54
+
55
+ ## CLI reference
56
+
57
+ | Command | Description |
58
+ |---|---|
59
+ | `setup` | One-shot: runs `init` + `install-mcp` + `install-hook` |
60
+ | `init` | Start Neo4j (Docker) and index the current repo |
61
+ | `index [path]` | Re-index (full or `--changed` for incremental) |
62
+ | `status` | Show graph stats: repos, files by language, function/class counts |
63
+ | `install-mcp` | Register the MCP server in `~/.claude/settings.json` and `~/.cursor/mcp.json` |
64
+ | `install-hook` | Install `.git/hooks/post-commit` to auto-reindex on commit |
65
+ | `query [cypher]` | Run a Cypher query or open an interactive REPL |
66
+ | `visualize` | Open a browser-based graph visualization on port 3333 |
67
+ | `mcp-serve` | Start the MCP server (called automatically by Claude Code / Cursor) |
68
+
69
+ ### `index` options
70
+
71
+ ```bash
72
+ rho-graph index # full reindex
73
+ rho-graph index --changed # only files changed since last index
74
+ rho-graph index src/auth # index a subtree
75
+ ```
76
+
77
+ ### `query` examples
78
+
79
+ ```bash
80
+ # Shorthand flags
81
+ rho-graph query --callers processPayment
82
+ rho-graph query --dependencies src/auth/middleware.ts
83
+ rho-graph query --structure
84
+
85
+ # Raw Cypher
86
+ rho-graph query "MATCH (f:Function) WHERE f.name STARTS WITH 'get' RETURN f.name, f.filePath LIMIT 20"
87
+
88
+ # Interactive REPL
89
+ rho-graph query
90
+ cypher> MATCH (c:Class)-[:CONTAINS]->(f:Function) RETURN c.name, count(f) ORDER BY count(f) DESC
91
+ ```
92
+
93
+ ### `visualize` options
94
+
95
+ ```bash
96
+ rho-graph visualize # full graph
97
+ rho-graph visualize --repo my-service # filter by repo
98
+ rho-graph visualize --file src/api.ts # focus on a file
99
+ rho-graph visualize --function handleRequest
100
+ rho-graph visualize --port 4000
101
+ ```
102
+
103
+ ---
104
+
105
+ ## MCP tools
106
+
107
+ Once installed, Claude Code and Cursor have access to these tools. They are designed to be used instead of reading source files.
108
+
109
+ | Tool | What it does |
110
+ |---|---|
111
+ | `search_code` | Full-text search across function/class names, signatures, and code snippets |
112
+ | `get_function` | Retrieve a function's source, signature, file, and line range |
113
+ | `get_class` | Retrieve a class definition and its members |
114
+ | `get_file_structure` | List all functions and classes defined in a file |
115
+ | `get_callers` | Find every function that calls a given function |
116
+ | `get_callees` | Find every function called by a given function |
117
+ | `get_dependencies` | Files imported by a given file |
118
+ | `get_dependents` | Files that import a given file |
119
+ | `get_repo_structure` | High-level view: repos, files per language |
120
+ | `reindex` | Trigger incremental reindex from within a conversation |
121
+
122
+ ### Example agent workflow
123
+
124
+ ```
125
+ Agent: search_code("authentication middleware")
126
+ → finds handleAuth in src/auth/middleware.ts
127
+
128
+ Agent: get_callers("handleAuth")
129
+ → finds 3 routes that depend on it
130
+
131
+ Agent: get_function("handleAuth", "src/auth/middleware.ts")
132
+ → retrieves the full source + signature
133
+
134
+ Agent: get_dependencies("src/auth/middleware.ts")
135
+ → finds what it imports, traces the dependency chain
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Graph schema
141
+
142
+ **Nodes**
143
+
144
+ | Label | Key properties |
145
+ |---|---|
146
+ | `Repository` | `path`, `name`, `lastIndexedAt` |
147
+ | `File` | `path`, `relativePath`, `language`, `hash`, `lastModified` |
148
+ | `Function` | `name`, `filePath`, `signature`, `snippet`, `startLine`, `endLine` |
149
+ | `Class` | `name`, `filePath`, `snippet`, `startLine`, `endLine` |
150
+
151
+ **Relationships**
152
+
153
+ | Relationship | Meaning |
154
+ |---|---|
155
+ | `(Repository)-[:CONTAINS_FILE]->(File)` | Repo owns file |
156
+ | `(File)-[:CONTAINS]->(Function\|Class)` | File contains top-level definition |
157
+ | `(Class)-[:HAS_METHOD]->(Function)` | Class method |
158
+ | `(Function)-[:CALLS]->(Function)` | Call edge |
159
+ | `(File)-[:IMPORTS]->(File)` | Import edge |
160
+ | `(File)-[:IMPORTS_SYMBOL]->(Function\|Class)` | Symbol-level import |
161
+
162
+ **Indexes**
163
+
164
+ - Uniqueness constraints on `Repository.path` and `File.path`
165
+ - B-tree indexes on `Function.name`, `Class.name`, `File.language`
166
+ - Full-text index (`code_search`) on `Function.name`, `Function.snippet`, `Function.docstring`, `Class.name`, `Class.snippet`, `Class.docstring`
167
+
168
+ ---
169
+
170
+ ## Configuration
171
+
172
+ Config is resolved in this order (later values win):
173
+
174
+ 1. Built-in defaults
175
+ 2. `~/.config/rho-graph/config.json` (global)
176
+ 3. `.rho-graph.json` in the repo root (per-repo)
177
+ 4. Environment variables
178
+
179
+ ### Full config reference
180
+
181
+ ```json
182
+ {
183
+ "neo4j": {
184
+ "uri": "bolt://localhost:7687",
185
+ "username": "neo4j",
186
+ "password": "rho-graph",
187
+ "managed": true
188
+ },
189
+ "index": {
190
+ "include": ["**/*"],
191
+ "exclude": ["node_modules", "dist", "vendor", ".git", "build", "__pycache__"],
192
+ "languages": "auto"
193
+ },
194
+ "repos": []
195
+ }
196
+ ```
197
+
198
+ `managed: true` means Neo4j is started automatically via Docker Compose. Set to `false` to connect to an existing instance.
199
+
200
+ ### Environment variable overrides
201
+
202
+ ```bash
203
+ NEO4J_URI=bolt://my-server:7687
204
+ NEO4J_USERNAME=neo4j
205
+ NEO4J_PASSWORD=secret
206
+ ```
207
+
208
+ ### Per-repo config example
209
+
210
+ ```json
211
+ {
212
+ "index": {
213
+ "include": ["src/**/*", "lib/**/*"],
214
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
215
+ }
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Bring your own Neo4j
222
+
223
+ If you already have Neo4j running (local, Aura, Docker Compose, etc.):
224
+
225
+ ```json
226
+ {
227
+ "neo4j": {
228
+ "uri": "bolt://localhost:7687",
229
+ "username": "neo4j",
230
+ "password": "your-password",
231
+ "managed": false
232
+ }
233
+ }
234
+ ```
235
+
236
+ The Docker Compose file is included in the package if you want to run it manually:
237
+
238
+ ```bash
239
+ docker compose -f node_modules/rho-graph/docker-compose.yml up -d
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Automatic reindexing
245
+
246
+ The `install-hook` command writes a `post-commit` git hook that runs `rho-graph index --changed` in the background after every commit. Only files that changed (by content hash) are re-parsed, so the overhead is minimal.
247
+
248
+ If you already have a `post-commit` hook, the command appends to it rather than replacing it.
249
+
250
+ ---
251
+
252
+ ## Development
253
+
254
+ ```bash
255
+ git clone https://github.com/rhofield/rho-graph
256
+ cd rho-graph
257
+ npm install
258
+
259
+ # Start Neo4j
260
+ docker compose up -d
261
+
262
+ # Build
263
+ npm run build
264
+
265
+ # Watch mode
266
+ npm run dev
267
+
268
+ # Tests
269
+ npm test
270
+
271
+ # Type check
272
+ npm run lint
273
+ ```
274
+
275
+ ## License
276
+
277
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/cli/index.js";
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerIndexCommand(program: Command): void;
@@ -0,0 +1,45 @@
1
+ import ora from "ora";
2
+ import { resolve } from "node:path";
3
+ import { loadConfig } from "../../config.js";
4
+ import { createConnection } from "../../db/connection.js";
5
+ import { indexRepository } from "../../indexer/index.js";
6
+ export function registerIndexCommand(program) {
7
+ program
8
+ .command("index")
9
+ .description("Re-index the repository")
10
+ .option("--changed", "Only index changed files")
11
+ .option("--path <path>", "Index a specific path")
12
+ .option("--repo <repoPath>", "Index a different repository")
13
+ .option("--concurrency <n>", "Number of parallel parse tasks", "8")
14
+ .option("--max-memory <mb>", "Max buffer memory in MB before backpressure", "8192")
15
+ .action(async (opts) => {
16
+ const repoPath = resolve(opts.repo || ".");
17
+ const config = loadConfig(repoPath);
18
+ const db = createConnection(config.neo4j);
19
+ const spinner = ora("Parsing files...").start();
20
+ const result = await indexRepository(db, repoPath, config.index, {
21
+ changedOnly: opts.changed,
22
+ specificPath: opts.path,
23
+ concurrency: parseInt(opts.concurrency, 10),
24
+ maxMemoryMB: parseInt(opts.maxMemory, 10),
25
+ onProgress: (current, total) => {
26
+ spinner.text = `Parsing files... ${current}/${total}`;
27
+ },
28
+ onFlushProgress: (completed, total) => {
29
+ spinner.text = `Writing to database... ${completed}/${total} batches`;
30
+ },
31
+ });
32
+ const orphanSuffix = result.orphansRemoved > 0
33
+ ? ` (removed ${result.orphansRemoved} orphaned files)`
34
+ : "";
35
+ spinner.succeed(`Indexed ${result.filesIndexed} files, ${result.functionsFound} functions, ${result.classesFound} classes${orphanSuffix}`);
36
+ if (result.errors.length > 0) {
37
+ console.log(`\n${result.errors.length} files had errors:`);
38
+ for (const err of result.errors.slice(0, 5)) {
39
+ console.log(` ${err.file}: ${err.error}`);
40
+ }
41
+ }
42
+ await db.close();
43
+ });
44
+ }
45
+ //# sourceMappingURL=index-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-cmd.js","sourceRoot":"","sources":["../../../src/cli/commands/index-cmd.ts"],"names":[],"mappings":"AAEA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;SAC/C,MAAM,CAAC,eAAe,EAAE,uBAAuB,CAAC;SAChD,MAAM,CAAC,mBAAmB,EAAE,8BAA8B,CAAC;SAC3D,MAAM,CAAC,mBAAmB,EAAE,gCAAgC,EAAE,GAAG,CAAC;SAClE,MAAM,CAAC,mBAAmB,EAAE,6CAA6C,EAAE,MAAM,CAAC;SAClF,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE1C,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,CAAC,CAAC,KAAK,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,EAAE;YAC/D,WAAW,EAAE,IAAI,CAAC,OAAO;YACzB,YAAY,EAAE,IAAI,CAAC,IAAI;YACvB,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YAC3C,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACzC,UAAU,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;gBAC7B,OAAO,CAAC,IAAI,GAAG,oBAAoB,OAAO,IAAI,KAAK,EAAE,CAAC;YACxD,CAAC;YACD,eAAe,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;gBACpC,OAAO,CAAC,IAAI,GAAG,0BAA0B,SAAS,IAAI,KAAK,UAAU,CAAC;YACxE,CAAC;SACF,CAAC,CAAC;QACH,MAAM,YAAY,GAChB,MAAM,CAAC,cAAc,GAAG,CAAC;YACvB,CAAC,CAAC,aAAa,MAAM,CAAC,cAAc,kBAAkB;YACtD,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,CAAC,OAAO,CACb,WAAW,MAAM,CAAC,YAAY,WAAW,MAAM,CAAC,cAAc,eAAe,MAAM,CAAC,YAAY,WAAW,YAAY,EAAE,CAC1H,CAAC;QAEF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,oBAAoB,CAAC,CAAC;YAC3D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAED,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function runInit(): Promise<void>;
3
+ export declare function registerInitCommand(program: Command): void;
@@ -0,0 +1,55 @@
1
+ import ora from "ora";
2
+ import { resolve, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { loadConfig } from "../../config.js";
5
+ import { createConnection } from "../../db/connection.js";
6
+ import { setupSchema } from "../../db/schema.js";
7
+ import { isDockerAvailable, startNeo4j, waitForNeo4j, } from "../../docker/neo4j.js";
8
+ import { indexRepository } from "../../indexer/index.js";
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ export async function runInit() {
11
+ const repoPath = resolve(".");
12
+ const config = loadConfig(repoPath);
13
+ if (config.neo4j.managed) {
14
+ const spinner = ora("Checking prerequisites...").start();
15
+ if (!isDockerAvailable()) {
16
+ spinner.fail("Docker is not available. Install Docker or set neo4j.managed to false.");
17
+ process.exit(1);
18
+ }
19
+ spinner.succeed("Docker available");
20
+ const neo4jSpinner = ora("Starting Neo4j...").start();
21
+ const composePath = resolve(__dirname, "../../../docker-compose.yml");
22
+ startNeo4j(composePath);
23
+ const ready = await waitForNeo4j(config.neo4j.uri, config.neo4j.username, config.neo4j.password);
24
+ if (!ready) {
25
+ neo4jSpinner.fail("Neo4j failed to start");
26
+ process.exit(1);
27
+ }
28
+ neo4jSpinner.succeed("Neo4j running");
29
+ }
30
+ const db = createConnection(config.neo4j);
31
+ const schemaSpinner = ora("Setting up schema...").start();
32
+ await setupSchema(db);
33
+ schemaSpinner.succeed("Schema ready");
34
+ const indexSpinner = ora("Indexing repository...").start();
35
+ const result = await indexRepository(db, repoPath, config.index, {
36
+ onProgress: (current, total) => {
37
+ indexSpinner.text = `Indexing... ${current}/${total}`;
38
+ },
39
+ });
40
+ indexSpinner.succeed(`Indexed ${result.filesIndexed} files, ${result.functionsFound} functions, ${result.classesFound} classes`);
41
+ if (result.errors.length > 0) {
42
+ console.log(`\n${result.errors.length} files had errors:`);
43
+ for (const err of result.errors.slice(0, 5)) {
44
+ console.log(` ${err.file}: ${err.error}`);
45
+ }
46
+ }
47
+ await db.close();
48
+ }
49
+ export function registerInitCommand(program) {
50
+ program
51
+ .command("init")
52
+ .description("Initialize Neo4j and index the current repository")
53
+ .action(runInit);
54
+ }
55
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function runInstallHook(): Promise<void>;
3
+ export declare function registerInstallHookCommand(program: Command): void;
@@ -0,0 +1,37 @@
1
+ import { writeFileSync, readFileSync, existsSync, chmodSync, } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import ora from "ora";
4
+ const HOOK_CONTENT = `#!/bin/sh
5
+ # code-graph-rag: re-index changed files after commit
6
+ code-graph-rag index --changed &
7
+ `;
8
+ export async function runInstallHook() {
9
+ const spinner = ora("Installing git hook...").start();
10
+ const repoRoot = resolve(".");
11
+ const hookDir = join(repoRoot, ".git", "hooks");
12
+ if (!existsSync(join(repoRoot, ".git"))) {
13
+ spinner.fail("Not a git repository");
14
+ process.exit(1);
15
+ }
16
+ const hookPath = join(hookDir, "post-commit");
17
+ if (existsSync(hookPath)) {
18
+ const existing = readFileSync(hookPath, "utf-8");
19
+ if (existing.includes("code-graph-rag")) {
20
+ spinner.succeed("Hook already installed");
21
+ return;
22
+ }
23
+ writeFileSync(hookPath, existing + "\n" + HOOK_CONTENT);
24
+ }
25
+ else {
26
+ writeFileSync(hookPath, HOOK_CONTENT);
27
+ }
28
+ chmodSync(hookPath, 0o755);
29
+ spinner.succeed(`Hook installed at ${hookPath}`);
30
+ }
31
+ export function registerInstallHookCommand(program) {
32
+ program
33
+ .command("install-hook")
34
+ .description("Install git post-commit hook for automatic re-indexing")
35
+ .action(runInstallHook);
36
+ }
37
+ //# sourceMappingURL=install-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hook.js","sourceRoot":"","sources":["../../../src/cli/commands/install-hook.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,YAAY,EACZ,UAAU,EACV,SAAS,GACV,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,MAAM,YAAY,GAAG;;;CAGpB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,OAAO,GAAG,GAAG,CAAC,wBAAwB,CAAC,CAAC,KAAK,EAAE,CAAC;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAE9C,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;YAC1C,OAAO;QACT,CAAC;QACD,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,YAAY,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,aAAa,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACxC,CAAC;IAED,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3B,OAAO,CAAC,OAAO,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,OAAgB;IACzD,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,wDAAwD,CAAC;SACrE,MAAM,CAAC,cAAc,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function runInstallMcp(): Promise<void>;
3
+ export declare function registerInstallMcpCommand(program: Command): void;
@@ -0,0 +1,32 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import ora from "ora";
5
+ export async function runInstallMcp() {
6
+ const spinner = ora("Installing MCP server...").start();
7
+ const claudeDir = join(homedir(), ".claude");
8
+ const settingsPath = join(claudeDir, "settings.json");
9
+ if (!existsSync(claudeDir)) {
10
+ mkdirSync(claudeDir, { recursive: true });
11
+ }
12
+ let settings = {};
13
+ if (existsSync(settingsPath)) {
14
+ settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
15
+ }
16
+ const mcpServers = settings.mcpServers || {};
17
+ mcpServers["code-graph-rag"] = {
18
+ command: "npx",
19
+ args: ["code-graph-rag", "mcp-serve"],
20
+ type: "stdio",
21
+ };
22
+ settings.mcpServers = mcpServers;
23
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
24
+ spinner.succeed("MCP server registered in ~/.claude/settings.json");
25
+ }
26
+ export function registerInstallMcpCommand(program) {
27
+ program
28
+ .command("install-mcp")
29
+ .description("Register the MCP server in Claude Code settings")
30
+ .action(runInstallMcp);
31
+ }
32
+ //# sourceMappingURL=install-mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-mcp.js","sourceRoot":"","sources":["../../../src/cli/commands/install-mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,OAAO,GAAG,GAAG,CAAC,0BAA0B,CAAC,CAAC,KAAK,EAAE,CAAC;IAExD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAEtD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,QAAQ,GAA4B,EAAE,CAAC;IAC3C,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,UAAU,GACb,QAAQ,CAAC,UAAsC,IAAI,EAAE,CAAC;IACzD,UAAU,CAAC,gBAAgB,CAAC,GAAG;QAC7B,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,CAAC,gBAAgB,EAAE,WAAW,CAAC;QACrC,IAAI,EAAE,OAAO;KACd,CAAC;IACF,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;IAEjC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAAgB;IACxD,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,iDAAiD,CAAC;SAC9D,MAAM,CAAC,aAAa,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerQueryCommand(program: Command): void;
@@ -0,0 +1,92 @@
1
+ import { resolve } from "node:path";
2
+ import { createInterface } from "node:readline";
3
+ import { loadConfig } from "../../config.js";
4
+ import { createConnection } from "../../db/connection.js";
5
+ export function registerQueryCommand(program) {
6
+ program
7
+ .command("query [cypher]")
8
+ .description("Run Cypher queries against the graph (interactive REPL if no query given)")
9
+ .option("--callers <functionName>", "Find all callers of a function")
10
+ .option("--dependencies <filePath>", "Find dependencies of a file")
11
+ .option("--structure", "Show high-level repo structure")
12
+ .action(async (cypher, opts) => {
13
+ const repoPath = resolve(".");
14
+ const config = loadConfig(repoPath);
15
+ const db = createConnection(config.neo4j);
16
+ const healthy = await db.healthCheck();
17
+ if (!healthy) {
18
+ console.log("Neo4j is not running. Run `code-graph-rag init` to start it.");
19
+ process.exit(1);
20
+ }
21
+ if (opts.callers) {
22
+ cypher =
23
+ "MATCH (caller:Function)-[:CALLS]->(callee:Function {name: $name}) RETURN caller.name AS caller, caller.filePath AS file, caller.startLine AS line";
24
+ }
25
+ else if (opts.dependencies) {
26
+ cypher =
27
+ "MATCH (f:File)-[:IMPORTS]->(dep:File) WHERE f.relativePath = $path OR f.path ENDS WITH $path RETURN dep.relativePath AS dependency";
28
+ }
29
+ else if (opts.structure) {
30
+ cypher =
31
+ "MATCH (r:Repository)-[:CONTAINS_FILE]->(f:File) RETURN r.name AS repo, f.language AS language, count(f) AS files ORDER BY files DESC";
32
+ }
33
+ if (cypher) {
34
+ const params = {};
35
+ if (opts.callers)
36
+ params.name = opts.callers;
37
+ if (opts.dependencies)
38
+ params.path = opts.dependencies;
39
+ await runQuery(db, cypher, params);
40
+ await db.close();
41
+ return;
42
+ }
43
+ // Interactive REPL
44
+ console.log("code-graph-rag query REPL (type 'exit' to quit)\n");
45
+ const rl = createInterface({
46
+ input: process.stdin,
47
+ output: process.stdout,
48
+ prompt: "cypher> ",
49
+ });
50
+ rl.prompt();
51
+ rl.on("line", async (line) => {
52
+ const trimmed = line.trim();
53
+ if (trimmed === "exit" || trimmed === "quit") {
54
+ await db.close();
55
+ rl.close();
56
+ return;
57
+ }
58
+ if (trimmed) {
59
+ await runQuery(db, trimmed, {});
60
+ }
61
+ rl.prompt();
62
+ });
63
+ });
64
+ }
65
+ async function runQuery(db, cypher, params) {
66
+ const session = db.session();
67
+ try {
68
+ const result = await session.run(cypher, params);
69
+ if (result.records.length === 0) {
70
+ console.log("(no results)");
71
+ return;
72
+ }
73
+ const keys = result.records[0].keys;
74
+ console.log(keys.join("\t"));
75
+ console.log(keys.map(() => "---").join("\t"));
76
+ for (const record of result.records) {
77
+ const values = keys.map((k) => {
78
+ const v = record.get(k);
79
+ return typeof v === "object" ? JSON.stringify(v) : String(v);
80
+ });
81
+ console.log(values.join("\t"));
82
+ }
83
+ console.log(`\n${result.records.length} row(s)`);
84
+ }
85
+ catch (error) {
86
+ console.error(`Query error: ${error instanceof Error ? error.message : error}`);
87
+ }
88
+ finally {
89
+ await session.close();
90
+ }
91
+ }
92
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/cli/commands/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerSetupCommand(parent: Command): void;
@@ -0,0 +1,15 @@
1
+ import { runInit } from "./init.js";
2
+ import { runInstallMcp } from "./install-mcp.js";
3
+ import { runInstallHook } from "./install-hook.js";
4
+ export function registerSetupCommand(parent) {
5
+ parent
6
+ .command("setup")
7
+ .description("Full setup: init + install MCP server + install git hook")
8
+ .action(async () => {
9
+ await runInit();
10
+ await runInstallMcp();
11
+ await runInstallHook();
12
+ console.log("\nReady! Your AI agent now has access to graph-powered code search.");
13
+ });
14
+ }
15
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,UAAU,oBAAoB,CAAC,MAAe;IAClD,MAAM;SACH,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,0DAA0D,CAAC;SACvE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,OAAO,EAAE,CAAC;QAChB,MAAM,aAAa,EAAE,CAAC;QACtB,MAAM,cAAc,EAAE,CAAC;QAEvB,OAAO,CAAC,GAAG,CACT,qEAAqE,CACtE,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerStatusCommand(program: Command): void;