lmgrep 0.1.18 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (408) hide show
  1. package/README.md +226 -63
  2. package/completions/_lmgrep +49 -40
  3. package/dist/application/Lmgrep.d.ts +107 -0
  4. package/dist/application/Lmgrep.js +99 -0
  5. package/dist/application/Lmgrep.js.map +1 -0
  6. package/dist/application/LmgrepFactory.d.ts +40 -0
  7. package/dist/application/LmgrepFactory.js +155 -0
  8. package/dist/application/LmgrepFactory.js.map +1 -0
  9. package/dist/application/indexing/BranchBootstrapper.d.ts +21 -0
  10. package/dist/application/indexing/BranchBootstrapper.js +52 -0
  11. package/dist/application/indexing/BranchBootstrapper.js.map +1 -0
  12. package/dist/application/indexing/BranchManifestSweeper.d.ts +17 -0
  13. package/dist/application/indexing/BranchManifestSweeper.js +35 -0
  14. package/dist/application/indexing/BranchManifestSweeper.js.map +1 -0
  15. package/dist/application/indexing/Duration.d.ts +9 -0
  16. package/dist/application/indexing/Duration.js +25 -0
  17. package/dist/application/indexing/Duration.js.map +1 -0
  18. package/dist/application/indexing/EmbeddingAbortError.d.ts +11 -0
  19. package/dist/application/indexing/EmbeddingAbortError.js +20 -0
  20. package/dist/application/indexing/EmbeddingAbortError.js.map +1 -0
  21. package/dist/application/indexing/EmbeddingPipeline.d.ts +59 -0
  22. package/dist/application/indexing/EmbeddingPipeline.js +140 -0
  23. package/dist/application/indexing/EmbeddingPipeline.js.map +1 -0
  24. package/dist/application/indexing/IndexBuilder.d.ts +112 -0
  25. package/dist/application/indexing/IndexBuilder.js +370 -0
  26. package/dist/application/indexing/IndexBuilder.js.map +1 -0
  27. package/dist/application/indexing/IndexingProgress.d.ts +34 -0
  28. package/dist/application/indexing/IndexingProgress.js +2 -0
  29. package/dist/application/indexing/IndexingProgress.js.map +1 -0
  30. package/dist/application/operations/Deadline.d.ts +13 -0
  31. package/dist/application/operations/Deadline.js +29 -0
  32. package/dist/application/operations/Deadline.js.map +1 -0
  33. package/dist/application/operations/HealthMonitor.d.ts +58 -0
  34. package/dist/application/operations/HealthMonitor.js +128 -0
  35. package/dist/application/operations/HealthMonitor.js.map +1 -0
  36. package/dist/application/operations/IndexAlternatives.d.ts +35 -0
  37. package/dist/application/operations/IndexAlternatives.js +61 -0
  38. package/dist/application/operations/IndexAlternatives.js.map +1 -0
  39. package/dist/application/operations/IndexInventory.d.ts +69 -0
  40. package/dist/application/operations/IndexInventory.js +99 -0
  41. package/dist/application/operations/IndexInventory.js.map +1 -0
  42. package/dist/application/operations/StatusService.d.ts +90 -0
  43. package/dist/application/operations/StatusService.js +171 -0
  44. package/dist/application/operations/StatusService.js.map +1 -0
  45. package/dist/application/operations/WatchService.d.ts +67 -0
  46. package/dist/application/operations/WatchService.js +145 -0
  47. package/dist/application/operations/WatchService.js.map +1 -0
  48. package/dist/application/operations/WorkingTreeDiff.d.ts +19 -0
  49. package/dist/application/operations/WorkingTreeDiff.js +36 -0
  50. package/dist/application/operations/WorkingTreeDiff.js.map +1 -0
  51. package/dist/application/research/ResearchAgent.d.ts +68 -0
  52. package/dist/application/research/ResearchAgent.js +201 -0
  53. package/dist/application/research/ResearchAgent.js.map +1 -0
  54. package/dist/application/research/ResearchPrompts.d.ts +16 -0
  55. package/dist/application/research/ResearchPrompts.js +34 -0
  56. package/dist/application/research/ResearchPrompts.js.map +1 -0
  57. package/dist/application/search/SearchCriteria.d.ts +37 -0
  58. package/dist/application/search/SearchCriteria.js +48 -0
  59. package/dist/application/search/SearchCriteria.js.map +1 -0
  60. package/dist/application/search/SearchService.d.ts +36 -0
  61. package/dist/application/search/SearchService.js +108 -0
  62. package/dist/application/search/SearchService.js.map +1 -0
  63. package/dist/application/search/SearchTargetResolver.d.ts +56 -0
  64. package/dist/application/search/SearchTargetResolver.js +104 -0
  65. package/dist/application/search/SearchTargetResolver.js.map +1 -0
  66. package/dist/cli.d.ts +1 -1
  67. package/dist/cli.js +4 -953
  68. package/dist/cli.js.map +1 -1
  69. package/dist/domain/config/ConfigSource.d.ts +16 -0
  70. package/dist/domain/config/ConfigSource.js +2 -0
  71. package/dist/domain/config/ConfigSource.js.map +1 -0
  72. package/dist/domain/config/LmgrepConfig.d.ts +53 -0
  73. package/dist/domain/config/LmgrepConfig.js +2 -0
  74. package/dist/domain/config/LmgrepConfig.js.map +1 -0
  75. package/dist/domain/corpus/Chunk.d.ts +49 -0
  76. package/dist/domain/corpus/Chunk.js +60 -0
  77. package/dist/domain/corpus/Chunk.js.map +1 -0
  78. package/dist/domain/corpus/CodeLocation.d.ts +18 -0
  79. package/dist/domain/corpus/CodeLocation.js +34 -0
  80. package/dist/domain/corpus/CodeLocation.js.map +1 -0
  81. package/dist/domain/corpus/ContentHash.d.ts +15 -0
  82. package/dist/domain/corpus/ContentHash.js +30 -0
  83. package/dist/domain/corpus/ContentHash.js.map +1 -0
  84. package/dist/domain/corpus/FileVersion.d.ts +31 -0
  85. package/dist/domain/corpus/FileVersion.js +47 -0
  86. package/dist/domain/corpus/FileVersion.js.map +1 -0
  87. package/dist/domain/corpus/SourceFile.d.ts +26 -0
  88. package/dist/domain/corpus/SourceFile.js +47 -0
  89. package/dist/domain/corpus/SourceFile.js.map +1 -0
  90. package/dist/domain/corpus/Vector.d.ts +37 -0
  91. package/dist/domain/corpus/Vector.js +96 -0
  92. package/dist/domain/corpus/Vector.js.map +1 -0
  93. package/dist/domain/ports/ChatModelPort.d.ts +57 -0
  94. package/dist/domain/ports/ChatModelPort.js +2 -0
  95. package/dist/domain/ports/ChatModelPort.js.map +1 -0
  96. package/dist/domain/ports/ChunkRepositoryPort.d.ts +42 -0
  97. package/dist/domain/ports/ChunkRepositoryPort.js +2 -0
  98. package/dist/domain/ports/ChunkRepositoryPort.js.map +1 -0
  99. package/dist/domain/ports/ChunkerPort.d.ts +5 -0
  100. package/dist/domain/ports/ChunkerPort.js +2 -0
  101. package/dist/domain/ports/ChunkerPort.js.map +1 -0
  102. package/dist/domain/ports/DatabaseSessionPort.d.ts +10 -0
  103. package/dist/domain/ports/DatabaseSessionPort.js +2 -0
  104. package/dist/domain/ports/DatabaseSessionPort.js.map +1 -0
  105. package/dist/domain/ports/EmbedderPort.d.ts +14 -0
  106. package/dist/domain/ports/EmbedderPort.js +2 -0
  107. package/dist/domain/ports/EmbedderPort.js.map +1 -0
  108. package/dist/domain/ports/FileManifestRepositoryPort.d.ts +32 -0
  109. package/dist/domain/ports/FileManifestRepositoryPort.js +2 -0
  110. package/dist/domain/ports/FileManifestRepositoryPort.js.map +1 -0
  111. package/dist/domain/ports/GitPort.d.ts +24 -0
  112. package/dist/domain/ports/GitPort.js +2 -0
  113. package/dist/domain/ports/GitPort.js.map +1 -0
  114. package/dist/domain/ports/IndexMaintenancePort.d.ts +58 -0
  115. package/dist/domain/ports/IndexMaintenancePort.js +2 -0
  116. package/dist/domain/ports/IndexMaintenancePort.js.map +1 -0
  117. package/dist/domain/ports/IndexMetadataPort.d.ts +23 -0
  118. package/dist/domain/ports/IndexMetadataPort.js +2 -0
  119. package/dist/domain/ports/IndexMetadataPort.js.map +1 -0
  120. package/dist/domain/ports/LockPort.d.ts +17 -0
  121. package/dist/domain/ports/LockPort.js +2 -0
  122. package/dist/domain/ports/LockPort.js.map +1 -0
  123. package/dist/domain/ports/LoggerPort.d.ts +5 -0
  124. package/dist/domain/ports/LoggerPort.js +2 -0
  125. package/dist/domain/ports/LoggerPort.js.map +1 -0
  126. package/dist/domain/ports/ProjectIndexesPort.d.ts +20 -0
  127. package/dist/domain/ports/ProjectIndexesPort.js +2 -0
  128. package/dist/domain/ports/ProjectIndexesPort.js.map +1 -0
  129. package/dist/domain/ports/ProjectRegistryPort.d.ts +42 -0
  130. package/dist/domain/ports/ProjectRegistryPort.js +2 -0
  131. package/dist/domain/ports/ProjectRegistryPort.js.map +1 -0
  132. package/dist/domain/ports/StateDirectoryPort.d.ts +29 -0
  133. package/dist/domain/ports/StateDirectoryPort.js +2 -0
  134. package/dist/domain/ports/StateDirectoryPort.js.map +1 -0
  135. package/dist/domain/ports/WorkspacePort.d.ts +38 -0
  136. package/dist/domain/ports/WorkspacePort.js +2 -0
  137. package/dist/domain/ports/WorkspacePort.js.map +1 -0
  138. package/dist/domain/project/Branch.d.ts +20 -0
  139. package/dist/domain/project/Branch.js +33 -0
  140. package/dist/domain/project/Branch.js.map +1 -0
  141. package/dist/domain/project/DatabaseLocation.d.ts +32 -0
  142. package/dist/domain/project/DatabaseLocation.js +35 -0
  143. package/dist/domain/project/DatabaseLocation.js.map +1 -0
  144. package/dist/domain/project/IndexMetadata.d.ts +17 -0
  145. package/dist/domain/project/IndexMetadata.js +2 -0
  146. package/dist/domain/project/IndexMetadata.js.map +1 -0
  147. package/dist/domain/project/ModelIdentity.d.ts +58 -0
  148. package/dist/domain/project/ModelIdentity.js +97 -0
  149. package/dist/domain/project/ModelIdentity.js.map +1 -0
  150. package/dist/domain/project/Project.d.ts +17 -0
  151. package/dist/domain/project/Project.js +21 -0
  152. package/dist/domain/project/Project.js.map +1 -0
  153. package/dist/domain/project/ProjectId.d.ts +28 -0
  154. package/dist/domain/project/ProjectId.js +58 -0
  155. package/dist/domain/project/ProjectId.js.map +1 -0
  156. package/dist/domain/project/ProjectLocator.d.ts +112 -0
  157. package/dist/domain/project/ProjectLocator.js +178 -0
  158. package/dist/domain/project/ProjectLocator.js.map +1 -0
  159. package/dist/domain/research/Citation.d.ts +27 -0
  160. package/dist/domain/research/Citation.js +43 -0
  161. package/dist/domain/research/Citation.js.map +1 -0
  162. package/dist/domain/research/EvidenceLedger.d.ts +47 -0
  163. package/dist/domain/research/EvidenceLedger.js +111 -0
  164. package/dist/domain/research/EvidenceLedger.js.map +1 -0
  165. package/dist/domain/research/ResearchTrace.d.ts +19 -0
  166. package/dist/domain/research/ResearchTrace.js +22 -0
  167. package/dist/domain/research/ResearchTrace.js.map +1 -0
  168. package/dist/domain/retrieval/Hit.d.ts +19 -0
  169. package/dist/domain/retrieval/Hit.js +28 -0
  170. package/dist/domain/retrieval/Hit.js.map +1 -0
  171. package/dist/domain/retrieval/HitList.d.ts +35 -0
  172. package/dist/domain/retrieval/HitList.js +81 -0
  173. package/dist/domain/retrieval/HitList.js.map +1 -0
  174. package/dist/domain/retrieval/MissingIndexError.d.ts +11 -0
  175. package/dist/domain/retrieval/MissingIndexError.js +15 -0
  176. package/dist/domain/retrieval/MissingIndexError.js.map +1 -0
  177. package/dist/index.d.ts +43 -45
  178. package/dist/index.js +30 -567
  179. package/dist/index.js.map +1 -1
  180. package/dist/infrastructure/ai/AiSdkChatModel.d.ts +31 -0
  181. package/dist/infrastructure/ai/AiSdkChatModel.js +137 -0
  182. package/dist/infrastructure/ai/AiSdkChatModel.js.map +1 -0
  183. package/dist/infrastructure/ai/AiSdkEmbedder.d.ts +28 -0
  184. package/dist/infrastructure/ai/AiSdkEmbedder.js +79 -0
  185. package/dist/infrastructure/ai/AiSdkEmbedder.js.map +1 -0
  186. package/dist/infrastructure/ai/EmbeddingPrefixes.d.ts +21 -0
  187. package/dist/infrastructure/ai/EmbeddingPrefixes.js +40 -0
  188. package/dist/infrastructure/ai/EmbeddingPrefixes.js.map +1 -0
  189. package/dist/infrastructure/ai/LmStudioProbe.d.ts +18 -0
  190. package/dist/infrastructure/ai/LmStudioProbe.js +49 -0
  191. package/dist/infrastructure/ai/LmStudioProbe.js.map +1 -0
  192. package/dist/infrastructure/ai/LocalModelReloader.d.ts +21 -0
  193. package/dist/infrastructure/ai/LocalModelReloader.js +61 -0
  194. package/dist/infrastructure/ai/LocalModelReloader.js.map +1 -0
  195. package/dist/infrastructure/ai/LocalRuntimeDetector.d.ts +36 -0
  196. package/dist/infrastructure/ai/LocalRuntimeDetector.js +61 -0
  197. package/dist/infrastructure/ai/LocalRuntimeDetector.js.map +1 -0
  198. package/dist/infrastructure/ai/ModelRuntime.d.ts +32 -0
  199. package/dist/infrastructure/ai/ModelRuntime.js +2 -0
  200. package/dist/infrastructure/ai/ModelRuntime.js.map +1 -0
  201. package/dist/infrastructure/ai/OllamaProbe.d.ts +21 -0
  202. package/dist/infrastructure/ai/OllamaProbe.js +69 -0
  203. package/dist/infrastructure/ai/OllamaProbe.js.map +1 -0
  204. package/dist/infrastructure/ai/ProviderFailure.d.ts +16 -0
  205. package/dist/infrastructure/ai/ProviderFailure.js +35 -0
  206. package/dist/infrastructure/ai/ProviderFailure.js.map +1 -0
  207. package/dist/infrastructure/ai/ProviderModuleLoader.d.ts +13 -0
  208. package/dist/infrastructure/ai/ProviderModuleLoader.js +49 -0
  209. package/dist/infrastructure/ai/ProviderModuleLoader.js.map +1 -0
  210. package/dist/infrastructure/ai/ProviderRegistry.d.ts +37 -0
  211. package/dist/infrastructure/ai/ProviderRegistry.js +55 -0
  212. package/dist/infrastructure/ai/ProviderRegistry.js.map +1 -0
  213. package/dist/infrastructure/fs/ConfigLoader.d.ts +59 -0
  214. package/dist/infrastructure/fs/ConfigLoader.js +194 -0
  215. package/dist/infrastructure/fs/ConfigLoader.js.map +1 -0
  216. package/dist/infrastructure/fs/DatabaseLocks.d.ts +52 -0
  217. package/dist/infrastructure/fs/DatabaseLocks.js +92 -0
  218. package/dist/infrastructure/fs/DatabaseLocks.js.map +1 -0
  219. package/dist/infrastructure/fs/DiskUsage.d.ts +6 -0
  220. package/dist/infrastructure/fs/DiskUsage.js +41 -0
  221. package/dist/infrastructure/fs/DiskUsage.js.map +1 -0
  222. package/dist/infrastructure/fs/IndexableFileRules.d.ts +33 -0
  223. package/dist/infrastructure/fs/IndexableFileRules.js +177 -0
  224. package/dist/infrastructure/fs/IndexableFileRules.js.map +1 -0
  225. package/dist/infrastructure/fs/Loggers.d.ts +14 -0
  226. package/dist/infrastructure/fs/Loggers.js +18 -0
  227. package/dist/infrastructure/fs/Loggers.js.map +1 -0
  228. package/dist/infrastructure/fs/PidFileLock.d.ts +40 -0
  229. package/dist/infrastructure/fs/PidFileLock.js +97 -0
  230. package/dist/infrastructure/fs/PidFileLock.js.map +1 -0
  231. package/dist/infrastructure/fs/ProjectIndexes.d.ts +8 -0
  232. package/dist/infrastructure/fs/ProjectIndexes.js +35 -0
  233. package/dist/infrastructure/fs/ProjectIndexes.js.map +1 -0
  234. package/dist/infrastructure/fs/ProjectMetadataStore.d.ts +42 -0
  235. package/dist/infrastructure/fs/ProjectMetadataStore.js +86 -0
  236. package/dist/infrastructure/fs/ProjectMetadataStore.js.map +1 -0
  237. package/dist/infrastructure/fs/ProjectRegistry.d.ts +25 -0
  238. package/dist/infrastructure/fs/ProjectRegistry.js +83 -0
  239. package/dist/infrastructure/fs/ProjectRegistry.js.map +1 -0
  240. package/dist/infrastructure/fs/StateDirectory.d.ts +28 -0
  241. package/dist/infrastructure/fs/StateDirectory.js +71 -0
  242. package/dist/infrastructure/fs/StateDirectory.js.map +1 -0
  243. package/dist/infrastructure/fs/Workspace.d.ts +25 -0
  244. package/dist/infrastructure/fs/Workspace.js +90 -0
  245. package/dist/infrastructure/fs/Workspace.js.map +1 -0
  246. package/dist/infrastructure/git/GitClient.d.ts +34 -0
  247. package/dist/infrastructure/git/GitClient.js +74 -0
  248. package/dist/infrastructure/git/GitClient.js.map +1 -0
  249. package/dist/infrastructure/lancedb/ChunkRepository.d.ts +38 -0
  250. package/dist/infrastructure/lancedb/ChunkRepository.js +166 -0
  251. package/dist/infrastructure/lancedb/ChunkRepository.js.map +1 -0
  252. package/dist/infrastructure/lancedb/DatabaseImporter.d.ts +22 -0
  253. package/dist/infrastructure/lancedb/DatabaseImporter.js +74 -0
  254. package/dist/infrastructure/lancedb/DatabaseImporter.js.map +1 -0
  255. package/dist/infrastructure/lancedb/FileManifestRepository.d.ts +34 -0
  256. package/dist/infrastructure/lancedb/FileManifestRepository.js +137 -0
  257. package/dist/infrastructure/lancedb/FileManifestRepository.js.map +1 -0
  258. package/dist/infrastructure/lancedb/IndexMaintenance.d.ts +53 -0
  259. package/dist/infrastructure/lancedb/IndexMaintenance.js +227 -0
  260. package/dist/infrastructure/lancedb/IndexMaintenance.js.map +1 -0
  261. package/dist/infrastructure/lancedb/LanceTables.d.ts +67 -0
  262. package/dist/infrastructure/lancedb/LanceTables.js +159 -0
  263. package/dist/infrastructure/lancedb/LanceTables.js.map +1 -0
  264. package/dist/{lib/native-tuning.js → infrastructure/lancedb/NativeTuning.js} +1 -1
  265. package/dist/infrastructure/lancedb/NativeTuning.js.map +1 -0
  266. package/dist/infrastructure/lancedb/RowReplication.d.ts +27 -0
  267. package/dist/infrastructure/lancedb/RowReplication.js +82 -0
  268. package/dist/infrastructure/lancedb/RowReplication.js.map +1 -0
  269. package/dist/infrastructure/lancedb/VectorIndexPolicy.d.ts +60 -0
  270. package/dist/infrastructure/lancedb/VectorIndexPolicy.js +72 -0
  271. package/dist/infrastructure/lancedb/VectorIndexPolicy.js.map +1 -0
  272. package/dist/infrastructure/p2p/IndexShare.d.ts +45 -0
  273. package/dist/infrastructure/p2p/IndexShare.js +160 -0
  274. package/dist/infrastructure/p2p/IndexShare.js.map +1 -0
  275. package/dist/infrastructure/p2p/PeerSwarm.d.ts +16 -0
  276. package/dist/infrastructure/p2p/PeerSwarm.js +41 -0
  277. package/dist/infrastructure/p2p/PeerSwarm.js.map +1 -0
  278. package/dist/infrastructure/p2p/SecureChannel.d.ts +60 -0
  279. package/dist/infrastructure/p2p/SecureChannel.js +71 -0
  280. package/dist/infrastructure/p2p/SecureChannel.js.map +1 -0
  281. package/dist/infrastructure/p2p/ShareCode.d.ts +25 -0
  282. package/dist/infrastructure/p2p/ShareCode.js +304 -0
  283. package/dist/infrastructure/p2p/ShareCode.js.map +1 -0
  284. package/dist/infrastructure/process/ProcessRegistry.d.ts +50 -0
  285. package/dist/infrastructure/process/ProcessRegistry.js +109 -0
  286. package/dist/infrastructure/process/ProcessRegistry.js.map +1 -0
  287. package/dist/infrastructure/treesitter/ChunkContextBuilder.d.ts +45 -0
  288. package/dist/infrastructure/treesitter/ChunkContextBuilder.js +159 -0
  289. package/dist/infrastructure/treesitter/ChunkContextBuilder.js.map +1 -0
  290. package/dist/infrastructure/treesitter/LanguageCatalog.d.ts +30 -0
  291. package/dist/{lib/chunker/languages.js → infrastructure/treesitter/LanguageCatalog.js} +34 -29
  292. package/dist/infrastructure/treesitter/LanguageCatalog.js.map +1 -0
  293. package/dist/infrastructure/treesitter/SlidingWindowChunker.d.ts +15 -0
  294. package/dist/infrastructure/treesitter/SlidingWindowChunker.js +42 -0
  295. package/dist/infrastructure/treesitter/SlidingWindowChunker.js.map +1 -0
  296. package/dist/infrastructure/treesitter/TreeSitterChunker.d.ts +42 -0
  297. package/dist/infrastructure/treesitter/TreeSitterChunker.js +163 -0
  298. package/dist/infrastructure/treesitter/TreeSitterChunker.js.map +1 -0
  299. package/dist/mcp.d.ts +1 -1
  300. package/dist/mcp.js +14 -72
  301. package/dist/mcp.js.map +1 -1
  302. package/dist/presentation/cli/Cli.d.ts +31 -0
  303. package/dist/presentation/cli/Cli.js +120 -0
  304. package/dist/presentation/cli/Cli.js.map +1 -0
  305. package/dist/presentation/cli/CliOptions.d.ts +18 -0
  306. package/dist/presentation/cli/CliOptions.js +25 -0
  307. package/dist/presentation/cli/CliOptions.js.map +1 -0
  308. package/dist/presentation/cli/CommandContext.d.ts +50 -0
  309. package/dist/presentation/cli/CommandContext.js +88 -0
  310. package/dist/presentation/cli/CommandContext.js.map +1 -0
  311. package/dist/presentation/cli/ConfigTemplate.d.ts +31 -0
  312. package/dist/presentation/cli/ConfigTemplate.js +83 -0
  313. package/dist/presentation/cli/ConfigTemplate.js.map +1 -0
  314. package/dist/presentation/cli/Renderer.d.ts +90 -0
  315. package/dist/presentation/cli/Renderer.js +290 -0
  316. package/dist/presentation/cli/Renderer.js.map +1 -0
  317. package/dist/presentation/cli/commands/AskCommand.d.ts +14 -0
  318. package/dist/presentation/cli/commands/AskCommand.js +48 -0
  319. package/dist/presentation/cli/commands/AskCommand.js.map +1 -0
  320. package/dist/presentation/cli/commands/CompletionsCommand.d.ts +18 -0
  321. package/dist/presentation/cli/commands/CompletionsCommand.js +96 -0
  322. package/dist/presentation/cli/commands/CompletionsCommand.js.map +1 -0
  323. package/dist/presentation/cli/commands/ConfigCommands.d.ts +55 -0
  324. package/dist/presentation/cli/commands/ConfigCommands.js +204 -0
  325. package/dist/presentation/cli/commands/ConfigCommands.js.map +1 -0
  326. package/dist/presentation/cli/commands/IndexCommand.d.ts +18 -0
  327. package/dist/presentation/cli/commands/IndexCommand.js +54 -0
  328. package/dist/presentation/cli/commands/IndexCommand.js.map +1 -0
  329. package/dist/presentation/cli/commands/ProjectsCommand.d.ts +48 -0
  330. package/dist/presentation/cli/commands/ProjectsCommand.js +240 -0
  331. package/dist/presentation/cli/commands/ProjectsCommand.js.map +1 -0
  332. package/dist/presentation/cli/commands/SearchCommand.d.ts +19 -0
  333. package/dist/presentation/cli/commands/SearchCommand.js +55 -0
  334. package/dist/presentation/cli/commands/SearchCommand.js.map +1 -0
  335. package/dist/presentation/cli/commands/ServerCommands.d.ts +13 -0
  336. package/dist/presentation/cli/commands/ServerCommands.js +40 -0
  337. package/dist/presentation/cli/commands/ServerCommands.js.map +1 -0
  338. package/dist/presentation/cli/commands/ShareCommands.d.ts +22 -0
  339. package/dist/presentation/cli/commands/ShareCommands.js +134 -0
  340. package/dist/presentation/cli/commands/ShareCommands.js.map +1 -0
  341. package/dist/presentation/cli/commands/StatusCommand.d.ts +15 -0
  342. package/dist/presentation/cli/commands/StatusCommand.js +53 -0
  343. package/dist/presentation/cli/commands/StatusCommand.js.map +1 -0
  344. package/dist/presentation/mcp/HitFormatter.d.ts +17 -0
  345. package/dist/presentation/mcp/HitFormatter.js +42 -0
  346. package/dist/presentation/mcp/HitFormatter.js.map +1 -0
  347. package/dist/presentation/mcp/IndexWatchController.d.ts +17 -0
  348. package/dist/presentation/mcp/IndexWatchController.js +31 -0
  349. package/dist/presentation/mcp/IndexWatchController.js.map +1 -0
  350. package/dist/presentation/mcp/LmgrepCore.d.ts +66 -0
  351. package/dist/presentation/mcp/LmgrepCore.js +178 -0
  352. package/dist/presentation/mcp/LmgrepCore.js.map +1 -0
  353. package/dist/presentation/mcp/McpServer.d.ts +18 -0
  354. package/dist/presentation/mcp/McpServer.js +63 -0
  355. package/dist/presentation/mcp/McpServer.js.map +1 -0
  356. package/dist/presentation/mcp/ToolDescriptions.d.ts +40 -0
  357. package/dist/presentation/mcp/ToolDescriptions.js +85 -0
  358. package/dist/presentation/mcp/ToolDescriptions.js.map +1 -0
  359. package/package.json +84 -89
  360. package/dist/lib/build.d.ts +0 -21
  361. package/dist/lib/build.js +0 -374
  362. package/dist/lib/build.js.map +0 -1
  363. package/dist/lib/chunker/context.d.ts +0 -21
  364. package/dist/lib/chunker/context.js +0 -131
  365. package/dist/lib/chunker/context.js.map +0 -1
  366. package/dist/lib/chunker/index.d.ts +0 -7
  367. package/dist/lib/chunker/index.js +0 -209
  368. package/dist/lib/chunker/index.js.map +0 -1
  369. package/dist/lib/chunker/languages.d.ts +0 -15
  370. package/dist/lib/chunker/languages.js.map +0 -1
  371. package/dist/lib/config.d.ts +0 -12
  372. package/dist/lib/config.js +0 -83
  373. package/dist/lib/config.js.map +0 -1
  374. package/dist/lib/embedder.d.ts +0 -65
  375. package/dist/lib/embedder.js +0 -236
  376. package/dist/lib/embedder.js.map +0 -1
  377. package/dist/lib/facet-session.d.ts +0 -44
  378. package/dist/lib/facet-session.js +0 -125
  379. package/dist/lib/facet-session.js.map +0 -1
  380. package/dist/lib/native-tuning.js.map +0 -1
  381. package/dist/lib/p2p.d.ts +0 -32
  382. package/dist/lib/p2p.js +0 -281
  383. package/dist/lib/p2p.js.map +0 -1
  384. package/dist/lib/providers.d.ts +0 -1
  385. package/dist/lib/providers.js +0 -41
  386. package/dist/lib/providers.js.map +0 -1
  387. package/dist/lib/repair.d.ts +0 -10
  388. package/dist/lib/repair.js +0 -57
  389. package/dist/lib/repair.js.map +0 -1
  390. package/dist/lib/scanner.d.ts +0 -34
  391. package/dist/lib/scanner.js +0 -242
  392. package/dist/lib/scanner.js.map +0 -1
  393. package/dist/lib/search-tool.d.ts +0 -55
  394. package/dist/lib/search-tool.js +0 -319
  395. package/dist/lib/search-tool.js.map +0 -1
  396. package/dist/lib/serve.d.ts +0 -11
  397. package/dist/lib/serve.js +0 -144
  398. package/dist/lib/serve.js.map +0 -1
  399. package/dist/lib/store.d.ts +0 -252
  400. package/dist/lib/store.js +0 -1216
  401. package/dist/lib/store.js.map +0 -1
  402. package/dist/lib/types.d.ts +0 -194
  403. package/dist/lib/types.js +0 -13
  404. package/dist/lib/types.js.map +0 -1
  405. package/dist/lib/vocab.d.ts +0 -20
  406. package/dist/lib/vocab.js +0 -275
  407. package/dist/lib/vocab.js.map +0 -1
  408. /package/dist/{lib/native-tuning.d.ts → infrastructure/lancedb/NativeTuning.d.ts} +0 -0
@@ -0,0 +1,201 @@
1
+ import { CitationMarkers, } from "../../domain/research/Citation.js";
2
+ import { EvidenceLedger } from "../../domain/research/EvidenceLedger.js";
3
+ import { ResearchTrace, } from "../../domain/research/ResearchTrace.js";
4
+ import { SearchCriteria, } from "../search/SearchCriteria.js";
5
+ import { ResearchPrompts } from "./ResearchPrompts.js";
6
+ /**
7
+ * Answers a question by searching the codebase and synthesizing a cited answer.
8
+ *
9
+ * Robustness is layered, because a local model fails in several distinct ways
10
+ * and none of them should hard-fail the caller:
11
+ *
12
+ * 1. Happy path — the model self-terminates with a cited answer.
13
+ * 2. It cannot self-terminate (step cap, timeout, or the transcript overflows
14
+ * its context) — synthesize from a budgeted digest in a fresh context.
15
+ * 3. It answered without ever searching — discard that, since it is ungrounded
16
+ * by construction, search directly and synthesize.
17
+ * 4. The model is unreachable — degrade to raw search hits.
18
+ */
19
+ export class ResearchAgent {
20
+ searcher;
21
+ chat;
22
+ config;
23
+ static DEFAULT_MAX_STEPS = 8;
24
+ /**
25
+ * Wall clock is only a backstop against a wedged run; the search and step
26
+ * budgets bound the real work. A local model doing a few steps plus a cold
27
+ * load can need minutes, so this stays generous.
28
+ */
29
+ static DEFAULT_TIMEOUT_MS = 240_000;
30
+ static MAX_SEARCHES = 8;
31
+ static DEFAULT_SEARCH_LIMIT = 5;
32
+ /** The model tends to ask for 10+, which bloats the transcript. */
33
+ static MAX_SEARCH_LIMIT = 6;
34
+ /** After this many searches, nudge it to wrap up. */
35
+ static NUDGE_AFTER = 3;
36
+ constructor(searcher, chat, config) {
37
+ this.searcher = searcher;
38
+ this.chat = chat;
39
+ this.config = config;
40
+ }
41
+ async research(question, onTrace) {
42
+ if (!this.chat.isConfigured) {
43
+ throw new Error("`lmgrep ask` requires a chat model. Set `chatModel` in your lmgrep config " +
44
+ "(e.g. `chatModel: lmstudio:qwen/qwen3.5-9b`).");
45
+ }
46
+ const started = Date.now();
47
+ const trace = new ResearchTrace(onTrace);
48
+ const ledger = new EvidenceLedger();
49
+ const timeoutMs = this.config.chatTimeoutMs ?? ResearchAgent.DEFAULT_TIMEOUT_MS;
50
+ const maxSteps = this.config.chatMaxSteps ?? ResearchAgent.DEFAULT_MAX_STEPS;
51
+ let searchCount = 0;
52
+ const runSearch = async (call) => {
53
+ if (searchCount >= ResearchAgent.MAX_SEARCHES) {
54
+ return ResearchPrompts.BUDGET_EXHAUSTED;
55
+ }
56
+ searchCount++;
57
+ const hits = await this.runSearch(call.query, {
58
+ limit: Math.min(call.limit ?? ResearchAgent.DEFAULT_SEARCH_LIMIT, ResearchAgent.MAX_SEARCH_LIMIT),
59
+ filePrefix: call.filePrefix,
60
+ type: call.type,
61
+ language: call.language,
62
+ });
63
+ trace.searched(call.query, hits.length);
64
+ if (hits.isEmpty) {
65
+ return `No results for "${call.query}". Try different wording or a broader query.`;
66
+ }
67
+ const blocks = ledger
68
+ .ingest(hits.toArray())
69
+ .map(({ id, hit, body }) => `[${id}] ${hit.location} · ${hit.type} ${hit.name} · score ${hit.score.toFixed(2)}\n${body}`);
70
+ const parts = [`Results for "${call.query}":`, ...blocks];
71
+ if (searchCount >= ResearchAgent.NUDGE_AFTER) {
72
+ parts.push(ResearchPrompts.WRAP_UP);
73
+ }
74
+ return parts.join("\n\n");
75
+ };
76
+ const outcome = await this.chat.runToolLoop({
77
+ system: ResearchPrompts.SYSTEM,
78
+ prompt: question,
79
+ maxSteps,
80
+ timeoutMs,
81
+ toolDescription: ResearchPrompts.SEARCH_TOOL,
82
+ onSearch: runSearch,
83
+ });
84
+ const steps = outcome.steps;
85
+ let answer = outcome.status === "completed" ? outcome.text : "";
86
+ if (outcome.status === "failed") {
87
+ return this.degrade(question, outcome.error, trace, steps, started);
88
+ }
89
+ if (outcome.status === "interrupted") {
90
+ trace.noted(outcome.reason === "timeout"
91
+ ? `Timed out after ${timeoutMs}ms`
92
+ : "Model context exceeded mid-loop — synthesizing from gathered evidence.");
93
+ }
94
+ // The provider cannot be made to force a tool call (LM Studio ignores
95
+ // toolChoice), so the model sometimes answers from prior knowledge. An
96
+ // answer with no search behind it is ungrounded by construction —
97
+ // discard it and ground the question directly.
98
+ if (searchCount === 0) {
99
+ trace.noted("Model answered without searching — grounding from a direct search.");
100
+ try {
101
+ const hits = await this.runSearch(question, {
102
+ limit: ResearchAgent.DEFAULT_SEARCH_LIMIT,
103
+ });
104
+ trace.searched(question, hits.length);
105
+ ledger.ingest(hits.toArray());
106
+ }
107
+ catch (err) {
108
+ return this.degrade(question, err, trace, steps, started);
109
+ }
110
+ answer = "";
111
+ }
112
+ if (!answer) {
113
+ answer =
114
+ (await this.synthesize(question, ledger, trace, timeoutMs)) ?? "";
115
+ }
116
+ if (!answer) {
117
+ return this.degrade(question, new Error("Model produced no answer."), trace, steps, started);
118
+ }
119
+ // Small models drop [n] markers inconsistently on terse answers. One
120
+ // cheap annotation pass beats returning an uncitable result.
121
+ if (!CitationMarkers.present(answer) && !ledger.isEmpty) {
122
+ answer = await this.addCitations(answer, ledger, trace, timeoutMs);
123
+ }
124
+ return {
125
+ question,
126
+ answer,
127
+ sources: CitationMarkers.resolve(answer, ledger.sources),
128
+ trace: trace.toArray(),
129
+ steps,
130
+ elapsedMs: Date.now() - started,
131
+ degraded: false,
132
+ };
133
+ }
134
+ runSearch(query, options) {
135
+ return this.searcher.search(query, new SearchCriteria(options));
136
+ }
137
+ /**
138
+ * One-shot synthesis over a budgeted digest, in a fresh context with no
139
+ * tool transcript to replay — which is what makes it work even when the
140
+ * agentic loop overflowed the window.
141
+ */
142
+ async synthesize(question, ledger, trace, timeoutMs) {
143
+ if (ledger.isEmpty)
144
+ return undefined;
145
+ trace.noted("Synthesizing answer from evidence…");
146
+ return this.chat.complete({
147
+ system: ResearchPrompts.SYSTEM,
148
+ prompt: `Question: ${question}\n\nEvidence gathered from the codebase:\n\n` +
149
+ `${ledger.digest()}\n\n${ResearchPrompts.FORCE_ANSWER}`,
150
+ timeoutMs,
151
+ });
152
+ }
153
+ /** Ask the model to insert markers into its own answer, wording unchanged. */
154
+ async addCitations(answer, ledger, trace, timeoutMs) {
155
+ trace.noted("Answer had no citations — adding them.");
156
+ const revised = await this.chat.complete({
157
+ system: ResearchPrompts.ADD_CITATIONS,
158
+ prompt: `Sources:\n${ledger.menu()}\n\nAnswer to annotate:\n${answer}`,
159
+ timeoutMs,
160
+ });
161
+ // Keep the original if the retry failed or still has no markers.
162
+ return revised && CitationMarkers.present(revised) ? revised : answer;
163
+ }
164
+ /** Last resort: return the raw hits, clearly marked as un-synthesized. */
165
+ async degrade(question, error, trace, steps, started) {
166
+ const message = error instanceof Error ? error.message : String(error);
167
+ trace.noted(`Synthesis unavailable: ${message}`);
168
+ let sources = [];
169
+ let body;
170
+ try {
171
+ const hits = await this.runSearch(question, {
172
+ limit: ResearchAgent.DEFAULT_SEARCH_LIMIT,
173
+ });
174
+ const list = hits.toArray();
175
+ sources = list.map((hit, i) => ({
176
+ n: i + 1,
177
+ path: hit.location.filePath,
178
+ startLine: hit.location.startLine,
179
+ endLine: hit.location.endLine,
180
+ }));
181
+ body = list.length
182
+ ? list
183
+ .map((hit, i) => `[${i + 1}] ${hit.location} (${hit.type} ${hit.name})`)
184
+ .join("\n")
185
+ : "No results found.";
186
+ }
187
+ catch {
188
+ body = "No results found (search also failed).";
189
+ }
190
+ return {
191
+ question,
192
+ answer: `Synthesis unavailable (${message}). Raw search results:\n${body}`,
193
+ sources,
194
+ trace: trace.toArray(),
195
+ steps,
196
+ elapsedMs: Date.now() - started,
197
+ degraded: true,
198
+ };
199
+ }
200
+ }
201
+ //# sourceMappingURL=ResearchAgent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResearchAgent.js","sourceRoot":"","sources":["../../../src/application/research/ResearchAgent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The instructions given to the research model.
3
+ *
4
+ * Tuned against small local models, which is why they are unusually blunt
5
+ * about stopping: left to themselves these models keep searching for
6
+ * completeness, and every extra step costs seconds.
7
+ */
8
+ export declare class ResearchPrompts {
9
+ static readonly SYSTEM: string;
10
+ /** How the one available tool is described to the model. */
11
+ static readonly SEARCH_TOOL = "Semantic code search. Returns the top matching code units, each with a [n] id, file:line, and its source. This is the only tool \u2014 answer from what it returns.";
12
+ static readonly FORCE_ANSWER = "Using ONLY the evidence above, write the final answer now. Cite [n] for every claim, reusing the ids shown. If the evidence is insufficient, say so plainly and list what is still missing. Do not ask to search further.";
13
+ static readonly ADD_CITATIONS = "You add source citations to an existing answer. Insert [n] markers after the claims each source supports, using the ids from the source list. Do not change the wording or substance otherwise. Output only the revised answer.";
14
+ static readonly BUDGET_EXHAUSTED = "Search budget exhausted. Stop searching and answer from what you have.";
15
+ static readonly WRAP_UP = "(You've searched several times \u2014 answer now from what you've gathered unless a specific detail is still missing.)";
16
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The instructions given to the research model.
3
+ *
4
+ * Tuned against small local models, which is why they are unusually blunt
5
+ * about stopping: left to themselves these models keep searching for
6
+ * completeness, and every extra step costs seconds.
7
+ */
8
+ export class ResearchPrompts {
9
+ static SYSTEM = [
10
+ "You are a code research assistant working inside a repository. Answer the user's question by searching the codebase and writing a concise, grounded answer.",
11
+ "",
12
+ "Tool:",
13
+ "- search({query, filePrefix?, type?, language?, limit?}): semantic code search. Returns the top matching code units (functions, classes, blocks), each with a [n] id, its file:line, and its source. Phrase `query` as a natural-language intent, not keywords. The returned source is what you answer from — there is no separate file-reading step.",
14
+ "",
15
+ "Method — be decisive, minimize steps (each step is slow):",
16
+ "- ALWAYS search before answering. Never answer from prior knowledge or assumptions — the codebase is the only source of truth, and defaults, names, and behavior often differ from what you'd guess.",
17
+ "- A grounded, focused answer beats an exhaustive survey. Aim to answer in as few searches as possible.",
18
+ "- Typical shape: one search → answer. Search again ONLY if the results revealed a specific gap, or surfaced codebase vocabulary you should follow up on with a sharper query.",
19
+ "- Never search for completeness, breadth, or to double-check. The moment the results let you answer, STOP searching and write the answer.",
20
+ "",
21
+ "Answer rules:",
22
+ '- Cite with the [n] id, never a bare file path. Every claim needs a [n]. Example: write "changes are debounced for 2s [2]", not "in scanner.ts, changes are debounced".',
23
+ "- Do NOT paste code blocks or quote source verbatim. Describe what the code does in your own words and cite [n].",
24
+ "- Be tight: what the code does, where, and how. No tours, no restating the question.",
25
+ "- If the results do not answer the question, say so plainly and list what's missing. Never invent file paths, line numbers, or behavior.",
26
+ ].join("\n");
27
+ /** How the one available tool is described to the model. */
28
+ static SEARCH_TOOL = "Semantic code search. Returns the top matching code units, each with a [n] id, file:line, and its source. This is the only tool — answer from what it returns.";
29
+ static FORCE_ANSWER = "Using ONLY the evidence above, write the final answer now. Cite [n] for every claim, reusing the ids shown. If the evidence is insufficient, say so plainly and list what is still missing. Do not ask to search further.";
30
+ static ADD_CITATIONS = "You add source citations to an existing answer. Insert [n] markers after the claims each source supports, using the ids from the source list. Do not change the wording or substance otherwise. Output only the revised answer.";
31
+ static BUDGET_EXHAUSTED = "Search budget exhausted. Stop searching and answer from what you have.";
32
+ static WRAP_UP = "(You've searched several times — answer now from what you've gathered unless a specific detail is still missing.)";
33
+ }
34
+ //# sourceMappingURL=ResearchPrompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResearchPrompts.js","sourceRoot":"","sources":["../../../src/application/research/ResearchPrompts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,OAAO,eAAe;IAC3B,MAAM,CAAU,MAAM,GAAG;QACxB,6JAA6J;QAC7J,EAAE;QACF,OAAO;QACP,uVAAuV;QACvV,EAAE;QACF,2DAA2D;QAC3D,sMAAsM;QACtM,wGAAwG;QACxG,+KAA+K;QAC/K,2IAA2I;QAC3I,EAAE;QACF,eAAe;QACf,yKAAyK;QACzK,kHAAkH;QAClH,sFAAsF;QACtF,0IAA0I;KAC1I,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,4DAA4D;IAC5D,MAAM,CAAU,WAAW,GAC1B,gKAAgK,CAAC;IAElK,MAAM,CAAU,YAAY,GAC3B,2NAA2N,CAAC;IAE7N,MAAM,CAAU,aAAa,GAC5B,iOAAiO,CAAC;IAEnO,MAAM,CAAU,gBAAgB,GAC/B,wEAAwE,CAAC;IAE1E,MAAM,CAAU,OAAO,GACtB,mHAAmH,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { Hit } from "../../domain/retrieval/Hit.js";
2
+ /** Everything a caller can ask of a search. */
3
+ export interface SearchOptions {
4
+ limit?: number;
5
+ filePrefix?: string;
6
+ /** Push results away from this meaning. */
7
+ not?: string;
8
+ minScore?: number;
9
+ /** Only chunks of these AST types. */
10
+ type?: string[];
11
+ /** Only files with these extensions (".ts", ".py"). */
12
+ language?: string[];
13
+ /** Search another project's index instead of this one. */
14
+ project?: string;
15
+ /** Search several project indexes and merge by score. */
16
+ across?: string[];
17
+ }
18
+ /**
19
+ * A search request, with the filters that can only be applied after retrieval.
20
+ *
21
+ * Language and score filters live here rather than in the query because
22
+ * neither is stored in a form the vector index can filter on: extensions are a
23
+ * property of the path, and scores only exist once distances are computed.
24
+ */
25
+ export declare class SearchCriteria {
26
+ private readonly options;
27
+ static readonly DEFAULT_LIMIT = 25;
28
+ private readonly extensions;
29
+ constructor(options: SearchOptions);
30
+ get limit(): number;
31
+ get filePrefix(): string | undefined;
32
+ get types(): string[] | undefined;
33
+ get negation(): string | undefined;
34
+ get project(): string | undefined;
35
+ get across(): string[] | undefined;
36
+ admits(hit: Hit): boolean;
37
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * A search request, with the filters that can only be applied after retrieval.
3
+ *
4
+ * Language and score filters live here rather than in the query because
5
+ * neither is stored in a form the vector index can filter on: extensions are a
6
+ * property of the path, and scores only exist once distances are computed.
7
+ */
8
+ export class SearchCriteria {
9
+ options;
10
+ static DEFAULT_LIMIT = 25;
11
+ extensions;
12
+ constructor(options) {
13
+ this.options = options;
14
+ const languages = options.language;
15
+ this.extensions =
16
+ languages && languages.length > 0
17
+ ? new Set(languages.map((l) => (l.startsWith(".") ? l : `.${l}`)))
18
+ : undefined;
19
+ }
20
+ get limit() {
21
+ return this.options.limit ?? SearchCriteria.DEFAULT_LIMIT;
22
+ }
23
+ get filePrefix() {
24
+ return this.options.filePrefix;
25
+ }
26
+ get types() {
27
+ return this.options.type;
28
+ }
29
+ get negation() {
30
+ return this.options.not;
31
+ }
32
+ get project() {
33
+ return this.options.project;
34
+ }
35
+ get across() {
36
+ return this.options.across;
37
+ }
38
+ admits(hit) {
39
+ if (this.extensions && !this.extensions.has(hit.location.extension)) {
40
+ return false;
41
+ }
42
+ if (this.options.minScore != null && hit.score < this.options.minScore) {
43
+ return false;
44
+ }
45
+ return true;
46
+ }
47
+ }
48
+ //# sourceMappingURL=SearchCriteria.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchCriteria.js","sourceRoot":"","sources":["../../../src/application/search/SearchCriteria.ts"],"names":[],"mappings":"AAmBA;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IAKG;IAJ7B,MAAM,CAAU,aAAa,GAAG,EAAE,CAAC;IAElB,UAAU,CAA0B;IAErD,YAA6B,OAAsB;QAAtB,YAAO,GAAP,OAAO,CAAe;QAClD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QACnC,IAAI,CAAC,UAAU;YACd,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;gBAChC,CAAC,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBAClE,CAAC,CAAC,SAAS,CAAC;IACf,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC,aAAa,CAAC;IAC3D,CAAC;IAED,IAAI,UAAU;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;IAChC,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;IACzB,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED,IAAI,MAAM;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,MAAM,CAAC,GAAQ;QACd,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACrE,OAAO,KAAK,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,IAAI,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACxE,OAAO,KAAK,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { LmgrepConfig } from "../../domain/config/LmgrepConfig.js";
2
+ import type { EmbedderPort } from "../../domain/ports/EmbedderPort.js";
3
+ import type { LoggerPort } from "../../domain/ports/LoggerPort.js";
4
+ import type { IndexMetadata } from "../../domain/project/IndexMetadata.js";
5
+ import { HitList } from "../../domain/retrieval/HitList.js";
6
+ import type { IndexAlternatives } from "../operations/IndexAlternatives.js";
7
+ import type { SearchCriteria } from "./SearchCriteria.js";
8
+ import type { SearchTargetResolver } from "./SearchTargetResolver.js";
9
+ /**
10
+ * Runs a semantic search: embed the query, retrieve from every target index,
11
+ * merge, and apply the filters retrieval cannot.
12
+ */
13
+ export declare class SearchService {
14
+ private readonly embedder;
15
+ private readonly targets;
16
+ private readonly config;
17
+ private readonly logger;
18
+ private readonly readMetadata;
19
+ private readonly alternatives;
20
+ /**
21
+ * How strongly a `--not` query pushes results away. Full subtraction
22
+ * overshoots into unrelated space; half keeps the original intent dominant
23
+ * while still displacing the unwanted sense.
24
+ */
25
+ private static readonly NEGATION_WEIGHT;
26
+ constructor(embedder: EmbedderPort, targets: SearchTargetResolver, config: LmgrepConfig, logger: LoggerPort, readMetadata: () => IndexMetadata | undefined, alternatives: IndexAlternatives);
27
+ search(query: string, criteria: SearchCriteria): Promise<HitList>;
28
+ private retrieveFrom;
29
+ private buildQueryVector;
30
+ /**
31
+ * A width mismatch is fatal — the vectors are simply incomparable. A family
32
+ * mismatch is only a warning: results degrade rather than break, and the
33
+ * user may have deliberately swapped a compatible model.
34
+ */
35
+ private verifyModelCompatibility;
36
+ }
@@ -0,0 +1,108 @@
1
+ import { ModelIdentity } from "../../domain/project/ModelIdentity.js";
2
+ import { HitList } from "../../domain/retrieval/HitList.js";
3
+ import { MissingIndexError } from "../../domain/retrieval/MissingIndexError.js";
4
+ /**
5
+ * Runs a semantic search: embed the query, retrieve from every target index,
6
+ * merge, and apply the filters retrieval cannot.
7
+ */
8
+ export class SearchService {
9
+ embedder;
10
+ targets;
11
+ config;
12
+ logger;
13
+ readMetadata;
14
+ alternatives;
15
+ /**
16
+ * How strongly a `--not` query pushes results away. Full subtraction
17
+ * overshoots into unrelated space; half keeps the original intent dominant
18
+ * while still displacing the unwanted sense.
19
+ */
20
+ static NEGATION_WEIGHT = 0.5;
21
+ constructor(embedder, targets, config, logger, readMetadata, alternatives) {
22
+ this.embedder = embedder;
23
+ this.targets = targets;
24
+ this.config = config;
25
+ this.logger = logger;
26
+ this.readMetadata = readMetadata;
27
+ this.alternatives = alternatives;
28
+ }
29
+ async search(query, criteria) {
30
+ const queryVector = await this.buildQueryVector(query, criteria);
31
+ const targets = await this.targets.resolve(criteria);
32
+ try {
33
+ const merged = await this.retrieveFrom(targets, queryVector, criteria);
34
+ return merged.filtered((hit) => criteria.admits(hit));
35
+ }
36
+ catch (err) {
37
+ // "No index found" is accurate and useless on its own: the usual
38
+ // cause is a model change, and the index the user is thinking of is
39
+ // intact one directory away.
40
+ if (err instanceof MissingIndexError) {
41
+ const absence = this.alternatives.explainAbsence();
42
+ if (absence) {
43
+ throw new MissingIndexError(`${absence.reason}\n${absence.fix}`);
44
+ }
45
+ }
46
+ throw err;
47
+ }
48
+ finally {
49
+ await this.targets.release(targets);
50
+ }
51
+ }
52
+ async retrieveFrom(targets, queryVector, criteria) {
53
+ let merged = HitList.empty();
54
+ for (const target of targets) {
55
+ const page = await target.chunks.search({
56
+ vector: queryVector,
57
+ limit: criteria.limit,
58
+ filePrefix: target.filePrefix,
59
+ types: criteria.types,
60
+ // A foreign index has no manifest for our branch, so scoping to
61
+ // it would filter everything away.
62
+ scopeToBranch: target.projectRoot === undefined,
63
+ });
64
+ merged = merged.concat(target.projectRoot
65
+ ? page.mapped((hit) => hit.relocatedUnder(target.projectRoot))
66
+ : page);
67
+ }
68
+ // Scores are comparable across indexes only when the same model built
69
+ // them; re-sorting is still the best available merge.
70
+ return targets.length > 1
71
+ ? merged.sortedByScoreDescending().takeAtMost(criteria.limit)
72
+ : merged;
73
+ }
74
+ async buildQueryVector(query, criteria) {
75
+ const vector = await this.embedder.embedQuery(query);
76
+ this.verifyModelCompatibility(vector);
77
+ const negation = criteria.negation;
78
+ if (!negation)
79
+ return vector;
80
+ const away = await this.embedder.embedQuery(negation);
81
+ return vector.minus(away.scaledBy(SearchService.NEGATION_WEIGHT));
82
+ }
83
+ /**
84
+ * A width mismatch is fatal — the vectors are simply incomparable. A family
85
+ * mismatch is only a warning: results degrade rather than break, and the
86
+ * user may have deliberately swapped a compatible model.
87
+ */
88
+ verifyModelCompatibility(queryVector) {
89
+ const meta = this.readMetadata();
90
+ if (!meta)
91
+ return;
92
+ if (meta.dimensions != null && queryVector.dimensions !== meta.dimensions) {
93
+ throw new Error(`Dimension mismatch: index has ${meta.dimensions}-dim vectors but ` +
94
+ `your model produces ${queryVector.dimensions}-dim. ` +
95
+ "These embeddings are incompatible.");
96
+ }
97
+ if (!meta.model)
98
+ return;
99
+ const indexModel = ModelIdentity.of(meta.model);
100
+ const queryModel = ModelIdentity.of(this.config.model);
101
+ if (!indexModel.isSameFamilyAs(queryModel)) {
102
+ this.logger.info(`Warning: index was built with "${meta.model}" (${indexModel.family}) ` +
103
+ `but searching with "${this.config.model}" (${queryModel.family}). ` +
104
+ "Results may be degraded if these are different model families.");
105
+ }
106
+ }
107
+ }
108
+ //# sourceMappingURL=SearchService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchService.js","sourceRoot":"","sources":["../../../src/application/search/SearchService.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAQhF;;;GAGG;AACH,MAAM,OAAO,aAAa;IASP;IACA;IACA;IACA;IACA;IACA;IAblB;;;;OAIG;IACK,MAAM,CAAU,eAAe,GAAG,GAAG,CAAC;IAE9C,YACkB,QAAsB,EACtB,OAA6B,EAC7B,MAAoB,EACpB,MAAkB,EAClB,YAA6C,EAC7C,YAA+B;QAL/B,aAAQ,GAAR,QAAQ,CAAc;QACtB,YAAO,GAAP,OAAO,CAAsB;QAC7B,WAAM,GAAN,MAAM,CAAc;QACpB,WAAM,GAAN,MAAM,CAAY;QAClB,iBAAY,GAAZ,YAAY,CAAiC;QAC7C,iBAAY,GAAZ,YAAY,CAAmB;IAC9C,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,QAAwB;QACnD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEjE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;YACvE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,iEAAiE;YACjE,oEAAoE;YACpE,6BAA6B;YAC7B,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;gBACnD,IAAI,OAAO,EAAE,CAAC;oBACb,MAAM,IAAI,iBAAiB,CAAC,GAAG,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;gBAClE,CAAC;YACF,CAAC;YACD,MAAM,GAAG,CAAC;QACX,CAAC;gBAAS,CAAC;YACV,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,YAAY,CACzB,OAAuB,EACvB,WAAmB,EACnB,QAAwB;QAExB,IAAI,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QAE7B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;gBACvC,MAAM,EAAE,WAAW;gBACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,gEAAgE;gBAChE,mCAAmC;gBACnC,aAAa,EAAE,MAAM,CAAC,WAAW,KAAK,SAAS;aAC/C,CAAC,CAAC;YAEH,MAAM,GAAG,MAAM,CAAC,MAAM,CACrB,MAAM,CAAC,WAAW;gBACjB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CACpB,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,WAAqB,CAAC,CAChD;gBACF,CAAC,CAAC,IAAI,CACP,CAAC;QACH,CAAC;QAED,sEAAsE;QACtE,sDAAsD;QACtD,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC;YACxB,CAAC,CAAC,MAAM,CAAC,uBAAuB,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC7D,CAAC,CAAC,MAAM,CAAC;IACX,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC7B,KAAa,EACb,QAAwB;QAExB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAEtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;QACnC,IAAI,CAAC,QAAQ;YAAE,OAAO,MAAM,CAAC;QAE7B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACtD,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;IACnE,CAAC;IAED;;;;OAIG;IACK,wBAAwB,CAAC,WAAmB;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,IAAI,WAAW,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3E,MAAM,IAAI,KAAK,CACd,iCAAiC,IAAI,CAAC,UAAU,mBAAmB;gBAClE,uBAAuB,WAAW,CAAC,UAAU,QAAQ;gBACrD,oCAAoC,CACrC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO;QACxB,MAAM,UAAU,GAAG,aAAa,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,aAAa,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvD,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,IAAI,CACf,kCAAkC,IAAI,CAAC,KAAK,MAAM,UAAU,CAAC,MAAM,IAAI;gBACtE,uBAAuB,IAAI,CAAC,MAAM,CAAC,KAAK,MAAM,UAAU,CAAC,MAAM,KAAK;gBACpE,gEAAgE,CACjE,CAAC;QACH,CAAC;IACF,CAAC"}
@@ -0,0 +1,56 @@
1
+ import type { ChunkRepositoryPort } from "../../domain/ports/ChunkRepositoryPort.js";
2
+ import type { DatabaseLocation } from "../../domain/project/DatabaseLocation.js";
3
+ import type { ProjectLocator } from "../../domain/project/ProjectLocator.js";
4
+ import type { SearchCriteria } from "./SearchCriteria.js";
5
+ /** One index a search should consult. */
6
+ export interface SearchTarget {
7
+ chunks: ChunkRepositoryPort;
8
+ filePrefix?: string;
9
+ /**
10
+ * Absolute root of a foreign project, used to make its relative paths
11
+ * meaningful here. Undefined for the local index.
12
+ */
13
+ projectRoot?: string;
14
+ /** Whether this target was opened for the query and must be closed after. */
15
+ borrowed: boolean;
16
+ }
17
+ /** Opens a chunk repository for another project's database. */
18
+ export interface ForeignIndexOpener {
19
+ open(projectPath: string): Promise<{
20
+ chunks: ChunkRepositoryPort;
21
+ close: () => Promise<void>;
22
+ }>;
23
+ }
24
+ /**
25
+ * Decides which indexes a search reads.
26
+ *
27
+ * Three cases, in precedence order: `--across` merges several projects,
28
+ * `--project` redirects to one, and the default resolves the local project —
29
+ * including the case where the working directory sits below an indexed root,
30
+ * where the offset becomes a path prefix filter.
31
+ */
32
+ export declare class SearchTargetResolver {
33
+ private readonly cwd;
34
+ private readonly local;
35
+ private readonly location;
36
+ private readonly locator;
37
+ private readonly foreign;
38
+ private readonly opened;
39
+ constructor(cwd: string, local: ChunkRepositoryPort, location: DatabaseLocation, locator: ProjectLocator, foreign: ForeignIndexOpener);
40
+ resolve(criteria: SearchCriteria): Promise<SearchTarget[]>;
41
+ /** Close the databases this resolver opened; leave the local one alone. */
42
+ release(targets: SearchTarget[]): Promise<void>;
43
+ private openForeign;
44
+ /**
45
+ * The local index, with the working directory's offset from the project
46
+ * root folded into the prefix filter — so searching from `src/lib` only
47
+ * returns hits from there. A manually targeted database is flat and skips
48
+ * this entirely.
49
+ *
50
+ * Inside a git repo the ancestor resolves to the same database, because
51
+ * project identity is the remote. Outside git the walk-up can land on a
52
+ * genuinely different database — an indexed parent directory — which must
53
+ * be opened rather than substituted with the local one.
54
+ */
55
+ private resolveLocal;
56
+ }