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,166 @@
|
|
|
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.runAgentCommandProposal = runAgentCommandProposal;
|
|
37
|
+
exports.summarizeAgentCommandRun = summarizeAgentCommandRun;
|
|
38
|
+
exports.formatAgentCommandRunMarkdown = formatAgentCommandRunMarkdown;
|
|
39
|
+
const cp = __importStar(require("child_process"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const vscode = __importStar(require("vscode"));
|
|
42
|
+
const approvalPolicy_1 = require("./approvalPolicy");
|
|
43
|
+
const logger_1 = require("../utils/logger");
|
|
44
|
+
async function runAgentCommandProposal(proposal) {
|
|
45
|
+
const command = proposal.command.trim();
|
|
46
|
+
if (!command) {
|
|
47
|
+
await vscode.window.showWarningMessage("FlowSeeker command proposal is empty.");
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const folders = vscode.workspace.workspaceFolders;
|
|
51
|
+
if (!folders?.[0]) {
|
|
52
|
+
await vscode.window.showWarningMessage("Open a workspace folder before running FlowSeeker agent commands.");
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const classification = (0, approvalPolicy_1.classifyCommand)(command);
|
|
56
|
+
const approved = await confirmCommandIfNeeded(command, classification);
|
|
57
|
+
if (!approved) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const cwd = resolveCommandCwd(folders[0].uri.fsPath, proposal.cwd);
|
|
61
|
+
(0, logger_1.logInfo)(`FlowSeeker agent command started: ${command}`);
|
|
62
|
+
const started = Date.now();
|
|
63
|
+
const result = await execCommand(command, cwd);
|
|
64
|
+
const run = {
|
|
65
|
+
proposal,
|
|
66
|
+
classification,
|
|
67
|
+
cwd,
|
|
68
|
+
...result,
|
|
69
|
+
durationMs: Date.now() - started
|
|
70
|
+
};
|
|
71
|
+
await showCommandResult(run);
|
|
72
|
+
return run;
|
|
73
|
+
}
|
|
74
|
+
function summarizeAgentCommandRun(run) {
|
|
75
|
+
const status = run.exitCode === 0 ? "passed" : run.timedOut ? "timed out" : run.exitCode === null ? "errored" : "failed";
|
|
76
|
+
return `Command ${status}: \`${run.proposal.command}\` (${run.durationMs}ms).`;
|
|
77
|
+
}
|
|
78
|
+
function formatAgentCommandRunMarkdown(run) {
|
|
79
|
+
const lines = [
|
|
80
|
+
`# FlowSeeker Agent Command`,
|
|
81
|
+
"",
|
|
82
|
+
`Command: \`${run.proposal.command}\``,
|
|
83
|
+
`Working directory: \`${run.cwd}\``,
|
|
84
|
+
`Status: ${run.exitCode === 0 ? "PASS" : run.timedOut ? "TIMEOUT" : run.exitCode === null ? "ERROR" : "FAIL"}`,
|
|
85
|
+
`Exit code: ${run.exitCode ?? "n/a"}`,
|
|
86
|
+
`Duration: ${run.durationMs}ms`,
|
|
87
|
+
`Safety: ${run.classification.reason}`,
|
|
88
|
+
""
|
|
89
|
+
];
|
|
90
|
+
if (run.proposal.rationale) {
|
|
91
|
+
lines.push("## Rationale", "", run.proposal.rationale, "");
|
|
92
|
+
}
|
|
93
|
+
if (run.stdout) {
|
|
94
|
+
lines.push("## Stdout", "", "```", truncate(run.stdout, 12000), "```", "");
|
|
95
|
+
}
|
|
96
|
+
if (run.stderr) {
|
|
97
|
+
lines.push("## Stderr", "", "```", truncate(run.stderr, 6000), "```", "");
|
|
98
|
+
}
|
|
99
|
+
if (!run.stdout && !run.stderr) {
|
|
100
|
+
lines.push("No output was produced.", "");
|
|
101
|
+
}
|
|
102
|
+
return lines.join("\n");
|
|
103
|
+
}
|
|
104
|
+
async function confirmCommandIfNeeded(command, classification) {
|
|
105
|
+
if (classification.destructive) {
|
|
106
|
+
const action = await vscode.window.showWarningMessage(`FlowSeeker classified this command as destructive: ${command}`, { modal: true, detail: classification.reason }, "Run Anyway", "Cancel");
|
|
107
|
+
return action === "Run Anyway";
|
|
108
|
+
}
|
|
109
|
+
const kind = classification.safe ? "safe_command" : "all_command";
|
|
110
|
+
if ((0, approvalPolicy_1.canAutoApprove)(kind)) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
const action = await vscode.window.showInformationMessage(`Run FlowSeeker agent command?\n${command}`, { modal: true, detail: classification.reason }, "Run", "Cancel");
|
|
114
|
+
return action === "Run";
|
|
115
|
+
}
|
|
116
|
+
function execCommand(command, cwd) {
|
|
117
|
+
return new Promise((resolve) => {
|
|
118
|
+
const child = cp.exec(command, {
|
|
119
|
+
cwd,
|
|
120
|
+
timeout: 120000,
|
|
121
|
+
windowsHide: true,
|
|
122
|
+
env: { ...process.env, FORCE_COLOR: "0", CI: "true" },
|
|
123
|
+
maxBuffer: 1024 * 1024
|
|
124
|
+
}, (error, stdout, stderr) => {
|
|
125
|
+
const execError = error;
|
|
126
|
+
resolve({
|
|
127
|
+
exitCode: execError?.code ?? 0,
|
|
128
|
+
stdout: stdout.trim(),
|
|
129
|
+
stderr: stderr.trim(),
|
|
130
|
+
timedOut: Boolean(execError?.killed)
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
child.on("error", (error) => {
|
|
134
|
+
resolve({
|
|
135
|
+
exitCode: null,
|
|
136
|
+
stdout: "",
|
|
137
|
+
stderr: error.message,
|
|
138
|
+
timedOut: false
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function resolveCommandCwd(workspaceRoot, requestedCwd) {
|
|
144
|
+
if (!requestedCwd?.trim()) {
|
|
145
|
+
return workspaceRoot;
|
|
146
|
+
}
|
|
147
|
+
const candidate = path.isAbsolute(requestedCwd)
|
|
148
|
+
? path.normalize(requestedCwd)
|
|
149
|
+
: path.normalize(path.join(workspaceRoot, requestedCwd));
|
|
150
|
+
const relative = path.relative(workspaceRoot, candidate);
|
|
151
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
152
|
+
throw new Error(`Refusing to run command outside the workspace: ${requestedCwd}`);
|
|
153
|
+
}
|
|
154
|
+
return candidate;
|
|
155
|
+
}
|
|
156
|
+
async function showCommandResult(run) {
|
|
157
|
+
const document = await vscode.workspace.openTextDocument({
|
|
158
|
+
content: formatAgentCommandRunMarkdown(run),
|
|
159
|
+
language: "markdown"
|
|
160
|
+
});
|
|
161
|
+
await vscode.window.showTextDocument(document, { preview: true, viewColumn: vscode.ViewColumn.Beside });
|
|
162
|
+
}
|
|
163
|
+
function truncate(value, maxLength) {
|
|
164
|
+
return value.length > maxLength ? `${value.slice(0, maxLength)}\n... (truncated)` : value;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=commandRunner.js.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runFlowCommand = runFlowCommand;
|
|
4
|
+
exports.commandToMode = commandToMode;
|
|
5
|
+
const agentPrompts_1 = require("../gateway/agentPrompts");
|
|
6
|
+
const runPipeline_1 = require("../pipeline/runPipeline");
|
|
7
|
+
const logger_1 = require("../utils/logger");
|
|
8
|
+
const contextExpansion_1 = require("../gateway/contextExpansion");
|
|
9
|
+
async function runFlowCommand(command, task, gateway, resultProvider, planStore, editStore, callbacks, token, approvedPlan) {
|
|
10
|
+
const mode = command === "auto" ? "auto" : "guide";
|
|
11
|
+
try {
|
|
12
|
+
(0, logger_1.logInfo)(`FlowSeeker ${command} started: ${task}`);
|
|
13
|
+
callbacks.onProgress("Finding relevant files...");
|
|
14
|
+
const result = await (0, runPipeline_1.runFlowSeeker)(task, {
|
|
15
|
+
token,
|
|
16
|
+
progress: { report: (msg) => callbacks.onProgress(msg.message ?? String(msg)) }
|
|
17
|
+
});
|
|
18
|
+
resultProvider.setResult(result);
|
|
19
|
+
callbacks.onRetrievalComplete(result);
|
|
20
|
+
const connection = await gateway.getConnection();
|
|
21
|
+
// If there's an approved plan, generate edits from it
|
|
22
|
+
if (approvedPlan && connection.connected) {
|
|
23
|
+
const providerLabel = connection.providerLabel ?? connection.provider ?? "AI provider";
|
|
24
|
+
callbacks.onProviderAsking(providerLabel, connection.model);
|
|
25
|
+
const answer = await gateway.askWithInstruction(result, "auto", (0, agentPrompts_1.createApprovedEditInstruction)(approvedPlan), { stage: "approved_edits", approvedPlan });
|
|
26
|
+
if (answer.edits?.length) {
|
|
27
|
+
const editId = editStore.store(answer.edits);
|
|
28
|
+
callbacks.onComplete({
|
|
29
|
+
mode: "auto",
|
|
30
|
+
result,
|
|
31
|
+
answer,
|
|
32
|
+
editProposalId: editId
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
mode: "auto",
|
|
36
|
+
result,
|
|
37
|
+
answer,
|
|
38
|
+
editProposalId: editId
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
callbacks.onComplete({
|
|
42
|
+
mode: "auto",
|
|
43
|
+
result,
|
|
44
|
+
answer,
|
|
45
|
+
error: "The AI provider did not return structured edits.",
|
|
46
|
+
needsMoreContext: (0, contextExpansion_1.isMissingContextRequest)(answer.message)
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
mode: "auto",
|
|
50
|
+
result,
|
|
51
|
+
answer,
|
|
52
|
+
error: "The AI provider did not return structured edits.",
|
|
53
|
+
needsMoreContext: (0, contextExpansion_1.isMissingContextRequest)(answer.message)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (!connection.connected) {
|
|
57
|
+
callbacks.onComplete({
|
|
58
|
+
mode,
|
|
59
|
+
result,
|
|
60
|
+
error: "No AI provider connected. Configure one or use Copy Agent Prompt."
|
|
61
|
+
});
|
|
62
|
+
return { mode, result, error: "No AI provider connected." };
|
|
63
|
+
}
|
|
64
|
+
const providerLabel = connection.providerLabel ?? connection.provider ?? "AI provider";
|
|
65
|
+
callbacks.onProviderAsking(providerLabel, connection.model);
|
|
66
|
+
const answer = await gateway.ask(result, mode);
|
|
67
|
+
if (mode === "auto" && (0, contextExpansion_1.isReviewablePlan)(answer.message)) {
|
|
68
|
+
const planId = planStore.store(result, answer.message);
|
|
69
|
+
callbacks.onComplete({
|
|
70
|
+
mode,
|
|
71
|
+
result,
|
|
72
|
+
answer,
|
|
73
|
+
planText: answer.message,
|
|
74
|
+
planProposalId: planId,
|
|
75
|
+
isApprovablePlan: true
|
|
76
|
+
});
|
|
77
|
+
return {
|
|
78
|
+
mode,
|
|
79
|
+
result,
|
|
80
|
+
answer,
|
|
81
|
+
planText: answer.message,
|
|
82
|
+
planProposalId: planId,
|
|
83
|
+
isApprovablePlan: true
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (answer.edits?.length) {
|
|
87
|
+
const editId = editStore.store(answer.edits);
|
|
88
|
+
callbacks.onComplete({
|
|
89
|
+
mode,
|
|
90
|
+
result,
|
|
91
|
+
answer,
|
|
92
|
+
editProposalId: editId
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
mode,
|
|
96
|
+
result,
|
|
97
|
+
answer,
|
|
98
|
+
editProposalId: editId
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
callbacks.onComplete({
|
|
102
|
+
mode,
|
|
103
|
+
result,
|
|
104
|
+
answer,
|
|
105
|
+
needsMoreContext: (0, contextExpansion_1.isMissingContextRequest)(answer.message)
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
mode,
|
|
109
|
+
result,
|
|
110
|
+
answer,
|
|
111
|
+
needsMoreContext: (0, contextExpansion_1.isMissingContextRequest)(answer.message)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
(0, logger_1.logError)(`FlowSeeker ${command} failed.`, error);
|
|
116
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
117
|
+
callbacks.onComplete({ mode, result: undefined, error: message });
|
|
118
|
+
return { mode, result: undefined, error: message };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function commandToMode(command) {
|
|
122
|
+
return command === "auto" ? "auto" : "guide";
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=flowCommandRunner.js.map
|
|
@@ -0,0 +1,167 @@
|
|
|
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.runMcpToolProposal = runMcpToolProposal;
|
|
37
|
+
exports.summarizeMcpToolRun = summarizeMcpToolRun;
|
|
38
|
+
exports.availableToolNames = availableToolNames;
|
|
39
|
+
const vscode = __importStar(require("vscode"));
|
|
40
|
+
const approvalPolicy_1 = require("./approvalPolicy");
|
|
41
|
+
const capabilities_1 = require("../runtime/capabilities");
|
|
42
|
+
const logger_1 = require("../utils/logger");
|
|
43
|
+
async function runMcpToolProposal(proposal) {
|
|
44
|
+
const toolName = proposal.tool.trim();
|
|
45
|
+
if (!toolName) {
|
|
46
|
+
await vscode.window.showWarningMessage("FlowSeeker MCP tool proposal is empty.");
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const candidate = vscode;
|
|
50
|
+
const capabilities = (0, capabilities_1.getHostCapabilities)();
|
|
51
|
+
if (!capabilities.hasLanguageModelTools || typeof candidate.lm?.invokeTool !== "function") {
|
|
52
|
+
await vscode.window.showWarningMessage("This editor host does not expose the VS Code Language Model tool API to FlowSeeker.");
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const tool = findTool(toolName, candidate.lm?.tools ?? []);
|
|
56
|
+
if (!tool) {
|
|
57
|
+
await vscode.window.showWarningMessage(`MCP/tool '${toolName}' is not available in this editor. Check FlowSeeker MCP config or host compatibility.`);
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const approved = await confirmToolIfNeeded(tool.name, proposal);
|
|
61
|
+
if (!approved) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
(0, logger_1.logInfo)(`FlowSeeker MCP/tool invocation started: ${tool.name}`);
|
|
65
|
+
const started = Date.now();
|
|
66
|
+
try {
|
|
67
|
+
const result = await candidate.lm.invokeTool(tool.name, {
|
|
68
|
+
input: proposal.input ?? {},
|
|
69
|
+
toolInvocationToken: undefined
|
|
70
|
+
}, undefined);
|
|
71
|
+
const run = {
|
|
72
|
+
proposal,
|
|
73
|
+
toolName: tool.name,
|
|
74
|
+
durationMs: Date.now() - started,
|
|
75
|
+
resultText: toolResultToText(result)
|
|
76
|
+
};
|
|
77
|
+
await showToolResult(run);
|
|
78
|
+
return run;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
(0, logger_1.logError)(`FlowSeeker MCP/tool invocation failed: ${tool.name}`, error);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function summarizeMcpToolRun(run) {
|
|
86
|
+
return `MCP/tool completed: \`${run.toolName}\` (${run.durationMs}ms).`;
|
|
87
|
+
}
|
|
88
|
+
function availableToolNames() {
|
|
89
|
+
const candidate = vscode;
|
|
90
|
+
return [...(candidate.lm?.tools ?? [])].map((tool) => tool.name).sort((left, right) => left.localeCompare(right));
|
|
91
|
+
}
|
|
92
|
+
function findTool(name, tools) {
|
|
93
|
+
const normalized = name.toLowerCase();
|
|
94
|
+
return tools.find((tool) => tool.name.toLowerCase() === normalized)
|
|
95
|
+
?? tools.find((tool) => tool.name.toLowerCase().endsWith(`.${normalized}`))
|
|
96
|
+
?? tools.find((tool) => tool.name.toLowerCase().endsWith(`_${normalized}`));
|
|
97
|
+
}
|
|
98
|
+
async function confirmToolIfNeeded(toolName, proposal) {
|
|
99
|
+
if ((0, approvalPolicy_1.canAutoApprove)("mcp_tool")) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
const action = await vscode.window.showInformationMessage(`Invoke FlowSeeker MCP/tool?\n${toolName}`, {
|
|
103
|
+
modal: true,
|
|
104
|
+
detail: proposal.rationale ?? "FlowSeeker will invoke this tool through VS Code's Language Model tool API."
|
|
105
|
+
}, "Invoke", "Cancel");
|
|
106
|
+
return action === "Invoke";
|
|
107
|
+
}
|
|
108
|
+
async function showToolResult(run) {
|
|
109
|
+
const document = await vscode.workspace.openTextDocument({
|
|
110
|
+
content: formatMcpToolRunMarkdown(run),
|
|
111
|
+
language: "markdown"
|
|
112
|
+
});
|
|
113
|
+
await vscode.window.showTextDocument(document, { preview: true, viewColumn: vscode.ViewColumn.Beside });
|
|
114
|
+
}
|
|
115
|
+
function formatMcpToolRunMarkdown(run) {
|
|
116
|
+
return [
|
|
117
|
+
"# FlowSeeker MCP Tool",
|
|
118
|
+
"",
|
|
119
|
+
`Tool: \`${run.toolName}\``,
|
|
120
|
+
`Duration: ${run.durationMs}ms`,
|
|
121
|
+
"",
|
|
122
|
+
run.proposal.rationale ? "## Rationale" : "",
|
|
123
|
+
run.proposal.rationale ?? "",
|
|
124
|
+
run.proposal.rationale ? "" : "",
|
|
125
|
+
"## Input",
|
|
126
|
+
"",
|
|
127
|
+
"```json",
|
|
128
|
+
JSON.stringify(run.proposal.input ?? {}, null, 2),
|
|
129
|
+
"```",
|
|
130
|
+
"",
|
|
131
|
+
"## Result",
|
|
132
|
+
"",
|
|
133
|
+
"```",
|
|
134
|
+
truncate(run.resultText || "(empty result)", 16000),
|
|
135
|
+
"```",
|
|
136
|
+
""
|
|
137
|
+
].filter((line, index, lines) => line !== "" || lines[index - 1] !== "").join("\n");
|
|
138
|
+
}
|
|
139
|
+
function toolResultToText(result) {
|
|
140
|
+
return result.content.map(partToText).filter(Boolean).join("\n\n");
|
|
141
|
+
}
|
|
142
|
+
function partToText(part) {
|
|
143
|
+
if (typeof part === "string") {
|
|
144
|
+
return part;
|
|
145
|
+
}
|
|
146
|
+
if (part && typeof part === "object") {
|
|
147
|
+
const value = part.value;
|
|
148
|
+
if (typeof value === "string") {
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
const data = part.data;
|
|
152
|
+
if (data instanceof Uint8Array) {
|
|
153
|
+
return `[${part.mimeType ?? "data"}: ${data.byteLength} bytes]`;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
return JSON.stringify(part, null, 2);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return String(part);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return String(part ?? "");
|
|
163
|
+
}
|
|
164
|
+
function truncate(value, maxLength) {
|
|
165
|
+
return value.length > maxLength ? `${value.slice(0, maxLength)}\n... (truncated)` : value;
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=mcpToolRunner.js.map
|
|
@@ -0,0 +1,71 @@
|
|
|
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.getGitHubSession = getGitHubSession;
|
|
37
|
+
exports.getSilentGitHubSession = getSilentGitHubSession;
|
|
38
|
+
exports.hasGitHubSession = hasGitHubSession;
|
|
39
|
+
const vscode = __importStar(require("vscode"));
|
|
40
|
+
const GITHUB_AUTH_PROVIDER = "github";
|
|
41
|
+
const GITHUB_MODELS_SCOPE = "read:user";
|
|
42
|
+
async function getGitHubSession() {
|
|
43
|
+
const session = await vscode.authentication.getSession(GITHUB_AUTH_PROVIDER, [GITHUB_MODELS_SCOPE], {
|
|
44
|
+
createIfNone: true,
|
|
45
|
+
silent: false
|
|
46
|
+
});
|
|
47
|
+
if (!session) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
accessToken: session.accessToken,
|
|
52
|
+
accountLabel: session.account.label
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async function getSilentGitHubSession() {
|
|
56
|
+
const session = await vscode.authentication.getSession(GITHUB_AUTH_PROVIDER, [GITHUB_MODELS_SCOPE], {
|
|
57
|
+
silent: true
|
|
58
|
+
});
|
|
59
|
+
if (!session) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
accessToken: session.accessToken,
|
|
64
|
+
accountLabel: session.account.label
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function hasGitHubSession() {
|
|
68
|
+
const session = await getSilentGitHubSession();
|
|
69
|
+
return session !== null;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=githubAuth.js.map
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchModelList = fetchModelList;
|
|
4
|
+
exports.getCachedModels = getCachedModels;
|
|
5
|
+
exports.cacheModels = cacheModels;
|
|
6
|
+
exports.clearCachedModels = clearCachedModels;
|
|
7
|
+
const aiProviders_1 = require("../gateway/aiProviders");
|
|
8
|
+
const MODELS_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
9
|
+
function cacheKey(providerId, baseUrl = "") {
|
|
10
|
+
return `flowseeker.models.${providerId}.${hashString(normalizeBaseUrl(baseUrl))}`;
|
|
11
|
+
}
|
|
12
|
+
async function fetchModelList(providerId, baseUrl, accessToken) {
|
|
13
|
+
const definition = (0, aiProviders_1.getProviderDefinition)(providerId);
|
|
14
|
+
const cleanBaseUrl = normalizeBaseUrl(baseUrl || definition.defaultBaseUrl);
|
|
15
|
+
let response;
|
|
16
|
+
if (providerId === "ollama") {
|
|
17
|
+
response = await fetch(joinUrl(cleanBaseUrl, "/api/tags"), {
|
|
18
|
+
headers: { "Content-Type": "application/json" }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
else if (providerId === "gemini") {
|
|
22
|
+
response = await fetch(`${joinUrl(cleanBaseUrl, "/models")}?key=${encodeURIComponent(accessToken ?? "")}`, {
|
|
23
|
+
headers: { "Content-Type": "application/json" }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
else if (providerId === "anthropic" || providerId === "customAnthropic") {
|
|
27
|
+
response = await fetch(joinUrl(cleanBaseUrl, "/models"), {
|
|
28
|
+
headers: {
|
|
29
|
+
"Content-Type": "application/json",
|
|
30
|
+
"x-api-key": accessToken ?? "",
|
|
31
|
+
"anthropic-version": "2023-06-01"
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
response = await fetch(joinUrl(cleanBaseUrl, "/models"), {
|
|
37
|
+
headers: { Authorization: `Bearer ${accessToken ?? ""}`, "Content-Type": "application/json" }
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw new Error(`Failed to fetch models (${response.status})`);
|
|
42
|
+
}
|
|
43
|
+
return parseModelResponse(providerId, await response.json());
|
|
44
|
+
}
|
|
45
|
+
function parseModelResponse(providerId, data) {
|
|
46
|
+
// GitHub Models returns a plain array
|
|
47
|
+
if (Array.isArray(data)) {
|
|
48
|
+
return data
|
|
49
|
+
.filter(isObject)
|
|
50
|
+
.map((model) => {
|
|
51
|
+
const rawId = stringValue(model.id) ?? stringValue(model.name) ?? stringValue(model.model);
|
|
52
|
+
if (!rawId) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const displayName = stringValue(model.display_name) ?? stringValue(model.displayName) ?? stringValue(model.name) ?? rawId;
|
|
56
|
+
return {
|
|
57
|
+
id: rawId,
|
|
58
|
+
name: displayName,
|
|
59
|
+
owned_by: stringValue(model.owned_by) ?? stringValue(model.ownedBy)
|
|
60
|
+
};
|
|
61
|
+
})
|
|
62
|
+
.filter((model) => Boolean(model?.id));
|
|
63
|
+
}
|
|
64
|
+
if (!isObject(data)) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
const rows = Array.isArray(data.data)
|
|
68
|
+
? data.data
|
|
69
|
+
: Array.isArray(data.models)
|
|
70
|
+
? data.models
|
|
71
|
+
: [];
|
|
72
|
+
return rows
|
|
73
|
+
.filter(isObject)
|
|
74
|
+
.map((model) => {
|
|
75
|
+
const rawId = stringValue(model.id) ?? stringValue(model.name) ?? stringValue(model.model);
|
|
76
|
+
if (!rawId) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const id = providerId === "gemini" ? rawId.replace(/^models\//, "") : rawId;
|
|
80
|
+
const displayName = stringValue(model.display_name) ?? stringValue(model.displayName) ?? stringValue(model.name) ?? id;
|
|
81
|
+
return {
|
|
82
|
+
id,
|
|
83
|
+
name: providerId === "gemini" ? displayName.replace(/^models\//, "") : displayName,
|
|
84
|
+
owned_by: stringValue(model.owned_by) ?? stringValue(model.ownedBy)
|
|
85
|
+
};
|
|
86
|
+
})
|
|
87
|
+
.filter((model) => Boolean(model?.id));
|
|
88
|
+
}
|
|
89
|
+
function getCachedModels(context, providerId, baseUrl = "") {
|
|
90
|
+
const cached = context.globalState.get(cacheKey(providerId, baseUrl));
|
|
91
|
+
if (!cached || !Array.isArray(cached.models)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
if (Date.now() - cached.fetchedAt > MODELS_CACHE_TTL_MS) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return cached.models;
|
|
98
|
+
}
|
|
99
|
+
async function cacheModels(context, providerId, baseUrl, models) {
|
|
100
|
+
await context.globalState.update(cacheKey(providerId, baseUrl), {
|
|
101
|
+
models,
|
|
102
|
+
fetchedAt: Date.now()
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function clearCachedModels(context, providerId, baseUrl = "") {
|
|
106
|
+
void context.globalState.update(cacheKey(providerId, baseUrl), undefined);
|
|
107
|
+
}
|
|
108
|
+
function joinUrl(baseUrl, path) {
|
|
109
|
+
return `${baseUrl.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
|
|
110
|
+
}
|
|
111
|
+
function normalizeBaseUrl(value) {
|
|
112
|
+
return value.trim().replace(/\/+$/, "");
|
|
113
|
+
}
|
|
114
|
+
function stringValue(value) {
|
|
115
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
116
|
+
}
|
|
117
|
+
function isObject(value) {
|
|
118
|
+
return typeof value === "object" && value !== null;
|
|
119
|
+
}
|
|
120
|
+
function hashString(value) {
|
|
121
|
+
let hash = 5381;
|
|
122
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
123
|
+
hash = ((hash << 5) + hash) ^ value.charCodeAt(index);
|
|
124
|
+
}
|
|
125
|
+
return (hash >>> 0).toString(36);
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=modelList.js.map
|