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.
- package/CHANGELOG.md +88 -5
- package/LICENSE +661 -21
- package/README.md +76 -40
- package/dist/app.js +17 -38
- package/dist/src/ast/CallExtractor.d.ts +8 -0
- package/dist/src/ast/CallExtractor.js +68 -0
- package/dist/src/ast/GraphqlNameExtractor.d.ts +22 -0
- package/dist/src/ast/GraphqlNameExtractor.js +240 -0
- package/dist/src/ast/ImportEdgeExtractor.d.ts +11 -0
- package/dist/src/ast/ImportEdgeExtractor.js +129 -0
- package/dist/src/ast/IndexedNodeResolver.d.ts +14 -0
- package/dist/src/ast/IndexedNodeResolver.js +217 -0
- package/dist/src/ast/MemberExtractor.d.ts +8 -0
- package/dist/src/ast/MemberExtractor.js +129 -0
- package/dist/src/ast/TopLevelSymbolExtractor.d.ts +5 -0
- package/dist/src/ast/TopLevelSymbolExtractor.js +86 -0
- package/dist/src/ast/graphql-grammar.d.ts +24 -0
- package/dist/src/ast/graphql-grammar.js +93 -0
- package/dist/src/ast/node-helpers.d.ts +11 -0
- package/dist/src/ast/node-helpers.js +55 -0
- package/dist/src/chunking/AstChunker.d.ts +12 -0
- package/dist/src/chunking/AstChunker.js +30 -0
- package/dist/src/chunking/CharacterChunkStrategy.d.ts +8 -0
- package/dist/src/chunking/CharacterChunkStrategy.js +15 -0
- package/dist/src/chunking/DeclarationChunkStrategy.d.ts +15 -0
- package/dist/src/chunking/DeclarationChunkStrategy.js +87 -0
- package/dist/src/chunking/FragmentMerger.d.ts +11 -0
- package/dist/src/chunking/FragmentMerger.js +61 -0
- package/dist/src/chunking/ImportOnlyFilter.d.ts +5 -0
- package/dist/src/chunking/ImportOnlyFilter.js +14 -0
- package/dist/src/chunking/LangchainTextSplitter.d.ts +21 -0
- package/dist/src/chunking/LangchainTextSplitter.js +133 -0
- package/dist/src/chunking/MinSizeSplitPolicy.d.ts +9 -0
- package/dist/src/chunking/MinSizeSplitPolicy.js +18 -0
- package/dist/src/chunking/RunPacker.d.ts +12 -0
- package/dist/src/chunking/RunPacker.js +84 -0
- package/dist/src/chunking/create-chunker.d.ts +3 -0
- package/dist/src/chunking/create-chunker.js +15 -0
- package/dist/src/chunking/interfaces.d.ts +27 -0
- package/dist/src/commands/ConfigCommand.js +1 -9
- package/dist/src/commands/EvalCommand.d.ts +10 -5
- package/dist/src/commands/EvalCommand.js +60 -149
- package/dist/src/commands/IndexCommand.d.ts +10 -4
- package/dist/src/commands/IndexCommand.js +52 -146
- package/dist/src/commands/McpCommand.d.ts +6 -3
- package/dist/src/commands/McpCommand.js +19 -20
- package/dist/src/commands/WebCommand.d.ts +9 -3
- package/dist/src/commands/WebCommand.js +17 -11
- package/dist/src/commands/eval/baseline-comparison.d.ts +6 -0
- package/dist/src/commands/eval/baseline-comparison.js +54 -0
- package/dist/src/commands/eval/eval-args.d.ts +6 -0
- package/dist/src/commands/eval/eval-args.js +71 -0
- package/dist/src/commands/eval/eval-corpora.d.ts +6 -0
- package/dist/src/commands/eval/eval-corpora.js +76 -0
- package/dist/src/commands/eval/eval-metadata.d.ts +17 -0
- package/dist/src/commands/eval/eval-metadata.js +75 -0
- package/dist/src/commands/eval/index-inspector.d.ts +3 -0
- package/dist/src/commands/eval/index-inspector.js +21 -0
- package/dist/src/commands/eval/staged-search.d.ts +3 -0
- package/dist/src/commands/eval/staged-search.js +20 -0
- package/dist/src/commands/eval/suite-loader.d.ts +8 -0
- package/dist/src/commands/eval/suite-loader.js +52 -0
- package/dist/src/commands/index/backend-probe.d.ts +2 -0
- package/dist/src/commands/index/backend-probe.js +15 -0
- package/dist/src/commands/index/embedding-setup.d.ts +3 -0
- package/dist/src/commands/index/embedding-setup.js +16 -0
- package/dist/src/commands/index/index-summary.d.ts +2 -0
- package/dist/src/commands/index/index-summary.js +22 -0
- package/dist/src/commands/index/legacy-ollama-guard.d.ts +3 -0
- package/dist/src/commands/index/legacy-ollama-guard.js +23 -0
- package/dist/src/commands/index/prune-step.d.ts +3 -0
- package/dist/src/commands/index/prune-step.js +22 -0
- package/dist/src/commands/index/scan-targets.d.ts +8 -0
- package/dist/src/commands/index/scan-targets.js +107 -0
- package/dist/src/config-error.d.ts +0 -4
- package/dist/src/config-error.js +0 -4
- package/dist/src/config-store.d.ts +1 -55
- package/dist/src/config-store.js +11 -73
- package/dist/src/config.d.ts +9 -18
- package/dist/src/config.js +36 -35
- package/dist/src/constants.d.ts +17 -28
- package/dist/src/constants.js +35 -29
- package/dist/src/container.d.ts +10 -2
- package/dist/src/container.js +19 -8
- package/dist/src/db/drizzle-types.d.ts +7 -0
- package/dist/src/db/drizzle-types.js +2 -0
- package/dist/src/db/index.d.ts +1 -0
- package/dist/src/db/schema-steps.d.ts +8 -0
- package/dist/src/db/schema-steps.js +105 -0
- package/dist/src/db/schema.d.ts +17 -0
- package/dist/src/db/schema.js +1 -6
- package/dist/src/declarations/DeclarationTree.d.ts +19 -0
- package/dist/src/declarations/DeclarationTree.js +66 -0
- package/dist/src/declarations/DeclarationTreeBuilder.d.ts +22 -0
- package/dist/src/declarations/DeclarationTreeBuilder.js +179 -0
- package/dist/src/declarations/SourceLines.d.ts +37 -0
- package/dist/src/declarations/SourceLines.js +415 -0
- package/dist/src/dependency-traversal.d.ts +0 -6
- package/dist/src/dependency-traversal.js +0 -6
- package/dist/src/enriched-prompt.d.ts +0 -6
- package/dist/src/enriched-prompt.js +0 -6
- package/dist/src/error-record.d.ts +12 -0
- package/dist/src/error-record.js +248 -0
- package/dist/src/eval-corpus.d.ts +16 -0
- package/dist/src/eval-corpus.js +169 -0
- package/dist/src/eval-results.d.ts +6 -3
- package/dist/src/eval-results.js +323 -26
- package/dist/src/eval-vector-index.d.ts +5 -0
- package/dist/src/eval-vector-index.js +60 -0
- package/dist/src/file-utils.d.ts +0 -5
- package/dist/src/file-utils.js +0 -5
- package/dist/src/graph.d.ts +0 -25
- package/dist/src/graph.js +0 -28
- package/dist/src/help.js +9 -1
- package/dist/src/hnsw-settings.d.ts +3 -0
- package/dist/src/hnsw-settings.js +24 -0
- package/dist/src/index-args.d.ts +13 -0
- package/dist/src/index-args.js +48 -0
- package/dist/src/indexing/AnalysisBatcher.d.ts +12 -0
- package/dist/src/indexing/AnalysisBatcher.js +28 -0
- package/dist/src/indexing/ChunkEmbedder.d.ts +24 -0
- package/dist/src/indexing/ChunkEmbedder.js +37 -0
- package/dist/src/indexing/ConsoleScanReporter.d.ts +10 -0
- package/dist/src/indexing/ConsoleScanReporter.js +73 -0
- package/dist/src/indexing/EmbeddingSchemaPreparer.d.ts +14 -0
- package/dist/src/indexing/EmbeddingSchemaPreparer.js +66 -0
- package/dist/src/indexing/FileIngestor.d.ts +22 -0
- package/dist/src/indexing/FileIngestor.js +116 -0
- package/dist/src/indexing/IndexStore.d.ts +24 -0
- package/dist/src/indexing/IndexStore.js +69 -0
- package/dist/src/indexing/StaleFilePruner.d.ts +8 -0
- package/dist/src/indexing/StaleFilePruner.js +55 -0
- package/dist/src/indexing/analysis-rows.d.ts +4 -0
- package/dist/src/indexing/analysis-rows.js +65 -0
- package/dist/src/indexing/project-notices.d.ts +2 -0
- package/dist/src/indexing/project-notices.js +63 -0
- package/dist/src/interfaces/IAstParser.d.ts +4 -40
- package/dist/src/interfaces/ICallGraph.d.ts +28 -0
- package/dist/src/interfaces/ICallGraph.js +2 -0
- package/dist/src/interfaces/IChunkSearch.d.ts +42 -0
- package/dist/src/interfaces/IChunkSearch.js +2 -0
- package/dist/src/interfaces/IChunker.d.ts +3 -12
- package/dist/src/interfaces/ICorpusInspector.d.ts +7 -0
- package/dist/src/interfaces/ICorpusInspector.js +2 -0
- package/dist/src/interfaces/IDatabase.d.ts +8 -24
- package/dist/src/interfaces/IDependencyGraph.d.ts +24 -0
- package/dist/src/interfaces/IDependencyGraph.js +2 -0
- package/dist/src/interfaces/IEmbedder.d.ts +0 -9
- package/dist/src/interfaces/IIndexIdentityGuard.d.ts +3 -0
- package/dist/src/interfaces/IIndexIdentityGuard.js +2 -0
- package/dist/src/interfaces/IIndexedNodeResolver.d.ts +10 -0
- package/dist/src/interfaces/IIndexedNodeResolver.js +2 -0
- package/dist/src/interfaces/ILogger.d.ts +1 -11
- package/dist/src/interfaces/IMcpReadiness.d.ts +12 -0
- package/dist/src/interfaces/IMcpReadiness.js +2 -0
- package/dist/src/interfaces/IMcpToolHandler.d.ts +0 -5
- package/dist/src/interfaces/IMonorepoResolver.d.ts +0 -22
- package/dist/src/interfaces/IProjectCatalog.d.ts +13 -0
- package/dist/src/interfaces/IProjectCatalog.js +2 -0
- package/dist/src/interfaces/IProjectDiscovery.d.ts +0 -17
- package/dist/src/interfaces/IProjectRoots.d.ts +3 -0
- package/dist/src/interfaces/IProjectRoots.js +2 -0
- package/dist/src/interfaces/IRetrievalEvaluator.d.ts +153 -12
- package/dist/src/interfaces/IScanReporter.d.ts +13 -0
- package/dist/src/interfaces/IScanReporter.js +2 -0
- package/dist/src/interfaces/ISymbolLookup.d.ts +49 -0
- package/dist/src/interfaces/ISymbolLookup.js +2 -0
- package/dist/src/interfaces/IToolPaths.d.ts +62 -0
- package/dist/src/interfaces/IToolPaths.js +2 -0
- package/dist/src/interfaces/IWorkspaceFiles.d.ts +28 -0
- package/dist/src/interfaces/IWorkspaceFiles.js +2 -0
- package/dist/src/interfaces/SymbolKind.d.ts +1 -0
- package/dist/src/interfaces/SymbolKind.js +2 -0
- package/dist/src/interfaces/index.d.ts +12 -1
- package/dist/src/interrupt.js +0 -2
- package/dist/src/owner-path.d.ts +9 -10
- package/dist/src/owner-path.js +11 -23
- package/dist/src/project-scope.d.ts +1 -12
- package/dist/src/project-scope.js +5 -12
- package/dist/src/project-selector.d.ts +0 -5
- package/dist/src/project-selector.js +0 -11
- package/dist/src/retrieval-eval.d.ts +15 -6
- package/dist/src/retrieval-eval.js +388 -59
- package/dist/src/search/CallGraph.d.ts +9 -0
- package/dist/src/search/CallGraph.js +84 -0
- package/dist/src/search/ChunkSearch.d.ts +23 -0
- package/dist/src/search/ChunkSearch.js +115 -0
- package/dist/src/search/DependencyGraph.d.ts +19 -0
- package/dist/src/search/DependencyGraph.js +180 -0
- package/dist/src/search/IndexIdentityGuard.d.ts +11 -0
- package/dist/src/search/IndexIdentityGuard.js +37 -0
- package/dist/src/search/ProjectCatalog.d.ts +11 -0
- package/dist/src/search/ProjectCatalog.js +38 -0
- package/dist/src/search/SymbolLookup.d.ts +24 -0
- package/dist/src/search/SymbolLookup.js +97 -0
- package/dist/src/search/chunks/CandidateFetcher.d.ts +19 -0
- package/dist/src/search/chunks/CandidateFetcher.js +40 -0
- package/dist/src/search/chunks/IterativeScanGate.d.ts +10 -0
- package/dist/src/search/chunks/IterativeScanGate.js +42 -0
- package/dist/src/search/chunks/RerankStage.d.ts +15 -0
- package/dist/src/search/chunks/RerankStage.js +42 -0
- package/dist/src/search/chunks/search-metrics.d.ts +18 -0
- package/dist/src/search/chunks/search-metrics.js +32 -0
- package/dist/src/search/chunks/search-plan.d.ts +18 -0
- package/dist/src/search/chunks/search-plan.js +19 -0
- package/dist/src/search/create-search-services.d.ts +26 -0
- package/dist/src/search/create-search-services.js +29 -0
- package/dist/src/search/index-paths.d.ts +1 -0
- package/dist/src/search/index-paths.js +5 -0
- package/dist/src/search/result-shaping.d.ts +4 -0
- package/dist/src/search/result-shaping.js +19 -0
- package/dist/src/search/symbol-sql.d.ts +13 -0
- package/dist/src/search/symbol-sql.js +66 -0
- package/dist/src/search/symbols/SymbolGrepFallback.d.ts +19 -0
- package/dist/src/search/symbols/SymbolGrepFallback.js +106 -0
- package/dist/src/search/symbols/SymbolIndexQuery.d.ts +14 -0
- package/dist/src/search/symbols/SymbolIndexQuery.js +52 -0
- package/dist/src/search/symbols/SymbolTextSearch.d.ts +13 -0
- package/dist/src/search/symbols/SymbolTextSearch.js +84 -0
- package/dist/src/search/symbols/TargetColumnGate.d.ts +7 -0
- package/dist/src/search/symbols/TargetColumnGate.js +23 -0
- package/dist/src/search/symbols/find-symbol-constants.d.ts +4 -0
- package/dist/src/search/symbols/find-symbol-constants.js +8 -0
- package/dist/src/search/symbols/grep-args.d.ts +3 -0
- package/dist/src/search/symbols/grep-args.js +7 -0
- package/dist/src/search/symbols/grep-patterns.d.ts +4 -0
- package/dist/src/search/symbols/grep-patterns.js +60 -0
- package/dist/src/services/AstParserService.d.ts +10 -106
- package/dist/src/services/AstParserService.js +37 -1068
- package/dist/src/services/DatabaseService.d.ts +10 -17
- package/dist/src/services/DatabaseService.js +71 -115
- package/dist/src/services/EmbedderFactory.d.ts +0 -4
- package/dist/src/services/EmbedderFactory.js +0 -5
- package/dist/src/services/IndexerService.d.ts +7 -26
- package/dist/src/services/IndexerService.js +38 -286
- package/dist/src/services/InfinityEmbedder.d.ts +0 -21
- package/dist/src/services/InfinityEmbedder.js +0 -15
- package/dist/src/services/LoggerService.d.ts +7 -5
- package/dist/src/services/LoggerService.js +37 -41
- package/dist/src/services/McpReadiness.d.ts +18 -0
- package/dist/src/services/McpReadiness.js +73 -0
- package/dist/src/services/McpServer.d.ts +50 -19
- package/dist/src/services/McpServer.js +132 -62
- package/dist/src/services/MonorepoAwareDiscoveryService.d.ts +1 -45
- package/dist/src/services/MonorepoAwareDiscoveryService.js +1 -51
- package/dist/src/services/NxMonorepoResolver.d.ts +0 -29
- package/dist/src/services/NxMonorepoResolver.js +5 -56
- package/dist/src/services/OpenAICompatibleEmbedder.d.ts +0 -6
- package/dist/src/services/OpenAICompatibleEmbedder.js +0 -14
- package/dist/src/services/ProjectDiscoveryService.d.ts +0 -4
- package/dist/src/services/ProjectDiscoveryService.js +0 -4
- package/dist/src/services/VoyageEmbedder.d.ts +0 -6
- package/dist/src/services/VoyageEmbedder.js +0 -6
- package/dist/src/services/WebServerService.d.ts +5 -56
- package/dist/src/services/WebServerService.js +25 -63
- package/dist/src/services/http-retry.d.ts +0 -7
- package/dist/src/services/http-retry.js +1 -10
- package/dist/src/services/infinity-provisioning.d.ts +0 -74
- package/dist/src/services/infinity-provisioning.js +5 -88
- package/dist/src/services/legacy-ollama-index.d.ts +0 -16
- package/dist/src/services/legacy-ollama-index.js +0 -23
- package/dist/src/services/reranker.d.ts +0 -9
- package/dist/src/services/reranker.js +46 -12
- package/dist/src/setup.d.ts +24 -24
- package/dist/src/setup.js +205 -103
- package/dist/src/symbol-name.d.ts +1 -12
- package/dist/src/symbol-name.js +16 -25
- package/dist/src/symbol-rows.d.ts +0 -14
- package/dist/src/symbol-rows.js +0 -14
- package/dist/src/tool-call-log.d.ts +2 -0
- package/dist/src/tool-call-log.js +24 -0
- package/dist/src/tools/FindSymbolTool.d.ts +17 -7
- package/dist/src/tools/FindSymbolTool.js +54 -35
- package/dist/src/tools/GetCallersTool.d.ts +16 -8
- package/dist/src/tools/GetCallersTool.js +65 -35
- package/dist/src/tools/GetDependenciesTool.d.ts +16 -8
- package/dist/src/tools/GetDependenciesTool.js +36 -29
- package/dist/src/tools/GetDependentsTool.d.ts +20 -8
- package/dist/src/tools/GetDependentsTool.js +48 -34
- package/dist/src/tools/ListFilesTool.d.ts +16 -8
- package/dist/src/tools/ListFilesTool.js +20 -26
- package/dist/src/tools/ListProjectsTool.d.ts +11 -7
- package/dist/src/tools/ListProjectsTool.js +13 -11
- package/dist/src/tools/McpTool.d.ts +17 -0
- package/dist/src/tools/McpTool.js +28 -0
- package/dist/src/tools/ReadFileRangeTool.d.ts +16 -8
- package/dist/src/tools/ReadFileRangeTool.js +23 -25
- package/dist/src/tools/ReadFileTool.d.ts +15 -8
- package/dist/src/tools/ReadFileTool.js +19 -24
- package/dist/src/tools/SearchCodebaseTool.d.ts +22 -10
- package/dist/src/tools/SearchCodebaseTool.js +71 -50
- package/dist/src/tools/format-helpers.d.ts +9 -9
- package/dist/src/tools/format-helpers.js +146 -28
- package/dist/src/tools/tool-args.d.ts +38 -0
- package/dist/src/tools/tool-args.js +95 -0
- package/dist/src/web/dashboard.d.ts +0 -8
- package/dist/src/web/dashboard.js +7 -10
- package/dist/src/workspace/GrepRunner.d.ts +15 -0
- package/dist/src/workspace/GrepRunner.js +104 -0
- package/dist/src/workspace/ProjectRoots.d.ts +22 -0
- package/dist/src/workspace/ProjectRoots.js +102 -0
- package/dist/src/workspace/ToolPaths.d.ts +31 -0
- package/dist/src/workspace/ToolPaths.js +312 -0
- package/dist/src/workspace/WorkspaceFiles.d.ts +19 -0
- package/dist/src/workspace/WorkspaceFiles.js +285 -0
- package/dist/src/workspace/fs-access.d.ts +9 -0
- package/dist/src/workspace/fs-access.js +47 -0
- package/dist/src/workspace/path-helpers.d.ts +3 -0
- package/dist/src/workspace/path-helpers.js +43 -0
- package/package.json +5 -4
- package/dist/src/interfaces/ISearcher.d.ts +0 -35
- package/dist/src/services/AstChunker.d.ts +0 -42
- package/dist/src/services/AstChunker.js +0 -158
- package/dist/src/services/SearcherService.d.ts +0 -342
- package/dist/src/services/SearcherService.js +0 -1199
- package/docs/web-dashboard.md +0 -206
- /package/dist/src/{interfaces/ISearcher.js → chunking/interfaces.js} +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChunkSearch = void 0;
|
|
4
|
+
const result_shaping_1 = require("./result-shaping");
|
|
5
|
+
const search_plan_1 = require("./chunks/search-plan");
|
|
6
|
+
const IterativeScanGate_1 = require("./chunks/IterativeScanGate");
|
|
7
|
+
const CandidateFetcher_1 = require("./chunks/CandidateFetcher");
|
|
8
|
+
const RerankStage_1 = require("./chunks/RerankStage");
|
|
9
|
+
const search_metrics_1 = require("./chunks/search-metrics");
|
|
10
|
+
class ChunkSearch {
|
|
11
|
+
db;
|
|
12
|
+
embedder;
|
|
13
|
+
identityGuard;
|
|
14
|
+
config;
|
|
15
|
+
logger;
|
|
16
|
+
gate;
|
|
17
|
+
fetcher;
|
|
18
|
+
rerankStage;
|
|
19
|
+
constructor(db, embedder, identityGuard, config, logger) {
|
|
20
|
+
this.db = db;
|
|
21
|
+
this.embedder = embedder;
|
|
22
|
+
this.identityGuard = identityGuard;
|
|
23
|
+
this.config = config;
|
|
24
|
+
this.logger = logger;
|
|
25
|
+
this.gate = new IterativeScanGate_1.IterativeScanGate(db, logger);
|
|
26
|
+
this.fetcher = new CandidateFetcher_1.CandidateFetcher(db, this.gate);
|
|
27
|
+
this.rerankStage = new RerankStage_1.RerankStage(embedder, logger);
|
|
28
|
+
}
|
|
29
|
+
async prepareQuery(raw) {
|
|
30
|
+
return { query: raw, translated: false };
|
|
31
|
+
}
|
|
32
|
+
async searchChunks(query, limit, project, threshold, rerankOverride, perFile = result_shaping_1.DEFAULT_PER_FILE) {
|
|
33
|
+
const { stages } = await this.searchChunksWithStages(query, limit, project, threshold, rerankOverride, perFile);
|
|
34
|
+
return stages.reranked ?? stages.vector;
|
|
35
|
+
}
|
|
36
|
+
async searchChunksWithStages(query, limit, project, threshold, rerankOverride, perFile = result_shaping_1.DEFAULT_PER_FILE) {
|
|
37
|
+
const t0 = Date.now();
|
|
38
|
+
await this.identityGuard.assertIndexMatches();
|
|
39
|
+
const plan = (0, search_plan_1.planSearch)({ limit, perFile, threshold, rerankOverride, rerankAvailable: !!this.embedder.rerank }, this.config);
|
|
40
|
+
this.logger.debug('ChunkSearch: searchChunks', {
|
|
41
|
+
query: query.slice(0, 120), limit, fetchLimit: plan.fetchLimit, project, threshold: plan.threshold.value,
|
|
42
|
+
});
|
|
43
|
+
const tEmbed0 = Date.now();
|
|
44
|
+
const embedding = await this.embedder.embed(query, 'query');
|
|
45
|
+
const embedMs = Date.now() - tEmbed0;
|
|
46
|
+
const pool = await this.fetcher.fetch(embedding, plan, project);
|
|
47
|
+
this.logger.debug('ChunkSearch: searchChunks candidates', {
|
|
48
|
+
count: pool.candidates.length,
|
|
49
|
+
scores: pool.candidates.map(r => r.score),
|
|
50
|
+
files: pool.candidates.map(r => r.filePath),
|
|
51
|
+
ms: Date.now() - t0,
|
|
52
|
+
});
|
|
53
|
+
const vector = (0, result_shaping_1.limitPerFile)(pool.candidates, limit, perFile);
|
|
54
|
+
const rerank = plan.reranking ? await this.rerankStage.run(query, pool.candidates, vector, plan, t0) : undefined;
|
|
55
|
+
this.logger.info('search metrics', (0, search_metrics_1.searchMetrics)(query, {
|
|
56
|
+
fetchLimit: plan.fetchLimit, candidates: pool.candidates, results: rerank?.reranked ?? vector, poolSaturated: pool.poolSaturated, indexParams: pool.indexParams, threshold: plan.threshold,
|
|
57
|
+
embedMs, dbMs: pool.dbMs, rerankMs: rerank?.rerankMs ?? 0, totalMs: Date.now() - t0,
|
|
58
|
+
}));
|
|
59
|
+
return {
|
|
60
|
+
pool: pool.candidates,
|
|
61
|
+
stages: rerank ? { vector, reranked: rerank.reranked } : { vector },
|
|
62
|
+
rerankFailed: rerank?.rerankFailed ?? false,
|
|
63
|
+
fetchLimit: plan.fetchLimit,
|
|
64
|
+
indexParams: pool.indexParams,
|
|
65
|
+
threshold: plan.threshold,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async fetchNeighbors(results) {
|
|
69
|
+
const t0 = Date.now();
|
|
70
|
+
if (results.length === 0)
|
|
71
|
+
return [];
|
|
72
|
+
this.logger.debug('ChunkSearch: fetchNeighbors', { count: results.length });
|
|
73
|
+
const values = results.map((_, i) => `(${i}, $${i * 2 + 1}, $${i * 2 + 2}::int)`).join(',');
|
|
74
|
+
const params = results.flatMap(r => [r.filePath, r.startLine]);
|
|
75
|
+
const rows = await this.db.query(`SELECT r.idx,
|
|
76
|
+
prev."serviceName" AS prev_sn, prev."filePath" AS prev_fp, prev."startLine" AS prev_sl, prev.content AS prev_c, prev."ownerPath" AS prev_op,
|
|
77
|
+
next."serviceName" AS next_sn, next."filePath" AS next_fp, next."startLine" AS next_sl, next.content AS next_c, next."ownerPath" AS next_op
|
|
78
|
+
FROM (VALUES ${values}) r(idx, fp, sl)
|
|
79
|
+
LEFT JOIN LATERAL (
|
|
80
|
+
SELECT "serviceName", "filePath", "startLine", content, "ownerPath"
|
|
81
|
+
FROM code_chunk WHERE "filePath" = r.fp AND "startLine" < r.sl
|
|
82
|
+
ORDER BY "startLine" DESC LIMIT 1
|
|
83
|
+
) prev ON true
|
|
84
|
+
LEFT JOIN LATERAL (
|
|
85
|
+
SELECT "serviceName", "filePath", "startLine", content, "ownerPath"
|
|
86
|
+
FROM code_chunk WHERE "filePath" = r.fp AND "startLine" > r.sl
|
|
87
|
+
ORDER BY "startLine" ASC LIMIT 1
|
|
88
|
+
) next ON true
|
|
89
|
+
ORDER BY r.idx`, params);
|
|
90
|
+
const neighbors = rows.map((row, i) => ({
|
|
91
|
+
result: results[i],
|
|
92
|
+
prevChunk: row.prev_fp ? { serviceName: row.prev_sn, filePath: row.prev_fp, startLine: row.prev_sl, content: row.prev_c, ownerPath: row.prev_op ?? null } : null,
|
|
93
|
+
nextChunk: row.next_fp ? { serviceName: row.next_sn, filePath: row.next_fp, startLine: row.next_sl, content: row.next_c, ownerPath: row.next_op ?? null } : null,
|
|
94
|
+
}));
|
|
95
|
+
this.logger.debug('ChunkSearch: fetchNeighbors result', {
|
|
96
|
+
withPrev: neighbors.filter(n => n.prevChunk).length,
|
|
97
|
+
withNext: neighbors.filter(n => n.nextChunk).length,
|
|
98
|
+
ms: Date.now() - t0,
|
|
99
|
+
});
|
|
100
|
+
return neighbors;
|
|
101
|
+
}
|
|
102
|
+
async explainNoResults(project) {
|
|
103
|
+
try {
|
|
104
|
+
const rows = await this.db.query(project
|
|
105
|
+
? `SELECT EXISTS (SELECT 1 FROM code_chunk WHERE "serviceName" = $1) AS present`
|
|
106
|
+
: `SELECT EXISTS (SELECT 1 FROM code_chunk) AS present`, project ? [project] : []);
|
|
107
|
+
return rows[0]?.present ? 'no-candidates' : 'empty-scope';
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
this.logger.warn('ChunkSearch: explainNoResults lookup failed', { err, project });
|
|
111
|
+
return 'lookup-failed';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.ChunkSearch = ChunkSearch;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Config } from '../config';
|
|
2
|
+
import type { IDatabase, ILogger } from '../interfaces';
|
|
3
|
+
import type { DependencyRow, GraphContext, IDependencyGraph } from '../interfaces/IDependencyGraph';
|
|
4
|
+
import type { SearchResult } from '../interfaces/IChunkSearch';
|
|
5
|
+
import type { ProjectRoots } from '../workspace/ProjectRoots';
|
|
6
|
+
export declare class DependencyGraph implements IDependencyGraph {
|
|
7
|
+
private db;
|
|
8
|
+
private roots;
|
|
9
|
+
private config;
|
|
10
|
+
private logger;
|
|
11
|
+
constructor(db: IDatabase, roots: ProjectRoots, config: Config, logger: ILogger);
|
|
12
|
+
getProjectEdges(): Promise<{
|
|
13
|
+
from: string;
|
|
14
|
+
to: string;
|
|
15
|
+
}[]>;
|
|
16
|
+
fetchGraphContext(results: SearchResult[]): Promise<Map<string, GraphContext>>;
|
|
17
|
+
getDependencies(filePath: string, symbol?: string | null, transitive?: boolean): Promise<DependencyRow[]>;
|
|
18
|
+
getDependents(filePath: string, symbol?: string | null, transitive?: boolean): Promise<DependencyRow[]>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
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.DependencyGraph = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const dependency_traversal_1 = require("../dependency-traversal");
|
|
39
|
+
const index_paths_1 = require("./index-paths");
|
|
40
|
+
class DependencyGraph {
|
|
41
|
+
db;
|
|
42
|
+
roots;
|
|
43
|
+
config;
|
|
44
|
+
logger;
|
|
45
|
+
constructor(db, roots, config, logger) {
|
|
46
|
+
this.db = db;
|
|
47
|
+
this.roots = roots;
|
|
48
|
+
this.config = config;
|
|
49
|
+
this.logger = logger;
|
|
50
|
+
}
|
|
51
|
+
async getProjectEdges() {
|
|
52
|
+
const rows = await this.db.query(`SELECT DISTINCT project, "toFile" FROM code_dependency`);
|
|
53
|
+
const byRelPath = [...this.roots.entries()]
|
|
54
|
+
.map(([name, abs]) => ({ name, rel: path.relative(this.config.workspaceRoot, abs) }))
|
|
55
|
+
.sort((a, b) => b.rel.length - a.rel.length);
|
|
56
|
+
const ownerOf = (toFile) => {
|
|
57
|
+
for (const { name, rel } of byRelPath) {
|
|
58
|
+
if (toFile === rel || toFile.startsWith(rel + path.sep) || toFile.startsWith(rel + '/'))
|
|
59
|
+
return name;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
};
|
|
63
|
+
const seen = new Set();
|
|
64
|
+
const edges = [];
|
|
65
|
+
for (const { project, toFile } of rows) {
|
|
66
|
+
const to = ownerOf(toFile);
|
|
67
|
+
if (!to || to === project)
|
|
68
|
+
continue;
|
|
69
|
+
const key = project + ' ' + to;
|
|
70
|
+
if (seen.has(key))
|
|
71
|
+
continue;
|
|
72
|
+
seen.add(key);
|
|
73
|
+
edges.push({ from: project, to });
|
|
74
|
+
}
|
|
75
|
+
return edges;
|
|
76
|
+
}
|
|
77
|
+
async fetchGraphContext(results) {
|
|
78
|
+
const t0 = Date.now();
|
|
79
|
+
const files = [...new Set(results.map(r => r.filePath))];
|
|
80
|
+
this.logger.debug('DependencyGraph: fetchGraphContext', { files: files.length });
|
|
81
|
+
if (files.length === 0)
|
|
82
|
+
return new Map();
|
|
83
|
+
const proportionalLimit = Math.max(2000, files.length * 100);
|
|
84
|
+
const values = files.map((_, i) => `($${i + 1}::text)`).join(', ');
|
|
85
|
+
const rows = await this.db.query(`SELECT r.fp AS "filePath", 'import' AS direction, d."toFile" AS related
|
|
86
|
+
FROM (VALUES ${values}) AS r(fp)
|
|
87
|
+
JOIN code_dependency d ON d."fromFile" = r.fp
|
|
88
|
+
WHERE NOT ${(0, index_paths_1.OUTSIDE_WORKSPACE_VALUE)('d."toFile"')}
|
|
89
|
+
|
|
90
|
+
UNION ALL
|
|
91
|
+
|
|
92
|
+
SELECT r.fp AS "filePath", 'usedby' AS direction, d."fromFile" AS related
|
|
93
|
+
FROM (VALUES ${values}) AS r(fp)
|
|
94
|
+
JOIN code_dependency d ON d."toFile" = r.fp
|
|
95
|
+
WHERE NOT ${(0, index_paths_1.OUTSIDE_WORKSPACE_VALUE)('d."fromFile"')}
|
|
96
|
+
|
|
97
|
+
LIMIT ${proportionalLimit}`, files);
|
|
98
|
+
const ctx = new Map();
|
|
99
|
+
for (const filePath of files)
|
|
100
|
+
ctx.set(filePath, { imports: new Set(), usedBy: new Set() });
|
|
101
|
+
for (const row of rows) {
|
|
102
|
+
const g = ctx.get(row.filePath);
|
|
103
|
+
if (row.direction === 'import')
|
|
104
|
+
g.imports.add(row.related);
|
|
105
|
+
else
|
|
106
|
+
g.usedBy.add(row.related);
|
|
107
|
+
}
|
|
108
|
+
this.logger.debug('DependencyGraph: fetchGraphContext result', { files: files.length, rows: rows.length, ms: Date.now() - t0 });
|
|
109
|
+
const result = new Map();
|
|
110
|
+
for (const [fp, g] of ctx)
|
|
111
|
+
result.set(fp, {
|
|
112
|
+
imports: [...g.imports].slice(0, 50),
|
|
113
|
+
usedBy: [...g.usedBy].slice(0, 50),
|
|
114
|
+
});
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
async getDependencies(filePath, symbol = null, transitive = false) {
|
|
118
|
+
const t0 = Date.now();
|
|
119
|
+
this.logger.debug('DependencyGraph: getDependencies', { filePath, symbol, transitive });
|
|
120
|
+
const params = [filePath];
|
|
121
|
+
let symbolFilter = '';
|
|
122
|
+
if (symbol) {
|
|
123
|
+
params.push(symbol);
|
|
124
|
+
symbolFilter = `AND "toSymbol" = $${params.length}`;
|
|
125
|
+
}
|
|
126
|
+
const direct = await this.db.query(`SELECT "fromFile", "fromSymbol", "toFile", "toSymbol", "depType", min("id"::text) AS "id"
|
|
127
|
+
FROM code_dependency
|
|
128
|
+
WHERE "fromFile" = $1 AND NOT ${(0, index_paths_1.OUTSIDE_WORKSPACE_VALUE)('"toFile"')}
|
|
129
|
+
${symbolFilter}
|
|
130
|
+
GROUP BY "fromFile", "fromSymbol", "toFile", "toSymbol", "depType"
|
|
131
|
+
ORDER BY "toFile", min("id"::text)`, params);
|
|
132
|
+
if (!transitive) {
|
|
133
|
+
this.logger.debug('DependencyGraph: getDependencies result', { direct: direct.length, ms: Date.now() - t0 });
|
|
134
|
+
return direct;
|
|
135
|
+
}
|
|
136
|
+
const neighbours = async (frontier) => {
|
|
137
|
+
const rows = await this.db.query(`SELECT DISTINCT "fromFile", "toFile" FROM code_dependency
|
|
138
|
+
WHERE "fromFile" = ANY($1::text[]) AND NOT ${(0, index_paths_1.OUTSIDE_WORKSPACE_VALUE)('"toFile"')}`, [frontier]);
|
|
139
|
+
return rows.map(r => ({ from: r.fromFile, to: r.toFile }));
|
|
140
|
+
};
|
|
141
|
+
const indirect = (await (0, dependency_traversal_1.traverse)(filePath, neighbours)).map(r => ({
|
|
142
|
+
toFile: r.file, depth: r.depth, via: r.via,
|
|
143
|
+
fromFile: null, fromSymbol: null, toSymbol: null, depType: null,
|
|
144
|
+
}));
|
|
145
|
+
this.logger.debug('DependencyGraph: getDependencies result', { direct: direct.length, indirect: indirect.length, ms: Date.now() - t0 });
|
|
146
|
+
return [...direct, ...indirect];
|
|
147
|
+
}
|
|
148
|
+
async getDependents(filePath, symbol = null, transitive = false) {
|
|
149
|
+
const t0 = Date.now();
|
|
150
|
+
this.logger.debug('DependencyGraph: getDependents', { filePath, symbol, transitive });
|
|
151
|
+
const params = [filePath];
|
|
152
|
+
let symbolFilter = '';
|
|
153
|
+
if (symbol) {
|
|
154
|
+
params.push(symbol);
|
|
155
|
+
symbolFilter = `AND "toSymbol" = $${params.length}`;
|
|
156
|
+
}
|
|
157
|
+
const direct = await this.db.query(`SELECT "fromFile", "fromSymbol", "toFile", "toSymbol", "depType", min("id"::text) AS "id"
|
|
158
|
+
FROM code_dependency
|
|
159
|
+
WHERE "toFile" = $1 AND NOT ${(0, index_paths_1.OUTSIDE_WORKSPACE_VALUE)('"fromFile"')}
|
|
160
|
+
${symbolFilter}
|
|
161
|
+
GROUP BY "fromFile", "fromSymbol", "toFile", "toSymbol", "depType"
|
|
162
|
+
ORDER BY "fromFile", min("id"::text)`, params);
|
|
163
|
+
if (!transitive) {
|
|
164
|
+
this.logger.debug('DependencyGraph: getDependents result', { direct: direct.length, ms: Date.now() - t0 });
|
|
165
|
+
return direct;
|
|
166
|
+
}
|
|
167
|
+
const neighbours = async (frontier) => {
|
|
168
|
+
const rows = await this.db.query(`SELECT DISTINCT "fromFile", "toFile" FROM code_dependency
|
|
169
|
+
WHERE "toFile" = ANY($1::text[]) AND NOT ${(0, index_paths_1.OUTSIDE_WORKSPACE_VALUE)('"fromFile"')}`, [frontier]);
|
|
170
|
+
return rows.map(r => ({ from: r.toFile, to: r.fromFile }));
|
|
171
|
+
};
|
|
172
|
+
const indirect = (await (0, dependency_traversal_1.traverse)(filePath, neighbours)).map(r => ({
|
|
173
|
+
fromFile: r.file, depth: r.depth, via: r.via,
|
|
174
|
+
toFile: null, fromSymbol: null, toSymbol: null, depType: null,
|
|
175
|
+
}));
|
|
176
|
+
this.logger.debug('DependencyGraph: getDependents result', { direct: direct.length, indirect: indirect.length, ms: Date.now() - t0 });
|
|
177
|
+
return [...direct, ...indirect];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.DependencyGraph = DependencyGraph;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Config } from '../config';
|
|
2
|
+
import type { IDatabase, IEmbedder } from '../interfaces';
|
|
3
|
+
import type { IIndexIdentityGuard } from '../interfaces/IIndexIdentityGuard';
|
|
4
|
+
export declare class IndexIdentityGuard implements IIndexIdentityGuard {
|
|
5
|
+
private db;
|
|
6
|
+
private embedder;
|
|
7
|
+
private config;
|
|
8
|
+
constructor(db: IDatabase, embedder: IEmbedder, config: Config);
|
|
9
|
+
assertIndexMatches(): Promise<void>;
|
|
10
|
+
private compareIndexed;
|
|
11
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IndexIdentityGuard = void 0;
|
|
4
|
+
const legacy_ollama_index_1 = require("../services/legacy-ollama-index");
|
|
5
|
+
class IndexIdentityGuard {
|
|
6
|
+
db;
|
|
7
|
+
embedder;
|
|
8
|
+
config;
|
|
9
|
+
constructor(db, embedder, config) {
|
|
10
|
+
this.db = db;
|
|
11
|
+
this.embedder = embedder;
|
|
12
|
+
this.config = config;
|
|
13
|
+
}
|
|
14
|
+
async assertIndexMatches() {
|
|
15
|
+
const meta = await this.db.readIndexMeta();
|
|
16
|
+
if (meta) {
|
|
17
|
+
this.compareIndexed(meta.provider, meta.model, meta.dimensions);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (await (0, legacy_ollama_index_1.hasIndexedChunks)(this.db)) {
|
|
21
|
+
this.compareIndexed(legacy_ollama_index_1.LEGACY_OLLAMA_IDENTITY.provider, legacy_ollama_index_1.LEGACY_OLLAMA_IDENTITY.model, null);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
compareIndexed(indexedProvider, indexedModel, indexedDimensions) {
|
|
25
|
+
const { provider, model } = this.config.embedding;
|
|
26
|
+
if (indexedProvider !== provider || indexedModel !== model) {
|
|
27
|
+
throw new Error(`Index was built with ${indexedProvider}/${indexedModel} but the config selects ${provider}/${model}. ` +
|
|
28
|
+
`Run \`rag-index --reindex\` to rebuild the index for the new model.`);
|
|
29
|
+
}
|
|
30
|
+
const dim = this.embedder.dimensions;
|
|
31
|
+
if (indexedDimensions != null && dim > 0 && dim !== indexedDimensions) {
|
|
32
|
+
throw new Error(`Index was built at ${indexedDimensions} dimensions but ${provider}/${model} now resolves to ${dim}. ` +
|
|
33
|
+
`Run \`rag-index --reindex\` to rebuild the index at the new dimension.`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.IndexIdentityGuard = IndexIdentityGuard;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IDatabase } from '../interfaces';
|
|
2
|
+
import type { IProjectCatalog, ProjectRow } from '../interfaces/IProjectCatalog';
|
|
3
|
+
import { type WorkspaceFs } from '../workspace/fs-access';
|
|
4
|
+
import type { ProjectRoots } from '../workspace/ProjectRoots';
|
|
5
|
+
export declare class ProjectCatalog implements IProjectCatalog {
|
|
6
|
+
private db;
|
|
7
|
+
private roots;
|
|
8
|
+
private fs;
|
|
9
|
+
constructor(db: IDatabase, roots: ProjectRoots, fs: WorkspaceFs);
|
|
10
|
+
listProjects(): Promise<ProjectRow[]>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProjectCatalog = void 0;
|
|
4
|
+
const file_utils_1 = require("../file-utils");
|
|
5
|
+
const fs_access_1 = require("../workspace/fs-access");
|
|
6
|
+
const EMPTY_META = { description: null, stack: null, notes: null, relations: null };
|
|
7
|
+
class ProjectCatalog {
|
|
8
|
+
db;
|
|
9
|
+
roots;
|
|
10
|
+
fs;
|
|
11
|
+
constructor(db, roots, fs) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
this.roots = roots;
|
|
14
|
+
this.fs = fs;
|
|
15
|
+
}
|
|
16
|
+
async listProjects() {
|
|
17
|
+
const rows = await this.db.query(`SELECT "serviceName", COUNT(*)::int AS chunks
|
|
18
|
+
FROM code_chunk
|
|
19
|
+
GROUP BY "serviceName"
|
|
20
|
+
ORDER BY "serviceName"`);
|
|
21
|
+
return Promise.all(rows.map(async (r) => {
|
|
22
|
+
const projectRoot = this.roots.resolveProjectRoot(r.serviceName);
|
|
23
|
+
const meta = (0, file_utils_1.readRagMeta)(projectRoot);
|
|
24
|
+
let rootError = null;
|
|
25
|
+
try {
|
|
26
|
+
await this.fs.stat(projectRoot);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
rootError = (0, fs_access_1.errorCode)(err);
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
...r, path: projectRoot, relPath: this.roots.toRel(projectRoot), rootError,
|
|
33
|
+
...(typeof meta === 'object' ? meta : EMPTY_META),
|
|
34
|
+
};
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.ProjectCatalog = ProjectCatalog;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Config } from '../config';
|
|
2
|
+
import type { IDatabase, ILogger } from '../interfaces';
|
|
3
|
+
import type { FindSymbolResult, GrepSymbolResult, ISymbolLookup, SymbolKind } from '../interfaces/ISymbolLookup';
|
|
4
|
+
import type { GrepRunner } from '../workspace/GrepRunner';
|
|
5
|
+
import type { ProjectRoots } from '../workspace/ProjectRoots';
|
|
6
|
+
import type { ToolPaths } from '../workspace/ToolPaths';
|
|
7
|
+
export declare class SymbolLookup implements ISymbolLookup {
|
|
8
|
+
private db;
|
|
9
|
+
private grep;
|
|
10
|
+
private roots;
|
|
11
|
+
private paths;
|
|
12
|
+
private config;
|
|
13
|
+
private logger;
|
|
14
|
+
private readonly textSearch;
|
|
15
|
+
private readonly gate;
|
|
16
|
+
private readonly indexQuery;
|
|
17
|
+
private readonly grepFallback;
|
|
18
|
+
constructor(db: IDatabase, grep: GrepRunner, roots: ProjectRoots, paths: ToolPaths, config: Config, logger: ILogger);
|
|
19
|
+
grepSymbol(symbol: string, rootDir: string, excludeFile: string): Promise<GrepSymbolResult>;
|
|
20
|
+
findSymbol(name: string, project: string | null, kind: SymbolKind): Promise<FindSymbolResult>;
|
|
21
|
+
private findSymbolFromIndex;
|
|
22
|
+
private indexedElsewhere;
|
|
23
|
+
private similarOrNone;
|
|
24
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SymbolLookup = void 0;
|
|
4
|
+
const symbol_name_1 = require("../symbol-name");
|
|
5
|
+
const symbol_sql_1 = require("./symbol-sql");
|
|
6
|
+
const find_symbol_constants_1 = require("./symbols/find-symbol-constants");
|
|
7
|
+
const SymbolGrepFallback_1 = require("./symbols/SymbolGrepFallback");
|
|
8
|
+
const SymbolIndexQuery_1 = require("./symbols/SymbolIndexQuery");
|
|
9
|
+
const SymbolTextSearch_1 = require("./symbols/SymbolTextSearch");
|
|
10
|
+
const TargetColumnGate_1 = require("./symbols/TargetColumnGate");
|
|
11
|
+
const NO_SIMILAR = { names: [], truncated: false };
|
|
12
|
+
class SymbolLookup {
|
|
13
|
+
db;
|
|
14
|
+
grep;
|
|
15
|
+
roots;
|
|
16
|
+
paths;
|
|
17
|
+
config;
|
|
18
|
+
logger;
|
|
19
|
+
textSearch;
|
|
20
|
+
gate;
|
|
21
|
+
indexQuery;
|
|
22
|
+
grepFallback;
|
|
23
|
+
constructor(db, grep, roots, paths, config, logger) {
|
|
24
|
+
this.db = db;
|
|
25
|
+
this.grep = grep;
|
|
26
|
+
this.roots = roots;
|
|
27
|
+
this.paths = paths;
|
|
28
|
+
this.config = config;
|
|
29
|
+
this.logger = logger;
|
|
30
|
+
this.textSearch = new SymbolTextSearch_1.SymbolTextSearch(grep, roots, config, logger);
|
|
31
|
+
this.gate = new TargetColumnGate_1.TargetColumnGate(db);
|
|
32
|
+
this.indexQuery = new SymbolIndexQuery_1.SymbolIndexQuery(db, this.gate);
|
|
33
|
+
this.grepFallback = new SymbolGrepFallback_1.SymbolGrepFallback(grep, paths, config, logger);
|
|
34
|
+
}
|
|
35
|
+
grepSymbol(symbol, rootDir, excludeFile) {
|
|
36
|
+
return this.textSearch.search(symbol, rootDir, excludeFile);
|
|
37
|
+
}
|
|
38
|
+
findSymbol(name, project, kind) {
|
|
39
|
+
const parsed = (0, symbol_name_1.parseFindSymbolName)(name);
|
|
40
|
+
if (!parsed)
|
|
41
|
+
throw new Error('Invalid symbol name');
|
|
42
|
+
return this.findSymbolFromIndex(parsed, project, kind);
|
|
43
|
+
}
|
|
44
|
+
async findSymbolFromIndex(parsed, project, kind) {
|
|
45
|
+
const t0 = Date.now();
|
|
46
|
+
this.logger.debug('SymbolLookup: findSymbol', { parsed, project, kind, source: 'index' });
|
|
47
|
+
const isGraphqlKind = find_symbol_constants_1.GRAPHQL_KINDS.has(kind);
|
|
48
|
+
const grepped = parsed.form === 'bare' || parsed.form === 'qualified';
|
|
49
|
+
let indexed;
|
|
50
|
+
try {
|
|
51
|
+
indexed = await this.indexQuery.query(parsed, project, kind);
|
|
52
|
+
this.logger.debug('SymbolLookup: findSymbol result', { source: 'index', hits: indexed.hits.length, truncated: indexed.truncated, ms: Date.now() - t0 });
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
this.logger.warn('SymbolLookup: symbol index unavailable', { err, ms: Date.now() - t0 });
|
|
56
|
+
if (isGraphqlKind)
|
|
57
|
+
throw err;
|
|
58
|
+
if (!grepped)
|
|
59
|
+
return { hits: [], truncated: false, grep: find_symbol_constants_1.COMPLETE, similar: NO_SIMILAR };
|
|
60
|
+
return { ...(await this.grepFallback.run(parsed, project, kind)), similar: NO_SIMILAR };
|
|
61
|
+
}
|
|
62
|
+
if (indexed.hits.length > 0)
|
|
63
|
+
return { ...indexed, grep: find_symbol_constants_1.COMPLETE, similar: NO_SIMILAR };
|
|
64
|
+
if (isGraphqlKind || !grepped)
|
|
65
|
+
return { hits: [], truncated: false, grep: find_symbol_constants_1.COMPLETE, similar: NO_SIMILAR };
|
|
66
|
+
let found;
|
|
67
|
+
if (parsed.form === 'qualified' && await this.indexedElsewhere(parsed.name, project, kind)) {
|
|
68
|
+
found = { hits: [], truncated: false, grep: { outcome: 'other-container' } };
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
found = await this.grepFallback.run(parsed, project, kind);
|
|
72
|
+
}
|
|
73
|
+
if (found.hits.length > 0)
|
|
74
|
+
return { ...found, similar: NO_SIMILAR };
|
|
75
|
+
const exactFirst = found.grep.outcome === 'other-container' || kind !== 'all';
|
|
76
|
+
return { ...found, similar: await this.similarOrNone(parsed.name, project, exactFirst) };
|
|
77
|
+
}
|
|
78
|
+
async indexedElsewhere(name, project, kind) {
|
|
79
|
+
try {
|
|
80
|
+
return await (0, symbol_sql_1.symbolIndexedElsewhere)(this.db, name, project, kind);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
this.logger.warn('SymbolLookup: findSymbol other-container check failed', { err, name, project });
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async similarOrNone(name, project, exactFirst) {
|
|
88
|
+
try {
|
|
89
|
+
return await (0, symbol_sql_1.similarSymbolNames)(this.db, name, project, exactFirst);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
this.logger.warn('SymbolLookup: findSymbol similar-name lookup failed', { err, name, project });
|
|
93
|
+
return NO_SIMILAR;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.SymbolLookup = SymbolLookup;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { IDatabase } from '../../interfaces';
|
|
2
|
+
import type { SearchResult } from '../../interfaces/IChunkSearch';
|
|
3
|
+
import type { IterativeScanGate } from './IterativeScanGate';
|
|
4
|
+
import type { SearchPlan } from './search-plan';
|
|
5
|
+
export interface CandidatePool {
|
|
6
|
+
candidates: SearchResult[];
|
|
7
|
+
poolSaturated: boolean;
|
|
8
|
+
indexParams: {
|
|
9
|
+
efSearch: number;
|
|
10
|
+
iterativeScan: string;
|
|
11
|
+
};
|
|
12
|
+
dbMs: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class CandidateFetcher {
|
|
15
|
+
private db;
|
|
16
|
+
private gate;
|
|
17
|
+
constructor(db: IDatabase, gate: IterativeScanGate);
|
|
18
|
+
fetch(embedding: number[], plan: SearchPlan, project: string | null): Promise<CandidatePool>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CandidateFetcher = void 0;
|
|
4
|
+
const hnsw_settings_1 = require("../../hnsw-settings");
|
|
5
|
+
class CandidateFetcher {
|
|
6
|
+
db;
|
|
7
|
+
gate;
|
|
8
|
+
constructor(db, gate) {
|
|
9
|
+
this.db = db;
|
|
10
|
+
this.gate = gate;
|
|
11
|
+
}
|
|
12
|
+
async fetch(embedding, plan, project) {
|
|
13
|
+
const params = [`[${embedding}]`, plan.threshold.value, plan.dbLimit];
|
|
14
|
+
let projectFilter = '';
|
|
15
|
+
if (project) {
|
|
16
|
+
params.push(project);
|
|
17
|
+
projectFilter = `AND "serviceName" = $${params.length}`;
|
|
18
|
+
}
|
|
19
|
+
const iterative = await this.gate.enabled();
|
|
20
|
+
const settings = (0, hnsw_settings_1.hnswSettings)(plan.dbLimit, iterative);
|
|
21
|
+
const indexParams = {
|
|
22
|
+
efSearch: settings['hnsw.ef_search'],
|
|
23
|
+
iterativeScan: iterative ? hnsw_settings_1.ITERATIVE_SCAN_MODE : 'off',
|
|
24
|
+
};
|
|
25
|
+
const tDb0 = Date.now();
|
|
26
|
+
const fetched = await this.db.queryWithLocalSettings(settings, `SELECT "serviceName", "filePath", "startLine", content, "ownerPath",
|
|
27
|
+
ROUND((embedding <=> $1)::numeric, 4)::float8 AS score
|
|
28
|
+
FROM code_chunk
|
|
29
|
+
WHERE embedding <=> $1 < $2
|
|
30
|
+
${projectFilter}
|
|
31
|
+
ORDER BY embedding <=> $1
|
|
32
|
+
LIMIT $3`, params);
|
|
33
|
+
const dbMs = Date.now() - tDb0;
|
|
34
|
+
fetched.sort((a, b) => a.score - b.score);
|
|
35
|
+
const poolSaturated = fetched.length > plan.fetchLimit;
|
|
36
|
+
const candidates = fetched.slice(0, plan.fetchLimit);
|
|
37
|
+
return { candidates, poolSaturated, indexParams, dbMs };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.CandidateFetcher = CandidateFetcher;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IDatabase, ILogger } from '../../interfaces';
|
|
2
|
+
export declare class IterativeScanGate {
|
|
3
|
+
private db;
|
|
4
|
+
private logger;
|
|
5
|
+
private pgvectorVersionRead?;
|
|
6
|
+
private degradedScanWarned;
|
|
7
|
+
constructor(db: IDatabase, logger: ILogger);
|
|
8
|
+
enabled(): Promise<boolean>;
|
|
9
|
+
private warnDegraded;
|
|
10
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IterativeScanGate = void 0;
|
|
4
|
+
const hnsw_settings_1 = require("../../hnsw-settings");
|
|
5
|
+
class IterativeScanGate {
|
|
6
|
+
db;
|
|
7
|
+
logger;
|
|
8
|
+
pgvectorVersionRead;
|
|
9
|
+
degradedScanWarned = false;
|
|
10
|
+
constructor(db, logger) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
this.logger = logger;
|
|
13
|
+
}
|
|
14
|
+
async enabled() {
|
|
15
|
+
const read = this.pgvectorVersionRead ??= this.db.pgvectorVersion().then(v => {
|
|
16
|
+
if (v === null)
|
|
17
|
+
throw new Error('vector extension not found in pg_extension');
|
|
18
|
+
return v;
|
|
19
|
+
});
|
|
20
|
+
let version;
|
|
21
|
+
try {
|
|
22
|
+
version = await read;
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
if (this.pgvectorVersionRead === read)
|
|
26
|
+
this.pgvectorVersionRead = undefined;
|
|
27
|
+
this.warnDegraded('unknown', err);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if ((0, hnsw_settings_1.supportsIterativeScan)(version))
|
|
31
|
+
return true;
|
|
32
|
+
this.warnDegraded(version);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
warnDegraded(version, err) {
|
|
36
|
+
if (this.degradedScanWarned)
|
|
37
|
+
return;
|
|
38
|
+
this.degradedScanWarned = true;
|
|
39
|
+
this.logger.warn(`IterativeScanGate: pgvector ${version} lacks hnsw.iterative_scan — filtered searches on large projects may return fewer candidates than requested; upgrade to pgvector ≥ 0.8`, err ? { err } : undefined);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.IterativeScanGate = IterativeScanGate;
|