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
@@ -7,6 +7,9 @@ exports.formatChunk = formatChunk;
7
7
  exports.formatGraphContext = formatGraphContext;
8
8
  exports.formatDependencies = formatDependencies;
9
9
  exports.formatDependents = formatDependents;
10
+ exports.formatTransitiveSection = formatTransitiveSection;
11
+ exports.formatDependenciesFilterMiss = formatDependenciesFilterMiss;
12
+ exports.formatDependentsFilterMiss = formatDependentsFilterMiss;
10
13
  exports.pathArgDescription = pathArgDescription;
11
14
  exports.pathErrorText = pathErrorText;
12
15
  exports.pathErrorResponse = pathErrorResponse;
@@ -28,40 +31,159 @@ function formatGraphContext(ctx) {
28
31
  parts.push(`**Used by:** ${ctx.usedBy.join(' · ')}`);
29
32
  return parts.length > 0 ? '\n' + parts.join('\n') : '';
30
33
  }
31
- function formatDependencies(filePath, rows, transitive) {
34
+ const MAX_NAMES = 8;
35
+ const MAX_IN = 3;
36
+ function nameEntry(r) {
37
+ switch (r.depType) {
38
+ case 'import': return r.toSymbol ? { text: r.toSymbol, isReexport: false } : null;
39
+ case 'import-default': return { text: r.toSymbol ?? 'default', isReexport: false };
40
+ case 'import-namespace': return { text: r.toSymbol ?? '* as namespace', isReexport: false };
41
+ case 'import-side-effect': return { text: 'side-effect', isReexport: false };
42
+ case 'reexport': return r.toSymbol ? { text: r.toSymbol, isReexport: true } : null;
43
+ case 'reexport-namespace': return { text: r.toSymbol ?? 'export *', isReexport: true };
44
+ default: return null;
45
+ }
46
+ }
47
+ function codeSpan(value) {
48
+ const text = value.replace(/\s+/g, ' ');
49
+ const fence = '`'.repeat(Math.max(0, ...(text.match(/`+/g) ?? []).map(run => run.length)) + 1);
50
+ const pad = text.startsWith('`') || text.endsWith('`') ? ' ' : '';
51
+ return `${fence}${pad}${text}${pad}${fence}`;
52
+ }
53
+ function capped(values, max) {
54
+ const shown = values.slice(0, max);
55
+ const more = values.length - shown.length;
56
+ const text = shown.map(codeSpan).join(', ');
57
+ return more > 0 ? `${text} (+${more} more)` : text;
58
+ }
59
+ function groupNames(rows) {
60
+ const plain = [];
61
+ const reexport = [];
62
+ for (const r of rows) {
63
+ const e = nameEntry(r);
64
+ if (!e)
65
+ continue;
66
+ const bucket = e.isReexport ? reexport : plain;
67
+ if (!bucket.includes(e.text))
68
+ bucket.push(e.text);
69
+ }
70
+ const total = plain.length + reexport.length;
71
+ const shownPlainCount = Math.min(plain.length, MAX_NAMES);
72
+ const shownReexportCount = Math.min(reexport.length, MAX_NAMES - shownPlainCount);
73
+ const more = total - shownPlainCount - shownReexportCount;
74
+ const parts = [];
75
+ if (shownPlainCount > 0) {
76
+ parts.push(plain.slice(0, shownPlainCount).map(codeSpan).join(', '));
77
+ }
78
+ if (shownReexportCount > 0) {
79
+ parts.push(`re-export ${reexport.slice(0, shownReexportCount).map(codeSpan).join(', ')}`);
80
+ }
81
+ let text = parts.join(', ');
82
+ if (more > 0)
83
+ text += ` (+${more} more)`;
84
+ return text;
85
+ }
86
+ function groupIn(rows) {
87
+ const values = [];
88
+ for (const r of rows) {
89
+ if (r.fromSymbol && !values.includes(r.fromSymbol))
90
+ values.push(r.fromSymbol);
91
+ }
92
+ return capped(values, MAX_IN);
93
+ }
94
+ function groupByFile(rows, key) {
95
+ const groups = new Map();
96
+ for (const r of rows) {
97
+ const k = r[key];
98
+ if (!groups.has(k))
99
+ groups.set(k, []);
100
+ groups.get(k).push(r);
101
+ }
102
+ return groups;
103
+ }
104
+ function directHeader(fileCount) {
105
+ return `**Direct:** ${fileCount} file${fileCount === 1 ? '' : 's'}`;
106
+ }
107
+ function transitiveLines(indirect, symbol, line) {
108
+ const note = symbol ? ' *(not filtered by `symbol`, which applies to direct imports only)*' : '';
109
+ return [`**Transitive:**${note}`, ...indirect.map(line)];
110
+ }
111
+ const dependencyLine = (r) => ` → \`${r.toFile}\` (depth ${r.depth}, via \`${r.via}\`)`;
112
+ const dependentLine = (r) => ` ← \`${r.fromFile}\` (depth ${r.depth}, via \`${r.via}\`)`;
113
+ function formatDependencies(filePath, rows, transitive, symbol = null) {
32
114
  const direct = rows.filter(r => !transitive || (r.depth ?? 1) === 1);
33
115
  const indirect = transitive ? rows.filter(r => (r.depth ?? 1) > 1) : [];
34
- const lines = [`**Dependencies of** \`${filePath}\`\n`, '**Direct:**'];
35
- for (const r of direct) {
36
- const sym = r.toSymbol ? ` (${r.depType} \`${r.toSymbol}\`)` : ` (${r.depType})`;
37
- lines.push(` → \`${r.toFile}\`${sym}`);
38
- }
39
- if (indirect.length > 0) {
40
- lines.push('\n**Transitive:**');
41
- for (const r of indirect) {
42
- lines.push(` → \`${r.toFile}\` (depth ${r.depth}, via \`${r.via}\`)`);
43
- }
116
+ const groups = groupByFile(direct, 'toFile');
117
+ const lines = [`**Dependencies of** \`${filePath}\`\n`, directHeader(groups.size)];
118
+ for (const [toFile, groupRows] of groups) {
119
+ const names = groupNames(groupRows);
120
+ lines.push(` → \`${toFile}\`${names ? ` — ${names}` : ''}`);
44
121
  }
122
+ if (indirect.length > 0)
123
+ lines.push('', ...transitiveLines(indirect, symbol, dependencyLine));
45
124
  return lines.join('\n');
46
125
  }
47
- function formatDependents(filePath, rows, transitive) {
126
+ function formatDependents(filePath, rows, transitive, symbol = null) {
48
127
  const direct = rows.filter(r => !transitive || (r.depth ?? 1) === 1);
49
128
  const indirect = transitive ? rows.filter(r => (r.depth ?? 1) > 1) : [];
50
- const lines = [`**Dependents of** \`${filePath}\`\n`, '**Direct:**'];
51
- for (const r of direct) {
52
- const sym = r.fromSymbol ? ` (in \`${r.fromSymbol}\`)` : '';
53
- lines.push(` ← \`${r.fromFile}\`${sym}`);
54
- }
55
- if (indirect.length > 0) {
56
- lines.push('\n**Transitive:**');
57
- for (const r of indirect) {
58
- lines.push(` ← \`${r.fromFile}\` (depth ${r.depth}, via \`${r.via}\`)`);
59
- }
129
+ const groups = groupByFile(direct, 'fromFile');
130
+ const lines = [`**Dependents of** \`${filePath}\`\n`, directHeader(groups.size)];
131
+ for (const [fromFile, groupRows] of groups) {
132
+ const names = groupNames(groupRows);
133
+ const inPart = groupIn(groupRows);
134
+ let line = ` ← \`${fromFile}\`${names ? ` — ${names}` : ''}`;
135
+ if (inPart)
136
+ line += ` · in ${inPart}`;
137
+ lines.push(line);
60
138
  }
139
+ if (indirect.length > 0)
140
+ lines.push('', ...transitiveLines(indirect, symbol, dependentLine));
61
141
  return lines.join('\n');
62
142
  }
143
+ function formatTransitiveSection(rows, symbol, side) {
144
+ const indirect = rows.filter(r => (r.depth ?? 1) > 1);
145
+ if (indirect.length === 0)
146
+ return '';
147
+ return transitiveLines(indirect, symbol, side === 'dependencies' ? dependencyLine : dependentLine).join('\n');
148
+ }
149
+ function filterMissSummary(rows, key) {
150
+ const groups = groupByFile(rows, key);
151
+ const names = [];
152
+ for (const r of rows) {
153
+ if (r.toSymbol !== null && !names.includes(r.toSymbol))
154
+ names.push(r.toSymbol);
155
+ }
156
+ const nameless = [...groups.values()].filter(g => g.some(r => r.toSymbol === null)).length;
157
+ return { files: groups.size, names: capped(names, MAX_NAMES), nameless };
158
+ }
159
+ function filterMissTail(nameless) {
160
+ const lines = [];
161
+ if (nameless > 0) {
162
+ lines.push(`${nameless} of them ${nameless === 1 ? 'uses' : 'use'} a default, namespace, side-effect or \`export *\` import, which the \`symbol\` filter cannot match.`);
163
+ }
164
+ lines.push('Retry without `symbol` to list them.');
165
+ return lines;
166
+ }
167
+ function formatDependenciesFilterMiss(filePath, symbol, unfiltered) {
168
+ const { files, names, nameless } = filterMissSummary(unfiltered, 'toFile');
169
+ const importing = names ? `, importing: ${names}` : '';
170
+ return [
171
+ `No import of \`${symbol}\` found in: ${filePath}`,
172
+ `It has ${files} direct ${files === 1 ? 'dependency' : 'dependencies'}${importing}.`,
173
+ ...filterMissTail(nameless),
174
+ ].join('\n');
175
+ }
176
+ function formatDependentsFilterMiss(filePath, symbol, unfiltered) {
177
+ const { files, names, nameless } = filterMissSummary(unfiltered, 'fromFile');
178
+ const using = names ? `, using: ${names}` : '';
179
+ return [
180
+ `**Dependents of** \`${filePath}\``,
181
+ '',
182
+ `**Direct:** No direct import of \`${symbol}\`. ${files} ${files === 1 ? 'file imports' : 'files import'} this file${using}.`,
183
+ ...filterMissTail(nameless),
184
+ ].join('\n');
185
+ }
63
186
  exports.PATH_EXAMPLE = { file: 'my-app/src/index.ts', directory: 'my-app/src' };
64
- /** Description of a path argument; `kind` names what the path points at. */
65
187
  function pathArgDescription(kind = 'file') {
66
188
  const root = kind === 'directory' ? ', "." for the workspace root' : '';
67
189
  const noun = kind === 'directory' ? 'directory' : 'path';
@@ -83,10 +205,6 @@ function notIndexedExplanation(e) {
83
205
  '(run rag-index), or it has no indexable content (empty, comments only, or imports of external packages only).';
84
206
  }
85
207
  }
86
- /**
87
- * Text of a path error. `input` is the raw argument (echoed by refusals);
88
- * `relPath` its canonical form, printed by every other message.
89
- */
90
208
  function pathErrorText(argName, input, relPath, err, kind = 'file') {
91
209
  const example = exports.PATH_EXAMPLE[kind];
92
210
  switch (err.reason) {
@@ -110,12 +228,12 @@ function pathErrorText(argName, input, relPath, err, kind = 'file') {
110
228
  return `Not indexed: ${relPath}\n${notIndexedExplanation(err.explanation)}`;
111
229
  case 'not_a_file': return `Not a file: ${relPath}`;
112
230
  case 'not_a_directory': return `Not a directory: ${relPath}`;
231
+ case 'binary': return `Binary file: ${relPath}`;
113
232
  case 'unreadable': return `Cannot read: ${relPath} (${err.code})`;
114
233
  case 'past_end': return `${relPath} has ${err.lineCount} lines; start_line ${err.startLine} is past the end`;
115
234
  case 'bad_range': return `end_line ${err.endLine} is before start_line ${err.startLine}`;
116
235
  }
117
236
  }
118
- /** Error response for a path error, logged at `warn` — a caller or index-freshness problem, not a server fault. */
119
237
  function pathErrorResponse(logger, tool, argName, input, relPath, err, kind = 'file') {
120
238
  logger.warn('Tool path error', { tool, input, reason: err.reason });
121
239
  return errorResponse(pathErrorText(argName, input, relPath, err, kind));
@@ -0,0 +1,38 @@
1
+ import { z } from 'zod';
2
+ import type { PathKind } from './format-helpers';
3
+ export declare function requiredText(description?: string): z.ZodType<string>;
4
+ export declare function optionalText(description?: string): z.ZodType<string | undefined>;
5
+ export declare function pathArg(description: string, kind?: PathKind): z.ZodType<string>;
6
+ export declare function optionalPathArg(description: string): z.ZodType<string | undefined>;
7
+ interface IntRange {
8
+ min?: number;
9
+ max?: number;
10
+ }
11
+ export declare function intInRange(description: string, range: IntRange & {
12
+ fallback: number;
13
+ }): z.ZodType<number>;
14
+ export declare function intInRange(description: string, range?: IntRange): z.ZodType<number | undefined>;
15
+ export declare function numberInRange(description: string, range: {
16
+ min: number;
17
+ max: number;
18
+ }): z.ZodType<number | undefined>;
19
+ export declare function flag(description: string): z.ZodType<boolean | undefined>;
20
+ export declare function oneOf<T extends string>(description: string, values: readonly T[], fallback: T): z.ZodType<T>;
21
+ export declare function toInputSchema(schema: z.ZodObject): Record<string, unknown>;
22
+ export type ArgFailure = {
23
+ kind: 'missing-path';
24
+ arg: string;
25
+ pathKind: PathKind;
26
+ } | {
27
+ kind: 'invalid';
28
+ text: string;
29
+ };
30
+ export type ParsedArgs<T> = {
31
+ ok: true;
32
+ args: T;
33
+ } | {
34
+ ok: false;
35
+ failure: ArgFailure;
36
+ };
37
+ export declare function parseToolArgs<S extends z.ZodObject>(schema: S, raw: Record<string, unknown>): ParsedArgs<z.output<S>>;
38
+ export {};
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requiredText = requiredText;
4
+ exports.optionalText = optionalText;
5
+ exports.pathArg = pathArg;
6
+ exports.optionalPathArg = optionalPathArg;
7
+ exports.intInRange = intInRange;
8
+ exports.numberInRange = numberInRange;
9
+ exports.flag = flag;
10
+ exports.oneOf = oneOf;
11
+ exports.toInputSchema = toInputSchema;
12
+ exports.parseToolArgs = parseToolArgs;
13
+ const zod_1 = require("zod");
14
+ const requiredPaths = zod_1.z.registry();
15
+ const isBlank = (value) => value == null || (typeof value === 'string' && !value.trim());
16
+ const blankToUndefined = (value) => (isBlank(value) ? undefined : value);
17
+ const emptyPathToUndefined = (value) => (value === '' ? undefined : value ?? undefined);
18
+ const readNumber = (value) => {
19
+ const present = blankToUndefined(value);
20
+ return typeof present === 'string' ? Number(present) : present;
21
+ };
22
+ const readFlag = (value) => {
23
+ const present = blankToUndefined(value);
24
+ if (present === 'true')
25
+ return true;
26
+ if (present === 'false')
27
+ return false;
28
+ return present;
29
+ };
30
+ const clamp = (value, min = -Infinity, max = Infinity) => Math.min(Math.max(min, value), max);
31
+ function described(schema, description) {
32
+ return description === undefined ? schema : schema.describe(description);
33
+ }
34
+ function requiredText(description) {
35
+ return described(zod_1.z.preprocess(blankToUndefined, zod_1.z.string()), description);
36
+ }
37
+ function optionalText(description) {
38
+ return described(zod_1.z.preprocess(blankToUndefined, zod_1.z.string().optional()), description);
39
+ }
40
+ function pathArg(description, kind = 'file') {
41
+ const schema = zod_1.z.preprocess(emptyPathToUndefined, zod_1.z.string()).describe(description);
42
+ requiredPaths.add(schema, { pathKind: kind });
43
+ return schema;
44
+ }
45
+ function optionalPathArg(description) {
46
+ return zod_1.z.preprocess(emptyPathToUndefined, zod_1.z.string().optional()).describe(description);
47
+ }
48
+ function intInRange(description, range = {}) {
49
+ const { min, max, fallback } = range;
50
+ const inRange = zod_1.z.number().optional().transform(value => {
51
+ const picked = value === undefined ? fallback : Math.trunc(value);
52
+ return picked === undefined ? undefined : clamp(picked, min, max);
53
+ });
54
+ return zod_1.z.preprocess(readNumber, inRange).describe(description);
55
+ }
56
+ function numberInRange(description, range) {
57
+ const inRange = zod_1.z.number().optional().transform(value => value === undefined ? undefined : clamp(value, range.min, range.max));
58
+ return zod_1.z.preprocess(readNumber, inRange).describe(description);
59
+ }
60
+ function flag(description) {
61
+ return zod_1.z.preprocess(readFlag, zod_1.z.boolean().optional()).describe(description);
62
+ }
63
+ function oneOf(description, values, fallback) {
64
+ const member = zod_1.z.enum(values).optional().transform(value => (value ?? fallback));
65
+ return zod_1.z.preprocess(blankToUndefined, member).describe(description);
66
+ }
67
+ function toInputSchema(schema) {
68
+ const { $schema: _, ...inputSchema } = zod_1.z.toJSONSchema(schema, { io: 'input' });
69
+ return inputSchema;
70
+ }
71
+ function expectation(issue) {
72
+ return issue.code === 'invalid_value'
73
+ ? `one of ${issue.values.join(', ')}`
74
+ : `a ${issue.expected}`;
75
+ }
76
+ function parseToolArgs(schema, raw) {
77
+ const parsed = schema.safeParse(raw);
78
+ if (parsed.success)
79
+ return { ok: true, args: parsed.data };
80
+ const lines = [];
81
+ for (const [arg, argSchema] of Object.entries(schema.shape)) {
82
+ const issue = parsed.error.issues.find(i => i.path[0] === arg);
83
+ if (!issue)
84
+ continue;
85
+ if (!isBlank(raw[arg])) {
86
+ lines.push(`Invalid ${arg}: expected ${expectation(issue)}`);
87
+ continue;
88
+ }
89
+ const path = requiredPaths.get(argSchema);
90
+ if (path)
91
+ return { ok: false, failure: { kind: 'missing-path', arg, pathKind: path.pathKind } };
92
+ lines.push(`Missing ${arg}`);
93
+ }
94
+ return { ok: false, failure: { kind: 'invalid', text: lines.join('\n') } };
95
+ }
@@ -1,9 +1 @@
1
- /**
2
- * Renders the RAG dashboard as a single self-contained HTML page (inline CSS +
3
- * JS), mirroring the approach in graph.ts. The page is schema-driven: it fetches
4
- * /api/schema (from buildJsonSchema — the same source as Step 1's editor support)
5
- * and /api/config, then renders a typed form. The Graph tab embeds the full
6
- * standalone graph page (GET /graph — same buildHtml as project-graph.html) in
7
- * an iframe rather than re-implementing the network here.
8
- */
9
1
  export declare function renderDashboardHtml(): string;
@@ -1,14 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.renderDashboardHtml = renderDashboardHtml;
4
- /**
5
- * Renders the RAG dashboard as a single self-contained HTML page (inline CSS +
6
- * JS), mirroring the approach in graph.ts. The page is schema-driven: it fetches
7
- * /api/schema (from buildJsonSchema — the same source as Step 1's editor support)
8
- * and /api/config, then renders a typed form. The Graph tab embeds the full
9
- * standalone graph page (GET /graph — same buildHtml as project-graph.html) in
10
- * an iframe rather than re-implementing the network here.
11
- */
12
4
  function renderDashboardHtml() {
13
5
  return `<!DOCTYPE html>
14
6
  <html lang="en">
@@ -168,7 +160,12 @@ function renderDashboardHtml() {
168
160
  if (spec.type === 'boolean') {
169
161
  const cb = document.createElement('input');
170
162
  cb.type = 'checkbox'; cb.dataset.key = key; cb.dataset.type = 'boolean';
171
- cb.checked = value === true;
163
+ cb.checked = isUnset ? def === true : value === true;
164
+ // An absent boolean can resolve from context (reranker.enabled), so it is saved only once changed.
165
+ if (isUnset) {
166
+ cb.dataset.unset = '1';
167
+ cb.addEventListener('change', () => { delete cb.dataset.unset; });
168
+ }
172
169
  return cb;
173
170
  }
174
171
  if (Array.isArray(enumVals)) return selectEl(key, enumVals, value, def);
@@ -236,7 +233,7 @@ function renderDashboardHtml() {
236
233
  document.querySelectorAll('[data-key]').forEach(el => {
237
234
  const key = el.dataset.key, type = el.dataset.type;
238
235
  let val;
239
- if (type === 'boolean') val = el.checked;
236
+ if (type === 'boolean') { if (el.dataset.unset) return; val = el.checked; }
240
237
  else if (el.value === '') return; // unset → omit (stay minimal)
241
238
  else if (type === 'number') { const n = Number(el.value); if (Number.isNaN(n)) return; val = n; }
242
239
  else val = el.value;
@@ -0,0 +1,15 @@
1
+ import type { ILogger } from '../interfaces';
2
+ export interface GrepRun {
3
+ ok: boolean;
4
+ output: string | null;
5
+ failure: string | null;
6
+ }
7
+ export declare class GrepRunner {
8
+ private logger;
9
+ private readonly liveGreps;
10
+ private readonly killLiveGreps;
11
+ constructor(logger: ILogger);
12
+ run(args: string[]): Promise<GrepRun>;
13
+ private trackGrep;
14
+ private untrackGrep;
15
+ }
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GrepRunner = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const fs_access_1 = require("./fs-access");
6
+ const GREP_TIMEOUT_MS = 60_000;
7
+ const FAILURE_MAX_CHARS = 200;
8
+ const STDERR_MAX_BYTES = 4096;
9
+ const capFailure = (text) => {
10
+ const capped = text.slice(0, FAILURE_MAX_CHARS);
11
+ return /[\uD800-\uDBFF]$/.test(capped) ? capped.slice(0, -1) : capped;
12
+ };
13
+ class GrepRunner {
14
+ logger;
15
+ liveGreps = new Set();
16
+ killLiveGreps = () => {
17
+ for (const proc of this.liveGreps)
18
+ proc.kill('SIGKILL');
19
+ };
20
+ constructor(logger) {
21
+ this.logger = logger;
22
+ }
23
+ run(args) {
24
+ return new Promise((resolve) => {
25
+ let proc;
26
+ try {
27
+ proc = (0, child_process_1.spawn)('grep', args, { stdio: ['ignore', 'pipe', 'pipe'] });
28
+ }
29
+ catch (err) {
30
+ this.logger.error('GrepRunner: grep spawn failed', { err });
31
+ resolve({ ok: false, output: null, failure: capFailure((0, fs_access_1.errorCode)(err)) });
32
+ return;
33
+ }
34
+ this.trackGrep(proc);
35
+ const chunks = [];
36
+ let totalBytes = 0;
37
+ const MAX_BUFFER = 10 * 1024 * 1024;
38
+ const printed = () => (chunks.length === 0 ? null : Buffer.concat(chunks).toString('utf-8'));
39
+ const stderrChunks = [];
40
+ let stderrBytes = 0;
41
+ const stderrLine = () => {
42
+ const text = Buffer.concat(stderrChunks).toString('utf-8');
43
+ const line = text.split('\n').map(l => l.trim()).find(l => l !== '');
44
+ return line ?? null;
45
+ };
46
+ const timer = setTimeout(() => {
47
+ this.logger.warn('GrepRunner: grep timed out', { ms: GREP_TIMEOUT_MS });
48
+ finish({ ok: false, output: printed(), failure: `timed out after ${GREP_TIMEOUT_MS / 1000} seconds` });
49
+ proc.kill('SIGKILL');
50
+ proc.stdout?.destroy();
51
+ proc.stderr?.destroy();
52
+ }, GREP_TIMEOUT_MS);
53
+ timer.unref();
54
+ let settled = false;
55
+ const finish = (result) => {
56
+ settled = true;
57
+ clearTimeout(timer);
58
+ this.untrackGrep(proc);
59
+ resolve(result);
60
+ };
61
+ proc.stdout?.on('data', (chunk) => {
62
+ totalBytes += chunk.length;
63
+ if (totalBytes <= MAX_BUFFER) {
64
+ chunks.push(chunk);
65
+ }
66
+ });
67
+ proc.stderr?.on('data', (chunk) => {
68
+ if (stderrBytes >= STDERR_MAX_BYTES)
69
+ return;
70
+ stderrChunks.push(chunk);
71
+ stderrBytes += chunk.length;
72
+ });
73
+ proc.on('error', (err) => {
74
+ if (settled)
75
+ return;
76
+ this.logger.error('GrepRunner: grep spawn failed', { err });
77
+ finish({ ok: false, output: null, failure: capFailure((0, fs_access_1.errorCode)(err)) });
78
+ });
79
+ proc.on('close', (code, signal) => {
80
+ if (settled)
81
+ return;
82
+ const output = printed();
83
+ if (code === 0 || code === 1) {
84
+ finish({ ok: true, output, failure: null });
85
+ return;
86
+ }
87
+ this.logger.warn('GrepRunner: grep exited with code', { code, signal });
88
+ const cause = stderrLine() ?? (code !== null ? `exit status ${code}` : `signal ${signal}`);
89
+ finish({ ok: false, output, failure: capFailure(cause) });
90
+ });
91
+ });
92
+ }
93
+ trackGrep(proc) {
94
+ if (this.liveGreps.size === 0)
95
+ process.on('exit', this.killLiveGreps);
96
+ this.liveGreps.add(proc);
97
+ }
98
+ untrackGrep(proc) {
99
+ this.liveGreps.delete(proc);
100
+ if (this.liveGreps.size === 0)
101
+ process.off('exit', this.killLiveGreps);
102
+ }
103
+ }
104
+ exports.GrepRunner = GrepRunner;
@@ -0,0 +1,22 @@
1
+ import type { Config } from '../config';
2
+ import type { IProjectDiscovery } from '../interfaces';
3
+ import type { IProjectRoots } from '../interfaces/IProjectRoots';
4
+ export declare class ProjectRoots implements IProjectRoots {
5
+ private discovery;
6
+ private config;
7
+ private rootMap?;
8
+ constructor(discovery: IProjectDiscovery, config: Config);
9
+ private projectRootMap;
10
+ entries(): IterableIterator<[string, string]>;
11
+ refresh(): void;
12
+ resolveProjectRoot(name: string): string;
13
+ toRel(absPath: string): string;
14
+ toAbs(relPath: string): string;
15
+ workspaceRoot(): string;
16
+ findProjectRootByName(name: string): string | null;
17
+ findProjectRoot(match: (rel: string) => boolean): {
18
+ name: string;
19
+ rel: string;
20
+ } | null;
21
+ fallbackRoot(relPath: string): string | null;
22
+ }
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ProjectRoots = void 0;
37
+ const path = __importStar(require("path"));
38
+ const MonorepoAwareDiscoveryService_1 = require("../services/MonorepoAwareDiscoveryService");
39
+ const path_helpers_1 = require("./path-helpers");
40
+ class ProjectRoots {
41
+ discovery;
42
+ config;
43
+ rootMap;
44
+ constructor(discovery, config) {
45
+ this.discovery = discovery;
46
+ this.config = config;
47
+ }
48
+ projectRootMap() {
49
+ if (!this.rootMap) {
50
+ this.rootMap = new Map((0, MonorepoAwareDiscoveryService_1.toLeafProjects)(this.discovery.discover(this.config.workspaceRoot)).map(p => [p.name, p.path]));
51
+ }
52
+ return this.rootMap;
53
+ }
54
+ entries() {
55
+ return this.projectRootMap().entries();
56
+ }
57
+ refresh() {
58
+ this.rootMap = undefined;
59
+ }
60
+ resolveProjectRoot(name) {
61
+ let root = this.projectRootMap().get(name);
62
+ if (root === undefined) {
63
+ this.rootMap = undefined;
64
+ root = this.projectRootMap().get(name);
65
+ }
66
+ return root ?? path.join(this.config.workspaceRoot, name);
67
+ }
68
+ toRel(absPath) {
69
+ return path.relative(this.config.workspaceRoot, absPath) || '.';
70
+ }
71
+ toAbs(relPath) {
72
+ return relPath === '.' ? this.workspaceRoot() : path.join(this.workspaceRoot(), relPath);
73
+ }
74
+ workspaceRoot() {
75
+ return (0, path_helpers_1.stripTrailingSlash)(path.posix.normalize(this.config.workspaceRoot));
76
+ }
77
+ findProjectRootByName(name) {
78
+ let root = this.projectRootMap().get(name);
79
+ if (root === undefined) {
80
+ this.rootMap = undefined;
81
+ root = this.projectRootMap().get(name);
82
+ }
83
+ return root === undefined ? null : this.toRel(root);
84
+ }
85
+ findProjectRoot(match) {
86
+ for (let attempt = 0; attempt < 2; attempt++) {
87
+ if (attempt === 1)
88
+ this.rootMap = undefined;
89
+ const best = [...this.projectRootMap().entries()]
90
+ .map(([name, abs]) => ({ name, rel: this.toRel(abs) }))
91
+ .filter(r => match(r.rel))
92
+ .sort((a, b) => b.rel.length - a.rel.length)[0];
93
+ if (best)
94
+ return best;
95
+ }
96
+ return null;
97
+ }
98
+ fallbackRoot(relPath) {
99
+ return this.findProjectRoot(r => (0, path_helpers_1.isWithin)(relPath, r))?.rel ?? null;
100
+ }
101
+ }
102
+ exports.ProjectRoots = ProjectRoots;