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.
Files changed (82) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/COMPATIBILITY.md +281 -0
  3. package/LICENSE +21 -0
  4. package/README.md +375 -0
  5. package/dist/adapters/frameworkEdges.js +586 -0
  6. package/dist/agent/approvalPolicy.js +81 -0
  7. package/dist/agent/commandRunner.js +166 -0
  8. package/dist/agent/flowCommandRunner.js +124 -0
  9. package/dist/agent/mcpToolRunner.js +167 -0
  10. package/dist/auth/githubAuth.js +71 -0
  11. package/dist/auth/modelList.js +127 -0
  12. package/dist/auth/oauthHandler.js +377 -0
  13. package/dist/chat/nativeChatParticipant.js +616 -0
  14. package/dist/cli/mcpServer.js +383 -0
  15. package/dist/cli/runEvaluation.js +789 -0
  16. package/dist/cli/runReplay.js +481 -0
  17. package/dist/commands/checkHostCompatibility.js +149 -0
  18. package/dist/commands/copyAgentPrompt.js +52 -0
  19. package/dist/commands/copyContext.js +54 -0
  20. package/dist/commands/explainSelectionRelevance.js +57 -0
  21. package/dist/commands/findRelevantContext.js +127 -0
  22. package/dist/commands/openEvidence.js +49 -0
  23. package/dist/commands/openMcpConfig.js +81 -0
  24. package/dist/commands/openRelatedTests.js +54 -0
  25. package/dist/commands/rebuildIndex.js +45 -0
  26. package/dist/commands/runEvaluationSuite.js +323 -0
  27. package/dist/commands/runReplaySuite.js +228 -0
  28. package/dist/config/defaultConfig.js +72 -0
  29. package/dist/config/loadConfig.js +84 -0
  30. package/dist/config/loadConfigFromPath.js +60 -0
  31. package/dist/extension.js +513 -0
  32. package/dist/gateway/agentPrompts.js +176 -0
  33. package/dist/gateway/aiGateway.js +1255 -0
  34. package/dist/gateway/aiProviders.js +901 -0
  35. package/dist/gateway/contextExpansion.js +331 -0
  36. package/dist/gateway/editProposalStore.js +238 -0
  37. package/dist/gateway/planProposalStore.js +28 -0
  38. package/dist/index/cacheStore.js +51 -0
  39. package/dist/index/chunker.js +45 -0
  40. package/dist/index/dependencyExtractor.js +107 -0
  41. package/dist/index/fileDiscovery.js +177 -0
  42. package/dist/index/structuredExtractor.js +256 -0
  43. package/dist/index/workspaceIndex.js +518 -0
  44. package/dist/mcp/mcpConfig.js +154 -0
  45. package/dist/mcp/mcpProvider.js +109 -0
  46. package/dist/mcp/mcpTools.js +215 -0
  47. package/dist/pipeline/agentPrompt.js +79 -0
  48. package/dist/pipeline/agentPromptHeadless.js +85 -0
  49. package/dist/pipeline/contextBlueprint.js +346 -0
  50. package/dist/pipeline/contextPack.js +80 -0
  51. package/dist/pipeline/diffPreview.js +79 -0
  52. package/dist/pipeline/evaluationMetrics.js +154 -0
  53. package/dist/pipeline/evidenceGraph.js +389 -0
  54. package/dist/pipeline/feedback.js +215 -0
  55. package/dist/pipeline/fileGroups.js +84 -0
  56. package/dist/pipeline/fileScanner.js +866 -0
  57. package/dist/pipeline/nodeScan.js +219 -0
  58. package/dist/pipeline/ranker.js +563 -0
  59. package/dist/pipeline/responseLanguage.js +39 -0
  60. package/dist/pipeline/retrievalPlan.js +163 -0
  61. package/dist/pipeline/runHeadless.js +54 -0
  62. package/dist/pipeline/runPipeline.js +114 -0
  63. package/dist/pipeline/solvePacket.js +382 -0
  64. package/dist/pipeline/subsystem.js +257 -0
  65. package/dist/pipeline/taskUnderstanding.js +453 -0
  66. package/dist/pipeline/tokenSavings.js +146 -0
  67. package/dist/pipeline/universalScan.js +216 -0
  68. package/dist/pipeline/verifyAfterApply.js +233 -0
  69. package/dist/runtime/capabilities.js +71 -0
  70. package/dist/runtime/hostDetect.js +98 -0
  71. package/dist/runtime/hostTier.js +68 -0
  72. package/dist/runtime/statusBar.js +80 -0
  73. package/dist/skills/skillRegistry.js +208 -0
  74. package/dist/types.js +3 -0
  75. package/dist/ui/chatViewProvider.js +3899 -0
  76. package/dist/ui/resultTreeProvider.js +174 -0
  77. package/dist/usage/quotaTracker.js +358 -0
  78. package/dist/utils/async.js +30 -0
  79. package/dist/utils/logger.js +64 -0
  80. package/dist/utils/text.js +364 -0
  81. package/dist/utils/updateChecker.js +140 -0
  82. package/package.json +561 -0
@@ -0,0 +1,377 @@
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.startOAuthFlow = startOAuthFlow;
37
+ exports.handleOAuthCallback = handleOAuthCallback;
38
+ exports.refreshAccessToken = refreshAccessToken;
39
+ exports.getValidAccessToken = getValidAccessToken;
40
+ exports.storeTokens = storeTokens;
41
+ exports.getStoredTokens = getStoredTokens;
42
+ exports.clearTokens = clearTokens;
43
+ exports.hasValidOAuthSession = hasValidOAuthSession;
44
+ const http = __importStar(require("http"));
45
+ const vscode = __importStar(require("vscode"));
46
+ const pendingStateKey = "flowseeker.oauth.pendingState";
47
+ const tokenExpiryKey = (providerId) => `flowseeker.oauth.${providerId}.expiresAt`;
48
+ const accessTokenSecretKey = (providerId) => `flowseeker.oauth.${providerId}.accessToken`;
49
+ const refreshTokenSecretKey = (providerId) => `flowseeker.oauth.${providerId}.refreshToken`;
50
+ const OAUTH_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
51
+ function base64UrlEncode(buffer) {
52
+ const bytes = new Uint8Array(buffer);
53
+ let binary = "";
54
+ for (let i = 0; i < bytes.length; i++) {
55
+ binary += String.fromCharCode(bytes[i]);
56
+ }
57
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
58
+ }
59
+ function generateNonce() {
60
+ const array = new Uint32Array(8);
61
+ crypto.getRandomValues(array);
62
+ return Array.from(array, (n) => n.toString(36)).join("");
63
+ }
64
+ async function generateCodeChallenge(verifier) {
65
+ const encoder = new TextEncoder();
66
+ const digest = await crypto.subtle.digest("SHA-256", encoder.encode(verifier));
67
+ return base64UrlEncode(digest);
68
+ }
69
+ function getRandomPort() {
70
+ return new Promise((resolve, reject) => {
71
+ const server = http.createServer();
72
+ server.listen(0, "127.0.0.1", () => {
73
+ const address = server.address();
74
+ if (address && typeof address === "object") {
75
+ const port = address.port;
76
+ server.close(() => resolve(port));
77
+ }
78
+ else {
79
+ server.close(() => reject(new Error("Failed to get random port.")));
80
+ }
81
+ });
82
+ server.on("error", reject);
83
+ });
84
+ }
85
+ const SUCCESS_HTML = `<!DOCTYPE html>
86
+ <html lang="en">
87
+ <head>
88
+ <meta charset="UTF-8">
89
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
90
+ <title>FlowSeeker - Authenticated</title>
91
+ <style>
92
+ body {
93
+ font-family: system-ui, -apple-system, sans-serif;
94
+ display: flex; justify-content: center; align-items: center;
95
+ height: 100vh; margin: 0;
96
+ background: #0d1117; color: #c9d1d9;
97
+ }
98
+ .card { text-align: center; padding: 40px; }
99
+ .icon { font-size: 48px; margin-bottom: 16px; }
100
+ h1 { font-size: 20px; margin: 0 0 8px; color: #f0f6fc; }
101
+ p { font-size: 14px; color: #8b949e; margin: 0; }
102
+ </style>
103
+ </head>
104
+ <body>
105
+ <div class="card">
106
+ <div class="icon">&#10003;</div>
107
+ <h1>Authenticated successfully</h1>
108
+ <p>You may close this window and return to VS Code.</p>
109
+ </div>
110
+ </body>
111
+ </html>`;
112
+ const ERROR_HTML = (message) => `<!DOCTYPE html>
113
+ <html lang="en">
114
+ <head>
115
+ <meta charset="UTF-8">
116
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
117
+ <title>FlowSeeker - Error</title>
118
+ <style>
119
+ body {
120
+ font-family: system-ui, -apple-system, sans-serif;
121
+ display: flex; justify-content: center; align-items: center;
122
+ height: 100vh; margin: 0;
123
+ background: #0d1117; color: #c9d1d9;
124
+ }
125
+ .card { text-align: center; padding: 40px; }
126
+ .icon { font-size: 48px; margin-bottom: 16px; }
127
+ h1 { font-size: 20px; margin: 0 0 8px; color: #f85149; }
128
+ p { font-size: 14px; color: #8b949e; margin: 0; max-width: 400px; }
129
+ </style>
130
+ </head>
131
+ <body>
132
+ <div class="card">
133
+ <div class="icon">&#10007;</div>
134
+ <h1>Authentication failed</h1>
135
+ <p>${message.replace(/</g, "&lt;").replace(/>/g, "&gt;")}</p>
136
+ </div>
137
+ </body>
138
+ </html>`;
139
+ async function startOAuthFlow(context, config) {
140
+ if (!config.clientId.trim()) {
141
+ throw new Error("OAuth client id is missing. Configure a provider-issued OAuth client before using browser sign-in.");
142
+ }
143
+ if (!config.authorizeUrl.trim() || !config.tokenUrl.trim()) {
144
+ throw new Error("OAuth authorize/token URL is missing.");
145
+ }
146
+ const state = generateNonce();
147
+ const codeVerifier = generateNonce();
148
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
149
+ const pending = { providerId: config.providerId, state, codeVerifier, config };
150
+ await context.globalState.update(pendingStateKey, pending);
151
+ // Start local HTTP server for the callback
152
+ const port = await getRandomPort();
153
+ const redirectUri = `http://127.0.0.1:${port}/callback`;
154
+ pending.config = { ...config, redirectUri };
155
+ const server = http.createServer(async (req, res) => {
156
+ const url = new URL(req.url ?? "/", `http://127.0.0.1:${port}`);
157
+ if (url.pathname !== "/callback") {
158
+ res.writeHead(404, { "Content-Type": "text/plain" });
159
+ res.end("Not found");
160
+ return;
161
+ }
162
+ const query = url.searchParams;
163
+ const error = query.get("error");
164
+ const code = query.get("code");
165
+ const returnedState = query.get("state");
166
+ try {
167
+ if (error) {
168
+ const desc = query.get("error_description") ?? error;
169
+ res.writeHead(200, { "Content-Type": "text/html" });
170
+ res.end(ERROR_HTML(desc));
171
+ server.closeAllConnections?.() ?? server.close();
172
+ await context.globalState.update(pendingStateKey, undefined);
173
+ await vscode.window.showErrorMessage(`FlowSeeker authentication failed: ${desc}`);
174
+ return;
175
+ }
176
+ if (!code) {
177
+ res.writeHead(200, { "Content-Type": "text/html" });
178
+ res.end(ERROR_HTML("No authorization code received."));
179
+ server.closeAllConnections?.() ?? server.close();
180
+ await context.globalState.update(pendingStateKey, undefined);
181
+ return;
182
+ }
183
+ const stored = context.globalState.get(pendingStateKey);
184
+ if (!stored || returnedState !== stored.state) {
185
+ res.writeHead(200, { "Content-Type": "text/html" });
186
+ res.end(ERROR_HTML("State mismatch. The request may have been tampered with."));
187
+ server.closeAllConnections?.() ?? server.close();
188
+ await context.globalState.update(pendingStateKey, undefined);
189
+ return;
190
+ }
191
+ // Exchange code for tokens
192
+ let tokens;
193
+ try {
194
+ tokens = await exchangeCodeForTokens(stored.config, code, stored.codeVerifier);
195
+ }
196
+ catch (err) {
197
+ const msg = err instanceof Error ? err.message : String(err);
198
+ res.writeHead(200, { "Content-Type": "text/html" });
199
+ res.end(ERROR_HTML(msg));
200
+ server.closeAllConnections?.() ?? server.close();
201
+ await context.globalState.update(pendingStateKey, undefined);
202
+ throw err;
203
+ }
204
+ await storeTokens(context, stored.providerId, tokens);
205
+ await context.globalState.update(pendingStateKey, undefined);
206
+ res.writeHead(200, { "Content-Type": "text/html" });
207
+ res.end(SUCCESS_HTML);
208
+ // Close server after a short delay so the response is sent
209
+ setTimeout(() => {
210
+ server.closeAllConnections?.() ?? server.close();
211
+ }, 500);
212
+ // Notify the extension
213
+ await vscode.commands.executeCommand("flowseeker.oauthComplete", stored.providerId);
214
+ }
215
+ catch (err) {
216
+ const msg = err instanceof Error ? err.message : String(err);
217
+ if (!res.headersSent) {
218
+ res.writeHead(200, { "Content-Type": "text/html" });
219
+ res.end(ERROR_HTML(msg));
220
+ }
221
+ server.closeAllConnections?.() ?? server.close();
222
+ await context.globalState.update(pendingStateKey, undefined);
223
+ }
224
+ });
225
+ server.listen(port, "127.0.0.1", () => {
226
+ // Timeout: close server after 5 minutes if no callback received
227
+ const timeout = setTimeout(() => {
228
+ server.closeAllConnections?.() ?? server.close();
229
+ context.globalState.update(pendingStateKey, undefined);
230
+ }, OAUTH_TIMEOUT_MS);
231
+ server.on("close", () => clearTimeout(timeout));
232
+ });
233
+ const params = new URLSearchParams({
234
+ client_id: config.clientId,
235
+ redirect_uri: redirectUri,
236
+ scope: config.scopes.join(" "),
237
+ response_type: "code",
238
+ state,
239
+ code_challenge: codeChallenge,
240
+ code_challenge_method: "S256"
241
+ });
242
+ const uri = vscode.Uri.parse(`${config.authorizeUrl}?${params.toString()}`);
243
+ await vscode.env.openExternal(uri);
244
+ }
245
+ async function handleOAuthCallback(context, query) {
246
+ const pending = context.globalState.get(pendingStateKey);
247
+ if (!pending) {
248
+ throw new Error("No pending OAuth flow. Please start authorization again.");
249
+ }
250
+ const state = query.get("state");
251
+ const code = query.get("code");
252
+ const error = query.get("error");
253
+ if (error) {
254
+ await context.globalState.update(pendingStateKey, undefined);
255
+ throw new Error(`Authorization failed: ${error}${query.get("error_description") ? ` - ${query.get("error_description")}` : ""}`);
256
+ }
257
+ if (!code) {
258
+ await context.globalState.update(pendingStateKey, undefined);
259
+ throw new Error("No authorization code received.");
260
+ }
261
+ if (state !== pending.state) {
262
+ await context.globalState.update(pendingStateKey, undefined);
263
+ throw new Error("OAuth state mismatch. Request may have been tampered with.");
264
+ }
265
+ let tokens;
266
+ try {
267
+ tokens = await exchangeCodeForTokens(pending.config, code, pending.codeVerifier);
268
+ }
269
+ catch (err) {
270
+ await context.globalState.update(pendingStateKey, undefined);
271
+ throw err;
272
+ }
273
+ await storeTokens(context, pending.providerId, tokens);
274
+ await context.globalState.update(pendingStateKey, undefined);
275
+ return { providerId: pending.providerId, tokens };
276
+ }
277
+ async function exchangeCodeForTokens(config, code, codeVerifier) {
278
+ const body = new URLSearchParams({
279
+ grant_type: "authorization_code",
280
+ code,
281
+ redirect_uri: config.redirectUri,
282
+ client_id: config.clientId,
283
+ code_verifier: codeVerifier
284
+ });
285
+ const response = await fetch(config.tokenUrl, {
286
+ method: "POST",
287
+ headers: { "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json" },
288
+ body: body.toString()
289
+ });
290
+ if (!response.ok) {
291
+ const text = await response.text().catch(() => "");
292
+ throw new Error(`Token exchange failed (${response.status}): ${text.slice(0, 300)}`);
293
+ }
294
+ const data = (await response.json());
295
+ if (!data.access_token) {
296
+ throw new Error("Token response missing access_token.");
297
+ }
298
+ return {
299
+ accessToken: data.access_token,
300
+ refreshToken: data.refresh_token ?? "",
301
+ expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000
302
+ };
303
+ }
304
+ async function refreshAccessToken(context, config) {
305
+ const refreshToken = await context.secrets.get(refreshTokenSecretKey(config.providerId));
306
+ if (!refreshToken) {
307
+ return null;
308
+ }
309
+ const body = new URLSearchParams({
310
+ grant_type: "refresh_token",
311
+ refresh_token: refreshToken,
312
+ client_id: config.clientId
313
+ });
314
+ let response;
315
+ try {
316
+ response = await fetch(config.tokenUrl, {
317
+ method: "POST",
318
+ headers: { "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json" },
319
+ body: body.toString()
320
+ });
321
+ }
322
+ catch {
323
+ return null;
324
+ }
325
+ if (!response.ok) {
326
+ return null;
327
+ }
328
+ const data = (await response.json());
329
+ if (!data.access_token) {
330
+ return null;
331
+ }
332
+ const tokens = {
333
+ accessToken: data.access_token,
334
+ refreshToken: data.refresh_token ?? refreshToken,
335
+ expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000
336
+ };
337
+ await storeTokens(context, config.providerId, tokens);
338
+ return tokens;
339
+ }
340
+ async function getValidAccessToken(context, config) {
341
+ const accessToken = await context.secrets.get(accessTokenSecretKey(config.providerId));
342
+ if (!accessToken) {
343
+ return null;
344
+ }
345
+ const expiresAt = context.globalState.get(tokenExpiryKey(config.providerId));
346
+ if (expiresAt && Date.now() < expiresAt - 60000) {
347
+ return accessToken;
348
+ }
349
+ const refreshed = await refreshAccessToken(context, config);
350
+ return refreshed?.accessToken ?? accessToken;
351
+ }
352
+ async function storeTokens(context, providerId, tokens) {
353
+ await context.secrets.store(accessTokenSecretKey(providerId), tokens.accessToken);
354
+ if (tokens.refreshToken) {
355
+ await context.secrets.store(refreshTokenSecretKey(providerId), tokens.refreshToken);
356
+ }
357
+ await context.globalState.update(tokenExpiryKey(providerId), tokens.expiresAt);
358
+ }
359
+ async function getStoredTokens(context, providerId) {
360
+ const accessToken = await context.secrets.get(accessTokenSecretKey(providerId));
361
+ if (!accessToken) {
362
+ return null;
363
+ }
364
+ const refreshToken = (await context.secrets.get(refreshTokenSecretKey(providerId))) ?? "";
365
+ const expiresAt = context.globalState.get(tokenExpiryKey(providerId)) ?? 0;
366
+ return { accessToken, refreshToken, expiresAt };
367
+ }
368
+ async function clearTokens(context, providerId) {
369
+ await context.secrets.delete(accessTokenSecretKey(providerId));
370
+ await context.secrets.delete(refreshTokenSecretKey(providerId));
371
+ await context.globalState.update(tokenExpiryKey(providerId), undefined);
372
+ }
373
+ async function hasValidOAuthSession(context, providerId) {
374
+ const token = await context.secrets.get(accessTokenSecretKey(providerId));
375
+ return Boolean(token);
376
+ }
377
+ //# sourceMappingURL=oauthHandler.js.map