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
@@ -0,0 +1,85 @@
1
+ // src/indexer/parser.ts
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { extname, resolve, join, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import Parser from "web-tree-sitter";
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ let parser = null;
8
+ const languageCache = new Map();
9
+ const EXTENSION_MAP = {
10
+ ".ts": "typescript",
11
+ ".tsx": "tsx",
12
+ ".js": "javascript",
13
+ ".jsx": "javascript",
14
+ ".py": "python",
15
+ ".go": "go",
16
+ ".java": "java",
17
+ ".rs": "rust",
18
+ ".c": "c",
19
+ ".h": "c",
20
+ ".cpp": "cpp",
21
+ ".hpp": "cpp",
22
+ ".cc": "cpp",
23
+ ".cs": "c_sharp",
24
+ ".rb": "ruby",
25
+ ".php": "php",
26
+ ".swift": "swift",
27
+ ".kt": "kotlin",
28
+ ".scala": "scala",
29
+ ".graphql": "graphql",
30
+ ".gql": "graphql",
31
+ ".html": "html",
32
+ ".css": "css",
33
+ ".yaml": "yaml",
34
+ ".yml": "yaml",
35
+ ".json": "json",
36
+ ".sql": "sql",
37
+ ".sh": "bash",
38
+ ".bash": "bash",
39
+ ".lua": "lua",
40
+ ".zig": "zig",
41
+ ".ex": "elixir",
42
+ ".exs": "elixir",
43
+ ".dart": "dart",
44
+ };
45
+ export function detectLanguage(filePath) {
46
+ const ext = extname(filePath).toLowerCase();
47
+ return EXTENSION_MAP[ext] ?? null;
48
+ }
49
+ export async function initParser() {
50
+ if (parser)
51
+ return;
52
+ await Parser.init();
53
+ parser = new Parser();
54
+ }
55
+ async function loadLanguage(languageName) {
56
+ if (languageCache.has(languageName)) {
57
+ return languageCache.get(languageName);
58
+ }
59
+ const wasmPath = join(__dirname, "../../node_modules/tree-sitter-wasms/out", `tree-sitter-${languageName}.wasm`);
60
+ if (!existsSync(wasmPath)) {
61
+ return null;
62
+ }
63
+ const language = await Parser.Language.load(wasmPath);
64
+ languageCache.set(languageName, language);
65
+ return language;
66
+ }
67
+ export async function parseFile(filePath) {
68
+ if (!parser) {
69
+ await initParser();
70
+ }
71
+ const language = detectLanguage(filePath);
72
+ if (!language)
73
+ return null;
74
+ const absPath = resolve(filePath);
75
+ if (!existsSync(absPath))
76
+ return null;
77
+ const lang = await loadLanguage(language);
78
+ if (!lang)
79
+ return null;
80
+ parser.setLanguage(lang);
81
+ const source = readFileSync(absPath, "utf-8");
82
+ const tree = parser.parse(source);
83
+ return { tree, language, source };
84
+ }
85
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/indexer/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export declare function computeFileHash(filePath: string, content?: string | Buffer): string;
2
+ export declare function getFileMtime(filePath: string): number;
3
+ export declare function isFileStale(filePath: string, storedHash: string, storedMtime: number): boolean;
4
+ export interface GitDiffResult {
5
+ changed: string[];
6
+ deleted: string[];
7
+ error?: boolean;
8
+ }
9
+ export declare function getChangedFilesSinceCommit(repoPath: string, baseSha?: string, options?: {
10
+ includeDeleted?: boolean;
11
+ }): GitDiffResult;
12
+ export declare function getCurrentCommitSha(repoPath: string): string | null;
@@ -0,0 +1,60 @@
1
+ // src/indexer/staleness.ts
2
+ import { readFileSync, statSync, existsSync } from "node:fs";
3
+ import { createHash } from "node:crypto";
4
+ import { execFileSync } from "node:child_process";
5
+ export function computeFileHash(filePath, content) {
6
+ const data = content ?? readFileSync(filePath);
7
+ return createHash("sha256").update(data).digest("hex");
8
+ }
9
+ export function getFileMtime(filePath) {
10
+ const stat = statSync(filePath);
11
+ return stat.mtimeMs;
12
+ }
13
+ export function isFileStale(filePath, storedHash, storedMtime) {
14
+ if (!existsSync(filePath)) {
15
+ return true; // File was deleted
16
+ }
17
+ const currentMtime = getFileMtime(filePath);
18
+ if (currentMtime <= storedMtime) {
19
+ return false; // mtime hasn't changed, skip expensive hash
20
+ }
21
+ const currentHash = computeFileHash(filePath);
22
+ return currentHash !== storedHash;
23
+ }
24
+ export function getChangedFilesSinceCommit(repoPath, baseSha, options) {
25
+ const base = baseSha ?? "HEAD~1";
26
+ try {
27
+ if (options?.includeDeleted) {
28
+ const output = execFileSync("git", ["diff", "--name-status", `${base}..HEAD`], { cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
29
+ const changed = [];
30
+ const deleted = [];
31
+ for (const line of output.trim().split("\n").filter((l) => l.length > 0)) {
32
+ const [status, ...rest] = line.split("\t");
33
+ const filePath = rest.join("\t"); // handles paths with tabs (rare)
34
+ if (status === "D") {
35
+ deleted.push(filePath);
36
+ }
37
+ else {
38
+ changed.push(filePath);
39
+ }
40
+ }
41
+ return { changed, deleted };
42
+ }
43
+ const result = execFileSync("git", ["diff", "--name-only", `${base}..HEAD`], { cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n").filter((f) => f.length > 0);
44
+ return { changed: result, deleted: [] };
45
+ }
46
+ catch {
47
+ return { changed: [], deleted: [], error: true };
48
+ }
49
+ }
50
+ export function getCurrentCommitSha(repoPath) {
51
+ try {
52
+ return execFileSync("git", ["rev-parse", "HEAD"], {
53
+ cwd: repoPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"],
54
+ }).trim();
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ }
60
+ //# sourceMappingURL=staleness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staleness.js","sourceRoot":"","sources":["../../src/indexer/staleness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function startMcpServer(): Promise<void>;
@@ -0,0 +1,38 @@
1
+ // src/mcp/index.ts
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { resolve } from "node:path";
5
+ import { loadConfig } from "../config.js";
6
+ import { createConnection } from "../db/connection.js";
7
+ import { registerSearchCode } from "./tools/search-code.js";
8
+ import { registerGetFunction } from "./tools/get-function.js";
9
+ import { registerGetClass } from "./tools/get-class.js";
10
+ import { registerGetFileStructure } from "./tools/get-file-structure.js";
11
+ import { registerGetCallers } from "./tools/get-callers.js";
12
+ import { registerGetCallees } from "./tools/get-callees.js";
13
+ import { registerGetDependencies } from "./tools/get-dependencies.js";
14
+ import { registerGetDependents } from "./tools/get-dependents.js";
15
+ import { registerGetRepoStructure } from "./tools/get-repo-structure.js";
16
+ import { registerReindex } from "./tools/reindex.js";
17
+ export async function startMcpServer() {
18
+ const repoPath = resolve(".");
19
+ const config = loadConfig(repoPath);
20
+ const db = createConnection(config.neo4j);
21
+ const server = new McpServer({
22
+ name: "code-graph-rag",
23
+ version: "0.1.0",
24
+ });
25
+ registerSearchCode(server, db);
26
+ registerGetFunction(server, db);
27
+ registerGetClass(server, db);
28
+ registerGetFileStructure(server, db);
29
+ registerGetCallers(server, db);
30
+ registerGetCallees(server, db);
31
+ registerGetDependencies(server, db);
32
+ registerGetDependents(server, db);
33
+ registerGetRepoStructure(server, db);
34
+ registerReindex(server, db, config, repoPath);
35
+ const transport = new StdioServerTransport();
36
+ await server.connect(transport);
37
+ }
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE1C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/B,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAChC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7B,wBAAwB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrC,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/B,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/B,uBAAuB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACpC,qBAAqB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAClC,wBAAwB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrC,eAAe,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAE9C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { DbConnection } from "../db/connection.js";
2
+ export interface StalenessResult {
3
+ staleFiles: string[];
4
+ needsWarning: boolean;
5
+ }
6
+ export declare function checkStaleness(db: DbConnection, filePaths: string[], isStaleCheck?: (filePath: string, storedHash: string, storedMtime: number) => boolean): Promise<StalenessResult>;
7
+ export declare function formatStalenessWarning(staleCount: number): string;
@@ -0,0 +1,31 @@
1
+ import { isFileStale as defaultIsFileStale } from "../indexer/staleness.js";
2
+ const STALE_THRESHOLD = 20;
3
+ export async function checkStaleness(db, filePaths, isStaleCheck = defaultIsFileStale) {
4
+ if (filePaths.length === 0) {
5
+ return { staleFiles: [], needsWarning: false };
6
+ }
7
+ const session = db.session();
8
+ try {
9
+ const result = await session.run("MATCH (f:File) WHERE f.path IN $paths RETURN f.path AS path, f.hash AS hash, f.lastModified AS lastModified", { paths: filePaths });
10
+ const staleFiles = [];
11
+ for (const record of result.records) {
12
+ const path = record.get("path");
13
+ const hash = record.get("hash");
14
+ const lastModified = record.get("lastModified");
15
+ if (isStaleCheck(path, hash, lastModified)) {
16
+ staleFiles.push(path);
17
+ }
18
+ }
19
+ return {
20
+ staleFiles,
21
+ needsWarning: staleFiles.length > STALE_THRESHOLD,
22
+ };
23
+ }
24
+ finally {
25
+ await session.close();
26
+ }
27
+ }
28
+ export function formatStalenessWarning(staleCount) {
29
+ return `Warning: Index is stale for ${staleCount} files. Run \`code-graph-rag index --changed\` for full refresh.`;
30
+ }
31
+ //# sourceMappingURL=staleness-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staleness-check.js","sourceRoot":"","sources":["../../src/mcp/staleness-check.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE5E,MAAM,eAAe,GAAG,EAAE,CAAC;AAO3B,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAgB,EAChB,SAAmB,EACnB,eAIe,kBAAkB;IAEjC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,6GAA6G,EAC7G,EAAE,KAAK,EAAE,SAAS,EAAE,CACrB,CAAC;QAEF,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAW,CAAC;YAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAW,CAAC;YAC1C,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAW,CAAC;YAE1D,IAAI,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC;gBAC3C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,OAAO;YACL,UAAU;YACV,YAAY,EAAE,UAAU,CAAC,MAAM,GAAG,eAAe;SAClD,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,UAAkB;IACvD,OAAO,+BAA+B,UAAU,kEAAkE,CAAC;AACrH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ export declare function registerGetCallees(server: McpServer, db: DbConnection): void;
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ export function registerGetCallees(server, db) {
3
+ server.tool("get_callees", "Find all functions that a specific function calls. Use this to understand what a function depends on.", {
4
+ functionName: z.string().describe("Name of the function to find callees of"),
5
+ filePath: z.string().optional().describe("Disambiguate by file path"),
6
+ }, async ({ functionName, filePath }) => {
7
+ const session = db.session();
8
+ try {
9
+ let cypher = `
10
+ MATCH (caller:Function {name: $functionName})
11
+ `;
12
+ const params = { functionName };
13
+ if (filePath) {
14
+ cypher += ` WHERE caller.filePath = $filePath`;
15
+ params.filePath = filePath;
16
+ }
17
+ cypher += `
18
+ MATCH (caller)-[:CALLS]->(callee:Function)
19
+ RETURN callee.name AS calleeName, callee.filePath AS calleeFilePath,
20
+ callee.signature AS signature, callee.startLine AS startLine
21
+ ORDER BY calleeFilePath, calleeName
22
+ `;
23
+ const result = await session.run(cypher, params);
24
+ const records = result.records.map((r) => r.toObject());
25
+ return {
26
+ content: [{ type: "text", text: JSON.stringify(records, null, 2) }],
27
+ };
28
+ }
29
+ finally {
30
+ await session.close();
31
+ }
32
+ });
33
+ }
34
+ //# sourceMappingURL=get-callees.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-callees.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-callees.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,EAAgB;IACpE,MAAM,CAAC,IAAI,CACT,aAAa,EACb,uGAAuG,EACvG;QACE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;QAC5E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;KACtE,EACD,KAAK,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,MAAM,GAAG;;SAEZ,CAAC;YACF,MAAM,MAAM,GAA4B,EAAE,YAAY,EAAE,CAAC;YACzD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,oCAAoC,CAAC;gBAC/C,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC7B,CAAC;YACD,MAAM,IAAI;;;;;SAKT,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ export declare function registerGetCallers(server: McpServer, db: DbConnection): void;
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ export function registerGetCallers(server, db) {
3
+ server.tool("get_callers", "Find all functions that call a specific function. Use this to understand who depends on a function.", {
4
+ functionName: z.string().describe("Name of the function to find callers of"),
5
+ filePath: z.string().optional().describe("Disambiguate by file path"),
6
+ }, async ({ functionName, filePath }) => {
7
+ const session = db.session();
8
+ try {
9
+ let cypher = `
10
+ MATCH (callee:Function {name: $functionName})
11
+ `;
12
+ const params = { functionName };
13
+ if (filePath) {
14
+ cypher += ` WHERE callee.filePath = $filePath`;
15
+ params.filePath = filePath;
16
+ }
17
+ cypher += `
18
+ MATCH (caller:Function)-[:CALLS]->(callee)
19
+ RETURN caller.name AS callerName, caller.filePath AS callerFilePath,
20
+ caller.signature AS signature, caller.startLine AS startLine
21
+ ORDER BY callerFilePath, callerName
22
+ `;
23
+ const result = await session.run(cypher, params);
24
+ const records = result.records.map((r) => r.toObject());
25
+ return {
26
+ content: [{ type: "text", text: JSON.stringify(records, null, 2) }],
27
+ };
28
+ }
29
+ finally {
30
+ await session.close();
31
+ }
32
+ });
33
+ }
34
+ //# sourceMappingURL=get-callers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-callers.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-callers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,EAAgB;IACpE,MAAM,CAAC,IAAI,CACT,aAAa,EACb,qGAAqG,EACrG;QACE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;QAC5E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;KACtE,EACD,KAAK,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,MAAM,GAAG;;SAEZ,CAAC;YACF,MAAM,MAAM,GAA4B,EAAE,YAAY,EAAE,CAAC;YACzD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,oCAAoC,CAAC;gBAC/C,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC7B,CAAC;YACD,MAAM,IAAI;;;;;SAKT,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ export declare function registerGetClass(server: McpServer, db: DbConnection): void;
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ export function registerGetClass(server, db) {
3
+ server.tool("get_class", "Get a class definition with all its methods. Use this INSTEAD OF reading the file.", {
4
+ name: z.string().describe("Class name"),
5
+ filePath: z.string().optional().describe("File path for disambiguation"),
6
+ }, async ({ name, filePath }) => {
7
+ const session = db.session();
8
+ try {
9
+ let cypher = `
10
+ MATCH (c:Class {name: $name})
11
+ `;
12
+ const params = { name };
13
+ if (filePath) {
14
+ cypher += ` WHERE c.filePath = $filePath`;
15
+ params.filePath = filePath;
16
+ }
17
+ cypher += `
18
+ OPTIONAL MATCH (c)-[:HAS_METHOD]->(m:Function)
19
+ RETURN c.name AS className, c.filePath AS filePath,
20
+ c.startLine AS startLine, c.endLine AS endLine,
21
+ c.docstring AS docstring,
22
+ collect({
23
+ name: m.name,
24
+ signature: m.signature,
25
+ snippet: m.snippet,
26
+ startLine: m.startLine,
27
+ endLine: m.endLine,
28
+ docstring: m.docstring
29
+ }) AS methods
30
+ `;
31
+ const result = await session.run(cypher, params);
32
+ const records = result.records.map((r) => r.toObject());
33
+ return {
34
+ content: [{ type: "text", text: JSON.stringify(records, null, 2) }],
35
+ };
36
+ }
37
+ finally {
38
+ await session.close();
39
+ }
40
+ });
41
+ }
42
+ //# sourceMappingURL=get-class.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-class.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-class.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,EAAgB;IAClE,MAAM,CAAC,IAAI,CACT,WAAW,EACX,oFAAoF,EACpF;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;QACvC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;KACzE,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,MAAM,GAAG;;SAEZ,CAAC;YACF,MAAM,MAAM,GAA4B,EAAE,IAAI,EAAE,CAAC;YACjD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,+BAA+B,CAAC;gBAC1C,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC7B,CAAC;YACD,MAAM,IAAI;;;;;;;;;;;;;SAaT,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ export declare function registerGetDependencies(server: McpServer, db: DbConnection): void;
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerGetDependencies(server, db) {
3
+ server.tool("get_dependencies", "Get all files that a specific file imports. Use this to understand a file's dependencies.", {
4
+ filePath: z.string().describe("Absolute or relative path of the file"),
5
+ }, async ({ filePath }) => {
6
+ const session = db.session();
7
+ try {
8
+ const result = await session.run(`
9
+ MATCH (f:File)
10
+ WHERE f.path = $filePath OR f.relativePath = $filePath
11
+ MATCH (f)-[:IMPORTS]->(dep:File)
12
+ RETURN dep.path AS dependencyPath, dep.relativePath AS relativePath,
13
+ dep.language AS language
14
+ ORDER BY relativePath
15
+ `, { filePath });
16
+ const records = result.records.map((r) => r.toObject());
17
+ return {
18
+ content: [{ type: "text", text: JSON.stringify(records, null, 2) }],
19
+ };
20
+ }
21
+ finally {
22
+ await session.close();
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=get-dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-dependencies.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-dependencies.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,uBAAuB,CAAC,MAAiB,EAAE,EAAgB;IACzE,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,2FAA2F,EAC3F;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;KACvE,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;;;;;;WAOC,EACD,EAAE,QAAQ,EAAE,CACb,CAAC;YACF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ export declare function registerGetDependents(server: McpServer, db: DbConnection): void;
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerGetDependents(server, db) {
3
+ server.tool("get_dependents", "Get all files that import a specific file. Use this to understand what depends on a file before making changes.", {
4
+ filePath: z.string().describe("Absolute or relative path of the file"),
5
+ }, async ({ filePath }) => {
6
+ const session = db.session();
7
+ try {
8
+ const result = await session.run(`
9
+ MATCH (f:File)
10
+ WHERE f.path = $filePath OR f.relativePath = $filePath
11
+ MATCH (dependent:File)-[:IMPORTS]->(f)
12
+ RETURN dependent.path AS dependentPath, dependent.relativePath AS relativePath,
13
+ dependent.language AS language
14
+ ORDER BY relativePath
15
+ `, { filePath });
16
+ const records = result.records.map((r) => r.toObject());
17
+ return {
18
+ content: [{ type: "text", text: JSON.stringify(records, null, 2) }],
19
+ };
20
+ }
21
+ finally {
22
+ await session.close();
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=get-dependents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-dependents.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-dependents.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,EAAgB;IACvE,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,iHAAiH,EACjH;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;KACvE,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;;;;;;WAOC,EACD,EAAE,QAAQ,EAAE,CACb,CAAC;YACF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ export declare function registerGetFileStructure(server: McpServer, db: DbConnection): void;
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ export function registerGetFileStructure(server, db) {
3
+ server.tool("get_file_structure", "Get the structure of a file — classes and functions with their signatures but without code bodies. Much more efficient than reading the whole file.", {
4
+ filePath: z.string().describe("Absolute or relative file path"),
5
+ }, async ({ filePath }) => {
6
+ const session = db.session();
7
+ try {
8
+ const result = await session.run(`
9
+ MATCH (f:File)
10
+ WHERE f.path = $filePath OR f.relativePath = $filePath
11
+ OPTIONAL MATCH (f)-[:CONTAINS]->(symbol)
12
+ WHERE symbol:Function OR symbol:Class
13
+ RETURN f.path AS filePath, f.language AS language,
14
+ collect({
15
+ type: labels(symbol)[0],
16
+ name: symbol.name,
17
+ signature: symbol.signature,
18
+ startLine: symbol.startLine,
19
+ endLine: symbol.endLine,
20
+ docstring: symbol.docstring
21
+ }) AS symbols
22
+ `, { filePath });
23
+ const records = result.records.map((r) => r.toObject());
24
+ return {
25
+ content: [{ type: "text", text: JSON.stringify(records, null, 2) }],
26
+ };
27
+ }
28
+ finally {
29
+ await session.close();
30
+ }
31
+ });
32
+ }
33
+ //# sourceMappingURL=get-file-structure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-file-structure.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-file-structure.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,EAAgB;IAC1E,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,qJAAqJ,EACrJ;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;KAChE,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;;;;;;;;;;;;;WAcC,EACD,EAAE,QAAQ,EAAE,CACb,CAAC;YACF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ export declare function registerGetFunction(server: McpServer, db: DbConnection): void;
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ export function registerGetFunction(server, db) {
3
+ server.tool("get_function", "Get the full source code of a specific function by name. Use this INSTEAD OF reading the file to find a function.", {
4
+ name: z.string().describe("Function name"),
5
+ filePath: z.string().optional().describe("File path for disambiguation when multiple functions share a name"),
6
+ }, async ({ name, filePath }) => {
7
+ const session = db.session();
8
+ try {
9
+ let cypher = `
10
+ MATCH (fn:Function {name: $name})
11
+ `;
12
+ const params = { name };
13
+ if (filePath) {
14
+ cypher += ` WHERE fn.filePath = $filePath`;
15
+ params.filePath = filePath;
16
+ }
17
+ cypher += `
18
+ RETURN fn.name AS name, fn.filePath AS filePath,
19
+ fn.signature AS signature, fn.snippet AS snippet,
20
+ fn.startLine AS startLine, fn.endLine AS endLine,
21
+ fn.docstring AS docstring, fn.className AS className
22
+ `;
23
+ const result = await session.run(cypher, params);
24
+ const records = result.records.map((r) => r.toObject());
25
+ return {
26
+ content: [{ type: "text", text: JSON.stringify(records, null, 2) }],
27
+ };
28
+ }
29
+ finally {
30
+ await session.close();
31
+ }
32
+ });
33
+ }
34
+ //# sourceMappingURL=get-function.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-function.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-function.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,EAAgB;IACrE,MAAM,CAAC,IAAI,CACT,cAAc,EACd,mHAAmH,EACnH;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;QAC1C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;KAC9G,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,MAAM,GAAG;;SAEZ,CAAC;YACF,MAAM,MAAM,GAA4B,EAAE,IAAI,EAAE,CAAC;YACjD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,gCAAgC,CAAC;gBAC3C,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC7B,CAAC;YACD,MAAM,IAAI;;;;;SAKT,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ export declare function registerGetRepoStructure(server: McpServer, db: DbConnection): void;
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ export function registerGetRepoStructure(server, db) {
3
+ server.tool("get_repo_structure", "Get a bird's-eye view of a repository — file counts by directory and top-level symbols. Use this to orient yourself in a new codebase.", {
4
+ repo: z.string().optional().describe("Repository path to query (defaults to all repos)"),
5
+ depth: z.number().optional().default(3).describe("Directory depth to show"),
6
+ }, async ({ repo, depth }) => {
7
+ const session = db.session();
8
+ try {
9
+ let cypher = `
10
+ MATCH (r:Repository)
11
+ `;
12
+ const params = { depth: depth ?? 3 };
13
+ if (repo) {
14
+ cypher += ` WHERE r.path = $repo OR r.name = $repo`;
15
+ params.repo = repo;
16
+ }
17
+ cypher += `
18
+ MATCH (r)-[:CONTAINS_FILE]->(f:File)
19
+ WITH r, f
20
+ OPTIONAL MATCH (f)-[:CONTAINS]->(fn:Function)
21
+ OPTIONAL MATCH (f)-[:CONTAINS]->(c:Class)
22
+ RETURN r.name AS repo, r.path AS repoPath,
23
+ f.relativePath AS filePath, f.language AS language,
24
+ count(DISTINCT fn) AS functionCount,
25
+ count(DISTINCT c) AS classCount
26
+ ORDER BY filePath
27
+ `;
28
+ const result = await session.run(cypher, params);
29
+ const records = result.records.map((r) => r.toObject());
30
+ return {
31
+ content: [{ type: "text", text: JSON.stringify(records, null, 2) }],
32
+ };
33
+ }
34
+ finally {
35
+ await session.close();
36
+ }
37
+ });
38
+ }
39
+ //# sourceMappingURL=get-repo-structure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-repo-structure.js","sourceRoot":"","sources":["../../../src/mcp/tools/get-repo-structure.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,EAAgB;IAC1E,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,wIAAwI,EACxI;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;QACxF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,yBAAyB,CAAC;KAC5E,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,MAAM,GAAG;;SAEZ,CAAC;YACF,MAAM,MAAM,GAA4B,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YAC9D,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,IAAI,yCAAyC,CAAC;gBACpD,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;YACrB,CAAC;YACD,MAAM,IAAI;;;;;;;;;;SAUT,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { DbConnection } from "../../db/connection.js";
3
+ import type { Config } from "../../config.js";
4
+ export declare function registerReindex(server: McpServer, db: DbConnection, config: Config, repoPath: string): void;