codesearch-mcp 0.3.0-alpha → 0.4.0-alpha

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 (224) hide show
  1. package/CHANGELOG.md +59 -6
  2. package/LICENSE +661 -21
  3. package/README.md +33 -17
  4. package/dist/app.js +13 -20
  5. package/dist/src/ast/CallExtractor.d.ts +8 -0
  6. package/dist/src/ast/CallExtractor.js +68 -0
  7. package/dist/src/ast/GraphqlNameExtractor.d.ts +22 -0
  8. package/dist/src/ast/GraphqlNameExtractor.js +240 -0
  9. package/dist/src/ast/ImportEdgeExtractor.d.ts +11 -0
  10. package/dist/src/ast/ImportEdgeExtractor.js +129 -0
  11. package/dist/src/ast/IndexedNodeResolver.d.ts +14 -0
  12. package/dist/src/ast/IndexedNodeResolver.js +217 -0
  13. package/dist/src/ast/MemberExtractor.d.ts +8 -0
  14. package/dist/src/ast/MemberExtractor.js +129 -0
  15. package/dist/src/ast/TopLevelSymbolExtractor.d.ts +5 -0
  16. package/dist/src/ast/TopLevelSymbolExtractor.js +86 -0
  17. package/dist/src/ast/graphql-grammar.d.ts +24 -0
  18. package/dist/src/ast/graphql-grammar.js +93 -0
  19. package/dist/src/ast/node-helpers.d.ts +11 -0
  20. package/dist/src/ast/node-helpers.js +55 -0
  21. package/dist/src/commands/EvalCommand.d.ts +7 -3
  22. package/dist/src/commands/EvalCommand.js +36 -158
  23. package/dist/src/commands/IndexCommand.d.ts +10 -4
  24. package/dist/src/commands/IndexCommand.js +52 -124
  25. package/dist/src/commands/McpCommand.d.ts +6 -3
  26. package/dist/src/commands/McpCommand.js +19 -14
  27. package/dist/src/commands/WebCommand.d.ts +9 -3
  28. package/dist/src/commands/WebCommand.js +17 -8
  29. package/dist/src/commands/eval/baseline-comparison.d.ts +6 -0
  30. package/dist/src/commands/eval/baseline-comparison.js +54 -0
  31. package/dist/src/commands/eval/eval-args.d.ts +6 -0
  32. package/dist/src/commands/eval/eval-args.js +71 -0
  33. package/dist/src/commands/eval/eval-corpora.d.ts +6 -0
  34. package/dist/src/commands/eval/eval-corpora.js +76 -0
  35. package/dist/src/commands/eval/eval-metadata.d.ts +17 -0
  36. package/dist/src/commands/eval/eval-metadata.js +75 -0
  37. package/dist/src/commands/eval/index-inspector.d.ts +3 -0
  38. package/dist/src/commands/eval/index-inspector.js +21 -0
  39. package/dist/src/commands/eval/staged-search.d.ts +3 -0
  40. package/dist/src/commands/eval/staged-search.js +20 -0
  41. package/dist/src/commands/eval/suite-loader.d.ts +8 -0
  42. package/dist/src/commands/eval/suite-loader.js +52 -0
  43. package/dist/src/commands/index/backend-probe.d.ts +2 -0
  44. package/dist/src/commands/index/backend-probe.js +15 -0
  45. package/dist/src/commands/index/embedding-setup.d.ts +3 -0
  46. package/dist/src/commands/index/embedding-setup.js +16 -0
  47. package/dist/src/commands/index/index-summary.d.ts +2 -0
  48. package/dist/src/commands/index/index-summary.js +22 -0
  49. package/dist/src/commands/index/legacy-ollama-guard.d.ts +3 -0
  50. package/dist/src/commands/index/legacy-ollama-guard.js +23 -0
  51. package/dist/src/commands/index/prune-step.d.ts +3 -0
  52. package/dist/src/commands/index/prune-step.js +22 -0
  53. package/dist/src/commands/index/scan-targets.d.ts +8 -0
  54. package/dist/src/commands/index/scan-targets.js +107 -0
  55. package/dist/src/config-store.d.ts +0 -1
  56. package/dist/src/config-store.js +3 -4
  57. package/dist/src/config.d.ts +1 -1
  58. package/dist/src/config.js +1 -1
  59. package/dist/src/constants.d.ts +15 -0
  60. package/dist/src/constants.js +34 -6
  61. package/dist/src/container.d.ts +4 -2
  62. package/dist/src/container.js +7 -5
  63. package/dist/src/db/drizzle-types.d.ts +7 -0
  64. package/dist/src/db/index.d.ts +1 -0
  65. package/dist/src/db/schema-steps.d.ts +8 -0
  66. package/dist/src/db/schema-steps.js +105 -0
  67. package/dist/src/declarations/DeclarationTree.d.ts +1 -1
  68. package/dist/src/eval-results.js +16 -2
  69. package/dist/src/eval-vector-index.d.ts +5 -0
  70. package/dist/src/eval-vector-index.js +60 -0
  71. package/dist/src/help.js +9 -1
  72. package/dist/src/index-args.d.ts +13 -0
  73. package/dist/src/index-args.js +48 -0
  74. package/dist/src/indexing/AnalysisBatcher.d.ts +12 -0
  75. package/dist/src/indexing/AnalysisBatcher.js +28 -0
  76. package/dist/src/indexing/ChunkEmbedder.d.ts +24 -0
  77. package/dist/src/indexing/ChunkEmbedder.js +37 -0
  78. package/dist/src/indexing/ConsoleScanReporter.d.ts +10 -0
  79. package/dist/src/indexing/ConsoleScanReporter.js +73 -0
  80. package/dist/src/indexing/EmbeddingSchemaPreparer.d.ts +14 -0
  81. package/dist/src/indexing/EmbeddingSchemaPreparer.js +66 -0
  82. package/dist/src/indexing/FileIngestor.d.ts +22 -0
  83. package/dist/src/indexing/FileIngestor.js +116 -0
  84. package/dist/src/indexing/IndexStore.d.ts +24 -0
  85. package/dist/src/indexing/IndexStore.js +69 -0
  86. package/dist/src/indexing/StaleFilePruner.d.ts +8 -0
  87. package/dist/src/indexing/StaleFilePruner.js +55 -0
  88. package/dist/src/indexing/analysis-rows.d.ts +4 -0
  89. package/dist/src/indexing/analysis-rows.js +65 -0
  90. package/dist/src/indexing/project-notices.d.ts +2 -0
  91. package/dist/src/indexing/project-notices.js +63 -0
  92. package/dist/src/interfaces/IAstParser.d.ts +2 -1
  93. package/dist/src/interfaces/ICallGraph.d.ts +28 -0
  94. package/dist/src/interfaces/ICallGraph.js +2 -0
  95. package/dist/src/interfaces/IChunkSearch.d.ts +42 -0
  96. package/dist/src/interfaces/IChunkSearch.js +2 -0
  97. package/dist/src/interfaces/IDatabase.d.ts +6 -2
  98. package/dist/src/interfaces/IDependencyGraph.d.ts +24 -0
  99. package/dist/src/interfaces/IDependencyGraph.js +2 -0
  100. package/dist/src/interfaces/IIndexIdentityGuard.d.ts +3 -0
  101. package/dist/src/interfaces/IIndexIdentityGuard.js +2 -0
  102. package/dist/src/interfaces/IIndexedNodeResolver.d.ts +10 -0
  103. package/dist/src/interfaces/IIndexedNodeResolver.js +2 -0
  104. package/dist/src/interfaces/IMcpReadiness.d.ts +12 -0
  105. package/dist/src/interfaces/IMcpReadiness.js +2 -0
  106. package/dist/src/interfaces/IProjectCatalog.d.ts +13 -0
  107. package/dist/src/interfaces/IProjectCatalog.js +2 -0
  108. package/dist/src/interfaces/IProjectRoots.d.ts +3 -0
  109. package/dist/src/interfaces/IProjectRoots.js +2 -0
  110. package/dist/src/interfaces/IRetrievalEvaluator.d.ts +21 -2
  111. package/dist/src/interfaces/IScanReporter.d.ts +13 -0
  112. package/dist/src/interfaces/IScanReporter.js +2 -0
  113. package/dist/src/interfaces/ISymbolLookup.d.ts +49 -0
  114. package/dist/src/interfaces/ISymbolLookup.js +2 -0
  115. package/dist/src/interfaces/IToolPaths.d.ts +62 -0
  116. package/dist/src/interfaces/IToolPaths.js +2 -0
  117. package/dist/src/interfaces/IWorkspaceFiles.d.ts +28 -0
  118. package/dist/src/interfaces/IWorkspaceFiles.js +2 -0
  119. package/dist/src/interfaces/SymbolKind.d.ts +1 -0
  120. package/dist/src/interfaces/SymbolKind.js +2 -0
  121. package/dist/src/interfaces/index.d.ts +12 -1
  122. package/dist/src/project-scope.d.ts +1 -0
  123. package/dist/src/project-scope.js +5 -0
  124. package/dist/src/retrieval-eval.d.ts +2 -1
  125. package/dist/src/retrieval-eval.js +45 -2
  126. package/dist/src/search/CallGraph.d.ts +9 -0
  127. package/dist/src/search/CallGraph.js +84 -0
  128. package/dist/src/search/ChunkSearch.d.ts +23 -0
  129. package/dist/src/search/ChunkSearch.js +115 -0
  130. package/dist/src/search/DependencyGraph.d.ts +19 -0
  131. package/dist/src/search/DependencyGraph.js +180 -0
  132. package/dist/src/search/IndexIdentityGuard.d.ts +11 -0
  133. package/dist/src/search/IndexIdentityGuard.js +37 -0
  134. package/dist/src/search/ProjectCatalog.d.ts +11 -0
  135. package/dist/src/search/ProjectCatalog.js +38 -0
  136. package/dist/src/search/SymbolLookup.d.ts +24 -0
  137. package/dist/src/search/SymbolLookup.js +97 -0
  138. package/dist/src/search/chunks/CandidateFetcher.d.ts +19 -0
  139. package/dist/src/search/chunks/CandidateFetcher.js +40 -0
  140. package/dist/src/search/chunks/IterativeScanGate.d.ts +10 -0
  141. package/dist/src/search/chunks/IterativeScanGate.js +42 -0
  142. package/dist/src/search/chunks/RerankStage.d.ts +15 -0
  143. package/dist/src/search/chunks/RerankStage.js +42 -0
  144. package/dist/src/search/chunks/search-metrics.d.ts +18 -0
  145. package/dist/src/search/chunks/search-metrics.js +32 -0
  146. package/dist/src/search/chunks/search-plan.d.ts +18 -0
  147. package/dist/src/search/chunks/search-plan.js +19 -0
  148. package/dist/src/search/create-search-services.d.ts +26 -0
  149. package/dist/src/search/create-search-services.js +29 -0
  150. package/dist/src/search/index-paths.d.ts +1 -0
  151. package/dist/src/search/index-paths.js +5 -0
  152. package/dist/src/search/symbol-sql.d.ts +13 -0
  153. package/dist/src/search/symbol-sql.js +66 -0
  154. package/dist/src/search/symbols/SymbolGrepFallback.d.ts +19 -0
  155. package/dist/src/search/symbols/SymbolGrepFallback.js +106 -0
  156. package/dist/src/search/symbols/SymbolIndexQuery.d.ts +14 -0
  157. package/dist/src/search/symbols/SymbolIndexQuery.js +52 -0
  158. package/dist/src/search/symbols/SymbolTextSearch.d.ts +13 -0
  159. package/dist/src/search/symbols/SymbolTextSearch.js +84 -0
  160. package/dist/src/search/symbols/TargetColumnGate.d.ts +7 -0
  161. package/dist/src/search/symbols/TargetColumnGate.js +23 -0
  162. package/dist/src/search/symbols/find-symbol-constants.d.ts +4 -0
  163. package/dist/src/search/symbols/find-symbol-constants.js +8 -0
  164. package/dist/src/search/symbols/grep-args.d.ts +3 -0
  165. package/dist/src/search/symbols/grep-args.js +7 -0
  166. package/dist/src/search/symbols/grep-patterns.d.ts +4 -0
  167. package/dist/src/search/symbols/grep-patterns.js +60 -0
  168. package/dist/src/services/AstParserService.d.ts +8 -44
  169. package/dist/src/services/AstParserService.js +19 -938
  170. package/dist/src/services/DatabaseService.d.ts +8 -10
  171. package/dist/src/services/DatabaseService.js +29 -86
  172. package/dist/src/services/IndexerService.d.ts +7 -10
  173. package/dist/src/services/IndexerService.js +36 -255
  174. package/dist/src/services/McpReadiness.d.ts +18 -0
  175. package/dist/src/services/McpReadiness.js +73 -0
  176. package/dist/src/services/McpServer.d.ts +32 -9
  177. package/dist/src/services/McpServer.js +78 -41
  178. package/dist/src/services/WebServerService.d.ts +4 -3
  179. package/dist/src/services/WebServerService.js +16 -8
  180. package/dist/src/setup.d.ts +16 -4
  181. package/dist/src/setup.js +115 -40
  182. package/dist/src/symbol-name.d.ts +1 -0
  183. package/dist/src/symbol-name.js +16 -12
  184. package/dist/src/tools/FindSymbolTool.d.ts +17 -7
  185. package/dist/src/tools/FindSymbolTool.js +54 -35
  186. package/dist/src/tools/GetCallersTool.d.ts +16 -8
  187. package/dist/src/tools/GetCallersTool.js +65 -35
  188. package/dist/src/tools/GetDependenciesTool.d.ts +16 -8
  189. package/dist/src/tools/GetDependenciesTool.js +35 -28
  190. package/dist/src/tools/GetDependentsTool.d.ts +20 -8
  191. package/dist/src/tools/GetDependentsTool.js +47 -33
  192. package/dist/src/tools/ListFilesTool.d.ts +16 -8
  193. package/dist/src/tools/ListFilesTool.js +20 -26
  194. package/dist/src/tools/ListProjectsTool.d.ts +11 -7
  195. package/dist/src/tools/ListProjectsTool.js +13 -11
  196. package/dist/src/tools/McpTool.d.ts +17 -0
  197. package/dist/src/tools/McpTool.js +28 -0
  198. package/dist/src/tools/ReadFileRangeTool.d.ts +16 -8
  199. package/dist/src/tools/ReadFileRangeTool.js +23 -25
  200. package/dist/src/tools/ReadFileTool.d.ts +15 -8
  201. package/dist/src/tools/ReadFileTool.js +19 -24
  202. package/dist/src/tools/SearchCodebaseTool.d.ts +22 -10
  203. package/dist/src/tools/SearchCodebaseTool.js +69 -51
  204. package/dist/src/tools/format-helpers.d.ts +9 -3
  205. package/dist/src/tools/format-helpers.js +59 -14
  206. package/dist/src/tools/tool-args.d.ts +38 -0
  207. package/dist/src/tools/tool-args.js +95 -0
  208. package/dist/src/workspace/GrepRunner.d.ts +15 -0
  209. package/dist/src/workspace/GrepRunner.js +104 -0
  210. package/dist/src/workspace/ProjectRoots.d.ts +22 -0
  211. package/dist/src/workspace/ProjectRoots.js +102 -0
  212. package/dist/src/workspace/ToolPaths.d.ts +31 -0
  213. package/dist/src/workspace/ToolPaths.js +312 -0
  214. package/dist/src/workspace/WorkspaceFiles.d.ts +19 -0
  215. package/dist/src/workspace/WorkspaceFiles.js +285 -0
  216. package/dist/src/workspace/fs-access.d.ts +9 -0
  217. package/dist/src/workspace/fs-access.js +47 -0
  218. package/dist/src/workspace/path-helpers.d.ts +3 -0
  219. package/dist/src/workspace/path-helpers.js +43 -0
  220. package/package.json +4 -3
  221. package/dist/src/interfaces/ISearcher.d.ts +0 -46
  222. package/dist/src/services/SearcherService.d.ts +0 -235
  223. package/dist/src/services/SearcherService.js +0 -1118
  224. /package/dist/src/{interfaces/ISearcher.js → db/drizzle-types.js} +0 -0
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.WorkspaceFiles = void 0;
37
+ const path = __importStar(require("path"));
38
+ const readline = __importStar(require("readline"));
39
+ const stream_1 = require("stream");
40
+ const file_utils_1 = require("../file-utils");
41
+ const fs_access_1 = require("./fs-access");
42
+ const MAX_LINE_BYTES = 64 * 1024 * 1024;
43
+ const LINE_TOO_LONG = 'ELINETOOLONG';
44
+ const BINARY_FILE = 'EBINARY';
45
+ const BINARY_SNIFF_BYTES = 8 * 1024;
46
+ const LF = 0x0a;
47
+ const CR = 0x0d;
48
+ function openLineBytes(open, chunk) {
49
+ const breaks = [chunk.indexOf(LF), chunk.indexOf(CR)].filter(i => i >= 0);
50
+ const head = breaks.length === 0 ? chunk.length : Math.min(...breaks);
51
+ const total = open + head;
52
+ if (total > MAX_LINE_BYTES)
53
+ return null;
54
+ if (breaks.length === 0)
55
+ return total;
56
+ return chunk.length - 1 - Math.max(chunk.lastIndexOf(LF), chunk.lastIndexOf(CR));
57
+ }
58
+ function lineLimitGuard() {
59
+ let open = 0;
60
+ let sniffed = 0;
61
+ let held = [];
62
+ const lineLimit = (chunk) => {
63
+ const next = openLineBytes(open, chunk);
64
+ if (next === null)
65
+ return Object.assign(new Error('line too long'), { code: LINE_TOO_LONG });
66
+ open = next;
67
+ return null;
68
+ };
69
+ return new stream_1.Transform({
70
+ encoding: 'utf-8',
71
+ transform(chunk, _encoding, done) {
72
+ if (sniffed < BINARY_SNIFF_BYTES) {
73
+ const head = chunk.subarray(0, BINARY_SNIFF_BYTES - sniffed);
74
+ if (head.includes(0)) {
75
+ done(Object.assign(new Error('binary file'), { code: BINARY_FILE }));
76
+ return;
77
+ }
78
+ sniffed += head.length;
79
+ held.push(chunk);
80
+ if (sniffed < BINARY_SNIFF_BYTES) {
81
+ done();
82
+ return;
83
+ }
84
+ chunk = Buffer.concat(held);
85
+ held = [];
86
+ }
87
+ const err = lineLimit(chunk);
88
+ if (err)
89
+ done(err);
90
+ else
91
+ done(null, chunk);
92
+ },
93
+ flush(done) {
94
+ if (held.length === 0) {
95
+ done();
96
+ return;
97
+ }
98
+ const chunk = Buffer.concat(held);
99
+ held = [];
100
+ const err = lineLimit(chunk);
101
+ if (err)
102
+ done(err);
103
+ else
104
+ done(null, chunk);
105
+ },
106
+ });
107
+ }
108
+ class WorkspaceFiles {
109
+ paths;
110
+ roots;
111
+ logger;
112
+ fs;
113
+ constructor(paths, roots, logger, fs) {
114
+ this.paths = paths;
115
+ this.roots = roots;
116
+ this.logger = logger;
117
+ this.fs = fs;
118
+ }
119
+ async listFiles(relPath, depth, pattern) {
120
+ const t0 = Date.now();
121
+ this.logger.debug('WorkspaceFiles: listFiles', { relPath, depth, pattern });
122
+ const absPath = this.roots.toAbs(relPath);
123
+ const loc = await this.paths.checkRealLocation(relPath, absPath, 'dir');
124
+ if (!loc.ok)
125
+ return loc;
126
+ let stat;
127
+ try {
128
+ stat = await this.fs.stat(absPath);
129
+ }
130
+ catch (err) {
131
+ if ((0, fs_access_1.errorCode)(err) !== 'ENOENT')
132
+ return { ok: false, reason: 'unreadable', code: (0, fs_access_1.errorCode)(err) };
133
+ return { ok: false, reason: 'not_found', candidates: await this.paths.candidatesOrNone(relPath, 'dir') };
134
+ }
135
+ if (!stat.isDirectory())
136
+ return { ok: false, reason: 'not_a_directory' };
137
+ const clampedDepth = Math.min(5, Math.max(1, depth));
138
+ const lines = [];
139
+ try {
140
+ await this.walkDir(absPath, 0, clampedDepth - 1, pattern, lines);
141
+ }
142
+ catch (err) {
143
+ return { ok: false, reason: 'unreadable', code: (0, fs_access_1.errorCode)(err) };
144
+ }
145
+ this.logger.debug('WorkspaceFiles: listFiles result', { entries: lines.length, ms: Date.now() - t0 });
146
+ if (lines.length === 0) {
147
+ return { ok: true, tree: pattern ? `No files matching "${pattern}" found within depth ${clampedDepth}.` : '(empty directory)' };
148
+ }
149
+ return { ok: true, tree: lines.join('\n') };
150
+ }
151
+ async openableFile(relPath, absPath) {
152
+ const loc = await this.paths.checkRealLocation(relPath, absPath, 'file');
153
+ if (!loc.ok)
154
+ return loc;
155
+ let stat;
156
+ try {
157
+ stat = await this.fs.stat(absPath);
158
+ }
159
+ catch (err) {
160
+ if ((0, fs_access_1.errorCode)(err) !== 'ENOENT')
161
+ return { ok: false, reason: 'unreadable', code: (0, fs_access_1.errorCode)(err) };
162
+ if (await this.paths.isIndexedPath(relPath))
163
+ return { ok: false, reason: 'deleted' };
164
+ return { ok: false, reason: 'not_found', candidates: await this.paths.candidatesOrNone(relPath, 'file') };
165
+ }
166
+ return stat.isFile() ? null : { ok: false, reason: 'not_a_file' };
167
+ }
168
+ async readLines(absPath, onLine) {
169
+ const stream = this.fs.createReadStream(absPath);
170
+ const guard = lineLimitGuard();
171
+ guard.on('error', () => { });
172
+ stream.on('error', err => guard.destroy(err));
173
+ stream.pipe(guard);
174
+ const rl = readline.createInterface({ input: guard, crlfDelay: Infinity });
175
+ let lineNo = 0;
176
+ try {
177
+ for await (const line of rl) {
178
+ lineNo++;
179
+ if (!onLine(line, lineNo))
180
+ break;
181
+ }
182
+ return { ok: true, lineCount: lineNo };
183
+ }
184
+ catch (err) {
185
+ if ((0, fs_access_1.errorCode)(err) === LINE_TOO_LONG && !onLine('', lineNo + 1))
186
+ return { ok: true, lineCount: lineNo };
187
+ return { ok: false, code: (0, fs_access_1.errorCode)(err) };
188
+ }
189
+ finally {
190
+ rl.close();
191
+ guard.destroy();
192
+ stream.destroy?.();
193
+ }
194
+ }
195
+ readFailure(code) {
196
+ return code === BINARY_FILE ? { ok: false, reason: 'binary' } : { ok: false, reason: 'unreadable', code };
197
+ }
198
+ async readFile(relPath, maxLines) {
199
+ const t0 = Date.now();
200
+ this.logger.debug('WorkspaceFiles: readFile', { relPath, maxLines });
201
+ const absPath = this.roots.toAbs(relPath);
202
+ const failure = await this.openableFile(relPath, absPath);
203
+ if (failure)
204
+ return failure;
205
+ const lines = [];
206
+ let hasMore = false;
207
+ const read = await this.readLines(absPath, line => {
208
+ if (lines.length < maxLines) {
209
+ lines.push(line);
210
+ return true;
211
+ }
212
+ hasMore = true;
213
+ return false;
214
+ });
215
+ if (!read.ok)
216
+ return this.readFailure(read.code);
217
+ this.logger.debug('WorkspaceFiles: readFile result', { linesRead: lines.length, hasMore, ms: Date.now() - t0 });
218
+ return { ok: true, filePath: relPath, startLine: 1, endLine: lines.length, lines, hasMore };
219
+ }
220
+ async readFileRange(relPath, startLine, endLine) {
221
+ const t0 = Date.now();
222
+ this.logger.debug('WorkspaceFiles: readFileRange', { relPath, startLine, endLine });
223
+ if (endLine < startLine)
224
+ return { ok: false, reason: 'bad_range', startLine, endLine };
225
+ const absPath = this.roots.toAbs(relPath);
226
+ const failure = await this.openableFile(relPath, absPath);
227
+ if (failure)
228
+ return failure;
229
+ const lines = [];
230
+ let lastRead = 0;
231
+ let hasMore = false;
232
+ const read = await this.readLines(absPath, (line, lineNo) => {
233
+ if (lineNo > endLine) {
234
+ hasMore = true;
235
+ return false;
236
+ }
237
+ if (lineNo >= startLine)
238
+ lines.push(line);
239
+ lastRead = lineNo;
240
+ return true;
241
+ });
242
+ if (!read.ok)
243
+ return this.readFailure(read.code);
244
+ if (!hasMore && startLine > Math.max(read.lineCount, 1)) {
245
+ return { ok: false, reason: 'past_end', lineCount: read.lineCount, startLine };
246
+ }
247
+ this.logger.debug('WorkspaceFiles: readFileRange result', { linesRead: lines.length, hasMore, ms: Date.now() - t0 });
248
+ return { ok: true, filePath: relPath, startLine, endLine: Math.min(endLine, lastRead), lines, hasMore };
249
+ }
250
+ async walkDir(absDir, currentDepth, maxDepth, pattern, lines) {
251
+ const entries = await this.fs.readdir(absDir);
252
+ entries.sort((a, b) => {
253
+ const ad = a.isDirectory() ? 0 : 1;
254
+ const bd = b.isDirectory() ? 0 : 1;
255
+ if (ad !== bd)
256
+ return ad - bd;
257
+ return a.name.localeCompare(b.name);
258
+ });
259
+ for (const entry of entries) {
260
+ if (file_utils_1.IGNORE_DIRS.has(entry.name))
261
+ continue;
262
+ const indent = ' '.repeat(currentDepth);
263
+ if (entry.isDirectory()) {
264
+ const at = lines.push(`${indent}${entry.name}/`) - 1;
265
+ if (currentDepth < maxDepth) {
266
+ try {
267
+ await this.walkDir(path.join(absDir, entry.name), currentDepth + 1, maxDepth, pattern, lines);
268
+ }
269
+ catch {
270
+ lines[at] += ' (unreadable)';
271
+ continue;
272
+ }
273
+ }
274
+ if (pattern && lines.length === at + 1)
275
+ lines.pop();
276
+ }
277
+ else {
278
+ if (pattern && !entry.name.includes(pattern))
279
+ continue;
280
+ lines.push(`${indent}${entry.name}`);
281
+ }
282
+ }
283
+ }
284
+ }
285
+ exports.WorkspaceFiles = WorkspaceFiles;
@@ -0,0 +1,9 @@
1
+ import * as fs from 'fs';
2
+ export interface WorkspaceFs {
3
+ realpath(p: string): Promise<string>;
4
+ stat(p: string): Promise<fs.Stats>;
5
+ readdir(p: string): Promise<fs.Dirent[]>;
6
+ createReadStream(p: string): NodeJS.ReadableStream;
7
+ }
8
+ export declare const NODE_FS: WorkspaceFs;
9
+ export declare function errorCode(err: unknown): string;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.NODE_FS = void 0;
37
+ exports.errorCode = errorCode;
38
+ const fs = __importStar(require("fs"));
39
+ exports.NODE_FS = {
40
+ realpath: p => fs.promises.realpath(p),
41
+ stat: p => fs.promises.stat(p),
42
+ readdir: p => fs.promises.readdir(p, { withFileTypes: true }),
43
+ createReadStream: p => fs.createReadStream(p),
44
+ };
45
+ function errorCode(err) {
46
+ return err?.code ?? 'EIO';
47
+ }
@@ -0,0 +1,3 @@
1
+ export declare function stripTrailingSlash(p: string): string;
2
+ export declare function isWithin(p: string, root: string): boolean;
3
+ export declare function editDistance(a: string, b: string, max: number): number;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stripTrailingSlash = stripTrailingSlash;
4
+ exports.isWithin = isWithin;
5
+ exports.editDistance = editDistance;
6
+ function stripTrailingSlash(p) {
7
+ return p.length > 1 && p.endsWith('/') ? p.slice(0, -1) : p;
8
+ }
9
+ function isWithin(p, root) {
10
+ if (root === '.')
11
+ return true;
12
+ if (root === '/')
13
+ return p.startsWith('/');
14
+ return p === root || p.startsWith(root + '/');
15
+ }
16
+ function editDistance(a, b, max) {
17
+ const x = [...a];
18
+ const y = [...b];
19
+ const over = max + 1;
20
+ if (Math.abs(x.length - y.length) > max)
21
+ return over;
22
+ let prev = Array.from({ length: y.length + 1 }, (_, j) => (j <= max ? j : over));
23
+ let row = new Array(y.length + 1).fill(over);
24
+ for (let i = 1; i <= x.length; i++) {
25
+ const from = Math.max(1, i - max);
26
+ const to = Math.min(y.length, i + max);
27
+ row[0] = i <= max ? i : over;
28
+ row[from - 1] = from === 1 ? row[0] : over;
29
+ let best = row[0];
30
+ for (let j = from; j <= to; j++) {
31
+ const cell = Math.min(prev[j] + 1, row[j - 1] + 1, prev[j - 1] + (x[i - 1] === y[j - 1] ? 0 : 1), over);
32
+ row[j] = cell;
33
+ if (cell < best)
34
+ best = cell;
35
+ }
36
+ if (to < y.length)
37
+ row[to + 1] = over;
38
+ if (best > max)
39
+ return over;
40
+ [prev, row] = [row, prev];
41
+ }
42
+ return prev[y.length];
43
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "codesearch-mcp",
3
- "version": "0.3.0-alpha",
3
+ "version": "0.4.0-alpha",
4
4
  "description": "Local semantic codebase search via MCP — indexes projects into pgvector, exposes search to Claude",
5
- "license": "MIT",
5
+ "license": "AGPL-3.0-only",
6
6
  "keywords": [
7
7
  "mcp",
8
8
  "model-context-protocol",
@@ -16,7 +16,7 @@
16
16
  "infinity"
17
17
  ],
18
18
  "engines": {
19
- "node": ">=18"
19
+ "node": "^22.13.0 || >=23.5.0"
20
20
  },
21
21
  "main": "dist/app.js",
22
22
  "bin": {
@@ -65,6 +65,7 @@
65
65
  "@types/cli-progress": "^3.11.6",
66
66
  "@types/node": "^22.0.0",
67
67
  "@types/pg": "^8.20.0",
68
+ "ai-aleks-tool": "^2.5.4",
68
69
  "ts-node": "^10.9.2",
69
70
  "typescript": "^5.6.0",
70
71
  "vitest": "^5.0.5"
@@ -1,46 +0,0 @@
1
- import type { SearchResult, NeighborResult, GraphContext, DependencyRow, ProjectRow, SymbolKind, SymbolHit, CallerRow, FileRangeResult, ListFilesResult, GrepSymbolResult, ResolvedToolPath, PathFailure } from '../services/SearcherService';
2
- export type StageName = 'vector' | 'reranked';
3
- export interface StagedSearchResult {
4
- pool: SearchResult[];
5
- stages: {
6
- vector: SearchResult[];
7
- reranked?: SearchResult[];
8
- };
9
- rerankFailed: boolean;
10
- fetchLimit: number;
11
- indexParams: {
12
- efSearch: number | null;
13
- iterativeScan: string;
14
- };
15
- }
16
- export interface ISearcher {
17
- prepareQuery(raw: string): Promise<{
18
- query: string;
19
- translated: boolean;
20
- }>;
21
- assertIndexMatches(): Promise<void>;
22
- listProjects(): Promise<ProjectRow[]>;
23
- getProjectEdges(): Promise<{
24
- from: string;
25
- to: string;
26
- }[]>;
27
- searchChunks(query: string, limit: number, project: string | null, threshold?: number, rerankOverride?: boolean, perFile?: number): Promise<SearchResult[]>;
28
- searchChunksWithStages(query: string, limit: number, project: string | null, threshold?: number, rerankOverride?: boolean, perFile?: number): Promise<StagedSearchResult>;
29
- fetchNeighbors(results: SearchResult[]): Promise<NeighborResult[]>;
30
- fetchGraphContext(results: SearchResult[]): Promise<Map<string, GraphContext>>;
31
- getDependencies(filePath: string, symbol?: string | null, transitive?: boolean): Promise<DependencyRow[]>;
32
- getDependents(filePath: string, symbol?: string | null, transitive?: boolean): Promise<DependencyRow[]>;
33
- getCallers(symbol: string, project: string, calleeFile?: string | null): Promise<CallerRow[]>;
34
- grepSymbol(symbol: string, rootDir: string, excludeFile: string): Promise<GrepSymbolResult>;
35
- findSymbol(name: string, project: string | null, kind: SymbolKind): Promise<{
36
- hits: SymbolHit[];
37
- truncated: boolean;
38
- grepFailed: boolean;
39
- }>;
40
- listFiles(relPath: string, depth: number, pattern: string | null): Promise<ListFilesResult>;
41
- readFile(relPath: string, maxLines: number): Promise<FileRangeResult>;
42
- readFileRange(relPath: string, startLine: number, endLine: number): Promise<FileRangeResult>;
43
- resolveToolPath(input: string | null | undefined): Promise<ResolvedToolPath>;
44
- checkGraphPath(relPath: string): Promise<PathFailure | null>;
45
- fallbackRoot(relPath: string): string | null;
46
- }