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
@@ -14,22 +14,13 @@ exports.HttpError = HttpError;
14
14
  function sleep(ms) {
15
15
  return ms > 0 ? new Promise(r => setTimeout(r, ms)) : Promise.resolve();
16
16
  }
17
- /** True for transient failures worth retrying (rate limit / server error / network / timeout). */
18
17
  function isRetryable(err) {
19
18
  if (err instanceof HttpError)
20
19
  return err.status === 429 || (err.status >= 500 && err.status <= 599);
21
- // A request timeout (AbortSignal.timeout) rejects with a DOMException named
22
- // 'TimeoutError' — the most common transient cloud failure, so retry it.
23
20
  if (err != null && typeof err === 'object' && err.name === 'TimeoutError')
24
21
  return true;
25
- // Network-level errors (fetch throws) are transient too.
26
22
  return err instanceof TypeError;
27
23
  }
28
- /**
29
- * Run `fn` with bounded exponential backoff on HTTP 429/5xx and network errors.
30
- * Re-throws the last error once attempts are exhausted or the error is not
31
- * transient.
32
- */
33
24
  async function withRetry(fn, opts = {}) {
34
25
  const attempts = opts.attempts ?? 4;
35
26
  const base = opts.baseDelayMs ?? 500;
@@ -45,7 +36,7 @@ async function withRetry(fn, opts = {}) {
45
36
  const delay = base * Math.pow(2, attempt - 1);
46
37
  opts.logger?.warn('http-retry: transient failure, retrying', {
47
38
  label: opts.label, attempt, attempts, delayMs: delay,
48
- reason: err instanceof Error ? err.message : String(err),
39
+ err,
49
40
  });
50
41
  await sleep(delay);
51
42
  }
@@ -1,115 +1,41 @@
1
1
  import type { Config } from '../config';
2
- /** Result of a shell command run, mirroring the parts of `spawnSync` we use. */
3
2
  export interface CommandResult {
4
3
  status: number | null;
5
4
  stdout?: string;
6
5
  stderr?: string;
7
6
  }
8
- /** Injection seams for the provisioning primitive. All optional, defaulted to the real implementations. */
9
7
  export interface ProvisioningDeps {
10
8
  fetchImpl?: typeof fetch;
11
- /** Runs a shell command (docker). Defaults to `spawnSync` with captured output. */
12
9
  runCommand?: (cmd: string, args: string[]) => CommandResult;
13
- /** Sleep between readiness polls (ms), capped at 5000. Defaults to 2000; tests pass 0. */
14
10
  pollIntervalMs?: number;
15
- /** Readiness wait timeout (ms). Defaults to 1,800,000 (30 min); tests override to run fast. */
16
11
  readinessTimeoutMs?: number;
17
12
  }
18
- /**
19
- * Strip trailing slashes and a trailing `/embeddings` or `/v1` to get the server
20
- * root — Infinity serves `/health`, `/models`, `/rerank`, `/embeddings` from the
21
- * root, so a baseURL written with an OpenAI-style suffix must be normalized here
22
- * to keep the probe/models URLs aligned with the embeddings URL.
23
- */
24
13
  export declare function serverRoot(baseURL: string): string;
25
- /**
26
- * Probe an Infinity-style `/health` endpoint. Resolves `true` when the server
27
- * answers with a 2xx, `false` on any error, non-2xx, or timeout.
28
- */
29
14
  export declare function probeInfinityHealth(baseURL: string, fetchImpl?: typeof fetch, timeoutMs?: number): Promise<boolean>;
30
- /**
31
- * List the model ids an Infinity server currently serves via its OpenAI-style
32
- * `/models` listing (`{ data: [{ id }] }`). Returns `[]` on any error, non-2xx,
33
- * or timeout — callers treat an empty/unverifiable listing as "served".
34
- */
35
15
  export declare function listInfinityModels(baseURL: string, fetchImpl?: typeof fetch, timeoutMs?: number): Promise<string[]>;
36
- /**
37
- * Two URLs target the same server when scheme, (loopback-normalised) host, and
38
- * port (explicit or scheme default) all match; path is ignored. An unparsable
39
- * URL is never the same server as another.
40
- */
41
16
  export declare function sameServer(a: string, b: string): boolean;
42
- /**
43
- * "Managed" per the managed-vs-external requirement: the compose file exists,
44
- * declares an `infinity` service, the base URL host is loopback, and its port
45
- * (explicit or scheme default) equals the service's published host port.
46
- * Never throws — an unreadable/unparsable file or an unrecognised port form
47
- * is simply "external".
48
- */
49
17
  export declare function isManagedInfinity(baseURL: string, composePath: string): boolean;
50
- /** The literal (non-`${…}`) `INFINITY_MODEL_ID` value in the compose file's `infinity` service, or null. */
51
18
  export declare function extractModelIdValue(composeContent: string): string | null;
52
- /** Write `content` to `targetPath` via a same-directory temp file + rename; removes the temp file on failure. */
53
19
  export declare function atomicWriteFile(targetPath: string, content: string, mode: number): void;
54
- /**
55
- * Write `modelSet` (embedding model first) as the literal `INFINITY_MODEL_ID`
56
- * of the compose file's `infinity` service, and remove a `profiles:` entry of
57
- * that service if present (a file written by an earlier version). At most
58
- * those two targeted edits — every other byte unchanged. Atomic (temp file +
59
- * rename), keeps the original file's mode. Throws (no write, original file
60
- * unchanged) when the file cannot be read, has no `infinity` service, has no
61
- * `INFINITY_MODEL_ID:` line, or the write itself fails.
62
- */
63
20
  export declare function writeComposeModelSet(composePath: string, modelSet: string[]): void;
64
- /** True when an NVIDIA GPU + `nvidia-smi` is available on this host. */
65
21
  export declare function hasNvidiaGpu(): boolean;
66
- /** The `-f` file args a docker compose invocation against `composePath` should use (base, plus GPU override when present + detected). */
67
22
  export declare function composeFileArgs(composePath: string): string[];
68
23
  export type BackendAction = 'served' | 'missing-managed' | 'missing-external' | 'unreachable-managed' | 'unreachable-external';
69
24
  export interface BackendEvaluation {
70
25
  action: BackendAction;
71
26
  managed: boolean;
72
- /** Required models absent from the served listing; empty for `served` or an unverifiable listing. */
73
27
  missingModels: string[];
74
- /** The full served listing at evaluation time; empty for an unverifiable listing or when unreachable. */
75
28
  servedModels: string[];
76
29
  }
77
- /**
78
- * Classify the backend against `requiredModels` without touching Docker:
79
- * reachable+served (or unverifiable listing) → `served`; reachable+missing →
80
- * `missing-managed`/`missing-external`; unreachable → `unreachable-managed`/
81
- * `unreachable-external`. Shared by `ensureBackendReady`, the web-dashboard
82
- * decision table, and `rag-setup`'s declined-Docker branch.
83
- */
84
30
  export declare function evaluateBackend(baseURL: string, composePath: string, requiredModels: string[], deps?: ProvisioningDeps): Promise<BackendEvaluation>;
85
- /** Human-readable manual instructions for a `missing-external`/`unreachable-external` evaluation. */
86
31
  export declare function manualInstructionMessage(evaluation: BackendEvaluation, base: string, modelSetToWrite: string[]): string;
87
32
  export interface EnsureBackendReadyOpts {
88
33
  baseURL: string;
89
- /** Models that must be served for the call to succeed without a recreate/instructions. */
90
34
  requiredModels: string[];
91
- /** Full model set to write into the compose file and bind at startup when a start/recreate is needed. */
92
35
  modelSetToWrite: string[];
93
36
  composePath: string;
94
37
  deps?: ProvisioningDeps;
95
38
  }
96
- /**
97
- * Bring the Infinity backend to a state serving `requiredModels`, per the
98
- * managed-vs-external decision tree:
99
- * served → return (no Docker)
100
- * missing-managed → recreate (writes modelSetToWrite) + wait
101
- * missing-external → throw (manual --model-id instructions)
102
- * unreachable-managed → (re)create + wait
103
- * unreachable-external → throw (manual launch instructions)
104
- */
105
39
  export declare function ensureBackendReady(opts: EnsureBackendReadyOpts): Promise<void>;
106
- /** `ensureBackendReady` with the full set as both the requirement and the write (rag-setup, web dashboard). */
107
40
  export declare function ensureModelSetServed(baseURL: string, composePath: string, modelSet: string[], deps?: ProvisioningDeps): Promise<void>;
108
- /**
109
- * The model set a managed Infinity container must serve, computed from a
110
- * `Config`: the embedding model, followed by the reranker model only when
111
- * reranking is enabled with a model on the same server as embeddings (the
112
- * effective `reranker.url`, which `Config` has already resolved from an
113
- * explicit value or derived from `reranker.baseURL`).
114
- */
115
41
  export declare function requiredModelSet(cfg: Config): string[];
@@ -51,19 +51,9 @@ exports.requiredModelSet = requiredModelSet;
51
51
  const fs = __importStar(require("fs"));
52
52
  const path = __importStar(require("path"));
53
53
  const child_process_1 = require("child_process");
54
- /**
55
- * Strip trailing slashes and a trailing `/embeddings` or `/v1` to get the server
56
- * root — Infinity serves `/health`, `/models`, `/rerank`, `/embeddings` from the
57
- * root, so a baseURL written with an OpenAI-style suffix must be normalized here
58
- * to keep the probe/models URLs aligned with the embeddings URL.
59
- */
60
54
  function serverRoot(baseURL) {
61
55
  return baseURL.replace(/\/+$/, '').replace(/\/(embeddings|v1)$/, '');
62
56
  }
63
- /**
64
- * Probe an Infinity-style `/health` endpoint. Resolves `true` when the server
65
- * answers with a 2xx, `false` on any error, non-2xx, or timeout.
66
- */
67
57
  async function probeInfinityHealth(baseURL, fetchImpl = fetch, timeoutMs = 2000) {
68
58
  try {
69
59
  const res = await fetchImpl(`${serverRoot(baseURL)}/health`, {
@@ -76,11 +66,6 @@ async function probeInfinityHealth(baseURL, fetchImpl = fetch, timeoutMs = 2000)
76
66
  return false;
77
67
  }
78
68
  }
79
- /**
80
- * List the model ids an Infinity server currently serves via its OpenAI-style
81
- * `/models` listing (`{ data: [{ id }] }`). Returns `[]` on any error, non-2xx,
82
- * or timeout — callers treat an empty/unverifiable listing as "served".
83
- */
84
69
  async function listInfinityModels(baseURL, fetchImpl = fetch, timeoutMs = 2000) {
85
70
  try {
86
71
  const res = await fetchImpl(`${serverRoot(baseURL)}/models`, {
@@ -96,13 +81,6 @@ async function listInfinityModels(baseURL, fetchImpl = fetch, timeoutMs = 2000)
96
81
  return [];
97
82
  }
98
83
  }
99
- // ---------------------------------------------------------------------------
100
- // Compose-file parsing — deliberately line-based, not a YAML library: we only
101
- // ever make targeted, well-anchored edits to our own shipped template, and
102
- // need "every other byte unchanged" — a round-trip through a YAML AST would
103
- // not guarantee that.
104
- // ---------------------------------------------------------------------------
105
- /** [start, end) line range of a top-level `services:` entry (2-space indent), or null if absent. */
106
84
  function findServiceBlock(lines, serviceName) {
107
85
  const headerRe = new RegExp(`^ ${serviceName}:\\s*$`);
108
86
  const start = lines.findIndex(l => headerRe.test(l));
@@ -120,15 +98,12 @@ function findServiceBlock(lines, serviceName) {
120
98
  }
121
99
  return [start, end];
122
100
  }
123
- /** Extract a published host port from one `ports:` list item's raw line(s), or null if unrecognised. */
124
101
  function parsePortItem(item) {
125
102
  if (item.length === 1) {
126
103
  const raw = item[0].replace(/^["']|["']$/g, '').trim();
127
- // Short form: "HOST:CONTAINER" or "IP:HOST:CONTAINER" (optional /tcp|/udp).
128
104
  const m = raw.match(/^(?:(?:\[[0-9a-fA-F:]+\]|[0-9.]+):)?(\d+):(\d+)(?:\/(?:tcp|udp))?$/);
129
105
  return m ? m[1] : null;
130
106
  }
131
- // Long form block ("- target: 7997\n published: 7997\n protocol: tcp").
132
107
  for (const line of item) {
133
108
  const m = line.match(/published:\s*["']?(\d+)["']?/);
134
109
  if (m)
@@ -136,7 +111,6 @@ function parsePortItem(item) {
136
111
  }
137
112
  return null;
138
113
  }
139
- /** Published host port of a service's `ports:` entries within `serviceLines`, or null if none/unrecognised. */
140
114
  function extractPublishedPort(serviceLines) {
141
115
  const portsIdx = serviceLines.findIndex(l => /^\s*ports:\s*$/.test(l));
142
116
  if (portsIdx === -1)
@@ -177,11 +151,6 @@ function normalizedHost(hostname) {
177
151
  function schemeDefaultPort(protocol) {
178
152
  return protocol === 'https:' ? '443' : '80';
179
153
  }
180
- /**
181
- * Two URLs target the same server when scheme, (loopback-normalised) host, and
182
- * port (explicit or scheme default) all match; path is ignored. An unparsable
183
- * URL is never the same server as another.
184
- */
185
154
  function sameServer(a, b) {
186
155
  try {
187
156
  const ua = new URL(a);
@@ -198,13 +167,6 @@ function sameServer(a, b) {
198
167
  return false;
199
168
  }
200
169
  }
201
- /**
202
- * "Managed" per the managed-vs-external requirement: the compose file exists,
203
- * declares an `infinity` service, the base URL host is loopback, and its port
204
- * (explicit or scheme default) equals the service's published host port.
205
- * Never throws — an unreadable/unparsable file or an unrecognised port form
206
- * is simply "external".
207
- */
208
170
  function isManagedInfinity(baseURL, composePath) {
209
171
  try {
210
172
  let url;
@@ -231,7 +193,6 @@ function isManagedInfinity(baseURL, composePath) {
231
193
  return false;
232
194
  }
233
195
  }
234
- /** The literal (non-`${…}`) `INFINITY_MODEL_ID` value in the compose file's `infinity` service, or null. */
235
196
  function extractModelIdValue(composeContent) {
236
197
  const lines = composeContent.split(/\r?\n/);
237
198
  const block = findServiceBlock(lines, 'infinity');
@@ -246,7 +207,6 @@ function extractModelIdValue(composeContent) {
246
207
  }
247
208
  return null;
248
209
  }
249
- /** Write `content` to `targetPath` via a same-directory temp file + rename; removes the temp file on failure. */
250
210
  function atomicWriteFile(targetPath, content, mode) {
251
211
  const dir = path.dirname(targetPath);
252
212
  const tmpPath = path.join(dir, `.${path.basename(targetPath)}.tmp-${process.pid}-${Date.now()}`);
@@ -258,19 +218,10 @@ function atomicWriteFile(targetPath, content, mode) {
258
218
  try {
259
219
  fs.unlinkSync(tmpPath);
260
220
  }
261
- catch { /* best effort cleanup */ }
221
+ catch { }
262
222
  throw err;
263
223
  }
264
224
  }
265
- /**
266
- * Write `modelSet` (embedding model first) as the literal `INFINITY_MODEL_ID`
267
- * of the compose file's `infinity` service, and remove a `profiles:` entry of
268
- * that service if present (a file written by an earlier version). At most
269
- * those two targeted edits — every other byte unchanged. Atomic (temp file +
270
- * rename), keeps the original file's mode. Throws (no write, original file
271
- * unchanged) when the file cannot be read, has no `infinity` service, has no
272
- * `INFINITY_MODEL_ID:` line, or the write itself fails.
273
- */
274
225
  function writeComposeModelSet(composePath, modelSet) {
275
226
  let content;
276
227
  let mode;
@@ -279,7 +230,7 @@ function writeComposeModelSet(composePath, modelSet) {
279
230
  mode = fs.statSync(composePath).mode;
280
231
  }
281
232
  catch (err) {
282
- throw new Error(`Cannot read managed compose file at ${composePath}: ${err.message}`);
233
+ throw new Error(`Cannot read managed compose file at ${composePath}: ${err.message}`, { cause: err });
283
234
  }
284
235
  const newline = content.includes('\r\n') ? '\r\n' : '\n';
285
236
  const lines = content.split(/\r?\n/);
@@ -327,10 +278,9 @@ function writeComposeModelSet(composePath, modelSet) {
327
278
  atomicWriteFile(composePath, outLines.join(newline), mode);
328
279
  }
329
280
  catch (err) {
330
- throw new Error(`Failed to write managed compose file at ${composePath}: ${err.message}`);
281
+ throw new Error(`Failed to write managed compose file at ${composePath}: ${err.message}`, { cause: err });
331
282
  }
332
283
  }
333
- /** True when an NVIDIA GPU + `nvidia-smi` is available on this host. */
334
284
  function hasNvidiaGpu() {
335
285
  try {
336
286
  return (0, child_process_1.spawnSync)('nvidia-smi', ['-L'], { stdio: 'ignore' }).status === 0;
@@ -342,7 +292,6 @@ function hasNvidiaGpu() {
342
292
  function gpuOverridePath(composePath) {
343
293
  return path.join(path.dirname(composePath), 'docker-compose.infinity-gpu.yml');
344
294
  }
345
- /** The `-f` file args a docker compose invocation against `composePath` should use (base, plus GPU override when present + detected). */
346
295
  function composeFileArgs(composePath) {
347
296
  const gpu = gpuOverridePath(composePath);
348
297
  return (fs.existsSync(gpu) && hasNvidiaGpu()) ? ['-f', composePath, '-f', gpu] : ['-f', composePath];
@@ -354,7 +303,6 @@ function defaultRunCommand(cmd, args) {
354
303
  function sleep(ms) {
355
304
  return new Promise(resolve => setTimeout(resolve, ms));
356
305
  }
357
- /** Parse `docker compose ps --all --format json` output (JSON-lines, or an array) for the `infinity` service's state. */
358
306
  function parseInfinityState(stdout) {
359
307
  const readState = (obj) => {
360
308
  const s = String(obj?.State ?? '').toLowerCase();
@@ -366,7 +314,7 @@ function parseInfinityState(stdout) {
366
314
  if (obj?.Service === 'infinity')
367
315
  return readState(obj);
368
316
  }
369
- catch { /* not a JSON-lines entry — fall through to array parsing below */ }
317
+ catch { }
370
318
  }
371
319
  try {
372
320
  const arr = JSON.parse(stdout);
@@ -376,14 +324,9 @@ function parseInfinityState(stdout) {
376
324
  return readState(svc);
377
325
  }
378
326
  }
379
- catch { /* not an array either */ }
327
+ catch { }
380
328
  return 'missing';
381
329
  }
382
- /**
383
- * Wait for `/health` after a start/recreate, failing fast on a crashed or
384
- * restart-looping container instead of waiting out the full timeout, then
385
- * re-check the models listing once more. Poll interval capped at 5s.
386
- */
387
330
  async function waitForReady(base, files, modelSetToWrite, requiredModels, deps) {
388
331
  const fetchImpl = deps.fetchImpl ?? fetch;
389
332
  const runCommand = deps.runCommand ?? defaultRunCommand;
@@ -412,7 +355,6 @@ async function waitForReady(base, files, modelSetToWrite, requiredModels, deps)
412
355
  consecutiveRestarting = 0;
413
356
  }
414
357
  }
415
- // A failing `ps` is ignored — neither counts toward nor resets the restarting streak.
416
358
  if (Date.now() >= deadline) {
417
359
  throw new Error(`Infinity did not become ready within ${Math.round(timeoutMs / 1000)}s at ${base}.`);
418
360
  }
@@ -438,13 +380,6 @@ async function recreateAndWait(base, composePath, modelSetToWrite, requiredModel
438
380
  }
439
381
  await waitForReady(base, files, modelSetToWrite, requiredModels, deps);
440
382
  }
441
- /**
442
- * Classify the backend against `requiredModels` without touching Docker:
443
- * reachable+served (or unverifiable listing) → `served`; reachable+missing →
444
- * `missing-managed`/`missing-external`; unreachable → `unreachable-managed`/
445
- * `unreachable-external`. Shared by `ensureBackendReady`, the web-dashboard
446
- * decision table, and `rag-setup`'s declined-Docker branch.
447
- */
448
383
  async function evaluateBackend(baseURL, composePath, requiredModels, deps = {}) {
449
384
  const fetchImpl = deps.fetchImpl ?? fetch;
450
385
  const base = serverRoot(baseURL);
@@ -458,7 +393,6 @@ async function evaluateBackend(baseURL, composePath, requiredModels, deps = {})
458
393
  }
459
394
  return { action: managed ? 'unreachable-managed' : 'unreachable-external', managed, missingModels: [], servedModels: [] };
460
395
  }
461
- /** Human-readable manual instructions for a `missing-external`/`unreachable-external` evaluation. */
462
396
  function manualInstructionMessage(evaluation, base, modelSetToWrite) {
463
397
  if (evaluation.action === 'missing-external') {
464
398
  return `Infinity at ${base} serves [${evaluation.servedModels.join(', ')}] but is missing [${evaluation.missingModels.join(', ')}]. ` +
@@ -470,15 +404,6 @@ function manualInstructionMessage(evaluation, base, modelSetToWrite) {
470
404
  ` v2 --model-id ${modelSetToWrite.join(';')} --port 7997\n` +
471
405
  `(drop --gpus all to run on CPU), or re-run rag-setup to provision it.`;
472
406
  }
473
- /**
474
- * Bring the Infinity backend to a state serving `requiredModels`, per the
475
- * managed-vs-external decision tree:
476
- * served → return (no Docker)
477
- * missing-managed → recreate (writes modelSetToWrite) + wait
478
- * missing-external → throw (manual --model-id instructions)
479
- * unreachable-managed → (re)create + wait
480
- * unreachable-external → throw (manual launch instructions)
481
- */
482
407
  async function ensureBackendReady(opts) {
483
408
  const { baseURL, requiredModels, modelSetToWrite, composePath } = opts;
484
409
  const deps = opts.deps ?? {};
@@ -496,17 +421,9 @@ async function ensureBackendReady(opts) {
496
421
  return;
497
422
  }
498
423
  }
499
- /** `ensureBackendReady` with the full set as both the requirement and the write (rag-setup, web dashboard). */
500
424
  async function ensureModelSetServed(baseURL, composePath, modelSet, deps) {
501
425
  return ensureBackendReady({ baseURL, requiredModels: modelSet, modelSetToWrite: modelSet, composePath, deps });
502
426
  }
503
- /**
504
- * The model set a managed Infinity container must serve, computed from a
505
- * `Config`: the embedding model, followed by the reranker model only when
506
- * reranking is enabled with a model on the same server as embeddings (the
507
- * effective `reranker.url`, which `Config` has already resolved from an
508
- * explicit value or derived from `reranker.baseURL`).
509
- */
510
427
  function requiredModelSet(cfg) {
511
428
  const set = [cfg.embedding.model];
512
429
  if (cfg.reranker.enabled && cfg.reranker.model && sameServer(cfg.reranker.url, cfg.embedding.baseURL)) {
@@ -3,22 +3,6 @@ export interface IndexedIdentity {
3
3
  provider: string;
4
4
  model: string;
5
5
  }
6
- /** A pre-`index_meta` install (populated `code_chunk`, no `index_meta` row) is always this. */
7
6
  export declare const LEGACY_OLLAMA_IDENTITY: IndexedIdentity;
8
- /**
9
- * Whether `code_chunk` has at least one row, tolerant only of a missing
10
- * table (→ false). Any other database error propagates. Exported so
11
- * `SearcherService.assertIndexMatches` can reuse the same strict count
12
- * (it reads `index_meta` via the existing lenient `IDatabase.readIndexMeta()`,
13
- * but the chunk count must fail loudly on a real DB error).
14
- */
15
7
  export declare function hasIndexedChunks(db: IDatabase): Promise<boolean>;
16
- /**
17
- * Resolve the "indexed identity" under the shared legacy interpretation used
18
- * both by the `rag-index` legacy-Ollama guard and the search-refusal check:
19
- * an `index_meta` row wins; absent a row, a populated `code_chunk` is
20
- * `ollama`/`bge-m3`; an empty (or altogether absent) DB is `null` — not
21
- * Ollama-built, no refusal. Missing tables count as absent/empty; any other
22
- * database error propagates rather than being read as "not Ollama-built".
23
- */
24
8
  export declare function resolveIndexedIdentity(db: IDatabase): Promise<IndexedIdentity | null>;
@@ -3,18 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LEGACY_OLLAMA_IDENTITY = void 0;
4
4
  exports.hasIndexedChunks = hasIndexedChunks;
5
5
  exports.resolveIndexedIdentity = resolveIndexedIdentity;
6
- /** A pre-`index_meta` install (populated `code_chunk`, no `index_meta` row) is always this. */
7
6
  exports.LEGACY_OLLAMA_IDENTITY = { provider: 'ollama', model: 'bge-m3' };
8
7
  function isMissingTableError(err) {
9
8
  return /does not exist/i.test(err?.message ?? '');
10
9
  }
11
- /**
12
- * Read `index_meta`'s (provider, model), tolerant only of a missing table
13
- * (→ null, un-migrated DB). Any other database error propagates — unlike
14
- * `IDatabase.readIndexMeta()`, which swallows every error into `null`, this
15
- * is used where a genuine DB error must fail the caller loudly rather than
16
- * be misread as "no row".
17
- */
18
10
  async function readIndexMetaStrict(db) {
19
11
  try {
20
12
  const rows = await db.query(`SELECT provider, model FROM index_meta LIMIT 1`);
@@ -27,13 +19,6 @@ async function readIndexMetaStrict(db) {
27
19
  throw err;
28
20
  }
29
21
  }
30
- /**
31
- * Whether `code_chunk` has at least one row, tolerant only of a missing
32
- * table (→ false). Any other database error propagates. Exported so
33
- * `SearcherService.assertIndexMatches` can reuse the same strict count
34
- * (it reads `index_meta` via the existing lenient `IDatabase.readIndexMeta()`,
35
- * but the chunk count must fail loudly on a real DB error).
36
- */
37
22
  async function hasIndexedChunks(db) {
38
23
  try {
39
24
  const rows = await db.query(`SELECT COUNT(*)::int AS n FROM code_chunk`);
@@ -45,14 +30,6 @@ async function hasIndexedChunks(db) {
45
30
  throw err;
46
31
  }
47
32
  }
48
- /**
49
- * Resolve the "indexed identity" under the shared legacy interpretation used
50
- * both by the `rag-index` legacy-Ollama guard and the search-refusal check:
51
- * an `index_meta` row wins; absent a row, a populated `code_chunk` is
52
- * `ollama`/`bge-m3`; an empty (or altogether absent) DB is `null` — not
53
- * Ollama-built, no refusal. Missing tables count as absent/empty; any other
54
- * database error propagates rather than being read as "not Ollama-built".
55
- */
56
33
  async function resolveIndexedIdentity(db) {
57
34
  const meta = await readIndexMetaStrict(db);
58
35
  if (meta)
@@ -1,14 +1,5 @@
1
1
  import type { Config } from '../config';
2
2
  import type { ILogger } from '../interfaces/ILogger';
3
- /**
4
- * Build a rerank function from `config.reranker`, or return `undefined` when
5
- * reranking is disabled / unconfigured. Targets an OpenAI-compatible `/rerank`
6
- * endpoint returning `{ results: [{ index }] }` (Infinity, TEI, vLLM,
7
- * Jina/Cohere-shape). The embedding provider is independent of the rerank
8
- * server (`reranker.baseURL`), so e.g. Voyage embeddings + an Infinity
9
- * reranker is fine.
10
- * Returns original indices into `documents`, best-first.
11
- */
12
3
  export declare function makeReranker(config: Config, logger: ILogger, deps?: {
13
4
  fetchImpl?: typeof fetch;
14
5
  baseDelayMs?: number;
@@ -3,17 +3,42 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeReranker = makeReranker;
4
4
  const config_1 = require("../config");
5
5
  const http_retry_1 = require("./http-retry");
6
- /**
7
- * Build a rerank function from `config.reranker`, or return `undefined` when
8
- * reranking is disabled / unconfigured. Targets an OpenAI-compatible `/rerank`
9
- * endpoint returning `{ results: [{ index }] }` (Infinity, TEI, vLLM,
10
- * Jina/Cohere-shape). The embedding provider is independent of the rerank
11
- * server (`reranker.baseURL`), so e.g. Voyage embeddings + an Infinity
12
- * reranker is fine.
13
- * Returns original indices into `documents`, best-first.
14
- */
6
+ function indexList(items) {
7
+ if (!Array.isArray(items))
8
+ return null;
9
+ const out = [];
10
+ for (const item of items) {
11
+ const index = item?.index;
12
+ if (typeof index !== 'number')
13
+ return null;
14
+ out.push(index);
15
+ }
16
+ return out;
17
+ }
18
+ const WIRES = {
19
+ 'openai-compatible': {
20
+ body: (model, query, documents, topN) => ({ model, query, documents, top_n: topN, truncate: true }),
21
+ indices: json => indexList(json?.results),
22
+ },
23
+ voyage: {
24
+ body: (model, query, documents, topN) => ({ model, query, documents, top_k: topN, truncation: true }),
25
+ indices: (json) => {
26
+ const data = json?.data;
27
+ if (!Array.isArray(data))
28
+ return null;
29
+ if (data.some(d => typeof d?.relevance_score !== 'number'))
30
+ return null;
31
+ const sorted = [...data].sort((a, b) => b.relevance_score - a.relevance_score);
32
+ return indexList(sorted);
33
+ },
34
+ },
35
+ };
15
36
  function makeReranker(config, logger, deps = {}) {
16
37
  const r = config.reranker;
38
+ if (r.missingApiKey) {
39
+ logger.warn('reranker: reranker.provider is voyage but reranker.apiKey is not set — reranking disabled. Set reranker.apiKey or reranker.enabled: false');
40
+ return undefined;
41
+ }
17
42
  if (!r.enabled)
18
43
  return undefined;
19
44
  if (!r.model) {
@@ -21,6 +46,7 @@ function makeReranker(config, logger, deps = {}) {
21
46
  return undefined;
22
47
  }
23
48
  const doFetch = deps.fetchImpl ?? fetch;
49
+ const wire = WIRES[r.provider] ?? WIRES['openai-compatible'];
24
50
  return async (query, documents, topN) => {
25
51
  return (0, http_retry_1.withRetry)(async () => {
26
52
  const headers = { 'Content-Type': 'application/json' };
@@ -31,14 +57,22 @@ function makeReranker(config, logger, deps = {}) {
31
57
  method: 'POST',
32
58
  headers,
33
59
  signal: AbortSignal.timeout(30_000),
34
- body: JSON.stringify({ model: r.model, query, documents, top_n: topN, truncate: true }),
60
+ body: JSON.stringify(wire.body(r.model, query, documents, topN)),
35
61
  });
36
62
  if (!res.ok) {
37
63
  const body = (await res.text().catch(() => res.statusText)).slice(0, 200);
38
64
  throw new http_retry_1.HttpError(res.status, `rerank failed: ${res.status} ${body}`);
39
65
  }
40
- const data = await res.json();
41
- return data.results.map(x => x.index);
66
+ const json = await res.json().catch((err) => {
67
+ if (err instanceof SyntaxError)
68
+ return null;
69
+ throw err;
70
+ });
71
+ const indices = wire.indices(json);
72
+ if (!indices || indices.some(i => !Number.isInteger(i) || i < 0 || i >= documents.length)) {
73
+ throw new Error(`rerank failed: unexpected response from ${r.url}`);
74
+ }
75
+ return indices;
42
76
  }, { logger, baseDelayMs: deps.baseDelayMs, label: 'rerank' });
43
77
  };
44
78
  }
@@ -1,45 +1,45 @@
1
1
  import { type EmbeddingProvider } from './constants';
2
+ import { type JsonConfig } from './config-store';
2
3
  import { Config } from './config';
3
4
  import { type ProvisioningDeps } from './services/infinity-provisioning';
4
5
  import type { LoggerService } from './services/LoggerService';
5
- type SetupStep = {
6
+ export type SetupStep = {
6
7
  q: string;
7
8
  a: string;
8
9
  };
9
- /** Providers the wizard offers, in prompt order; the first is the preselected default. Exported for unit testing. */
10
+ export declare function recordedStep(question: string, raw: string): SetupStep;
11
+ export declare function setupStepLogger(logger: LoggerService | undefined, steps: SetupStep[]): (question: string, raw: string) => void;
12
+ type NonVoyageProvider = Exclude<EmbeddingProvider, 'voyage'>;
10
13
  export declare const EMBEDDING_PROVIDER_CHOICES: readonly EmbeddingProvider[];
11
- /**
12
- * Default answer for the "start Docker containers?" prompt: no only when both
13
- * the database and the embedding backend are already reachable. Pure — exported
14
- * for unit testing.
15
- */
16
14
  export declare function dockerPromptDefault(dbReachable: boolean, embReachable: boolean): 'y' | 'n';
15
+ export type RerankerChoice = 'infinity' | 'voyage' | 'openai-compatible' | 'none';
16
+ type RerankerBlock = NonNullable<JsonConfig['reranker']>;
17
+ type EmbeddingBlock = NonNullable<JsonConfig['embedding']>;
18
+ export interface SetupPromptIO {
19
+ prompt(label: string, def: string): Promise<string>;
20
+ ask(question: string): Promise<string>;
21
+ writeEnvKey(name: string, value: string): void;
22
+ log(message: string): void;
23
+ }
24
+ export declare function rerankerChoices(embProvider: NonVoyageProvider): RerankerChoice[];
25
+ export declare function voyageEmbeddingModels(): string[];
26
+ export declare function promptModelChoice(io: SetupPromptIO, label: string, models: readonly string[]): Promise<string>;
27
+ export declare function promptVoyageSetup(io: SetupPromptIO): Promise<{
28
+ embedding: EmbeddingBlock;
29
+ reranker: RerankerBlock;
30
+ }>;
31
+ export declare function promptSearchThreshold(io: SetupPromptIO, model: string): Promise<number | undefined>;
32
+ export declare function searchThresholdBlock(threshold: number | undefined): Pick<JsonConfig, 'search'>;
33
+ export declare function promptReranker(embProvider: NonVoyageProvider, embBaseURL: string, io: SetupPromptIO): Promise<RerankerBlock>;
17
34
  interface DbDockerOpts {
18
35
  dbPort: string;
19
36
  dbUser: string;
20
37
  dbPass: string;
21
- /** Bring up the local db container (skip when a remote db is already reachable). */
22
38
  startDb: boolean;
23
39
  logger?: LoggerService;
24
40
  steps?: SetupStep[];
25
41
  }
26
- /**
27
- * Regenerate `CONFIG_DIR/docker-compose.yml` from the shipped template
28
- * (carrying over an existing literal `INFINITY_MODEL_ID`, written atomically),
29
- * copy the GPU override, and start the DB container when requested. Runs
30
- * BEFORE the config file is written — its failure aborts setup unsaved,
31
- * matching the existing "abort without saving" behavior of the DB step. Does
32
- * NOT touch Infinity provisioning (moved after `writeConfigJson` — see D6a).
33
- */
34
42
  export declare function prepareComposeAndStartDb(opts: DbDockerOpts): Promise<void>;
35
- /**
36
- * Infinity provisioning (D6a) — runs AFTER the config file is written, so no
37
- * outcome here can leave the config unsaved. `savedConfig` is a fresh read of
38
- * the just-written file (never the process's own startup config). Exit-status
39
- * rules: 0 for served / timeout (warning) / external instructions / declined
40
- * Docker; 1 for any other provisioning failure — the cause is printed and the
41
- * remaining setup steps (DB schema init) still run.
42
- */
43
43
  export declare function provisionInfinity(savedConfig: Config, startDocker: boolean, logger?: LoggerService, deps?: ProvisioningDeps, composePathOverride?: string): Promise<void>;
44
44
  export declare function runSetup(logger?: LoggerService): Promise<void>;
45
45
  export {};