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