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
package/dist/src/setup.js CHANGED
@@ -34,7 +34,16 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.EMBEDDING_PROVIDER_CHOICES = void 0;
37
+ exports.recordedStep = recordedStep;
38
+ exports.setupStepLogger = setupStepLogger;
37
39
  exports.dockerPromptDefault = dockerPromptDefault;
40
+ exports.rerankerChoices = rerankerChoices;
41
+ exports.voyageEmbeddingModels = voyageEmbeddingModels;
42
+ exports.promptModelChoice = promptModelChoice;
43
+ exports.promptVoyageSetup = promptVoyageSetup;
44
+ exports.promptSearchThreshold = promptSearchThreshold;
45
+ exports.searchThresholdBlock = searchThresholdBlock;
46
+ exports.promptReranker = promptReranker;
38
47
  exports.prepareComposeAndStartDb = prepareComposeAndStartDb;
39
48
  exports.provisionInfinity = provisionInfinity;
40
49
  exports.runSetup = runSetup;
@@ -43,6 +52,7 @@ const fs = __importStar(require("fs"));
43
52
  const path = __importStar(require("path"));
44
53
  const os = __importStar(require("os"));
45
54
  const child_process_1 = require("child_process");
55
+ const constants_1 = require("./constants");
46
56
  const config_store_1 = require("./config-store");
47
57
  const config_1 = require("./config");
48
58
  const infinity_provisioning_1 = require("./services/infinity-provisioning");
@@ -54,6 +64,18 @@ const DOCKER_COMPOSE_SRC = path.join(_projectRoot, 'docker', 'docker-compose.yml
54
64
  const DOCKER_COMPOSE_DST = path.join(config_store_1.CONFIG_DIR, 'docker-compose.yml');
55
65
  const DOCKER_GPU_OVERRIDE_SRC = path.join(_projectRoot, 'docker', 'docker-compose.infinity-gpu.yml');
56
66
  const DOCKER_GPU_OVERRIDE_DST = path.join(config_store_1.CONFIG_DIR, 'docker-compose.infinity-gpu.yml');
67
+ function recordedStep(question, raw) {
68
+ const q = question.split('\n').find(l => l.trim())?.trim() ?? question.trim();
69
+ const a = /password|key|secret|token/i.test(q) ? '***' : raw.trim();
70
+ return { q, a };
71
+ }
72
+ function setupStepLogger(logger, steps) {
73
+ return (question, raw) => {
74
+ const step = recordedStep(question, raw);
75
+ logger?.debug('setup: prompt', step);
76
+ steps.push(step);
77
+ };
78
+ }
57
79
  function ask(rl, question) {
58
80
  return new Promise(resolve => rl.question(question, resolve));
59
81
  }
@@ -68,51 +90,194 @@ function expandHome(p) {
68
90
  }
69
91
  const PROVIDER_DEFAULTS = {
70
92
  'openai-compatible': { baseURL: 'https://api.openai.com/v1', model: 'text-embedding-3-small', envVar: 'OPENAI_API_KEY' },
71
- 'voyage': { baseURL: 'https://api.voyageai.com/v1', model: 'voyage-code-3', envVar: 'VOYAGE_API_KEY' },
72
93
  'infinity': { baseURL: 'http://localhost:7997', model: 'jinaai/jina-embeddings-v2-base-code', envVar: '' },
73
94
  };
74
- /** Providers the wizard offers, in prompt order; the first is the preselected default. Exported for unit testing. */
75
95
  exports.EMBEDDING_PROVIDER_CHOICES = ['infinity', 'openai-compatible', 'voyage'];
76
- /** Providers that run a local inference backend we can probe / provision. */
77
96
  function isLocalBackend(p) {
78
97
  return p === 'infinity';
79
98
  }
80
- /**
81
- * Probe whether the embedding backend is already reachable, so the "start
82
- * Docker?" prompt can default to no (mirrors the DB `checkRemoteDb` flow).
83
- * Cloud providers have no local backend → always "reachable" (nothing to start).
84
- */
85
99
  async function checkEmbeddingBackend(provider, baseURL) {
86
- if (!isLocalBackend(provider))
100
+ if (!isLocalBackend(provider) || !baseURL)
87
101
  return true;
88
102
  return (0, infinity_provisioning_1.probeInfinityHealth)(baseURL);
89
103
  }
90
- /**
91
- * Default answer for the "start Docker containers?" prompt: no only when both
92
- * the database and the embedding backend are already reachable. Pure — exported
93
- * for unit testing.
94
- */
95
104
  function dockerPromptDefault(dbReachable, embReachable) {
96
105
  return (dbReachable && embReachable) ? 'n' : 'y';
97
106
  }
98
- /**
99
- * Write (or replace) a single `KEY=VALUE` line in `~/.config/codesearch-mcp/.env`,
100
- * chmod 600. API keys live here — never in config.json — referenced as `env:KEY`.
101
- */
102
107
  function writeEnvKey(name, value) {
103
108
  fs.mkdirSync(config_store_1.CONFIG_DIR, { recursive: true });
104
109
  let existing = '';
105
110
  try {
106
111
  existing = fs.readFileSync(config_store_1.ENV_FILE, 'utf-8');
107
112
  }
108
- catch { /* absent */ }
113
+ catch { }
109
114
  const kept = existing.split(/\r?\n/).filter(l => l.trim() && !l.trim().startsWith(`${name}=`));
110
115
  kept.push(`${name}=${value}`);
111
116
  fs.writeFileSync(config_store_1.ENV_FILE, kept.join('\n') + '\n', { mode: 0o600 });
112
117
  try {
113
118
  fs.chmodSync(config_store_1.ENV_FILE, 0o600);
114
119
  }
115
- catch { /* best effort */ }
120
+ catch { }
121
+ }
122
+ const VOYAGE_API_ENV = 'VOYAGE_API_KEY';
123
+ const VOYAGE_RERANK_ENV = 'VOYAGE_RERANK_API_KEY';
124
+ const RERANKER_ENV = 'RERANKER_API_KEY';
125
+ function rerankerChoices(embProvider) {
126
+ if (embProvider === 'infinity')
127
+ return ['infinity', 'voyage', 'openai-compatible', 'none'];
128
+ return ['none', 'voyage', 'openai-compatible'];
129
+ }
130
+ function voyageEmbeddingModels() {
131
+ return Object.entries(constants_1.MODEL_REGISTRY).filter(([, info]) => info.provider === 'voyage').map(([name]) => name);
132
+ }
133
+ async function askRequired(io, question, required = ' A value is required.') {
134
+ for (;;) {
135
+ const answer = (await io.ask(question)).trim();
136
+ if (answer)
137
+ return answer;
138
+ io.log(required);
139
+ }
140
+ }
141
+ async function promptModelChoice(io, label, models) {
142
+ models.forEach((m, i) => io.log(` ${i + 1}) ${m}${i === 0 ? ' (default)' : ''}`));
143
+ for (;;) {
144
+ const answer = (await io.ask(`${label} (1-${models.length} or a model name) (1): `)).trim();
145
+ if (!answer)
146
+ return models[0];
147
+ if (!/^\d+$/.test(answer))
148
+ return answer;
149
+ const n = parseInt(answer, 10);
150
+ if (n >= 1 && n <= models.length)
151
+ return models[n - 1];
152
+ io.log(` Enter a number from 1-${models.length}, or a model name.`);
153
+ }
154
+ }
155
+ async function promptVoyageSetup(io) {
156
+ const key = await askRequired(io, `Voyage API key (stored in ${config_store_1.ENV_FILE} as ${VOYAGE_API_ENV}): `, ' The Voyage API key is required.');
157
+ io.writeEnvKey(VOYAGE_API_ENV, key);
158
+ io.log(` Saved API key to ${config_store_1.ENV_FILE} as ${VOYAGE_API_ENV}.`);
159
+ const apiKey = `env:${VOYAGE_API_ENV}`;
160
+ const model = await promptModelChoice(io, 'Embedding model', voyageEmbeddingModels());
161
+ const embedding = { provider: 'voyage', model, apiKey };
162
+ io.log('\n--- Reranker ---');
163
+ let enable;
164
+ for (;;) {
165
+ enable = (await io.prompt('Enable Voyage reranker? (y/n)', 'y')).trim().toLowerCase();
166
+ if (enable === 'y' || enable === 'n')
167
+ break;
168
+ io.log(' Answer y or n.');
169
+ }
170
+ if (enable === 'n')
171
+ return { embedding, reranker: { enabled: false } };
172
+ const rerankModel = await promptModelChoice(io, 'Reranker model', constants_1.VOYAGE_RERANK_MODELS);
173
+ return { embedding, reranker: { enabled: true, provider: 'voyage', model: rerankModel, apiKey } };
174
+ }
175
+ async function promptSearchThreshold(io, model) {
176
+ const recommended = constants_1.MODEL_REGISTRY[model]?.defaultThreshold;
177
+ io.log('\n--- Search threshold ---');
178
+ io.log(recommended !== undefined
179
+ ? ` Recommended for ${model}: ${(0, constants_1.formatThreshold)(recommended)}`
180
+ : ` ${model} has no recommended value; left blank, only unrelated results are filtered out.`);
181
+ for (;;) {
182
+ const answer = (await io.ask('Similarity threshold: max cosine distance 0-1, lower is stricter (blank to follow the model): ')).trim();
183
+ if (!answer)
184
+ return undefined;
185
+ const value = Number(answer);
186
+ if (value >= 0 && value <= 1)
187
+ return value;
188
+ io.log(' Enter a number from 0 to 1, or leave it blank.');
189
+ }
190
+ }
191
+ function searchThresholdBlock(threshold) {
192
+ return threshold === undefined ? {} : { search: { similarityThreshold: threshold } };
193
+ }
194
+ function isHttpUrl(value) {
195
+ try {
196
+ const { protocol, username, password } = new URL(value);
197
+ return (protocol === 'http:' || protocol === 'https:') && !username && !password;
198
+ }
199
+ catch {
200
+ return false;
201
+ }
202
+ }
203
+ async function askHttpUrl(io, question) {
204
+ for (;;) {
205
+ const answer = await askRequired(io, question);
206
+ if (isHttpUrl(answer))
207
+ return answer;
208
+ io.log(' Enter an absolute http(s):// URL without credentials, e.g. http://localhost:7997.');
209
+ }
210
+ }
211
+ async function promptReranker(embProvider, embBaseURL, io) {
212
+ const choices = rerankerChoices(embProvider);
213
+ io.log('\n--- Reranker ---');
214
+ if (choices.includes('infinity'))
215
+ io.log(' infinity — served by the same Infinity container');
216
+ io.log(' voyage — Voyage AI cloud (needs a Voyage API key)');
217
+ io.log(' openai-compatible — any /rerank server (Infinity, vLLM)');
218
+ io.log(' none — no reranking');
219
+ let choice;
220
+ for (;;) {
221
+ choice = (await io.prompt(`Reranker (${choices.join('/')})`, choices[0])).trim();
222
+ if (choices.includes(choice))
223
+ break;
224
+ io.log(` Invalid reranker. Choose: ${choices.join(', ')}`);
225
+ }
226
+ if (choice === 'none')
227
+ return { enabled: false };
228
+ if (choice === 'infinity') {
229
+ const model = (await io.prompt('Reranker model (served by the same Infinity container)', config_store_1.CONFIG_DEFAULTS['reranker.model'])).trim();
230
+ return { enabled: true, provider: 'openai-compatible', baseURL: embBaseURL, model };
231
+ }
232
+ if (choice === 'voyage') {
233
+ const model = (await io.prompt(`Reranker model (${constants_1.VOYAGE_RERANK_MODELS.join(' / ')})`, constants_1.VOYAGE_RERANK_MODELS[0])).trim();
234
+ for (;;) {
235
+ const key = (await io.ask(`Voyage reranker API key (stored in ${config_store_1.ENV_FILE} as ${VOYAGE_RERANK_ENV}): `)).trim();
236
+ if (key) {
237
+ io.writeEnvKey(VOYAGE_RERANK_ENV, key);
238
+ io.log(` Saved reranker API key to ${config_store_1.ENV_FILE} as ${VOYAGE_RERANK_ENV}.`);
239
+ return { enabled: true, provider: 'voyage', model, apiKey: `env:${VOYAGE_RERANK_ENV}` };
240
+ }
241
+ io.log(' The Voyage reranker is not configured without an API key.');
242
+ const disable = (await io.prompt('Disable the reranker? (y/n)', 'y')).trim().toLowerCase();
243
+ if (disable === 'y')
244
+ return { enabled: false };
245
+ }
246
+ }
247
+ const baseURL = await askHttpUrl(io, 'Rerank server base URL: ');
248
+ const model = await askRequired(io, 'Reranker model: ');
249
+ const key = (await io.ask(`Reranker API key (stored in ${config_store_1.ENV_FILE} as ${RERANKER_ENV}, blank for none): `)).trim();
250
+ if (key)
251
+ io.writeEnvKey(RERANKER_ENV, key);
252
+ return {
253
+ enabled: true, provider: 'openai-compatible', baseURL, model,
254
+ ...(key ? { apiKey: `env:${RERANKER_ENV}` } : {}),
255
+ };
256
+ }
257
+ async function promptGenericBackend(embProvider, io) {
258
+ const pd = PROVIDER_DEFAULTS[embProvider];
259
+ const embBaseURL = await io.prompt('Base URL', pd.baseURL);
260
+ const embModel = await io.prompt('Embedding model', pd.model);
261
+ let apiKeyRef = '';
262
+ if (!isLocalBackend(embProvider)) {
263
+ const key = (await io.ask(`API key (stored in ${config_store_1.ENV_FILE}, leave blank to set later): `)).trim();
264
+ apiKeyRef = `env:${pd.envVar}`;
265
+ if (key) {
266
+ io.writeEnvKey(pd.envVar, key);
267
+ io.log(` Saved API key to ${config_store_1.ENV_FILE} as ${pd.envVar} (config references env:${pd.envVar}).`);
268
+ }
269
+ else {
270
+ io.log(` No key entered — set it later: echo '${pd.envVar}=sk-…' >> ${config_store_1.ENV_FILE}`);
271
+ }
272
+ }
273
+ const reranker = await promptReranker(embProvider, embBaseURL, io);
274
+ const embedding = {
275
+ provider: embProvider,
276
+ baseURL: embBaseURL,
277
+ model: embModel,
278
+ ...(apiKeyRef ? { apiKey: apiKeyRef } : {}),
279
+ };
280
+ return { embedding, reranker };
116
281
  }
117
282
  async function waitForDb(host, port, user, pass, db, maxWaitSec = 60, logger, steps) {
118
283
  const { Client } = await Promise.resolve().then(() => __importStar(require('pg')));
@@ -147,18 +312,10 @@ async function checkRemoteDb(host, port, user, pass, db, logger, steps) {
147
312
  catch (err) {
148
313
  const msg = err instanceof Error ? err.message : String(err);
149
314
  console.error(` Connection failed: ${msg}`);
150
- logger?.error('checkRemoteDb: connection failed', { reason: msg, steps: JSON.stringify(steps) });
315
+ logger?.error('checkRemoteDb: connection failed', { err, steps: JSON.stringify(steps) });
151
316
  return false;
152
317
  }
153
318
  }
154
- /**
155
- * Regenerate `CONFIG_DIR/docker-compose.yml` from the shipped template
156
- * (carrying over an existing literal `INFINITY_MODEL_ID`, written atomically),
157
- * copy the GPU override, and start the DB container when requested. Runs
158
- * BEFORE the config file is written — its failure aborts setup unsaved,
159
- * matching the existing "abort without saving" behavior of the DB step. Does
160
- * NOT touch Infinity provisioning (moved after `writeConfigJson` — see D6a).
161
- */
162
319
  async function prepareComposeAndStartDb(opts) {
163
320
  const { dbPort, dbUser, dbPass, startDb, logger, steps } = opts;
164
321
  console.log('\nWriting docker-compose.yml to', DOCKER_COMPOSE_DST);
@@ -168,14 +325,11 @@ async function prepareComposeAndStartDb(opts) {
168
325
  .replace('POSTGRES_USER: dev', `POSTGRES_USER: ${yamlQuote(dbUser)}`)
169
326
  .replace('POSTGRES_PASSWORD: dev', `POSTGRES_PASSWORD: ${yamlQuote(dbPass)}`)
170
327
  .replace('"5433:5432"', `"${dbPort}:5432"`);
171
- // Carry over an existing literal INFINITY_MODEL_ID — never the set of the
172
- // config still being entered — so a setup that aborts before the config is
173
- // written leaves a file consistent with the previously saved config.
174
328
  let existingModelId = null;
175
329
  try {
176
330
  existingModelId = (0, infinity_provisioning_1.extractModelIdValue)(fs.readFileSync(DOCKER_COMPOSE_DST, 'utf-8'));
177
331
  }
178
- catch { /* no prior file */ }
332
+ catch { }
179
333
  if (existingModelId) {
180
334
  composeContent = composeContent.replace(/INFINITY_MODEL_ID:\s*"[^"]*"/, `INFINITY_MODEL_ID: "${existingModelId}"`);
181
335
  }
@@ -184,13 +338,12 @@ async function prepareComposeAndStartDb(opts) {
184
338
  try {
185
339
  existingMode = fs.statSync(DOCKER_COMPOSE_DST).mode;
186
340
  }
187
- catch { /* first-ever write */ }
341
+ catch { }
188
342
  (0, infinity_provisioning_1.atomicWriteFile)(DOCKER_COMPOSE_DST, composeContent, existingMode);
189
- // The GPU override is copied verbatim so the managed Infinity path can layer it.
190
343
  try {
191
344
  fs.copyFileSync(DOCKER_GPU_OVERRIDE_SRC, DOCKER_GPU_OVERRIDE_DST);
192
345
  }
193
- catch { /* absent → CPU only */ }
346
+ catch { }
194
347
  if (!startDb)
195
348
  return;
196
349
  console.log('\nStarting the database container...');
@@ -202,30 +355,19 @@ async function prepareComposeAndStartDb(opts) {
202
355
  }
203
356
  await waitForDb('localhost', parseInt(dbPort), dbUser, dbPass, 'postgres', 60, logger, steps);
204
357
  }
205
- /**
206
- * Infinity provisioning (D6a) — runs AFTER the config file is written, so no
207
- * outcome here can leave the config unsaved. `savedConfig` is a fresh read of
208
- * the just-written file (never the process's own startup config). Exit-status
209
- * rules: 0 for served / timeout (warning) / external instructions / declined
210
- * Docker; 1 for any other provisioning failure — the cause is printed and the
211
- * remaining setup steps (DB schema init) still run.
212
- */
213
358
  async function provisionInfinity(savedConfig, startDocker, logger, deps = {}, composePathOverride) {
214
359
  const composePath = composePathOverride ?? DOCKER_COMPOSE_DST;
215
360
  const baseURL = savedConfig.embedding.baseURL;
216
361
  const base = (0, infinity_provisioning_1.serverRoot)(baseURL);
217
362
  const set = (0, infinity_provisioning_1.requiredModelSet)(savedConfig);
218
363
  const managed = (0, infinity_provisioning_1.isManagedInfinity)(baseURL, composePath);
219
- // Targeted write happens for a managed backend regardless of what follows
220
- // (yes/no, served/missing), so the compose file always matches the saved
221
- // config — even when the running container already serves the set.
222
364
  if (managed) {
223
365
  try {
224
366
  (0, infinity_provisioning_1.writeComposeModelSet)(composePath, set);
225
367
  }
226
368
  catch (err) {
227
369
  console.error(`\nFailed to write the managed compose file: ${err.message}`);
228
- logger?.error('provisionInfinity: compose write failed', { reason: err.message });
370
+ logger?.error('provisionInfinity: compose write failed', { err });
229
371
  process.exitCode = 1;
230
372
  }
231
373
  }
@@ -239,17 +381,16 @@ async function provisionInfinity(savedConfig, startDocker, logger, deps = {}, co
239
381
  if (/did not become ready within/.test(msg)) {
240
382
  console.warn(`\nWarning: ${msg}`);
241
383
  console.warn('The container is running and likely still warming up. Check again once /health responds, then run: rag-index');
242
- logger?.warn('provisionInfinity: readiness timeout (non-fatal)', { reason: msg });
384
+ logger?.warn('provisionInfinity: readiness timeout (non-fatal)', { err });
243
385
  }
244
386
  else {
245
387
  console.error(`\nInfinity provisioning failed: ${msg}`);
246
- logger?.error('provisionInfinity: failed', { reason: msg });
388
+ logger?.error('provisionInfinity: failed', { err });
247
389
  process.exitCode = 1;
248
390
  }
249
391
  }
250
392
  return;
251
393
  }
252
- // Docker declined — no Docker command; print what would apply the set.
253
394
  const evaluation = await (0, infinity_provisioning_1.evaluateBackend)(baseURL, composePath, set, deps);
254
395
  if (evaluation.action === 'served')
255
396
  return;
@@ -266,15 +407,10 @@ async function provisionInfinity(savedConfig, startDocker, logger, deps = {}, co
266
407
  async function runSetup(logger) {
267
408
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
268
409
  const steps = [];
269
- function logStep(q, raw) {
270
- const a = /password|key|secret|token/i.test(q) ? '***' : raw.trim();
271
- logger?.debug('setup: prompt', { q, a });
272
- steps.push({ q, a });
273
- }
410
+ const logStep = setupStepLogger(logger, steps);
274
411
  const loggedAsk = async (question) => {
275
412
  const answer = await ask(rl, question);
276
- const key = question.split('\n').find(l => l.trim())?.trim() ?? question.trim();
277
- logStep(key, answer);
413
+ logStep(question, answer);
278
414
  return answer;
279
415
  };
280
416
  const loggedPrompt = async (label, def) => {
@@ -308,28 +444,11 @@ async function runSetup(logger) {
308
444
  if (!exports.EMBEDDING_PROVIDER_CHOICES.includes(embProvider))
309
445
  console.log(` Invalid provider. Choose: ${exports.EMBEDDING_PROVIDER_CHOICES.join(', ')}`);
310
446
  } while (!exports.EMBEDDING_PROVIDER_CHOICES.includes(embProvider));
311
- const pd = PROVIDER_DEFAULTS[embProvider];
312
- const embBaseURL = await loggedPrompt('Base URL', pd.baseURL);
313
- const embModel = await loggedPrompt('Embedding model', pd.model);
314
- // Infinity serves a reranker from the same container — offer to provision one.
315
- let rerankModel = '';
316
- if (embProvider === 'infinity') {
317
- rerankModel = (await loggedPrompt(`Reranker model (served by the same Infinity container; blank to disable)`, config_store_1.CONFIG_DEFAULTS['reranker.model'])).trim();
318
- }
319
- // API keys go into .env (chmod 600); config.json only stores the env: reference.
320
- let apiKeyRef = '';
321
- if (!isLocalBackend(embProvider)) {
322
- const key = (await loggedAsk(`API key (stored in ${config_store_1.ENV_FILE}, leave blank to set later): `)).trim();
323
- if (key) {
324
- writeEnvKey(pd.envVar, key);
325
- apiKeyRef = `env:${pd.envVar}`;
326
- console.log(` Saved API key to ${config_store_1.ENV_FILE} as ${pd.envVar} (config references env:${pd.envVar}).`);
327
- }
328
- else {
329
- apiKeyRef = `env:${pd.envVar}`;
330
- console.log(` No key entered — set it later: echo '${pd.envVar}=sk-…' >> ${config_store_1.ENV_FILE}`);
331
- }
332
- }
447
+ const promptIO = { prompt: loggedPrompt, ask: loggedAsk, writeEnvKey, log: msg => console.log(msg) };
448
+ const { embedding, reranker } = embProvider === 'voyage'
449
+ ? await promptVoyageSetup(promptIO)
450
+ : await promptGenericBackend(embProvider, promptIO);
451
+ const searchThreshold = await promptSearchThreshold(promptIO, embedding.model ?? config_store_1.CONFIG_DEFAULTS['embedding.model']);
333
452
  console.log('\n--- Database ---');
334
453
  const dbHost = await loggedPrompt('DB host', 'localhost');
335
454
  const dbPort = await loggedPrompt('DB port', '5433');
@@ -339,10 +458,8 @@ async function runSetup(logger) {
339
458
  const dbReachable = await checkRemoteDb(dbHost, dbPort, dbUser, dbPass, 'postgres', logger, steps);
340
459
  if (dbReachable)
341
460
  console.log(' Database is already reachable.');
342
- // Symmetric to the DB probe: a reachable embedding backend defaults "start
343
- // Docker?" to no. Cloud providers have no local backend to start.
344
461
  process.stdout.write('Checking embedding backend...');
345
- const embReachable = await checkEmbeddingBackend(embProvider, embBaseURL);
462
+ const embReachable = await checkEmbeddingBackend(embProvider, embedding.baseURL);
346
463
  if (isLocalBackend(embProvider)) {
347
464
  console.log(embReachable ? ` ${embProvider} is already reachable.` : ` ${embProvider} is not reachable — it can be started via Docker.`);
348
465
  }
@@ -394,38 +511,23 @@ async function runSetup(logger) {
394
511
  user: dbVars.user,
395
512
  password: dbVars.password,
396
513
  },
397
- embedding: {
398
- provider: embProvider,
399
- baseURL: embBaseURL,
400
- model: embModel,
401
- ...(apiKeyRef ? { apiKey: apiKeyRef } : {}),
402
- },
514
+ embedding,
515
+ reranker,
516
+ ...searchThresholdBlock(searchThreshold),
403
517
  logging: { level: logLevel },
404
518
  workspaceRoot,
405
519
  };
406
- // Infinity serves the reranker from the same container — auto-wire reranker.*
407
- // to that server. `url` derives from provider + baseURL in the Config constructor.
408
- if (embProvider === 'infinity' && rerankModel) {
409
- cfg.reranker = {
410
- enabled: true,
411
- provider: 'openai-compatible',
412
- baseURL: embBaseURL,
413
- model: rerankModel,
414
- };
415
- }
416
520
  if (logDir)
417
521
  cfg.logging.dir = logDir;
418
522
  (0, config_store_1.writeConfigJson)(cfg);
419
523
  console.log(`\nConfig saved to ${config_store_1.CONFIG_FILE}`);
420
524
  rl.close();
421
- // Infinity provisioning happens only now — after the config is safely on
422
- // disk — so a provisioning failure never leaves the wizard's answers unsaved.
423
525
  if (embProvider === 'infinity') {
424
526
  await provisionInfinity(new config_1.Config(), startDocker, logger);
425
527
  }
426
528
  console.log('\nInitializing database schema...');
427
529
  const { DatabaseService } = await Promise.resolve().then(() => __importStar(require('./services/DatabaseService')));
428
- const dbService = new DatabaseService(new config_1.Config());
530
+ const dbService = new DatabaseService(new config_1.Config(), logger);
429
531
  let initError = null;
430
532
  try {
431
533
  await dbService.initDbWithSchema();
@@ -438,7 +540,7 @@ async function runSetup(logger) {
438
540
  }
439
541
  if (initError) {
440
542
  console.error(`Database schema init failed: ${initError.message}`);
441
- logger?.error('runSetup: database schema init failed', { reason: initError.message, steps: JSON.stringify(steps) });
543
+ logger?.error('runSetup: database schema init failed', { err: initError, steps: JSON.stringify(steps) });
442
544
  process.exit(1);
443
545
  }
444
546
  console.log('\nSetup complete!');
@@ -1,5 +1,6 @@
1
1
  export declare const BARE_NAME_RE: RegExp;
2
2
  export declare const QUALIFIED_NAME_RE: RegExp;
3
+ export declare const MAX_GREPPED_NAME_LEN = 256;
3
4
  export type FindSymbolQuery = {
4
5
  form: 'bare';
5
6
  name: string;
@@ -16,22 +17,11 @@ export type FindSymbolQuery = {
16
17
  container: string | null;
17
18
  name: string;
18
19
  };
19
- /** Split `P.n` into container `P` and last segment `n`. Requires a qualified name. */
20
20
  export declare function splitQualified(input: string): {
21
21
  container: string;
22
22
  name: string;
23
23
  };
24
- /**
25
- * Parse a `find_symbol` name into one of the four accepted forms (bare,
26
- * qualified, quoted, computed), or null when it matches none — the caller
27
- * should reject with `Invalid symbol name` without querying anything.
28
- */
29
24
  export declare function parseFindSymbolName(input: string): FindSymbolQuery | null;
30
- /**
31
- * Parse a `get_callers` symbol into bare or qualified form only — the quoted
32
- * and computed forms of `find_symbol` are meaningless here (calls through
33
- * element access are never recorded in the call graph).
34
- */
35
25
  export declare function parseCallerSymbol(input: string): {
36
26
  form: 'bare';
37
27
  name: string;
@@ -40,5 +30,4 @@ export declare function parseCallerSymbol(input: string): {
40
30
  container: string;
41
31
  name: string;
42
32
  } | null;
43
- /** Escape `%`, `_` and `\` for a `LIKE ... ESCAPE '\'` pattern. */
44
33
  export declare function escapeLike(s: string): string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QUALIFIED_NAME_RE = exports.BARE_NAME_RE = void 0;
3
+ exports.MAX_GREPPED_NAME_LEN = exports.QUALIFIED_NAME_RE = exports.BARE_NAME_RE = void 0;
4
4
  exports.splitQualified = splitQualified;
5
5
  exports.parseFindSymbolName = parseFindSymbolName;
6
6
  exports.parseCallerSymbol = parseCallerSymbol;
@@ -10,33 +10,26 @@ exports.QUALIFIED_NAME_RE = /^#?[\w$]+(\.#?[\w$]+)+$/;
10
10
  const PFX_SRC = '(?:#?[\\w$]+(?:\\.#?[\\w$]+)*\\.)?';
11
11
  const QUOTED_RE = new RegExp(`^(${PFX_SRC})('[^'\\r\\n]+'|"[^"\\r\\n]+")$`);
12
12
  const COMPUTED_RE = new RegExp(`^(${PFX_SRC})(\\[[^\\]\\r\\n]+\\])$`);
13
- const MAX_QUOTED_COMPUTED_LEN = 256;
14
- /** Strip a qualified name's trailing `.` container prefix, if present. */
13
+ exports.MAX_GREPPED_NAME_LEN = 256;
15
14
  function stripTrailingDot(prefix) {
16
15
  if (!prefix)
17
16
  return null;
18
17
  return prefix.slice(0, -1);
19
18
  }
20
- /** Split `P.n` into container `P` and last segment `n`. Requires a qualified name. */
21
19
  function splitQualified(input) {
22
20
  const idx = input.lastIndexOf('.');
23
21
  return { container: input.slice(0, idx), name: input.slice(idx + 1) };
24
22
  }
25
- /**
26
- * Parse a `find_symbol` name into one of the four accepted forms (bare,
27
- * qualified, quoted, computed), or null when it matches none — the caller
28
- * should reject with `Invalid symbol name` without querying anything.
29
- */
30
23
  function parseFindSymbolName(input) {
31
- if (input.length <= MAX_QUOTED_COMPUTED_LEN) {
32
- const quoted = input.match(QUOTED_RE);
33
- if (quoted) {
34
- return { form: 'quoted', container: stripTrailingDot(quoted[1]), name: quoted[2].slice(1, -1) };
35
- }
36
- const computed = input.match(COMPUTED_RE);
37
- if (computed) {
38
- return { form: 'computed', container: stripTrailingDot(computed[1]), name: computed[2].replace(/\s+/g, '') };
39
- }
24
+ if (input.length > exports.MAX_GREPPED_NAME_LEN)
25
+ return null;
26
+ const quoted = input.match(QUOTED_RE);
27
+ if (quoted) {
28
+ return { form: 'quoted', container: stripTrailingDot(quoted[1]), name: quoted[2].slice(1, -1) };
29
+ }
30
+ const computed = input.match(COMPUTED_RE);
31
+ if (computed) {
32
+ return { form: 'computed', container: stripTrailingDot(computed[1]), name: computed[2].replace(/\s+/g, '') };
40
33
  }
41
34
  if (exports.QUALIFIED_NAME_RE.test(input)) {
42
35
  const { container, name } = splitQualified(input);
@@ -47,13 +40,12 @@ function parseFindSymbolName(input) {
47
40
  }
48
41
  return null;
49
42
  }
50
- /**
51
- * Parse a `get_callers` symbol into bare or qualified form only — the quoted
52
- * and computed forms of `find_symbol` are meaningless here (calls through
53
- * element access are never recorded in the call graph).
54
- */
43
+ function isQualifiedName(input) {
44
+ const segments = input.split('.');
45
+ return segments.length >= 2 && segments.every(segment => exports.BARE_NAME_RE.test(segment));
46
+ }
55
47
  function parseCallerSymbol(input) {
56
- if (exports.QUALIFIED_NAME_RE.test(input)) {
48
+ if (isQualifiedName(input)) {
57
49
  const { container, name } = splitQualified(input);
58
50
  return { form: 'qualified', container, name };
59
51
  }
@@ -62,7 +54,6 @@ function parseCallerSymbol(input) {
62
54
  }
63
55
  return null;
64
56
  }
65
- /** Escape `%`, `_` and `\` for a `LIKE ... ESCAPE '\'` pattern. */
66
57
  function escapeLike(s) {
67
58
  return s.replace(/\\/g, '\\\\').replace(/%/g, '\\%').replace(/_/g, '\\_');
68
59
  }
@@ -1,17 +1,3 @@
1
1
  import type { SymbolEntry } from './interfaces/IAstParser';
2
2
  export type CodeSymbolRow = Pick<SymbolEntry, 'project' | 'filePath' | 'name' | 'kind' | 'signature' | 'line' | 'col' | 'container' | 'isStatic' | 'target'>;
3
- /**
4
- * Combine top-level symbols, members and GraphQL-named rows into the rows
5
- * written to `code_symbol`. Overload signatures of one declaration — same
6
- * `(container, name, kind, isStatic)` — collapse to a single representative
7
- * row: the one with a body (the implementation) when present, otherwise the
8
- * earliest by line (the first signature in source order). Static and instance
9
- * members sharing a name are never collapsed into each other (`isStatic` is
10
- * part of the group key). `graphqlNames` bypass this collapse — decorators
11
- * cannot sit on overload signatures, so there is nothing to collapse, and the
12
- * collapse's `(container, name, kind, isStatic)` key would wrongly merge two
13
- * different methods exposing the same GraphQL name from two resolver classes
14
- * (both with container `Query`). A final dedup by `(container, name, kind,
15
- * line)` matches the DB's unique index.
16
- */
17
3
  export declare function buildSymbolRows(symbols: SymbolEntry[], members: SymbolEntry[], graphqlNames?: SymbolEntry[]): CodeSymbolRow[];
@@ -1,20 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildSymbolRows = buildSymbolRows;
4
- /**
5
- * Combine top-level symbols, members and GraphQL-named rows into the rows
6
- * written to `code_symbol`. Overload signatures of one declaration — same
7
- * `(container, name, kind, isStatic)` — collapse to a single representative
8
- * row: the one with a body (the implementation) when present, otherwise the
9
- * earliest by line (the first signature in source order). Static and instance
10
- * members sharing a name are never collapsed into each other (`isStatic` is
11
- * part of the group key). `graphqlNames` bypass this collapse — decorators
12
- * cannot sit on overload signatures, so there is nothing to collapse, and the
13
- * collapse's `(container, name, kind, isStatic)` key would wrongly merge two
14
- * different methods exposing the same GraphQL name from two resolver classes
15
- * (both with container `Query`). A final dedup by `(container, name, kind,
16
- * line)` matches the DB's unique index.
17
- */
18
4
  function buildSymbolRows(symbols, members, graphqlNames = []) {
19
5
  const groups = new Map();
20
6
  for (const entry of [...symbols, ...members]) {
@@ -0,0 +1,2 @@
1
+ export declare function truncateForLog(value: unknown, depth?: number): unknown;
2
+ export declare function resolveSession(env: Record<string, string | undefined>): string | null;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.truncateForLog = truncateForLog;
4
+ exports.resolveSession = resolveSession;
5
+ const MAX_STRING = 500;
6
+ const MAX_ITEMS = 20;
7
+ const MAX_DEPTH = 4;
8
+ function truncateForLog(value, depth = 1) {
9
+ if (typeof value === 'string') {
10
+ return value.length > MAX_STRING ? `${value.slice(0, MAX_STRING)}…(+${value.length - MAX_STRING})` : value;
11
+ }
12
+ if (value === null || typeof value !== 'object')
13
+ return value;
14
+ if (depth > MAX_DEPTH)
15
+ return '[depth]';
16
+ if (Array.isArray(value)) {
17
+ const kept = value.slice(0, MAX_ITEMS).map(v => truncateForLog(v, depth + 1));
18
+ return value.length > MAX_ITEMS ? [...kept, `…(+${value.length - MAX_ITEMS})`] : kept;
19
+ }
20
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, truncateForLog(v, depth + 1)]));
21
+ }
22
+ function resolveSession(env) {
23
+ return env.CLAUDE_CODE_SESSION_ID ?? null;
24
+ }