codesearch-mcp 0.2.3-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 (317) hide show
  1. package/CHANGELOG.md +88 -5
  2. package/LICENSE +661 -21
  3. package/README.md +76 -40
  4. package/dist/app.js +17 -38
  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/chunking/AstChunker.d.ts +12 -0
  22. package/dist/src/chunking/AstChunker.js +30 -0
  23. package/dist/src/chunking/CharacterChunkStrategy.d.ts +8 -0
  24. package/dist/src/chunking/CharacterChunkStrategy.js +15 -0
  25. package/dist/src/chunking/DeclarationChunkStrategy.d.ts +15 -0
  26. package/dist/src/chunking/DeclarationChunkStrategy.js +87 -0
  27. package/dist/src/chunking/FragmentMerger.d.ts +11 -0
  28. package/dist/src/chunking/FragmentMerger.js +61 -0
  29. package/dist/src/chunking/ImportOnlyFilter.d.ts +5 -0
  30. package/dist/src/chunking/ImportOnlyFilter.js +14 -0
  31. package/dist/src/chunking/LangchainTextSplitter.d.ts +21 -0
  32. package/dist/src/chunking/LangchainTextSplitter.js +133 -0
  33. package/dist/src/chunking/MinSizeSplitPolicy.d.ts +9 -0
  34. package/dist/src/chunking/MinSizeSplitPolicy.js +18 -0
  35. package/dist/src/chunking/RunPacker.d.ts +12 -0
  36. package/dist/src/chunking/RunPacker.js +84 -0
  37. package/dist/src/chunking/create-chunker.d.ts +3 -0
  38. package/dist/src/chunking/create-chunker.js +15 -0
  39. package/dist/src/chunking/interfaces.d.ts +27 -0
  40. package/dist/src/commands/ConfigCommand.js +1 -9
  41. package/dist/src/commands/EvalCommand.d.ts +10 -5
  42. package/dist/src/commands/EvalCommand.js +60 -149
  43. package/dist/src/commands/IndexCommand.d.ts +10 -4
  44. package/dist/src/commands/IndexCommand.js +52 -146
  45. package/dist/src/commands/McpCommand.d.ts +6 -3
  46. package/dist/src/commands/McpCommand.js +19 -20
  47. package/dist/src/commands/WebCommand.d.ts +9 -3
  48. package/dist/src/commands/WebCommand.js +17 -11
  49. package/dist/src/commands/eval/baseline-comparison.d.ts +6 -0
  50. package/dist/src/commands/eval/baseline-comparison.js +54 -0
  51. package/dist/src/commands/eval/eval-args.d.ts +6 -0
  52. package/dist/src/commands/eval/eval-args.js +71 -0
  53. package/dist/src/commands/eval/eval-corpora.d.ts +6 -0
  54. package/dist/src/commands/eval/eval-corpora.js +76 -0
  55. package/dist/src/commands/eval/eval-metadata.d.ts +17 -0
  56. package/dist/src/commands/eval/eval-metadata.js +75 -0
  57. package/dist/src/commands/eval/index-inspector.d.ts +3 -0
  58. package/dist/src/commands/eval/index-inspector.js +21 -0
  59. package/dist/src/commands/eval/staged-search.d.ts +3 -0
  60. package/dist/src/commands/eval/staged-search.js +20 -0
  61. package/dist/src/commands/eval/suite-loader.d.ts +8 -0
  62. package/dist/src/commands/eval/suite-loader.js +52 -0
  63. package/dist/src/commands/index/backend-probe.d.ts +2 -0
  64. package/dist/src/commands/index/backend-probe.js +15 -0
  65. package/dist/src/commands/index/embedding-setup.d.ts +3 -0
  66. package/dist/src/commands/index/embedding-setup.js +16 -0
  67. package/dist/src/commands/index/index-summary.d.ts +2 -0
  68. package/dist/src/commands/index/index-summary.js +22 -0
  69. package/dist/src/commands/index/legacy-ollama-guard.d.ts +3 -0
  70. package/dist/src/commands/index/legacy-ollama-guard.js +23 -0
  71. package/dist/src/commands/index/prune-step.d.ts +3 -0
  72. package/dist/src/commands/index/prune-step.js +22 -0
  73. package/dist/src/commands/index/scan-targets.d.ts +8 -0
  74. package/dist/src/commands/index/scan-targets.js +107 -0
  75. package/dist/src/config-error.d.ts +0 -4
  76. package/dist/src/config-error.js +0 -4
  77. package/dist/src/config-store.d.ts +1 -55
  78. package/dist/src/config-store.js +11 -73
  79. package/dist/src/config.d.ts +9 -18
  80. package/dist/src/config.js +36 -35
  81. package/dist/src/constants.d.ts +17 -28
  82. package/dist/src/constants.js +35 -29
  83. package/dist/src/container.d.ts +10 -2
  84. package/dist/src/container.js +19 -8
  85. package/dist/src/db/drizzle-types.d.ts +7 -0
  86. package/dist/src/db/drizzle-types.js +2 -0
  87. package/dist/src/db/index.d.ts +1 -0
  88. package/dist/src/db/schema-steps.d.ts +8 -0
  89. package/dist/src/db/schema-steps.js +105 -0
  90. package/dist/src/db/schema.d.ts +17 -0
  91. package/dist/src/db/schema.js +1 -6
  92. package/dist/src/declarations/DeclarationTree.d.ts +19 -0
  93. package/dist/src/declarations/DeclarationTree.js +66 -0
  94. package/dist/src/declarations/DeclarationTreeBuilder.d.ts +22 -0
  95. package/dist/src/declarations/DeclarationTreeBuilder.js +179 -0
  96. package/dist/src/declarations/SourceLines.d.ts +37 -0
  97. package/dist/src/declarations/SourceLines.js +415 -0
  98. package/dist/src/dependency-traversal.d.ts +0 -6
  99. package/dist/src/dependency-traversal.js +0 -6
  100. package/dist/src/enriched-prompt.d.ts +0 -6
  101. package/dist/src/enriched-prompt.js +0 -6
  102. package/dist/src/error-record.d.ts +12 -0
  103. package/dist/src/error-record.js +248 -0
  104. package/dist/src/eval-corpus.d.ts +16 -0
  105. package/dist/src/eval-corpus.js +169 -0
  106. package/dist/src/eval-results.d.ts +6 -3
  107. package/dist/src/eval-results.js +323 -26
  108. package/dist/src/eval-vector-index.d.ts +5 -0
  109. package/dist/src/eval-vector-index.js +60 -0
  110. package/dist/src/file-utils.d.ts +0 -5
  111. package/dist/src/file-utils.js +0 -5
  112. package/dist/src/graph.d.ts +0 -25
  113. package/dist/src/graph.js +0 -28
  114. package/dist/src/help.js +9 -1
  115. package/dist/src/hnsw-settings.d.ts +3 -0
  116. package/dist/src/hnsw-settings.js +24 -0
  117. package/dist/src/index-args.d.ts +13 -0
  118. package/dist/src/index-args.js +48 -0
  119. package/dist/src/indexing/AnalysisBatcher.d.ts +12 -0
  120. package/dist/src/indexing/AnalysisBatcher.js +28 -0
  121. package/dist/src/indexing/ChunkEmbedder.d.ts +24 -0
  122. package/dist/src/indexing/ChunkEmbedder.js +37 -0
  123. package/dist/src/indexing/ConsoleScanReporter.d.ts +10 -0
  124. package/dist/src/indexing/ConsoleScanReporter.js +73 -0
  125. package/dist/src/indexing/EmbeddingSchemaPreparer.d.ts +14 -0
  126. package/dist/src/indexing/EmbeddingSchemaPreparer.js +66 -0
  127. package/dist/src/indexing/FileIngestor.d.ts +22 -0
  128. package/dist/src/indexing/FileIngestor.js +116 -0
  129. package/dist/src/indexing/IndexStore.d.ts +24 -0
  130. package/dist/src/indexing/IndexStore.js +69 -0
  131. package/dist/src/indexing/StaleFilePruner.d.ts +8 -0
  132. package/dist/src/indexing/StaleFilePruner.js +55 -0
  133. package/dist/src/indexing/analysis-rows.d.ts +4 -0
  134. package/dist/src/indexing/analysis-rows.js +65 -0
  135. package/dist/src/indexing/project-notices.d.ts +2 -0
  136. package/dist/src/indexing/project-notices.js +63 -0
  137. package/dist/src/interfaces/IAstParser.d.ts +4 -40
  138. package/dist/src/interfaces/ICallGraph.d.ts +28 -0
  139. package/dist/src/interfaces/ICallGraph.js +2 -0
  140. package/dist/src/interfaces/IChunkSearch.d.ts +42 -0
  141. package/dist/src/interfaces/IChunkSearch.js +2 -0
  142. package/dist/src/interfaces/IChunker.d.ts +3 -12
  143. package/dist/src/interfaces/ICorpusInspector.d.ts +7 -0
  144. package/dist/src/interfaces/ICorpusInspector.js +2 -0
  145. package/dist/src/interfaces/IDatabase.d.ts +8 -24
  146. package/dist/src/interfaces/IDependencyGraph.d.ts +24 -0
  147. package/dist/src/interfaces/IDependencyGraph.js +2 -0
  148. package/dist/src/interfaces/IEmbedder.d.ts +0 -9
  149. package/dist/src/interfaces/IIndexIdentityGuard.d.ts +3 -0
  150. package/dist/src/interfaces/IIndexIdentityGuard.js +2 -0
  151. package/dist/src/interfaces/IIndexedNodeResolver.d.ts +10 -0
  152. package/dist/src/interfaces/IIndexedNodeResolver.js +2 -0
  153. package/dist/src/interfaces/ILogger.d.ts +1 -11
  154. package/dist/src/interfaces/IMcpReadiness.d.ts +12 -0
  155. package/dist/src/interfaces/IMcpReadiness.js +2 -0
  156. package/dist/src/interfaces/IMcpToolHandler.d.ts +0 -5
  157. package/dist/src/interfaces/IMonorepoResolver.d.ts +0 -22
  158. package/dist/src/interfaces/IProjectCatalog.d.ts +13 -0
  159. package/dist/src/interfaces/IProjectCatalog.js +2 -0
  160. package/dist/src/interfaces/IProjectDiscovery.d.ts +0 -17
  161. package/dist/src/interfaces/IProjectRoots.d.ts +3 -0
  162. package/dist/src/interfaces/IProjectRoots.js +2 -0
  163. package/dist/src/interfaces/IRetrievalEvaluator.d.ts +153 -12
  164. package/dist/src/interfaces/IScanReporter.d.ts +13 -0
  165. package/dist/src/interfaces/IScanReporter.js +2 -0
  166. package/dist/src/interfaces/ISymbolLookup.d.ts +49 -0
  167. package/dist/src/interfaces/ISymbolLookup.js +2 -0
  168. package/dist/src/interfaces/IToolPaths.d.ts +62 -0
  169. package/dist/src/interfaces/IToolPaths.js +2 -0
  170. package/dist/src/interfaces/IWorkspaceFiles.d.ts +28 -0
  171. package/dist/src/interfaces/IWorkspaceFiles.js +2 -0
  172. package/dist/src/interfaces/SymbolKind.d.ts +1 -0
  173. package/dist/src/interfaces/SymbolKind.js +2 -0
  174. package/dist/src/interfaces/index.d.ts +12 -1
  175. package/dist/src/interrupt.js +0 -2
  176. package/dist/src/owner-path.d.ts +9 -10
  177. package/dist/src/owner-path.js +11 -23
  178. package/dist/src/project-scope.d.ts +1 -12
  179. package/dist/src/project-scope.js +5 -12
  180. package/dist/src/project-selector.d.ts +0 -5
  181. package/dist/src/project-selector.js +0 -11
  182. package/dist/src/retrieval-eval.d.ts +15 -6
  183. package/dist/src/retrieval-eval.js +388 -59
  184. package/dist/src/search/CallGraph.d.ts +9 -0
  185. package/dist/src/search/CallGraph.js +84 -0
  186. package/dist/src/search/ChunkSearch.d.ts +23 -0
  187. package/dist/src/search/ChunkSearch.js +115 -0
  188. package/dist/src/search/DependencyGraph.d.ts +19 -0
  189. package/dist/src/search/DependencyGraph.js +180 -0
  190. package/dist/src/search/IndexIdentityGuard.d.ts +11 -0
  191. package/dist/src/search/IndexIdentityGuard.js +37 -0
  192. package/dist/src/search/ProjectCatalog.d.ts +11 -0
  193. package/dist/src/search/ProjectCatalog.js +38 -0
  194. package/dist/src/search/SymbolLookup.d.ts +24 -0
  195. package/dist/src/search/SymbolLookup.js +97 -0
  196. package/dist/src/search/chunks/CandidateFetcher.d.ts +19 -0
  197. package/dist/src/search/chunks/CandidateFetcher.js +40 -0
  198. package/dist/src/search/chunks/IterativeScanGate.d.ts +10 -0
  199. package/dist/src/search/chunks/IterativeScanGate.js +42 -0
  200. package/dist/src/search/chunks/RerankStage.d.ts +15 -0
  201. package/dist/src/search/chunks/RerankStage.js +42 -0
  202. package/dist/src/search/chunks/search-metrics.d.ts +18 -0
  203. package/dist/src/search/chunks/search-metrics.js +32 -0
  204. package/dist/src/search/chunks/search-plan.d.ts +18 -0
  205. package/dist/src/search/chunks/search-plan.js +19 -0
  206. package/dist/src/search/create-search-services.d.ts +26 -0
  207. package/dist/src/search/create-search-services.js +29 -0
  208. package/dist/src/search/index-paths.d.ts +1 -0
  209. package/dist/src/search/index-paths.js +5 -0
  210. package/dist/src/search/result-shaping.d.ts +4 -0
  211. package/dist/src/search/result-shaping.js +19 -0
  212. package/dist/src/search/symbol-sql.d.ts +13 -0
  213. package/dist/src/search/symbol-sql.js +66 -0
  214. package/dist/src/search/symbols/SymbolGrepFallback.d.ts +19 -0
  215. package/dist/src/search/symbols/SymbolGrepFallback.js +106 -0
  216. package/dist/src/search/symbols/SymbolIndexQuery.d.ts +14 -0
  217. package/dist/src/search/symbols/SymbolIndexQuery.js +52 -0
  218. package/dist/src/search/symbols/SymbolTextSearch.d.ts +13 -0
  219. package/dist/src/search/symbols/SymbolTextSearch.js +84 -0
  220. package/dist/src/search/symbols/TargetColumnGate.d.ts +7 -0
  221. package/dist/src/search/symbols/TargetColumnGate.js +23 -0
  222. package/dist/src/search/symbols/find-symbol-constants.d.ts +4 -0
  223. package/dist/src/search/symbols/find-symbol-constants.js +8 -0
  224. package/dist/src/search/symbols/grep-args.d.ts +3 -0
  225. package/dist/src/search/symbols/grep-args.js +7 -0
  226. package/dist/src/search/symbols/grep-patterns.d.ts +4 -0
  227. package/dist/src/search/symbols/grep-patterns.js +60 -0
  228. package/dist/src/services/AstParserService.d.ts +10 -106
  229. package/dist/src/services/AstParserService.js +37 -1068
  230. package/dist/src/services/DatabaseService.d.ts +10 -17
  231. package/dist/src/services/DatabaseService.js +71 -115
  232. package/dist/src/services/EmbedderFactory.d.ts +0 -4
  233. package/dist/src/services/EmbedderFactory.js +0 -5
  234. package/dist/src/services/IndexerService.d.ts +7 -26
  235. package/dist/src/services/IndexerService.js +38 -286
  236. package/dist/src/services/InfinityEmbedder.d.ts +0 -21
  237. package/dist/src/services/InfinityEmbedder.js +0 -15
  238. package/dist/src/services/LoggerService.d.ts +7 -5
  239. package/dist/src/services/LoggerService.js +37 -41
  240. package/dist/src/services/McpReadiness.d.ts +18 -0
  241. package/dist/src/services/McpReadiness.js +73 -0
  242. package/dist/src/services/McpServer.d.ts +50 -19
  243. package/dist/src/services/McpServer.js +132 -62
  244. package/dist/src/services/MonorepoAwareDiscoveryService.d.ts +1 -45
  245. package/dist/src/services/MonorepoAwareDiscoveryService.js +1 -51
  246. package/dist/src/services/NxMonorepoResolver.d.ts +0 -29
  247. package/dist/src/services/NxMonorepoResolver.js +5 -56
  248. package/dist/src/services/OpenAICompatibleEmbedder.d.ts +0 -6
  249. package/dist/src/services/OpenAICompatibleEmbedder.js +0 -14
  250. package/dist/src/services/ProjectDiscoveryService.d.ts +0 -4
  251. package/dist/src/services/ProjectDiscoveryService.js +0 -4
  252. package/dist/src/services/VoyageEmbedder.d.ts +0 -6
  253. package/dist/src/services/VoyageEmbedder.js +0 -6
  254. package/dist/src/services/WebServerService.d.ts +5 -56
  255. package/dist/src/services/WebServerService.js +25 -63
  256. package/dist/src/services/http-retry.d.ts +0 -7
  257. package/dist/src/services/http-retry.js +1 -10
  258. package/dist/src/services/infinity-provisioning.d.ts +0 -74
  259. package/dist/src/services/infinity-provisioning.js +5 -88
  260. package/dist/src/services/legacy-ollama-index.d.ts +0 -16
  261. package/dist/src/services/legacy-ollama-index.js +0 -23
  262. package/dist/src/services/reranker.d.ts +0 -9
  263. package/dist/src/services/reranker.js +46 -12
  264. package/dist/src/setup.d.ts +24 -24
  265. package/dist/src/setup.js +205 -103
  266. package/dist/src/symbol-name.d.ts +1 -12
  267. package/dist/src/symbol-name.js +16 -25
  268. package/dist/src/symbol-rows.d.ts +0 -14
  269. package/dist/src/symbol-rows.js +0 -14
  270. package/dist/src/tool-call-log.d.ts +2 -0
  271. package/dist/src/tool-call-log.js +24 -0
  272. package/dist/src/tools/FindSymbolTool.d.ts +17 -7
  273. package/dist/src/tools/FindSymbolTool.js +54 -35
  274. package/dist/src/tools/GetCallersTool.d.ts +16 -8
  275. package/dist/src/tools/GetCallersTool.js +65 -35
  276. package/dist/src/tools/GetDependenciesTool.d.ts +16 -8
  277. package/dist/src/tools/GetDependenciesTool.js +36 -29
  278. package/dist/src/tools/GetDependentsTool.d.ts +20 -8
  279. package/dist/src/tools/GetDependentsTool.js +48 -34
  280. package/dist/src/tools/ListFilesTool.d.ts +16 -8
  281. package/dist/src/tools/ListFilesTool.js +20 -26
  282. package/dist/src/tools/ListProjectsTool.d.ts +11 -7
  283. package/dist/src/tools/ListProjectsTool.js +13 -11
  284. package/dist/src/tools/McpTool.d.ts +17 -0
  285. package/dist/src/tools/McpTool.js +28 -0
  286. package/dist/src/tools/ReadFileRangeTool.d.ts +16 -8
  287. package/dist/src/tools/ReadFileRangeTool.js +23 -25
  288. package/dist/src/tools/ReadFileTool.d.ts +15 -8
  289. package/dist/src/tools/ReadFileTool.js +19 -24
  290. package/dist/src/tools/SearchCodebaseTool.d.ts +22 -10
  291. package/dist/src/tools/SearchCodebaseTool.js +71 -50
  292. package/dist/src/tools/format-helpers.d.ts +9 -9
  293. package/dist/src/tools/format-helpers.js +146 -28
  294. package/dist/src/tools/tool-args.d.ts +38 -0
  295. package/dist/src/tools/tool-args.js +95 -0
  296. package/dist/src/web/dashboard.d.ts +0 -8
  297. package/dist/src/web/dashboard.js +7 -10
  298. package/dist/src/workspace/GrepRunner.d.ts +15 -0
  299. package/dist/src/workspace/GrepRunner.js +104 -0
  300. package/dist/src/workspace/ProjectRoots.d.ts +22 -0
  301. package/dist/src/workspace/ProjectRoots.js +102 -0
  302. package/dist/src/workspace/ToolPaths.d.ts +31 -0
  303. package/dist/src/workspace/ToolPaths.js +312 -0
  304. package/dist/src/workspace/WorkspaceFiles.d.ts +19 -0
  305. package/dist/src/workspace/WorkspaceFiles.js +285 -0
  306. package/dist/src/workspace/fs-access.d.ts +9 -0
  307. package/dist/src/workspace/fs-access.js +47 -0
  308. package/dist/src/workspace/path-helpers.d.ts +3 -0
  309. package/dist/src/workspace/path-helpers.js +43 -0
  310. package/package.json +5 -4
  311. package/dist/src/interfaces/ISearcher.d.ts +0 -35
  312. package/dist/src/services/AstChunker.d.ts +0 -42
  313. package/dist/src/services/AstChunker.js +0 -158
  314. package/dist/src/services/SearcherService.d.ts +0 -342
  315. package/dist/src/services/SearcherService.js +0 -1199
  316. package/docs/web-dashboard.md +0 -206
  317. /package/dist/src/{interfaces/ISearcher.js → chunking/interfaces.js} +0 -0
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ImportOnlyFilter = void 0;
4
+ class ImportOnlyFilter {
5
+ process(pieces, ctx) {
6
+ return pieces.filter((p) => {
7
+ if (!ctx.lines.isImportOnly(p.startLine, p.endLine))
8
+ return true;
9
+ ctx.removed.push({ start: p.startLine, end: p.endLine });
10
+ return false;
11
+ });
12
+ }
13
+ }
14
+ exports.ImportOnlyFilter = ImportOnlyFilter;
@@ -0,0 +1,21 @@
1
+ import type { Config } from '../config';
2
+ import type { ChunkPiece } from '../interfaces/IChunker';
3
+ import type { ITextSplitter, KeepWindow } from './interfaces';
4
+ export interface SplitterOptions {
5
+ chunkSize: number;
6
+ chunkOverlap: number;
7
+ separators: string[];
8
+ }
9
+ export declare class LangchainTextSplitter implements ITextSplitter {
10
+ private readonly opts;
11
+ constructor(opts: SplitterOptions);
12
+ static forJs(config: Config): LangchainTextSplitter;
13
+ static forSchema(config: Config): LangchainTextSplitter;
14
+ split(text: string, firstLine: number, keep?: KeepWindow): Promise<ChunkPiece[]>;
15
+ private splitSpan;
16
+ private static splitOn;
17
+ private static joinKept;
18
+ private merge;
19
+ private static trim;
20
+ private static newlines;
21
+ }
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LangchainTextSplitter = void 0;
4
+ const textsplitters_1 = require("@langchain/textsplitters");
5
+ class LangchainTextSplitter {
6
+ opts;
7
+ constructor(opts) {
8
+ this.opts = opts;
9
+ if (opts.chunkOverlap >= opts.chunkSize)
10
+ throw new Error('Cannot have chunkOverlap >= chunkSize');
11
+ }
12
+ static forJs(config) {
13
+ return new LangchainTextSplitter({
14
+ chunkSize: config.indexer.chunkSize,
15
+ chunkOverlap: config.indexer.chunkOverlap,
16
+ separators: textsplitters_1.RecursiveCharacterTextSplitter.getSeparatorsForLanguage('js'),
17
+ });
18
+ }
19
+ static forSchema(config) {
20
+ return new LangchainTextSplitter({
21
+ chunkSize: config.indexer.chunkSize,
22
+ chunkOverlap: config.indexer.chunkOverlap,
23
+ separators: ['\n\n', '\n', ' '],
24
+ });
25
+ }
26
+ async split(text, firstLine, keep = { from: 0, to: 0 }) {
27
+ const pieces = [];
28
+ let offset = 0;
29
+ let line = firstLine;
30
+ for (const span of this.splitSpan(text, { start: 0, end: text.length }, this.opts.separators, keep)) {
31
+ line += LangchainTextSplitter.newlines(text, offset, span.start);
32
+ offset = span.start;
33
+ const content = text.slice(span.start, span.end);
34
+ pieces.push({ content, startLine: line, endLine: line + LangchainTextSplitter.newlines(content, 0, content.length) });
35
+ }
36
+ return pieces;
37
+ }
38
+ splitSpan(text, span, separators, keep) {
39
+ const sub = text.slice(span.start, span.end);
40
+ let separator = separators[separators.length - 1];
41
+ let next;
42
+ for (let i = 0; i < separators.length; i++) {
43
+ if (separators[i] === '') {
44
+ separator = '';
45
+ break;
46
+ }
47
+ if (sub.includes(separators[i])) {
48
+ separator = separators[i];
49
+ next = separators.slice(i + 1);
50
+ break;
51
+ }
52
+ }
53
+ const out = [];
54
+ let good = [];
55
+ const splits = LangchainTextSplitter.splitOn(sub, separator, span.start);
56
+ for (const s of separator ? LangchainTextSplitter.joinKept(splits, keep) : splits) {
57
+ if (s.end - s.start < this.opts.chunkSize) {
58
+ good.push(s);
59
+ continue;
60
+ }
61
+ if (good.length) {
62
+ out.push(...this.merge(text, good));
63
+ good = [];
64
+ }
65
+ out.push(...(next ? this.splitSpan(text, s, next, keep) : [s]));
66
+ }
67
+ if (good.length)
68
+ out.push(...this.merge(text, good));
69
+ return out;
70
+ }
71
+ static splitOn(sub, separator, base) {
72
+ const parts = separator
73
+ ? sub.split(new RegExp(`(?=${separator.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&')})`))
74
+ : sub.split('');
75
+ const spans = [];
76
+ let at = base;
77
+ for (const p of parts) {
78
+ if (p !== '')
79
+ spans.push({ start: at, end: at + p.length });
80
+ at += p.length;
81
+ }
82
+ return spans;
83
+ }
84
+ static joinKept(splits, keep) {
85
+ const out = [];
86
+ for (const s of splits) {
87
+ if (out.length && s.start > keep.from && s.start <= keep.to)
88
+ out[out.length - 1] = { start: out[out.length - 1].start, end: s.end };
89
+ else
90
+ out.push(s);
91
+ }
92
+ return out;
93
+ }
94
+ merge(text, splits) {
95
+ const { chunkSize, chunkOverlap } = this.opts;
96
+ const docs = [];
97
+ const current = [];
98
+ let total = 0;
99
+ const flush = () => {
100
+ const doc = LangchainTextSplitter.trim(text, { start: current[0].start, end: current[current.length - 1].end });
101
+ if (doc)
102
+ docs.push(doc);
103
+ };
104
+ for (const d of splits) {
105
+ const len = d.end - d.start;
106
+ if (total + len > chunkSize && current.length > 0) {
107
+ flush();
108
+ while (total > chunkOverlap || (total + len > chunkSize && total > 0)) {
109
+ total -= current[0].end - current[0].start;
110
+ current.shift();
111
+ }
112
+ }
113
+ current.push(d);
114
+ total += len;
115
+ }
116
+ if (current.length > 0)
117
+ flush();
118
+ return docs;
119
+ }
120
+ static trim(text, span) {
121
+ let { start, end } = span;
122
+ while (start < end && /\s/.test(text[start]))
123
+ start++;
124
+ while (end > start && /\s/.test(text[end - 1]))
125
+ end--;
126
+ return start < end ? { start, end } : null;
127
+ }
128
+ static newlines(text, from, to) {
129
+ const count = (a, b) => (text.slice(a, b).match(/\n/g) ?? []).length;
130
+ return to >= from ? count(from, to) : -count(to, from);
131
+ }
132
+ }
133
+ exports.LangchainTextSplitter = LangchainTextSplitter;
@@ -0,0 +1,9 @@
1
+ import type { DeclarationNode } from '../declarations/DeclarationTree';
2
+ import type { SourceLines } from '../declarations/SourceLines';
3
+ import type { ISplitPolicy } from './interfaces';
4
+ export declare const MIN_MEMBER_CHARS = 200;
5
+ export declare class MinSizeSplitPolicy implements ISplitPolicy {
6
+ private readonly minChars;
7
+ constructor(minChars?: number);
8
+ isSplitPoint(child: DeclarationNode, siblings: DeclarationNode[], parent: DeclarationNode | null, lines: SourceLines): boolean;
9
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MinSizeSplitPolicy = exports.MIN_MEMBER_CHARS = void 0;
4
+ exports.MIN_MEMBER_CHARS = 200;
5
+ class MinSizeSplitPolicy {
6
+ minChars;
7
+ constructor(minChars = exports.MIN_MEMBER_CHARS) {
8
+ this.minChars = minChars;
9
+ }
10
+ isSplitPoint(child, siblings, parent, lines) {
11
+ if (lines.length(child.start, child.end) < this.minChars)
12
+ return false;
13
+ if (parent && (child.start <= parent.nameLine || child.end >= parent.end))
14
+ return false;
15
+ return !siblings.some(s => s !== child && s.start <= child.end && child.start <= s.end);
16
+ }
17
+ }
18
+ exports.MinSizeSplitPolicy = MinSizeSplitPolicy;
@@ -0,0 +1,12 @@
1
+ import type { ChunkPiece } from '../interfaces/IChunker';
2
+ import type { DeclarationNode } from '../declarations/DeclarationTree';
3
+ import type { LineRange, SourceLines } from '../declarations/SourceLines';
4
+ import type { ITextSplitter } from './interfaces';
5
+ export declare class RunPacker {
6
+ private readonly splitter;
7
+ constructor(splitter: ITextSplitter);
8
+ pack(run: LineRange, children: DeclarationNode[], lines: SourceLines, chunkSize: number, characterSplit?: LineRange[], owner?: DeclarationNode | null): Promise<ChunkPiece[]>;
9
+ private static leadWindow;
10
+ static units(run: LineRange, children: DeclarationNode[]): LineRange[];
11
+ static piece(range: LineRange, lines: SourceLines): ChunkPiece[];
12
+ }
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RunPacker = void 0;
4
+ class RunPacker {
5
+ splitter;
6
+ constructor(splitter) {
7
+ this.splitter = splitter;
8
+ }
9
+ async pack(run, children, lines, chunkSize, characterSplit = [], owner = null) {
10
+ const pieces = [];
11
+ let current = null;
12
+ const flush = () => {
13
+ if (current)
14
+ pieces.push(...RunPacker.piece(current, lines));
15
+ current = null;
16
+ };
17
+ for (const unit of RunPacker.units(run, children)) {
18
+ if (lines.length(unit.start, unit.end) > chunkSize) {
19
+ flush();
20
+ characterSplit.push(unit);
21
+ const keep = RunPacker.leadWindow(unit, [owner, ...children], lines, chunkSize);
22
+ pieces.push(...await this.splitter.split(lines.slice(unit.start, unit.end), unit.start, keep));
23
+ continue;
24
+ }
25
+ if (current && lines.length(current.start, unit.end) <= chunkSize) {
26
+ current.end = unit.end;
27
+ continue;
28
+ }
29
+ flush();
30
+ current = { ...unit };
31
+ }
32
+ flush();
33
+ return pieces;
34
+ }
35
+ static leadWindow(unit, nodes, lines, chunkSize) {
36
+ const lead = nodes.find(n => n !== null && n.start === unit.start && n.nameLine > unit.start);
37
+ if (!lead)
38
+ return undefined;
39
+ const to = lines.length(unit.start, lead.nameLine - 1);
40
+ if (lines.length(unit.start, lead.nameLine) < chunkSize)
41
+ return { from: 0, to };
42
+ let first = unit.start;
43
+ while (first < lead.nameLine && (lines.isBlank(first) || lines.isCommentOnly(first)))
44
+ first++;
45
+ if (first === lead.nameLine || 1 + lines.length(first, lead.nameLine) >= chunkSize)
46
+ return undefined;
47
+ return { from: lines.length(unit.start, first - 1), to };
48
+ }
49
+ static units(run, children) {
50
+ const inside = children
51
+ .filter(c => c.end >= run.start && c.start <= run.end)
52
+ .sort((a, b) => a.start - b.start);
53
+ const units = [];
54
+ let cursor = run.start;
55
+ for (let i = 0; i < inside.length;) {
56
+ const start = Math.max(inside[i].start, run.start);
57
+ let end = Math.min(inside[i].end, run.end);
58
+ let j = i + 1;
59
+ while (j < inside.length && inside[j].start <= end) {
60
+ end = Math.min(Math.max(end, inside[j].end), run.end);
61
+ j++;
62
+ }
63
+ if (cursor < start)
64
+ units.push({ start: cursor, end: start - 1 });
65
+ units.push({ start, end });
66
+ cursor = end + 1;
67
+ i = j;
68
+ }
69
+ if (cursor <= run.end)
70
+ units.push({ start: cursor, end: run.end });
71
+ return units;
72
+ }
73
+ static piece(range, lines) {
74
+ let { start, end } = range;
75
+ while (start <= end && lines.isBlank(start))
76
+ start++;
77
+ while (end >= start && lines.isBlank(end))
78
+ end--;
79
+ if (start > end)
80
+ return [];
81
+ return [{ content: lines.slice(start, end), startLine: start, endLine: end }];
82
+ }
83
+ }
84
+ exports.RunPacker = RunPacker;
@@ -0,0 +1,3 @@
1
+ import type { Config } from '../config';
2
+ import { AstChunker } from './AstChunker';
3
+ export declare function createChunker(config: Config): AstChunker;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createChunker = createChunker;
4
+ const AstChunker_1 = require("./AstChunker");
5
+ const CharacterChunkStrategy_1 = require("./CharacterChunkStrategy");
6
+ const DeclarationChunkStrategy_1 = require("./DeclarationChunkStrategy");
7
+ const FragmentMerger_1 = require("./FragmentMerger");
8
+ const ImportOnlyFilter_1 = require("./ImportOnlyFilter");
9
+ const LangchainTextSplitter_1 = require("./LangchainTextSplitter");
10
+ const MinSizeSplitPolicy_1 = require("./MinSizeSplitPolicy");
11
+ const RunPacker_1 = require("./RunPacker");
12
+ function createChunker(config) {
13
+ const jsSplitter = LangchainTextSplitter_1.LangchainTextSplitter.forJs(config);
14
+ return new AstChunker_1.AstChunker(new DeclarationChunkStrategy_1.DeclarationChunkStrategy(new MinSizeSplitPolicy_1.MinSizeSplitPolicy(), new RunPacker_1.RunPacker(jsSplitter)), new CharacterChunkStrategy_1.CharacterChunkStrategy(jsSplitter, LangchainTextSplitter_1.LangchainTextSplitter.forSchema(config)), [new ImportOnlyFilter_1.ImportOnlyFilter()], [new FragmentMerger_1.FragmentMerger()], config);
15
+ }
@@ -0,0 +1,27 @@
1
+ import type { ChunkOpts, ChunkPiece } from '../interfaces/IChunker';
2
+ import type { DeclarationNode, DeclarationTree } from '../declarations/DeclarationTree';
3
+ import type { LineRange, SourceLines } from '../declarations/SourceLines';
4
+ export interface ChunkContext {
5
+ lines: SourceLines;
6
+ declarations: DeclarationTree;
7
+ chunkSize: number;
8
+ removed: LineRange[];
9
+ splitPoints: LineRange[];
10
+ characterSplit: LineRange[];
11
+ }
12
+ export interface IChunkStrategy {
13
+ chunk(ctx: ChunkContext, opts: ChunkOpts): Promise<ChunkPiece[]>;
14
+ }
15
+ export interface ISplitPolicy {
16
+ isSplitPoint(child: DeclarationNode, siblings: DeclarationNode[], parent: DeclarationNode | null, lines: SourceLines): boolean;
17
+ }
18
+ export interface KeepWindow {
19
+ from: number;
20
+ to: number;
21
+ }
22
+ export interface ITextSplitter {
23
+ split(text: string, firstLine: number, keep?: KeepWindow): Promise<ChunkPiece[]>;
24
+ }
25
+ export interface IChunkPostProcessor {
26
+ process(pieces: ChunkPiece[], ctx: ChunkContext): ChunkPiece[];
27
+ }
@@ -72,7 +72,6 @@ class ConfigCommand {
72
72
  console.log(`No config found at ${config_store_1.CONFIG_FILE}. Run rag-setup.`);
73
73
  return;
74
74
  }
75
- // redact password for display
76
75
  const display = JSON.parse(JSON.stringify(cfg));
77
76
  if (display.db?.password !== undefined)
78
77
  display.db.password = '***';
@@ -131,24 +130,18 @@ class ConfigCommand {
131
130
  }
132
131
  }
133
132
  edit() {
134
- // Ensure config + schema exist so the editor has something to open and
135
- // resolve the schema against.
136
133
  try {
137
134
  if (!fs.existsSync(config_store_1.CONFIG_FILE)) {
138
135
  (0, config_store_1.writeConfigJson)({});
139
136
  }
140
137
  else {
141
138
  (0, config_store_1.writeSchemaFile)();
142
- // Migrate existing configs: re-add the "$schema" reference if absent
143
- // (rewrite through writeConfigJson) so editors bind to the schema.
144
- // Skip silently if the file is currently invalid — the user will fix
145
- // it in the editor and validation runs on save.
146
139
  try {
147
140
  const cfg = (0, config_store_1.readConfigJson)();
148
141
  if (cfg)
149
142
  (0, config_store_1.writeConfigJson)(cfg);
150
143
  }
151
- catch { /* invalid file — leave as-is for the user to edit */ }
144
+ catch { }
152
145
  }
153
146
  }
154
147
  catch (e) {
@@ -164,7 +157,6 @@ class ConfigCommand {
164
157
  console.error('Set $EDITOR or edit the file directly: ' + config_store_1.CONFIG_FILE);
165
158
  process.exit(1);
166
159
  }
167
- // Validate what the user saved; readConfigJson throws with a helpful message.
168
160
  try {
169
161
  (0, config_store_1.readConfigJson)();
170
162
  console.log('Config OK');
@@ -1,10 +1,15 @@
1
- import type { Container } from '../container';
1
+ import type { Config } from '../config';
2
+ import type { IDatabase, IChunkSearch, IProjectCatalog } from '../interfaces';
2
3
  import type { ICommand } from './ICommand';
4
+ import type { ICorpusInspector } from '../interfaces/ICorpusInspector';
3
5
  export declare class EvalCommand implements ICommand {
4
- private container;
6
+ private db;
7
+ private chunks;
8
+ private catalog;
9
+ private config;
5
10
  private argv1;
6
- constructor(container: Container, argv1: string);
11
+ private corpusInspector;
12
+ private resultsDir;
13
+ constructor(db: IDatabase, chunks: IChunkSearch, catalog: IProjectCatalog, config: Config, argv1: string, corpusInspector?: ICorpusInspector, resultsDir?: string);
7
14
  execute(): Promise<void>;
8
- private printSummary;
9
- private printComparison;
10
15
  }
@@ -36,93 +36,53 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.EvalCommand = void 0;
37
37
  const fs = __importStar(require("fs"));
38
38
  const path = __importStar(require("path"));
39
- const crypto = __importStar(require("crypto"));
40
- const child_process_1 = require("child_process");
41
39
  const retrieval_eval_1 = require("../retrieval-eval");
42
40
  const eval_results_1 = require("../eval-results");
43
- const DEFAULT_SUITE_DIR = path.join('benchmarks', 'eval');
41
+ const eval_corpus_1 = require("../eval-corpus");
42
+ const eval_vector_index_1 = require("../eval-vector-index");
43
+ const constants_1 = require("../constants");
44
+ const eval_args_1 = require("./eval/eval-args");
45
+ const suite_loader_1 = require("./eval/suite-loader");
46
+ const eval_corpora_1 = require("./eval/eval-corpora");
47
+ const index_inspector_1 = require("./eval/index-inspector");
48
+ const staged_search_1 = require("./eval/staged-search");
49
+ const eval_metadata_1 = require("./eval/eval-metadata");
50
+ const baseline_comparison_1 = require("./eval/baseline-comparison");
44
51
  const RESULTS_DIR_NAME = path.join('benchmarks', 'results');
45
- // Resolves to the repo root in both `ts-node app.ts` (one level above `src/`) and
46
- // the compiled `dist/` layout (two levels above `dist/src/commands/`).
47
52
  const _projectRoot = fs.existsSync(path.join(__dirname, '..', '..', 'package.json'))
48
53
  ? path.join(__dirname, '..', '..')
49
54
  : path.join(__dirname, '..', '..', '..');
50
- function gitCommit() {
51
- try {
52
- return (0, child_process_1.execFileSync)('git', ['rev-parse', 'HEAD'], { cwd: _projectRoot, encoding: 'utf-8' }).trim();
53
- }
54
- catch {
55
- return 'unknown';
56
- }
57
- }
58
- function hashContent(text) {
59
- return crypto.createHash('sha256').update(text).digest('hex').slice(0, 16);
60
- }
61
- /** `--suite <path>` — a file or a directory of `*.json` suite files (default: `benchmarks/eval/`). */
62
- function parseSuiteFlag(args) {
63
- const i = args.indexOf('--suite');
64
- if (i === -1)
65
- return DEFAULT_SUITE_DIR;
66
- const next = args[i + 1];
67
- if (next === undefined || next.startsWith('-'))
68
- throw new Error('--suite requires a path');
69
- return next;
70
- }
71
- function parseBaselineFlag(args) {
72
- const i = args.indexOf('--baseline');
73
- if (i === -1)
74
- return null;
75
- const next = args[i + 1];
76
- if (next === undefined || next.startsWith('-'))
77
- throw new Error('--baseline requires a path');
78
- return next;
79
- }
80
- function parseProjectFlag(args) {
81
- const i = args.indexOf('--project');
82
- if (i === -1)
83
- return null;
84
- const next = args[i + 1];
85
- if (next === undefined || next.startsWith('-'))
86
- throw new Error('--project requires a name');
87
- return next;
88
- }
89
- /** Loads one suite file, or every `*.json` file directly under a directory, merged into one. */
90
- function loadSuite(suitePath) {
91
- const resolved = path.resolve(_projectRoot, suitePath);
92
- const stat = fs.statSync(resolved);
93
- if (stat.isDirectory()) {
94
- const files = fs.readdirSync(resolved).filter(f => f.endsWith('.json')).sort();
95
- const parts = files.map(f => fs.readFileSync(path.join(resolved, f), 'utf-8'));
96
- const suites = parts.map(text => (0, retrieval_eval_1.parseSuite)(JSON.parse(text)));
97
- return { suite: (0, retrieval_eval_1.mergeSuites)(suites), rawContent: parts.join('\n'), label: 'all' };
98
- }
99
- const text = fs.readFileSync(resolved, 'utf-8');
100
- return { suite: (0, retrieval_eval_1.parseSuite)(JSON.parse(text)), rawContent: text, label: path.basename(resolved, '.json') };
101
- }
102
55
  class EvalCommand {
103
- container;
56
+ db;
57
+ chunks;
58
+ catalog;
59
+ config;
104
60
  argv1;
105
- constructor(container, argv1) {
106
- this.container = container;
61
+ corpusInspector;
62
+ resultsDir;
63
+ constructor(db, chunks, catalog, config, argv1, corpusInspector = new eval_corpus_1.GitCorpusInspector(), resultsDir = path.join(_projectRoot, RESULTS_DIR_NAME)) {
64
+ this.db = db;
65
+ this.chunks = chunks;
66
+ this.catalog = catalog;
67
+ this.config = config;
107
68
  this.argv1 = argv1;
69
+ this.corpusInspector = corpusInspector;
70
+ this.resultsDir = resultsDir;
108
71
  }
109
72
  async execute() {
110
- const { db, searcher, config } = this.container;
111
- const args = process.argv.slice(this.argv1 === 'rag-index' ? 3 : 4); // after `rag-index eval` / `index eval`
73
+ const args = process.argv.slice(this.argv1 === 'rag-index' ? 3 : 4);
112
74
  let suitePath, baselinePath, projectFilter;
113
75
  try {
114
- suitePath = parseSuiteFlag(args);
115
- baselinePath = parseBaselineFlag(args);
116
- projectFilter = parseProjectFlag(args);
76
+ ({ suitePath, baselinePath, projectFilter } = (0, eval_args_1.parseEvalArgs)(args));
117
77
  }
118
78
  catch (err) {
119
79
  console.error(`\n${err.message}`);
120
80
  process.exitCode = 1;
121
81
  return;
122
82
  }
123
- let suite, rawContent, label;
83
+ let suite, corpora, rawContent, label;
124
84
  try {
125
- ({ suite, rawContent, label } = loadSuite(suitePath));
85
+ ({ suite, corpora, rawContent, label } = (0, suite_loader_1.loadSuite)(_projectRoot, suitePath));
126
86
  }
127
87
  catch (err) {
128
88
  if (err instanceof retrieval_eval_1.EvalSuiteError) {
@@ -142,90 +102,41 @@ class EvalCommand {
142
102
  process.exitCode = 1;
143
103
  return;
144
104
  }
145
- await db.initDbWithSchema();
146
- const knownFilesCache = new Map();
147
- const inspect = {
148
- async isFileIndexed(project, file) {
149
- if (!knownFilesCache.has(project))
150
- knownFilesCache.set(project, db.listKnownFiles(project));
151
- const files = await knownFilesCache.get(project);
152
- return files.includes(file);
153
- },
154
- async ownerPathsOfFile(project, file) {
155
- const rows = await db.query(`SELECT DISTINCT "ownerPath" FROM code_chunk WHERE "serviceName" = $1 AND "filePath" = $2 AND "ownerPath" IS NOT NULL`, [project, file]);
156
- return rows.map(r => r.ownerPath);
157
- },
158
- };
159
- const search = async (query, limit, project, threshold) => {
160
- const prepared = await searcher.prepareQuery(query);
161
- const results = await searcher.searchChunks(prepared.query, limit, project, threshold);
162
- return results.map(r => ({ filePath: r.filePath, ownerPath: r.ownerPath ?? null }));
163
- };
164
- const run = await new retrieval_eval_1.RetrievalEvaluator().evaluate(suite, search, inspect);
165
- const indexMeta = await db.readIndexMeta();
166
- const metadata = {
167
- suitePath,
168
- suiteHash: hashContent(rawContent),
169
- embeddingProvider: config.embedding.provider,
170
- embeddingModel: config.embedding.model,
171
- rerankerModel: config.reranker.enabled ? config.reranker.model : null,
172
- indexMeta: indexMeta ? { provider: indexMeta.provider, model: indexMeta.model, dimensions: indexMeta.dimensions } : null,
173
- gitCommit: gitCommit(),
174
- timestamp: new Date().toISOString(),
175
- };
176
- const resultFile = { metadata, run };
177
- this.printSummary(resultFile);
178
- let comparison;
179
- if (baselinePath) {
180
- try {
181
- const baseline = (0, eval_results_1.readResultFile)(path.resolve(_projectRoot, baselinePath));
182
- const cmp = (0, retrieval_eval_1.compare)(baseline, resultFile);
183
- comparison = { baselinePath, result: cmp };
184
- this.printComparison(baselinePath, cmp);
185
- }
186
- catch (err) {
187
- console.error(`\nFailed to read baseline '${baselinePath}': ${err.message}`);
188
- process.exitCode = 1;
189
- }
190
- }
191
- const resultsDir = path.join(_projectRoot, RESULTS_DIR_NAME);
192
- const { jsonPath, mdPath } = (0, eval_results_1.writeResultFiles)(resultsDir, label, resultFile, new Date(), comparison);
193
- console.log(`\nResults written to:\n ${path.relative(_projectRoot, jsonPath)}\n ${path.relative(_projectRoot, mdPath)}`);
194
- }
195
- printSummary(result) {
196
- const { run, metadata } = result;
197
- console.log(`\nEvaluated ${run.cases.length} case(s) (${run.invalid.length} invalid) against ${metadata.embeddingProvider}/${metadata.embeddingModel}`);
198
- const o = run.metrics.overall;
199
- console.log(` Overall — hit@1: ${(o.hit1 * 100).toFixed(1)}% hit@5: ${(o.hit5 * 100).toFixed(1)}% MRR@10: ${o.mrr10.toFixed(4)}`);
200
- for (const category of ['identifier', 'behaviour', 'concept']) {
201
- const m = run.metrics.byCategory[category];
202
- if (m)
203
- console.log(` ${category.padEnd(10)} — hit@1: ${(m.hit1 * 100).toFixed(1)}% hit@5: ${(m.hit5 * 100).toFixed(1)}% MRR@10: ${m.mrr10.toFixed(4)} (${m.count})`);
204
- }
205
- if (run.invalid.length > 0) {
206
- console.log(`\nInvalid cases:`);
207
- for (const c of run.invalid)
208
- console.log(` ${c.id}: ${c.reason} — ${c.invalidExpects.map(e => e.file).join(', ')}`);
209
- }
210
- if (run.warnings.length > 0) {
211
- console.log(`\nWarnings (scored on remaining valid answers):`);
212
- for (const w of run.warnings)
213
- console.log(` ${w.id}: dropped ${w.droppedExpects.map(e => e.file).join(', ')}`);
105
+ const runCorpora = corpora.filter(c => suite.cases.some(k => k.corpus === c.root));
106
+ if (await (0, eval_corpora_1.refusesMovedCorpus)(runCorpora, this.config, _projectRoot, this.corpusInspector))
107
+ return;
108
+ await this.db.initDbWithSchema();
109
+ const projectDirs = new Map((await this.catalog.listProjects()).map(p => [p.serviceName, p.relPath ?? null]));
110
+ const inspect = (0, index_inspector_1.createIndexInspector)(this.db, projectDirs);
111
+ const search = (0, staged_search_1.createStagedSearch)(this.chunks);
112
+ const thresholdWarning = (0, constants_1.thresholdMismatchWarning)(this.config.search.similarityThreshold, this.config.embedding.model);
113
+ if (thresholdWarning)
114
+ console.warn(`\n⚠ ${thresholdWarning}\n`);
115
+ const vectorIndex = await (0, eval_vector_index_1.describeVectorIndex)(this.db);
116
+ let outcome;
117
+ try {
118
+ outcome = await new retrieval_eval_1.RetrievalEvaluator().evaluate(suite, search, inspect, p => console.error((0, eval_results_1.renderProgress)(p)));
214
119
  }
215
- }
216
- printComparison(baselinePath, cmp) {
217
- console.log(`\nComparison against ${baselinePath}:`);
218
- if (cmp.conditionWarnings.length > 0) {
219
- for (const w of cmp.conditionWarnings)
220
- console.log(` ⚠ ${w}`);
120
+ catch (err) {
121
+ if (!(err instanceof retrieval_eval_1.EvalSuiteError))
122
+ throw err;
123
+ console.error(`\nInvalid suite: ${err.message}`);
124
+ process.exitCode = 1;
125
+ return;
221
126
  }
222
- const sign = (n) => (n >= 0 ? '+' : '') + n.toFixed(4);
223
- console.log(` MRR@10: ${cmp.overall.mrr10.baseline.toFixed(4)} → ${cmp.overall.mrr10.current.toFixed(4)} (${sign(cmp.overall.mrr10.delta)})`);
224
- console.log(` hit@5: ${(cmp.overall.hit5.baseline * 100).toFixed(1)}% → ${(cmp.overall.hit5.current * 100).toFixed(1)}%`);
225
- if (cmp.hit5Lost.length > 0)
226
- console.log(` Lost hit@5: ${cmp.hit5Lost.join(', ')}`);
227
- if (cmp.hit5Gained.length > 0)
228
- console.log(` Gained hit@5: ${cmp.hit5Gained.join(', ')}`);
127
+ const { run, observed } = outcome;
128
+ const corpusRecords = await (0, eval_corpora_1.recordCorpora)(this.db, runCorpora, projectDirs);
129
+ const indexMeta = await this.db.readIndexMeta();
130
+ const metadata = (0, eval_metadata_1.buildResultMetadata)({
131
+ suitePath, rawContent, config: this.config, indexMeta, observed, vectorIndex, corpusRecords,
132
+ liveCases: suite.cases.filter(c => !c.corpus).length, projectRoot: _projectRoot,
133
+ });
134
+ const resultFile = { metadata, run };
135
+ for (const line of (0, eval_results_1.renderSummary)(resultFile))
136
+ console.log(line);
137
+ const comparison = baselinePath ? (0, baseline_comparison_1.compareWithBaseline)(_projectRoot, baselinePath, resultFile) : undefined;
138
+ const { jsonPath, mdPath } = (0, eval_results_1.writeResultFiles)(this.resultsDir, label, resultFile, new Date(), comparison);
139
+ console.log(`\nResults written to:\n ${path.relative(_projectRoot, jsonPath)}\n ${path.relative(_projectRoot, mdPath)}`);
229
140
  }
230
141
  }
231
142
  exports.EvalCommand = EvalCommand;