flowseeker 0.1.7
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 +111 -0
- package/COMPATIBILITY.md +281 -0
- package/LICENSE +21 -0
- package/README.md +375 -0
- package/dist/adapters/frameworkEdges.js +586 -0
- package/dist/agent/approvalPolicy.js +81 -0
- package/dist/agent/commandRunner.js +166 -0
- package/dist/agent/flowCommandRunner.js +124 -0
- package/dist/agent/mcpToolRunner.js +167 -0
- package/dist/auth/githubAuth.js +71 -0
- package/dist/auth/modelList.js +127 -0
- package/dist/auth/oauthHandler.js +377 -0
- package/dist/chat/nativeChatParticipant.js +616 -0
- package/dist/cli/mcpServer.js +383 -0
- package/dist/cli/runEvaluation.js +789 -0
- package/dist/cli/runReplay.js +481 -0
- package/dist/commands/checkHostCompatibility.js +149 -0
- package/dist/commands/copyAgentPrompt.js +52 -0
- package/dist/commands/copyContext.js +54 -0
- package/dist/commands/explainSelectionRelevance.js +57 -0
- package/dist/commands/findRelevantContext.js +127 -0
- package/dist/commands/openEvidence.js +49 -0
- package/dist/commands/openMcpConfig.js +81 -0
- package/dist/commands/openRelatedTests.js +54 -0
- package/dist/commands/rebuildIndex.js +45 -0
- package/dist/commands/runEvaluationSuite.js +323 -0
- package/dist/commands/runReplaySuite.js +228 -0
- package/dist/config/defaultConfig.js +72 -0
- package/dist/config/loadConfig.js +84 -0
- package/dist/config/loadConfigFromPath.js +60 -0
- package/dist/extension.js +513 -0
- package/dist/gateway/agentPrompts.js +176 -0
- package/dist/gateway/aiGateway.js +1255 -0
- package/dist/gateway/aiProviders.js +901 -0
- package/dist/gateway/contextExpansion.js +331 -0
- package/dist/gateway/editProposalStore.js +238 -0
- package/dist/gateway/planProposalStore.js +28 -0
- package/dist/index/cacheStore.js +51 -0
- package/dist/index/chunker.js +45 -0
- package/dist/index/dependencyExtractor.js +107 -0
- package/dist/index/fileDiscovery.js +177 -0
- package/dist/index/structuredExtractor.js +256 -0
- package/dist/index/workspaceIndex.js +518 -0
- package/dist/mcp/mcpConfig.js +154 -0
- package/dist/mcp/mcpProvider.js +109 -0
- package/dist/mcp/mcpTools.js +215 -0
- package/dist/pipeline/agentPrompt.js +79 -0
- package/dist/pipeline/agentPromptHeadless.js +85 -0
- package/dist/pipeline/contextBlueprint.js +346 -0
- package/dist/pipeline/contextPack.js +80 -0
- package/dist/pipeline/diffPreview.js +79 -0
- package/dist/pipeline/evaluationMetrics.js +154 -0
- package/dist/pipeline/evidenceGraph.js +389 -0
- package/dist/pipeline/feedback.js +215 -0
- package/dist/pipeline/fileGroups.js +84 -0
- package/dist/pipeline/fileScanner.js +866 -0
- package/dist/pipeline/nodeScan.js +219 -0
- package/dist/pipeline/ranker.js +563 -0
- package/dist/pipeline/responseLanguage.js +39 -0
- package/dist/pipeline/retrievalPlan.js +163 -0
- package/dist/pipeline/runHeadless.js +54 -0
- package/dist/pipeline/runPipeline.js +114 -0
- package/dist/pipeline/solvePacket.js +382 -0
- package/dist/pipeline/subsystem.js +257 -0
- package/dist/pipeline/taskUnderstanding.js +453 -0
- package/dist/pipeline/tokenSavings.js +146 -0
- package/dist/pipeline/universalScan.js +216 -0
- package/dist/pipeline/verifyAfterApply.js +233 -0
- package/dist/runtime/capabilities.js +71 -0
- package/dist/runtime/hostDetect.js +98 -0
- package/dist/runtime/hostTier.js +68 -0
- package/dist/runtime/statusBar.js +80 -0
- package/dist/skills/skillRegistry.js +208 -0
- package/dist/types.js +3 -0
- package/dist/ui/chatViewProvider.js +3899 -0
- package/dist/ui/resultTreeProvider.js +174 -0
- package/dist/usage/quotaTracker.js +358 -0
- package/dist/utils/async.js +30 -0
- package/dist/utils/logger.js +64 -0
- package/dist/utils/text.js +364 -0
- package/dist/utils/updateChecker.js +140 -0
- package/package.json +561 -0
|
@@ -0,0 +1,518 @@
|
|
|
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.loadOrBuildWorkspaceIndex = loadOrBuildWorkspaceIndex;
|
|
37
|
+
exports.selectIndexCandidates = selectIndexCandidates;
|
|
38
|
+
exports.clearNodeWorkspaceIndex = clearNodeWorkspaceIndex;
|
|
39
|
+
const fs = __importStar(require("fs/promises"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const dependencyExtractor_1 = require("./dependencyExtractor");
|
|
42
|
+
const fileDiscovery_1 = require("./fileDiscovery");
|
|
43
|
+
const structuredExtractor_1 = require("./structuredExtractor");
|
|
44
|
+
const text_1 = require("../utils/text");
|
|
45
|
+
const fileScanner_1 = require("../pipeline/fileScanner");
|
|
46
|
+
const subsystem_1 = require("../pipeline/subsystem");
|
|
47
|
+
const indexVersion = 6;
|
|
48
|
+
const tokenLimitPerFile = 2500;
|
|
49
|
+
async function loadOrBuildWorkspaceIndex(rootPath, config, options = {}) {
|
|
50
|
+
const startedAt = options.startedAt ?? Date.now();
|
|
51
|
+
const resolvedRoot = path.resolve(rootPath);
|
|
52
|
+
const discovery = await (0, fileDiscovery_1.discoverWorkspaceFiles)(resolvedRoot, config, { startedAt, shouldCancel: options.shouldCancel });
|
|
53
|
+
const priorIndex = await readIndex(resolvedRoot);
|
|
54
|
+
const currentFingerprint = fingerprintConfig(config);
|
|
55
|
+
const reusablePriorIndex = priorIndex?.configFingerprint === currentFingerprint ? priorIndex : undefined;
|
|
56
|
+
const priorByPath = new Map((reusablePriorIndex?.files ?? []).map((file) => [file.relativePath, file]));
|
|
57
|
+
const files = [];
|
|
58
|
+
let reusedFiles = 0;
|
|
59
|
+
let updatedFiles = 0;
|
|
60
|
+
let updatedBytes = 0;
|
|
61
|
+
const maxUpdatedBytes = config.pipeline.maxTotalBytesMb * 1024 * 1024;
|
|
62
|
+
let stopReason = discovery.stopReason;
|
|
63
|
+
let processedFiles = 0;
|
|
64
|
+
for (const discovered of discovery.files) {
|
|
65
|
+
processedFiles += 1;
|
|
66
|
+
if (options.shouldCancel?.()) {
|
|
67
|
+
stopReason = "cancelled";
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
if (Date.now() - startedAt > config.pipeline.maxScanMs) {
|
|
71
|
+
stopReason = `maxScanMs ${config.pipeline.maxScanMs} reached while indexing`;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
if (updatedBytes >= maxUpdatedBytes) {
|
|
75
|
+
stopReason = `maxTotalBytesMb ${config.pipeline.maxTotalBytesMb} reached while indexing`;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
if (processedFiles === 1 || processedFiles % 25 === 0) {
|
|
79
|
+
options.onProgress?.(`Indexing ${processedFiles}/${discovery.files.length}: ${formatProgressPath(discovered.relativePath)}`);
|
|
80
|
+
}
|
|
81
|
+
const indexed = await indexFile(discovered, priorByPath.get(discovered.relativePath), config);
|
|
82
|
+
if (!indexed) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (indexed.reused) {
|
|
86
|
+
reusedFiles += 1;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
updatedFiles += 1;
|
|
90
|
+
updatedBytes += indexed.file.size;
|
|
91
|
+
}
|
|
92
|
+
files.push(indexed.file);
|
|
93
|
+
if ((reusedFiles + updatedFiles) % 50 === 0) {
|
|
94
|
+
options.onProgress?.(`Indexed ${reusedFiles + updatedFiles}/${discovery.files.length} files`);
|
|
95
|
+
}
|
|
96
|
+
if (processedFiles % 25 === 0) {
|
|
97
|
+
await yieldToHost();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const index = {
|
|
101
|
+
version: indexVersion,
|
|
102
|
+
rootPath: resolvedRoot,
|
|
103
|
+
createdAt: new Date().toISOString(),
|
|
104
|
+
configFingerprint: currentFingerprint,
|
|
105
|
+
files
|
|
106
|
+
};
|
|
107
|
+
await writeIndex(resolvedRoot, index);
|
|
108
|
+
return {
|
|
109
|
+
index,
|
|
110
|
+
discoveredFiles: discovery.files.length,
|
|
111
|
+
reusedFiles,
|
|
112
|
+
updatedFiles,
|
|
113
|
+
indexedBytes: files.reduce((sum, file) => sum + file.size, 0),
|
|
114
|
+
indexedTokens: files.reduce((sum, file) => sum + (file.tokenCount ?? Math.ceil(file.size / 4)), 0),
|
|
115
|
+
stopReason
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function selectIndexCandidates(index, profile, config) {
|
|
119
|
+
const terms = (0, fileScanner_1.getWeightedTerms)(profile);
|
|
120
|
+
if (terms.length === 0) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
const scored = index.files
|
|
124
|
+
.map((file) => ({
|
|
125
|
+
file,
|
|
126
|
+
score: scoreIndexedFile(file, terms, profile)
|
|
127
|
+
}))
|
|
128
|
+
.filter((item) => item.score > 0)
|
|
129
|
+
.sort((left, right) => right.score - left.score);
|
|
130
|
+
const selected = new Map();
|
|
131
|
+
const maxCandidates = config.index.maxIndexedCandidateFiles;
|
|
132
|
+
const maxSeeds = Math.min(config.index.maxSeedCandidateFiles, maxCandidates);
|
|
133
|
+
const seeds = scored.slice(0, maxSeeds).map((item) => item.file);
|
|
134
|
+
for (const seed of seeds) {
|
|
135
|
+
selected.set(seed.relativePath, seed);
|
|
136
|
+
}
|
|
137
|
+
if (config.index.enableDependencyExpansion && selected.size < maxCandidates) {
|
|
138
|
+
const maxExpansion = Math.min(config.index.maxDependencyExpansionFiles, maxCandidates - selected.size);
|
|
139
|
+
let expanded = 0;
|
|
140
|
+
for (const related of findDependencyRelatedFiles(index.files, seeds, maxExpansion)) {
|
|
141
|
+
if (expanded >= maxExpansion || selected.size >= maxCandidates) {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
if (!selected.has(related.relativePath)) {
|
|
145
|
+
selected.set(related.relativePath, related);
|
|
146
|
+
expanded += 1;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const item of scored) {
|
|
151
|
+
if (selected.size >= maxCandidates) {
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
selected.set(item.file.relativePath, item.file);
|
|
155
|
+
}
|
|
156
|
+
return Array.from(selected.values()).map((item) => ({
|
|
157
|
+
absolutePath: path.join(index.rootPath, item.relativePath),
|
|
158
|
+
relativePath: item.relativePath
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
function findDependencyRelatedFiles(files, seeds, maxResults) {
|
|
162
|
+
const lookup = buildDependencyLookup(files);
|
|
163
|
+
const related = [];
|
|
164
|
+
for (const seed of seeds) {
|
|
165
|
+
if (related.length >= maxResults) {
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
for (const candidate of lookupImportTargets(seed, lookup)) {
|
|
169
|
+
if (candidate.relativePath !== seed.relativePath && importsFile(seed, candidate)) {
|
|
170
|
+
related.push(candidate);
|
|
171
|
+
}
|
|
172
|
+
if (related.length >= maxResults) {
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (related.length >= maxResults) {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
for (const candidate of lookupImporters(seed, lookup)) {
|
|
180
|
+
if (candidate.relativePath !== seed.relativePath && importsFile(candidate, seed)) {
|
|
181
|
+
related.push(candidate);
|
|
182
|
+
}
|
|
183
|
+
if (related.length >= maxResults) {
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (related.length >= maxResults) {
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
for (const candidate of lookupCallGraphRelated(seed, lookup)) {
|
|
191
|
+
if (candidate.relativePath !== seed.relativePath) {
|
|
192
|
+
related.push(candidate);
|
|
193
|
+
}
|
|
194
|
+
if (related.length >= maxResults) {
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return uniqueByPath(related);
|
|
200
|
+
}
|
|
201
|
+
function buildDependencyLookup(files) {
|
|
202
|
+
const byBaseName = new Map();
|
|
203
|
+
const byImportBaseName = new Map();
|
|
204
|
+
const bySymbolName = new Map();
|
|
205
|
+
const byCallName = new Map();
|
|
206
|
+
for (const file of files) {
|
|
207
|
+
addToMap(byBaseName, fileBaseName(file.relativePath), file);
|
|
208
|
+
for (const importSource of file.imports) {
|
|
209
|
+
addToMap(byImportBaseName, importBaseName(importSource), file);
|
|
210
|
+
}
|
|
211
|
+
for (const symbol of file.symbols) {
|
|
212
|
+
addToMap(bySymbolName, normalizeGraphName(symbol.name), file);
|
|
213
|
+
}
|
|
214
|
+
for (const call of file.calls ?? []) {
|
|
215
|
+
addToMap(byCallName, normalizeGraphName(call), file);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return { byBaseName, byImportBaseName, bySymbolName, byCallName };
|
|
219
|
+
}
|
|
220
|
+
function lookupImportTargets(seed, lookup) {
|
|
221
|
+
const candidates = [];
|
|
222
|
+
for (const importSource of seed.imports) {
|
|
223
|
+
candidates.push(...(lookup.byBaseName.get(importBaseName(importSource)) ?? []));
|
|
224
|
+
}
|
|
225
|
+
return uniqueByPath(candidates);
|
|
226
|
+
}
|
|
227
|
+
function lookupImporters(seed, lookup) {
|
|
228
|
+
return lookup.byImportBaseName.get(fileBaseName(seed.relativePath)) ?? [];
|
|
229
|
+
}
|
|
230
|
+
function lookupCallGraphRelated(seed, lookup) {
|
|
231
|
+
const candidates = [];
|
|
232
|
+
for (const call of seed.calls ?? []) {
|
|
233
|
+
candidates.push(...(lookup.bySymbolName.get(normalizeGraphName(call)) ?? []));
|
|
234
|
+
}
|
|
235
|
+
for (const symbol of seed.symbols) {
|
|
236
|
+
candidates.push(...(lookup.byCallName.get(normalizeGraphName(symbol.name)) ?? []));
|
|
237
|
+
}
|
|
238
|
+
return uniqueByPath(candidates);
|
|
239
|
+
}
|
|
240
|
+
function normalizeGraphName(name) {
|
|
241
|
+
const parts = name.split(/\.|::|->/).filter(Boolean);
|
|
242
|
+
return (0, text_1.normalizeText)(parts[parts.length - 1] ?? name);
|
|
243
|
+
}
|
|
244
|
+
function addToMap(map, key, file) {
|
|
245
|
+
if (!key) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const files = map.get(key) ?? [];
|
|
249
|
+
files.push(file);
|
|
250
|
+
map.set(key, files);
|
|
251
|
+
}
|
|
252
|
+
function fileBaseName(relativePath) {
|
|
253
|
+
return path.posix.basename(relativePath.replace(/\\/g, "/").replace(/\.[^.]+$/, "")).toLowerCase();
|
|
254
|
+
}
|
|
255
|
+
function importBaseName(importSource) {
|
|
256
|
+
return path.posix.basename(importSource.replace(/\\/g, "/").replace(/\.[^.]+$/, "")).toLowerCase();
|
|
257
|
+
}
|
|
258
|
+
function importsFile(source, target) {
|
|
259
|
+
return source.imports.some((importSource) => (0, dependencyExtractor_1.fileMatchesImport)(target.relativePath, importSource));
|
|
260
|
+
}
|
|
261
|
+
function uniqueByPath(files) {
|
|
262
|
+
const seen = new Set();
|
|
263
|
+
const result = [];
|
|
264
|
+
for (const file of files) {
|
|
265
|
+
if (!seen.has(file.relativePath)) {
|
|
266
|
+
seen.add(file.relativePath);
|
|
267
|
+
result.push(file);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
async function clearNodeWorkspaceIndex(rootPath) {
|
|
273
|
+
try {
|
|
274
|
+
await fs.rm(cachePath(rootPath), { force: true });
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// Cache may not exist.
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
async function indexFile(discovered, prior, config) {
|
|
281
|
+
if (!(0, text_1.isLikelyTextPath)(discovered.relativePath)) {
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
284
|
+
let stat;
|
|
285
|
+
try {
|
|
286
|
+
stat = await fs.stat(discovered.absolutePath);
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
if (stat.size > config.project.maxFileSizeKb * 1024) {
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
if (prior && prior.size === stat.size && prior.mtimeMs === stat.mtimeMs) {
|
|
295
|
+
return { file: prior, reused: true };
|
|
296
|
+
}
|
|
297
|
+
let content;
|
|
298
|
+
try {
|
|
299
|
+
content = await fs.readFile(discovered.absolutePath, "utf8");
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
if (content.includes("\u0000")) {
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
const structuredNodes = extractStructuredNodesForIndex(discovered.relativePath, content);
|
|
308
|
+
const symbols = extractSymbols(structuredNodes);
|
|
309
|
+
const calls = extractCalls(structuredNodes);
|
|
310
|
+
const subsystemTerms = (0, subsystem_1.inferSubsystemTerms)(discovered.relativePath, symbols.map((symbol) => symbol.name));
|
|
311
|
+
return {
|
|
312
|
+
reused: false,
|
|
313
|
+
file: {
|
|
314
|
+
relativePath: discovered.relativePath,
|
|
315
|
+
size: stat.size,
|
|
316
|
+
mtimeMs: stat.mtimeMs,
|
|
317
|
+
language: (0, text_1.languageFromPath)(discovered.relativePath),
|
|
318
|
+
tokenCount: (0, text_1.fastTokenEstimate)(`${discovered.relativePath}\n${content}`),
|
|
319
|
+
tokens: tokenizeForIndex(`${discovered.relativePath}\n${content}\n${symbolText(symbols)}`),
|
|
320
|
+
imports: (0, dependencyExtractor_1.extractImports)(content).map((item) => item.source).slice(0, 50),
|
|
321
|
+
symbols,
|
|
322
|
+
calls,
|
|
323
|
+
subsystem: subsystemTerms[0],
|
|
324
|
+
subsystemTerms
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function scoreIndexedFile(file, terms, profile) {
|
|
329
|
+
const normalizedPath = (0, text_1.normalizeText)(file.relativePath);
|
|
330
|
+
const compactPath = normalizedPath.replace(/[^a-z0-9]+/g, "");
|
|
331
|
+
const normalizedBaseName = (0, text_1.normalizeText)(fileBaseName(file.relativePath));
|
|
332
|
+
const compactBaseName = normalizedBaseName.replace(/[^a-z0-9]+/g, "");
|
|
333
|
+
const tokenSet = new Set(file.tokens);
|
|
334
|
+
const imports = file.imports.map(text_1.normalizeText).join("\n");
|
|
335
|
+
const symbolNames = file.symbols.map((symbol) => (0, text_1.normalizeText)(symbol.name));
|
|
336
|
+
const callNames = (file.calls ?? []).map(text_1.normalizeText);
|
|
337
|
+
const subsystemTerms = file.subsystemTerms ?? [];
|
|
338
|
+
const taskSubsystems = (0, subsystem_1.inferTaskSubsystemTerms)(profile);
|
|
339
|
+
let score = 0;
|
|
340
|
+
for (const term of terms) {
|
|
341
|
+
const normalizedTerm = (0, text_1.normalizeText)(term.term);
|
|
342
|
+
const compactTerm = normalizedTerm.replace(/[^a-z0-9]+/g, "");
|
|
343
|
+
if (normalizedPath.includes(normalizedTerm)) {
|
|
344
|
+
score += 6 * term.weight;
|
|
345
|
+
}
|
|
346
|
+
if (compactTerm.length >= 5 && compactBaseName.includes(compactTerm)) {
|
|
347
|
+
score += 18 * term.weight;
|
|
348
|
+
}
|
|
349
|
+
if (compactTerm.length >= 5 && compactPath.includes(compactTerm)) {
|
|
350
|
+
score += 8 * term.weight;
|
|
351
|
+
}
|
|
352
|
+
if (tokenSet.has(normalizedTerm)) {
|
|
353
|
+
score += 5 * term.weight;
|
|
354
|
+
}
|
|
355
|
+
if (imports.includes(normalizedTerm)) {
|
|
356
|
+
score += 2 * term.weight;
|
|
357
|
+
}
|
|
358
|
+
if (symbolNames.some((symbol) => symbol === normalizedTerm || symbol.includes(normalizedTerm))) {
|
|
359
|
+
score += 5 * term.weight;
|
|
360
|
+
}
|
|
361
|
+
if (callNames.some((call) => call === normalizedTerm || call.includes(normalizedTerm))) {
|
|
362
|
+
score += 3 * term.weight;
|
|
363
|
+
}
|
|
364
|
+
if (subsystemTerms.some((subsystem) => subsystem === normalizedTerm || subsystem.includes(normalizedTerm))) {
|
|
365
|
+
score += 4 * term.weight;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const subsystemMatches = subsystemTerms.filter((subsystem) => taskSubsystems.some((taskSubsystem) => subsystem === taskSubsystem || subsystem.includes(taskSubsystem) || taskSubsystem.includes(subsystem)));
|
|
369
|
+
if (subsystemMatches.length > 0) {
|
|
370
|
+
score += 4 + Math.min(10, subsystemMatches.length * 4);
|
|
371
|
+
}
|
|
372
|
+
if (wantsSourceCode(profile) && /(^|\/)src\//.test(file.relativePath.replace(/\\/g, "/"))) {
|
|
373
|
+
score += 14;
|
|
374
|
+
}
|
|
375
|
+
if (score <= 0) {
|
|
376
|
+
return 0;
|
|
377
|
+
}
|
|
378
|
+
return Math.max(0, score + pathQualityModifier(file.relativePath));
|
|
379
|
+
}
|
|
380
|
+
function wantsSourceCode(profile) {
|
|
381
|
+
return /\b(source\s+code|source|src|implementation)\b/.test(profile.normalizedTask);
|
|
382
|
+
}
|
|
383
|
+
function pathQualityModifier(relativePath) {
|
|
384
|
+
const normalizedPath = relativePath.replace(/\\/g, "/").toLowerCase();
|
|
385
|
+
let modifier = 0;
|
|
386
|
+
if (/(^|\/)(src|app|lib|server|backend|frontend|packages|modules|routes|database|resources)(\/|$)/.test(normalizedPath)) {
|
|
387
|
+
modifier += 5;
|
|
388
|
+
}
|
|
389
|
+
if (/(controller|handler|service|repository|model|route|router|worker|job|listener|command|resolver|middleware|policy|request|resource)/.test(normalizedPath)) {
|
|
390
|
+
modifier += 8;
|
|
391
|
+
}
|
|
392
|
+
if (/(^|\/)(tests?|specs?|__tests__)(\/|$)|\.(test|spec)\./.test(normalizedPath)) {
|
|
393
|
+
modifier += 4;
|
|
394
|
+
}
|
|
395
|
+
if (/(^|\/)(node_modules|vendor|dist|build|out|coverage|cache|tmp|temp|storage\/framework|target|\.next|\.nuxt|\.svelte-kit)(\/|$)/.test(normalizedPath)) {
|
|
396
|
+
modifier -= 40;
|
|
397
|
+
}
|
|
398
|
+
if (/(^|\/)\.flowseeker(\/|$)|(^|\/)_gen[^/]*\.(py|sh)$|(^|\/)_bulk_write\.js$/.test(normalizedPath)) {
|
|
399
|
+
modifier -= 80;
|
|
400
|
+
}
|
|
401
|
+
if (/(^|\/)(__generated__|generated|gen|codegen|autogen|snapshots?|__snapshots__|fixtures?|mocks?)(\/|$)|\.generated\.|\.(pb\.go|pb\.cc|pb\.h|pb\.rs|pb\.swift)$|_pb2(_grpc)?\.py$|\.snap$/.test(normalizedPath)) {
|
|
402
|
+
modifier -= 34;
|
|
403
|
+
}
|
|
404
|
+
if (/(^|\/)(public|assets?|static|dashboard\/plugins|plugins|themes?)(\/|$)/.test(normalizedPath)) {
|
|
405
|
+
modifier -= 22;
|
|
406
|
+
}
|
|
407
|
+
if (/(\.min\.(js|css)$|\.(bundle|chunk)\.(js|css)$|jquery|bootstrap|datatables|select2|moment|chart(\.|js)|ckeditor|tinymce|sweetalert|slick|swiper)/.test(normalizedPath)) {
|
|
408
|
+
modifier -= 24;
|
|
409
|
+
}
|
|
410
|
+
if (/(package-lock\.json|pnpm-lock\.yaml|yarn\.lock|composer\.lock|poetry\.lock|cargo\.lock)$/.test(normalizedPath)) {
|
|
411
|
+
modifier -= 40;
|
|
412
|
+
}
|
|
413
|
+
return modifier;
|
|
414
|
+
}
|
|
415
|
+
function tokenizeForIndex(text) {
|
|
416
|
+
const spaced = text.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ");
|
|
417
|
+
const normalized = (0, text_1.normalizeText)(spaced);
|
|
418
|
+
const tokens = new Set();
|
|
419
|
+
const pattern = /[a-z0-9]{2,}/g;
|
|
420
|
+
const orderedTokens = [];
|
|
421
|
+
let match = pattern.exec(normalized);
|
|
422
|
+
while (match && tokens.size < tokenLimitPerFile) {
|
|
423
|
+
tokens.add(match[0]);
|
|
424
|
+
orderedTokens.push(match[0]);
|
|
425
|
+
match = pattern.exec(normalized);
|
|
426
|
+
}
|
|
427
|
+
for (let index = 0; index < orderedTokens.length - 1 && tokens.size < tokenLimitPerFile; index += 1) {
|
|
428
|
+
tokens.add(`${orderedTokens[index]}_${orderedTokens[index + 1]}`);
|
|
429
|
+
}
|
|
430
|
+
for (let index = 0; index < orderedTokens.length - 2 && tokens.size < tokenLimitPerFile; index += 1) {
|
|
431
|
+
tokens.add(`${orderedTokens[index]}_${orderedTokens[index + 1]}_${orderedTokens[index + 2]}`);
|
|
432
|
+
}
|
|
433
|
+
return Array.from(tokens);
|
|
434
|
+
}
|
|
435
|
+
function extractStructuredNodesForIndex(relativePath, content) {
|
|
436
|
+
const language = (0, structuredExtractor_1.detectLanguage)(relativePath);
|
|
437
|
+
if (!language) {
|
|
438
|
+
return [];
|
|
439
|
+
}
|
|
440
|
+
return (0, structuredExtractor_1.extractStructuredNodes)(content.slice(0, 200000), language);
|
|
441
|
+
}
|
|
442
|
+
function extractSymbols(nodes) {
|
|
443
|
+
return nodes
|
|
444
|
+
.filter((node) => node.kind === "declaration" && node.name)
|
|
445
|
+
.slice(0, 80)
|
|
446
|
+
.map((node) => ({
|
|
447
|
+
name: node.name ?? "",
|
|
448
|
+
kind: "declaration",
|
|
449
|
+
line: node.range.startLine,
|
|
450
|
+
exported: node.parent === "exported"
|
|
451
|
+
}));
|
|
452
|
+
}
|
|
453
|
+
function extractCalls(nodes) {
|
|
454
|
+
const calls = nodes
|
|
455
|
+
.filter((node) => node.kind === "call" && node.name)
|
|
456
|
+
.map((node) => normalizeGraphName(node.name ?? ""))
|
|
457
|
+
.filter((name) => name && !commonCallNames.has(name));
|
|
458
|
+
return Array.from(new Set(calls)).slice(0, 120);
|
|
459
|
+
}
|
|
460
|
+
const commonCallNames = new Set([
|
|
461
|
+
"if",
|
|
462
|
+
"for",
|
|
463
|
+
"while",
|
|
464
|
+
"switch",
|
|
465
|
+
"catch",
|
|
466
|
+
"return",
|
|
467
|
+
"typeof",
|
|
468
|
+
"sizeof",
|
|
469
|
+
"console",
|
|
470
|
+
"log",
|
|
471
|
+
"map",
|
|
472
|
+
"filter",
|
|
473
|
+
"reduce",
|
|
474
|
+
"then",
|
|
475
|
+
"catch",
|
|
476
|
+
"finally"
|
|
477
|
+
]);
|
|
478
|
+
function symbolText(symbols) {
|
|
479
|
+
return symbols.map((symbol) => symbol.name).join("\n");
|
|
480
|
+
}
|
|
481
|
+
function formatProgressPath(relativePath) {
|
|
482
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
483
|
+
return normalized.length > 96 ? `...${normalized.slice(-93)}` : normalized;
|
|
484
|
+
}
|
|
485
|
+
function yieldToHost() {
|
|
486
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
487
|
+
}
|
|
488
|
+
async function readIndex(rootPath) {
|
|
489
|
+
try {
|
|
490
|
+
const text = await fs.readFile(cachePath(rootPath), "utf8");
|
|
491
|
+
const parsed = JSON.parse(text);
|
|
492
|
+
if (parsed.version !== indexVersion || parsed.rootPath !== path.resolve(rootPath)) {
|
|
493
|
+
return undefined;
|
|
494
|
+
}
|
|
495
|
+
return parsed;
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
return undefined;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
async function writeIndex(rootPath, index) {
|
|
502
|
+
const filePath = cachePath(rootPath);
|
|
503
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
504
|
+
await fs.writeFile(filePath, JSON.stringify(index), "utf8");
|
|
505
|
+
}
|
|
506
|
+
function cachePath(rootPath) {
|
|
507
|
+
return path.join(path.resolve(rootPath), ".flowseeker", "cache", "workspace-index.json");
|
|
508
|
+
}
|
|
509
|
+
function fingerprintConfig(config) {
|
|
510
|
+
return JSON.stringify({
|
|
511
|
+
include: config.project.include,
|
|
512
|
+
exclude: config.project.exclude,
|
|
513
|
+
maxFileSizeKb: config.project.maxFileSizeKb,
|
|
514
|
+
tokenLimitPerFile,
|
|
515
|
+
indexVersion
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
//# sourceMappingURL=workspaceIndex.js.map
|
|
@@ -0,0 +1,154 @@
|
|
|
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.loadMcpServerConfigs = loadMcpServerConfigs;
|
|
37
|
+
const fs = __importStar(require("fs/promises"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const vscode = __importStar(require("vscode"));
|
|
40
|
+
async function loadMcpServerConfigs() {
|
|
41
|
+
const configured = readConfiguredServers();
|
|
42
|
+
const workspace = await readWorkspaceMcpServers();
|
|
43
|
+
return dedupeServers([...configured, ...workspace]).filter(isValidServerConfig);
|
|
44
|
+
}
|
|
45
|
+
function readConfiguredServers() {
|
|
46
|
+
const value = vscode.workspace.getConfiguration("flowseeker").get("mcp.servers", []);
|
|
47
|
+
if (!Array.isArray(value)) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
return value.flatMap((item) => normalizeServerEntry(undefined, item));
|
|
51
|
+
}
|
|
52
|
+
async function readWorkspaceMcpServers() {
|
|
53
|
+
const folders = vscode.workspace.workspaceFolders;
|
|
54
|
+
if (!folders?.[0]) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const configPath = path.join(folders[0].uri.fsPath, ".vscode", "mcp.json");
|
|
58
|
+
let text;
|
|
59
|
+
try {
|
|
60
|
+
text = await fs.readFile(configPath, "utf8");
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(text);
|
|
67
|
+
if (!isObject(parsed)) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const rawServers = parsed.servers;
|
|
71
|
+
if (Array.isArray(rawServers)) {
|
|
72
|
+
return rawServers.flatMap((item) => normalizeServerEntry(undefined, item));
|
|
73
|
+
}
|
|
74
|
+
if (isObject(rawServers)) {
|
|
75
|
+
return Object.entries(rawServers).flatMap(([name, item]) => normalizeServerEntry(name, item));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
function normalizeServerEntry(nameFromKey, value) {
|
|
84
|
+
if (!isObject(value)) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
const name = stringValue(value.name) ?? nameFromKey;
|
|
88
|
+
if (!name) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const hasUrl = Boolean(stringValue(value.url) ?? stringValue(value.uri));
|
|
92
|
+
const type = stringValue(value.type) === "http" || hasUrl ? "http" : "stdio";
|
|
93
|
+
return [{
|
|
94
|
+
name,
|
|
95
|
+
type,
|
|
96
|
+
enabled: value.enabled === false ? false : true,
|
|
97
|
+
command: stringValue(value.command),
|
|
98
|
+
args: arrayOfStrings(value.args),
|
|
99
|
+
cwd: stringValue(value.cwd),
|
|
100
|
+
env: objectOfPrimitiveEnv(value.env),
|
|
101
|
+
url: stringValue(value.url) ?? stringValue(value.uri),
|
|
102
|
+
headers: objectOfStrings(value.headers),
|
|
103
|
+
version: stringValue(value.version)
|
|
104
|
+
}];
|
|
105
|
+
}
|
|
106
|
+
function isValidServerConfig(server) {
|
|
107
|
+
if (!server.name.trim()) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
if (server.enabled === false) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return server.type === "http" ? Boolean(server.url?.trim()) : Boolean(server.command?.trim());
|
|
114
|
+
}
|
|
115
|
+
function dedupeServers(servers) {
|
|
116
|
+
const seen = new Set();
|
|
117
|
+
const result = [];
|
|
118
|
+
for (const server of servers) {
|
|
119
|
+
const key = server.name.toLowerCase();
|
|
120
|
+
if (seen.has(key)) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
seen.add(key);
|
|
124
|
+
result.push(server);
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
function stringValue(value) {
|
|
129
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
130
|
+
}
|
|
131
|
+
function arrayOfStrings(value) {
|
|
132
|
+
if (!Array.isArray(value)) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
return value.filter((item) => typeof item === "string");
|
|
136
|
+
}
|
|
137
|
+
function objectOfStrings(value) {
|
|
138
|
+
if (!isObject(value)) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
|
|
142
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
143
|
+
}
|
|
144
|
+
function objectOfPrimitiveEnv(value) {
|
|
145
|
+
if (!isObject(value)) {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
const entries = Object.entries(value).filter((entry) => (typeof entry[1] === "string" || typeof entry[1] === "number" || entry[1] === null));
|
|
149
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
150
|
+
}
|
|
151
|
+
function isObject(value) {
|
|
152
|
+
return typeof value === "object" && value !== null;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=mcpConfig.js.map
|