codesearch-mcp 0.3.0-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 +59 -6
- package/LICENSE +661 -21
- package/README.md +33 -17
- package/dist/app.js +13 -20
- 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/commands/EvalCommand.d.ts +7 -3
- package/dist/src/commands/EvalCommand.js +36 -158
- package/dist/src/commands/IndexCommand.d.ts +10 -4
- package/dist/src/commands/IndexCommand.js +52 -124
- package/dist/src/commands/McpCommand.d.ts +6 -3
- package/dist/src/commands/McpCommand.js +19 -14
- package/dist/src/commands/WebCommand.d.ts +9 -3
- package/dist/src/commands/WebCommand.js +17 -8
- 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-store.d.ts +0 -1
- package/dist/src/config-store.js +3 -4
- package/dist/src/config.d.ts +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/constants.d.ts +15 -0
- package/dist/src/constants.js +34 -6
- package/dist/src/container.d.ts +4 -2
- package/dist/src/container.js +7 -5
- package/dist/src/db/drizzle-types.d.ts +7 -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/declarations/DeclarationTree.d.ts +1 -1
- package/dist/src/eval-results.js +16 -2
- package/dist/src/eval-vector-index.d.ts +5 -0
- package/dist/src/eval-vector-index.js +60 -0
- package/dist/src/help.js +9 -1
- 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 +2 -1
- 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/IDatabase.d.ts +6 -2
- package/dist/src/interfaces/IDependencyGraph.d.ts +24 -0
- package/dist/src/interfaces/IDependencyGraph.js +2 -0
- 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/IMcpReadiness.d.ts +12 -0
- package/dist/src/interfaces/IMcpReadiness.js +2 -0
- package/dist/src/interfaces/IProjectCatalog.d.ts +13 -0
- package/dist/src/interfaces/IProjectCatalog.js +2 -0
- package/dist/src/interfaces/IProjectRoots.d.ts +3 -0
- package/dist/src/interfaces/IProjectRoots.js +2 -0
- package/dist/src/interfaces/IRetrievalEvaluator.d.ts +21 -2
- 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/project-scope.d.ts +1 -0
- package/dist/src/project-scope.js +5 -0
- package/dist/src/retrieval-eval.d.ts +2 -1
- package/dist/src/retrieval-eval.js +45 -2
- 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/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 +8 -44
- package/dist/src/services/AstParserService.js +19 -938
- package/dist/src/services/DatabaseService.d.ts +8 -10
- package/dist/src/services/DatabaseService.js +29 -86
- package/dist/src/services/IndexerService.d.ts +7 -10
- package/dist/src/services/IndexerService.js +36 -255
- package/dist/src/services/McpReadiness.d.ts +18 -0
- package/dist/src/services/McpReadiness.js +73 -0
- package/dist/src/services/McpServer.d.ts +32 -9
- package/dist/src/services/McpServer.js +78 -41
- package/dist/src/services/WebServerService.d.ts +4 -3
- package/dist/src/services/WebServerService.js +16 -8
- package/dist/src/setup.d.ts +16 -4
- package/dist/src/setup.js +115 -40
- package/dist/src/symbol-name.d.ts +1 -0
- package/dist/src/symbol-name.js +16 -12
- 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 +35 -28
- package/dist/src/tools/GetDependentsTool.d.ts +20 -8
- package/dist/src/tools/GetDependentsTool.js +47 -33
- 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 +69 -51
- package/dist/src/tools/format-helpers.d.ts +9 -3
- package/dist/src/tools/format-helpers.js +59 -14
- package/dist/src/tools/tool-args.d.ts +38 -0
- package/dist/src/tools/tool-args.js +95 -0
- 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 +4 -3
- package/dist/src/interfaces/ISearcher.d.ts +0 -46
- package/dist/src/services/SearcherService.d.ts +0 -235
- package/dist/src/services/SearcherService.js +0 -1118
- /package/dist/src/{interfaces/ISearcher.js → db/drizzle-types.js} +0 -0
|
@@ -0,0 +1,285 @@
|
|
|
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.WorkspaceFiles = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const readline = __importStar(require("readline"));
|
|
39
|
+
const stream_1 = require("stream");
|
|
40
|
+
const file_utils_1 = require("../file-utils");
|
|
41
|
+
const fs_access_1 = require("./fs-access");
|
|
42
|
+
const MAX_LINE_BYTES = 64 * 1024 * 1024;
|
|
43
|
+
const LINE_TOO_LONG = 'ELINETOOLONG';
|
|
44
|
+
const BINARY_FILE = 'EBINARY';
|
|
45
|
+
const BINARY_SNIFF_BYTES = 8 * 1024;
|
|
46
|
+
const LF = 0x0a;
|
|
47
|
+
const CR = 0x0d;
|
|
48
|
+
function openLineBytes(open, chunk) {
|
|
49
|
+
const breaks = [chunk.indexOf(LF), chunk.indexOf(CR)].filter(i => i >= 0);
|
|
50
|
+
const head = breaks.length === 0 ? chunk.length : Math.min(...breaks);
|
|
51
|
+
const total = open + head;
|
|
52
|
+
if (total > MAX_LINE_BYTES)
|
|
53
|
+
return null;
|
|
54
|
+
if (breaks.length === 0)
|
|
55
|
+
return total;
|
|
56
|
+
return chunk.length - 1 - Math.max(chunk.lastIndexOf(LF), chunk.lastIndexOf(CR));
|
|
57
|
+
}
|
|
58
|
+
function lineLimitGuard() {
|
|
59
|
+
let open = 0;
|
|
60
|
+
let sniffed = 0;
|
|
61
|
+
let held = [];
|
|
62
|
+
const lineLimit = (chunk) => {
|
|
63
|
+
const next = openLineBytes(open, chunk);
|
|
64
|
+
if (next === null)
|
|
65
|
+
return Object.assign(new Error('line too long'), { code: LINE_TOO_LONG });
|
|
66
|
+
open = next;
|
|
67
|
+
return null;
|
|
68
|
+
};
|
|
69
|
+
return new stream_1.Transform({
|
|
70
|
+
encoding: 'utf-8',
|
|
71
|
+
transform(chunk, _encoding, done) {
|
|
72
|
+
if (sniffed < BINARY_SNIFF_BYTES) {
|
|
73
|
+
const head = chunk.subarray(0, BINARY_SNIFF_BYTES - sniffed);
|
|
74
|
+
if (head.includes(0)) {
|
|
75
|
+
done(Object.assign(new Error('binary file'), { code: BINARY_FILE }));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
sniffed += head.length;
|
|
79
|
+
held.push(chunk);
|
|
80
|
+
if (sniffed < BINARY_SNIFF_BYTES) {
|
|
81
|
+
done();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
chunk = Buffer.concat(held);
|
|
85
|
+
held = [];
|
|
86
|
+
}
|
|
87
|
+
const err = lineLimit(chunk);
|
|
88
|
+
if (err)
|
|
89
|
+
done(err);
|
|
90
|
+
else
|
|
91
|
+
done(null, chunk);
|
|
92
|
+
},
|
|
93
|
+
flush(done) {
|
|
94
|
+
if (held.length === 0) {
|
|
95
|
+
done();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const chunk = Buffer.concat(held);
|
|
99
|
+
held = [];
|
|
100
|
+
const err = lineLimit(chunk);
|
|
101
|
+
if (err)
|
|
102
|
+
done(err);
|
|
103
|
+
else
|
|
104
|
+
done(null, chunk);
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
class WorkspaceFiles {
|
|
109
|
+
paths;
|
|
110
|
+
roots;
|
|
111
|
+
logger;
|
|
112
|
+
fs;
|
|
113
|
+
constructor(paths, roots, logger, fs) {
|
|
114
|
+
this.paths = paths;
|
|
115
|
+
this.roots = roots;
|
|
116
|
+
this.logger = logger;
|
|
117
|
+
this.fs = fs;
|
|
118
|
+
}
|
|
119
|
+
async listFiles(relPath, depth, pattern) {
|
|
120
|
+
const t0 = Date.now();
|
|
121
|
+
this.logger.debug('WorkspaceFiles: listFiles', { relPath, depth, pattern });
|
|
122
|
+
const absPath = this.roots.toAbs(relPath);
|
|
123
|
+
const loc = await this.paths.checkRealLocation(relPath, absPath, 'dir');
|
|
124
|
+
if (!loc.ok)
|
|
125
|
+
return loc;
|
|
126
|
+
let stat;
|
|
127
|
+
try {
|
|
128
|
+
stat = await this.fs.stat(absPath);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
if ((0, fs_access_1.errorCode)(err) !== 'ENOENT')
|
|
132
|
+
return { ok: false, reason: 'unreadable', code: (0, fs_access_1.errorCode)(err) };
|
|
133
|
+
return { ok: false, reason: 'not_found', candidates: await this.paths.candidatesOrNone(relPath, 'dir') };
|
|
134
|
+
}
|
|
135
|
+
if (!stat.isDirectory())
|
|
136
|
+
return { ok: false, reason: 'not_a_directory' };
|
|
137
|
+
const clampedDepth = Math.min(5, Math.max(1, depth));
|
|
138
|
+
const lines = [];
|
|
139
|
+
try {
|
|
140
|
+
await this.walkDir(absPath, 0, clampedDepth - 1, pattern, lines);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
return { ok: false, reason: 'unreadable', code: (0, fs_access_1.errorCode)(err) };
|
|
144
|
+
}
|
|
145
|
+
this.logger.debug('WorkspaceFiles: listFiles result', { entries: lines.length, ms: Date.now() - t0 });
|
|
146
|
+
if (lines.length === 0) {
|
|
147
|
+
return { ok: true, tree: pattern ? `No files matching "${pattern}" found within depth ${clampedDepth}.` : '(empty directory)' };
|
|
148
|
+
}
|
|
149
|
+
return { ok: true, tree: lines.join('\n') };
|
|
150
|
+
}
|
|
151
|
+
async openableFile(relPath, absPath) {
|
|
152
|
+
const loc = await this.paths.checkRealLocation(relPath, absPath, 'file');
|
|
153
|
+
if (!loc.ok)
|
|
154
|
+
return loc;
|
|
155
|
+
let stat;
|
|
156
|
+
try {
|
|
157
|
+
stat = await this.fs.stat(absPath);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
if ((0, fs_access_1.errorCode)(err) !== 'ENOENT')
|
|
161
|
+
return { ok: false, reason: 'unreadable', code: (0, fs_access_1.errorCode)(err) };
|
|
162
|
+
if (await this.paths.isIndexedPath(relPath))
|
|
163
|
+
return { ok: false, reason: 'deleted' };
|
|
164
|
+
return { ok: false, reason: 'not_found', candidates: await this.paths.candidatesOrNone(relPath, 'file') };
|
|
165
|
+
}
|
|
166
|
+
return stat.isFile() ? null : { ok: false, reason: 'not_a_file' };
|
|
167
|
+
}
|
|
168
|
+
async readLines(absPath, onLine) {
|
|
169
|
+
const stream = this.fs.createReadStream(absPath);
|
|
170
|
+
const guard = lineLimitGuard();
|
|
171
|
+
guard.on('error', () => { });
|
|
172
|
+
stream.on('error', err => guard.destroy(err));
|
|
173
|
+
stream.pipe(guard);
|
|
174
|
+
const rl = readline.createInterface({ input: guard, crlfDelay: Infinity });
|
|
175
|
+
let lineNo = 0;
|
|
176
|
+
try {
|
|
177
|
+
for await (const line of rl) {
|
|
178
|
+
lineNo++;
|
|
179
|
+
if (!onLine(line, lineNo))
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
return { ok: true, lineCount: lineNo };
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
if ((0, fs_access_1.errorCode)(err) === LINE_TOO_LONG && !onLine('', lineNo + 1))
|
|
186
|
+
return { ok: true, lineCount: lineNo };
|
|
187
|
+
return { ok: false, code: (0, fs_access_1.errorCode)(err) };
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
rl.close();
|
|
191
|
+
guard.destroy();
|
|
192
|
+
stream.destroy?.();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
readFailure(code) {
|
|
196
|
+
return code === BINARY_FILE ? { ok: false, reason: 'binary' } : { ok: false, reason: 'unreadable', code };
|
|
197
|
+
}
|
|
198
|
+
async readFile(relPath, maxLines) {
|
|
199
|
+
const t0 = Date.now();
|
|
200
|
+
this.logger.debug('WorkspaceFiles: readFile', { relPath, maxLines });
|
|
201
|
+
const absPath = this.roots.toAbs(relPath);
|
|
202
|
+
const failure = await this.openableFile(relPath, absPath);
|
|
203
|
+
if (failure)
|
|
204
|
+
return failure;
|
|
205
|
+
const lines = [];
|
|
206
|
+
let hasMore = false;
|
|
207
|
+
const read = await this.readLines(absPath, line => {
|
|
208
|
+
if (lines.length < maxLines) {
|
|
209
|
+
lines.push(line);
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
hasMore = true;
|
|
213
|
+
return false;
|
|
214
|
+
});
|
|
215
|
+
if (!read.ok)
|
|
216
|
+
return this.readFailure(read.code);
|
|
217
|
+
this.logger.debug('WorkspaceFiles: readFile result', { linesRead: lines.length, hasMore, ms: Date.now() - t0 });
|
|
218
|
+
return { ok: true, filePath: relPath, startLine: 1, endLine: lines.length, lines, hasMore };
|
|
219
|
+
}
|
|
220
|
+
async readFileRange(relPath, startLine, endLine) {
|
|
221
|
+
const t0 = Date.now();
|
|
222
|
+
this.logger.debug('WorkspaceFiles: readFileRange', { relPath, startLine, endLine });
|
|
223
|
+
if (endLine < startLine)
|
|
224
|
+
return { ok: false, reason: 'bad_range', startLine, endLine };
|
|
225
|
+
const absPath = this.roots.toAbs(relPath);
|
|
226
|
+
const failure = await this.openableFile(relPath, absPath);
|
|
227
|
+
if (failure)
|
|
228
|
+
return failure;
|
|
229
|
+
const lines = [];
|
|
230
|
+
let lastRead = 0;
|
|
231
|
+
let hasMore = false;
|
|
232
|
+
const read = await this.readLines(absPath, (line, lineNo) => {
|
|
233
|
+
if (lineNo > endLine) {
|
|
234
|
+
hasMore = true;
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
if (lineNo >= startLine)
|
|
238
|
+
lines.push(line);
|
|
239
|
+
lastRead = lineNo;
|
|
240
|
+
return true;
|
|
241
|
+
});
|
|
242
|
+
if (!read.ok)
|
|
243
|
+
return this.readFailure(read.code);
|
|
244
|
+
if (!hasMore && startLine > Math.max(read.lineCount, 1)) {
|
|
245
|
+
return { ok: false, reason: 'past_end', lineCount: read.lineCount, startLine };
|
|
246
|
+
}
|
|
247
|
+
this.logger.debug('WorkspaceFiles: readFileRange result', { linesRead: lines.length, hasMore, ms: Date.now() - t0 });
|
|
248
|
+
return { ok: true, filePath: relPath, startLine, endLine: Math.min(endLine, lastRead), lines, hasMore };
|
|
249
|
+
}
|
|
250
|
+
async walkDir(absDir, currentDepth, maxDepth, pattern, lines) {
|
|
251
|
+
const entries = await this.fs.readdir(absDir);
|
|
252
|
+
entries.sort((a, b) => {
|
|
253
|
+
const ad = a.isDirectory() ? 0 : 1;
|
|
254
|
+
const bd = b.isDirectory() ? 0 : 1;
|
|
255
|
+
if (ad !== bd)
|
|
256
|
+
return ad - bd;
|
|
257
|
+
return a.name.localeCompare(b.name);
|
|
258
|
+
});
|
|
259
|
+
for (const entry of entries) {
|
|
260
|
+
if (file_utils_1.IGNORE_DIRS.has(entry.name))
|
|
261
|
+
continue;
|
|
262
|
+
const indent = ' '.repeat(currentDepth);
|
|
263
|
+
if (entry.isDirectory()) {
|
|
264
|
+
const at = lines.push(`${indent}${entry.name}/`) - 1;
|
|
265
|
+
if (currentDepth < maxDepth) {
|
|
266
|
+
try {
|
|
267
|
+
await this.walkDir(path.join(absDir, entry.name), currentDepth + 1, maxDepth, pattern, lines);
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
lines[at] += ' (unreadable)';
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (pattern && lines.length === at + 1)
|
|
275
|
+
lines.pop();
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
if (pattern && !entry.name.includes(pattern))
|
|
279
|
+
continue;
|
|
280
|
+
lines.push(`${indent}${entry.name}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
exports.WorkspaceFiles = WorkspaceFiles;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
export interface WorkspaceFs {
|
|
3
|
+
realpath(p: string): Promise<string>;
|
|
4
|
+
stat(p: string): Promise<fs.Stats>;
|
|
5
|
+
readdir(p: string): Promise<fs.Dirent[]>;
|
|
6
|
+
createReadStream(p: string): NodeJS.ReadableStream;
|
|
7
|
+
}
|
|
8
|
+
export declare const NODE_FS: WorkspaceFs;
|
|
9
|
+
export declare function errorCode(err: unknown): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
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.NODE_FS = void 0;
|
|
37
|
+
exports.errorCode = errorCode;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
exports.NODE_FS = {
|
|
40
|
+
realpath: p => fs.promises.realpath(p),
|
|
41
|
+
stat: p => fs.promises.stat(p),
|
|
42
|
+
readdir: p => fs.promises.readdir(p, { withFileTypes: true }),
|
|
43
|
+
createReadStream: p => fs.createReadStream(p),
|
|
44
|
+
};
|
|
45
|
+
function errorCode(err) {
|
|
46
|
+
return err?.code ?? 'EIO';
|
|
47
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripTrailingSlash = stripTrailingSlash;
|
|
4
|
+
exports.isWithin = isWithin;
|
|
5
|
+
exports.editDistance = editDistance;
|
|
6
|
+
function stripTrailingSlash(p) {
|
|
7
|
+
return p.length > 1 && p.endsWith('/') ? p.slice(0, -1) : p;
|
|
8
|
+
}
|
|
9
|
+
function isWithin(p, root) {
|
|
10
|
+
if (root === '.')
|
|
11
|
+
return true;
|
|
12
|
+
if (root === '/')
|
|
13
|
+
return p.startsWith('/');
|
|
14
|
+
return p === root || p.startsWith(root + '/');
|
|
15
|
+
}
|
|
16
|
+
function editDistance(a, b, max) {
|
|
17
|
+
const x = [...a];
|
|
18
|
+
const y = [...b];
|
|
19
|
+
const over = max + 1;
|
|
20
|
+
if (Math.abs(x.length - y.length) > max)
|
|
21
|
+
return over;
|
|
22
|
+
let prev = Array.from({ length: y.length + 1 }, (_, j) => (j <= max ? j : over));
|
|
23
|
+
let row = new Array(y.length + 1).fill(over);
|
|
24
|
+
for (let i = 1; i <= x.length; i++) {
|
|
25
|
+
const from = Math.max(1, i - max);
|
|
26
|
+
const to = Math.min(y.length, i + max);
|
|
27
|
+
row[0] = i <= max ? i : over;
|
|
28
|
+
row[from - 1] = from === 1 ? row[0] : over;
|
|
29
|
+
let best = row[0];
|
|
30
|
+
for (let j = from; j <= to; j++) {
|
|
31
|
+
const cell = Math.min(prev[j] + 1, row[j - 1] + 1, prev[j - 1] + (x[i - 1] === y[j - 1] ? 0 : 1), over);
|
|
32
|
+
row[j] = cell;
|
|
33
|
+
if (cell < best)
|
|
34
|
+
best = cell;
|
|
35
|
+
}
|
|
36
|
+
if (to < y.length)
|
|
37
|
+
row[to + 1] = over;
|
|
38
|
+
if (best > max)
|
|
39
|
+
return over;
|
|
40
|
+
[prev, row] = [row, prev];
|
|
41
|
+
}
|
|
42
|
+
return prev[y.length];
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codesearch-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-alpha",
|
|
4
4
|
"description": "Local semantic codebase search via MCP — indexes projects into pgvector, exposes search to Claude",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mcp",
|
|
8
8
|
"model-context-protocol",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"infinity"
|
|
17
17
|
],
|
|
18
18
|
"engines": {
|
|
19
|
-
"node": ">=
|
|
19
|
+
"node": "^22.13.0 || >=23.5.0"
|
|
20
20
|
},
|
|
21
21
|
"main": "dist/app.js",
|
|
22
22
|
"bin": {
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"@types/cli-progress": "^3.11.6",
|
|
66
66
|
"@types/node": "^22.0.0",
|
|
67
67
|
"@types/pg": "^8.20.0",
|
|
68
|
+
"ai-aleks-tool": "^2.5.4",
|
|
68
69
|
"ts-node": "^10.9.2",
|
|
69
70
|
"typescript": "^5.6.0",
|
|
70
71
|
"vitest": "^5.0.5"
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { SearchResult, NeighborResult, GraphContext, DependencyRow, ProjectRow, SymbolKind, SymbolHit, CallerRow, FileRangeResult, ListFilesResult, GrepSymbolResult, ResolvedToolPath, PathFailure } from '../services/SearcherService';
|
|
2
|
-
export type StageName = 'vector' | 'reranked';
|
|
3
|
-
export interface StagedSearchResult {
|
|
4
|
-
pool: SearchResult[];
|
|
5
|
-
stages: {
|
|
6
|
-
vector: SearchResult[];
|
|
7
|
-
reranked?: SearchResult[];
|
|
8
|
-
};
|
|
9
|
-
rerankFailed: boolean;
|
|
10
|
-
fetchLimit: number;
|
|
11
|
-
indexParams: {
|
|
12
|
-
efSearch: number | null;
|
|
13
|
-
iterativeScan: string;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
export interface ISearcher {
|
|
17
|
-
prepareQuery(raw: string): Promise<{
|
|
18
|
-
query: string;
|
|
19
|
-
translated: boolean;
|
|
20
|
-
}>;
|
|
21
|
-
assertIndexMatches(): Promise<void>;
|
|
22
|
-
listProjects(): Promise<ProjectRow[]>;
|
|
23
|
-
getProjectEdges(): Promise<{
|
|
24
|
-
from: string;
|
|
25
|
-
to: string;
|
|
26
|
-
}[]>;
|
|
27
|
-
searchChunks(query: string, limit: number, project: string | null, threshold?: number, rerankOverride?: boolean, perFile?: number): Promise<SearchResult[]>;
|
|
28
|
-
searchChunksWithStages(query: string, limit: number, project: string | null, threshold?: number, rerankOverride?: boolean, perFile?: number): Promise<StagedSearchResult>;
|
|
29
|
-
fetchNeighbors(results: SearchResult[]): Promise<NeighborResult[]>;
|
|
30
|
-
fetchGraphContext(results: SearchResult[]): Promise<Map<string, GraphContext>>;
|
|
31
|
-
getDependencies(filePath: string, symbol?: string | null, transitive?: boolean): Promise<DependencyRow[]>;
|
|
32
|
-
getDependents(filePath: string, symbol?: string | null, transitive?: boolean): Promise<DependencyRow[]>;
|
|
33
|
-
getCallers(symbol: string, project: string, calleeFile?: string | null): Promise<CallerRow[]>;
|
|
34
|
-
grepSymbol(symbol: string, rootDir: string, excludeFile: string): Promise<GrepSymbolResult>;
|
|
35
|
-
findSymbol(name: string, project: string | null, kind: SymbolKind): Promise<{
|
|
36
|
-
hits: SymbolHit[];
|
|
37
|
-
truncated: boolean;
|
|
38
|
-
grepFailed: boolean;
|
|
39
|
-
}>;
|
|
40
|
-
listFiles(relPath: string, depth: number, pattern: string | null): Promise<ListFilesResult>;
|
|
41
|
-
readFile(relPath: string, maxLines: number): Promise<FileRangeResult>;
|
|
42
|
-
readFileRange(relPath: string, startLine: number, endLine: number): Promise<FileRangeResult>;
|
|
43
|
-
resolveToolPath(input: string | null | undefined): Promise<ResolvedToolPath>;
|
|
44
|
-
checkGraphPath(relPath: string): Promise<PathFailure | null>;
|
|
45
|
-
fallbackRoot(relPath: string): string | null;
|
|
46
|
-
}
|