Files

108 lines
3.9 KiB
TypeScript

import { commands, ExtensionContext, extensions, lm, LanguageModelChatSelector, window, workspace, LogOutputChannel, version } from "vscode";
import { SemVer } from "semver";
export const REQUIRED_EXTENSION = 'github.copilot-chat';
const DEFAULT_MODEL_SELECTOR: LanguageModelChatSelector = { vendor: 'copilot', family: 'gpt-4' };
export const logger: LogOutputChannel = window.createOutputChannel("Spring tools copilot", { log: true });
export async function activateCopilotFeatures(context: ExtensionContext): Promise<void> {
if(!isLlmApiAvailable("1.90.0-insider")) { // lm API is available since 1.90.0-insider
return;
}
workspace.onDidChangeConfiguration(event => {
if (event.affectsConfiguration('boot-java.highlight-copilot-codelens.on')) {
promptReloadWindow();
}
});
logger.info("vscode.lm is ready.");
await ensureExtensionInstalledAndActivated();
await updateConfigurationBasedOnCopilotAccess();
// Add listener to handle installation/uninstallation of the required extension
extensions.onDidChange(async () => {
await ensureExtensionInstalledAndActivated();
await updateConfigurationBasedOnCopilotAccess();
});
explainQueryWithCopilot();
}
function isLlmApiAvailable(v: string): boolean {
return new SemVer(version).compare(new SemVer(v)) >= 0;
}
async function ensureExtensionInstalledAndActivated() {
if (!isExtensionInstalled(REQUIRED_EXTENSION)) {
logger.error(`Required extension ${REQUIRED_EXTENSION} is not installed.`);
return;
}
if (!isExtensionActivated(REQUIRED_EXTENSION)) {
logger.error(`Required extension ${REQUIRED_EXTENSION} is not activated.`);
await waitUntilExtensionActivated(REQUIRED_EXTENSION);
}
}
function isExtensionInstalled(extensionId: string): boolean {
return !!extensions.getExtension(extensionId);
}
function isExtensionActivated(extensionId: string): boolean {
return !!extensions.getExtension(extensionId)?.isActive;
}
async function waitUntilExtensionActivated(extensionId: string, interval: number = 3500) {
logger.info(`Waiting for extension ${extensionId} to be activated...`);
return new Promise<void>((resolve) => {
const id = setInterval(() => {
if (extensions.getExtension(extensionId)?.isActive) {
clearInterval(id);
resolve();
}
}, interval);
});
}
async function updateConfigurationBasedOnCopilotAccess() {
if (!isExtensionInstalled(REQUIRED_EXTENSION) || !isExtensionActivated(REQUIRED_EXTENSION)) {
await updateConfiguration(false);
return;
}
const model = (await lm.selectChatModels(DEFAULT_MODEL_SELECTOR))?.[0];
if (!model) {
const models = await lm.selectChatModels();
logger.error(`No suitable model, available models: [${models.map(m => m.name).join(', ')}]. Please make sure you have installed the latest "GitHub Copilot Chat" (v0.16.0 or later) and all \`lm\` API is enabled.`);
await updateConfiguration(false);
} else {
await updateConfiguration(true);
}
}
async function updateConfiguration(value: boolean) {
const configValue = workspace.getConfiguration().get('boot-java.highlight-copilot-codelens.on');
if(value && configValue === true) {
commands.executeCommand('sts/enable/copilot/features', value);
}
}
async function explainQueryWithCopilot() {
commands.registerCommand('vscode-spring-boot.query.explain', async (userPrompt) => {
await commands.executeCommand('workbench.action.chat.open', { query: userPrompt });
})
}
async function promptReloadWindow() {
const reload = await window.showInformationMessage(
'Configuration updated. Please reload VS Code to apply changes.',
'Reload'
);
if (reload === 'Reload') {
await commands.executeCommand('workbench.action.reloadWindow');
}
}