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