mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-30 13:31:07 +01:00
Chat sign-in: auto-enable GitHub Authentication extension if silently disabled (#296303)
* Initial plan * Auto-enable GitHub Authentication extension during chat sign-in if disabled Co-authored-by: TylerLeonhardt <2644648+TylerLeonhardt@users.noreply.github.com> * Apply during the chat request * feedback * delete the tests that didn't exist in the first place --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TylerLeonhardt <2644648+TylerLeonhardt@users.noreply.github.com> Co-authored-by: Tyler Leonhardt <tyleonha@microsoft.com>
This commit is contained in:
@@ -116,6 +116,7 @@
|
|||||||
"name": "Apple"
|
"name": "Apple"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"providerExtensionId": "vscode.github-authentication",
|
||||||
"providerUriSetting": "github-enterprise.uri",
|
"providerUriSetting": "github-enterprise.uri",
|
||||||
"providerScopes": [
|
"providerScopes": [
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -360,6 +360,7 @@ export interface IDefaultChatAgent {
|
|||||||
apple: { id: string; name: string };
|
apple: { id: string; name: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
readonly providerExtensionId: string;
|
||||||
readonly providerUriSetting: string;
|
readonly providerUriSetting: string;
|
||||||
readonly providerScopes: string[][];
|
readonly providerScopes: string[][];
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,17 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ICommandService } from '../../../../../platform/commands/common/commands.js';
|
import { ICommandService } from '../../../../../platform/commands/common/commands.js';
|
||||||
|
import { ExtensionIdentifier } from '../../../../../platform/extensions/common/extensions.js';
|
||||||
|
import { ILogService } from '../../../../../platform/log/common/log.js';
|
||||||
import product from '../../../../../platform/product/common/product.js';
|
import product from '../../../../../platform/product/common/product.js';
|
||||||
|
import { localize } from '../../../../../nls.js';
|
||||||
|
import { EnablementState } from '../../../../services/extensionManagement/common/extensionManagement.js';
|
||||||
|
import { IExtensionsWorkbenchService } from '../../../extensions/common/extensions.js';
|
||||||
|
|
||||||
const defaultChat = {
|
const defaultChat = {
|
||||||
completionsRefreshTokenCommand: product.defaultChatAgent?.completionsRefreshTokenCommand ?? '',
|
completionsRefreshTokenCommand: product.defaultChatAgent?.completionsRefreshTokenCommand ?? '',
|
||||||
chatRefreshTokenCommand: product.defaultChatAgent?.chatRefreshTokenCommand ?? '',
|
chatRefreshTokenCommand: product.defaultChatAgent?.chatRefreshTokenCommand ?? '',
|
||||||
|
providerExtensionId: product.defaultChatAgent?.providerExtensionId ?? '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InstallChatClassification = {
|
export type InstallChatClassification = {
|
||||||
@@ -59,3 +65,44 @@ export function refreshTokens(commandService: ICommandService): void {
|
|||||||
commandService.executeCommand(defaultChat.completionsRefreshTokenCommand);
|
commandService.executeCommand(defaultChat.completionsRefreshTokenCommand);
|
||||||
commandService.executeCommand(defaultChat.chatRefreshTokenCommand);
|
commandService.executeCommand(defaultChat.chatRefreshTokenCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the authentication provider extension is enabled.
|
||||||
|
* If the extension is found locally but disabled, it will be
|
||||||
|
* re-enabled and running extensions will be updated.
|
||||||
|
*
|
||||||
|
* @returns `true` if the extension was re-enabled, `false` otherwise.
|
||||||
|
*/
|
||||||
|
export async function maybeEnableAuthExtension(
|
||||||
|
extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||||
|
logService: ILogService
|
||||||
|
): Promise<boolean> {
|
||||||
|
if (!defaultChat.providerExtensionId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerExtension = extensionsWorkbenchService.local.find(
|
||||||
|
e => ExtensionIdentifier.equals(e.identifier.id, defaultChat.providerExtensionId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!providerExtension) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
providerExtension.enablementState === EnablementState.DisabledGlobally ||
|
||||||
|
providerExtension.enablementState === EnablementState.DisabledWorkspace
|
||||||
|
) {
|
||||||
|
logService.info(`[chat setup] auth provider extension '${defaultChat.providerExtensionId}' is disabled, re-enabling it`);
|
||||||
|
try {
|
||||||
|
await extensionsWorkbenchService.setEnablement([providerExtension], EnablementState.EnabledGlobally);
|
||||||
|
await extensionsWorkbenchService.updateRunningExtensions(localize('enableAuthExtension', "Enabling GitHub Authentication"));
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logService.error(`[chat setup] failed to re-enable auth provider extension '${defaultChat.providerExtensionId}'`, error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { IExtensionsWorkbenchService } from '../../../extensions/common/extensio
|
|||||||
import { ChatEntitlement, ChatEntitlementContext, ChatEntitlementRequests, isProUser } from '../../../../services/chat/common/chatEntitlementService.js';
|
import { ChatEntitlement, ChatEntitlementContext, ChatEntitlementRequests, isProUser } from '../../../../services/chat/common/chatEntitlementService.js';
|
||||||
import { CHAT_OPEN_ACTION_ID } from '../actions/chatActions.js';
|
import { CHAT_OPEN_ACTION_ID } from '../actions/chatActions.js';
|
||||||
import { ChatViewId, ChatViewContainerId } from '../chat.js';
|
import { ChatViewId, ChatViewContainerId } from '../chat.js';
|
||||||
import { ChatSetupAnonymous, ChatSetupStep, ChatSetupResultValue, InstallChatEvent, InstallChatClassification, refreshTokens } from './chatSetup.js';
|
import { ChatSetupAnonymous, ChatSetupStep, ChatSetupResultValue, InstallChatEvent, InstallChatClassification, refreshTokens, maybeEnableAuthExtension } from './chatSetup.js';
|
||||||
import { IDefaultAccount } from '../../../../../base/common/defaultAccount.js';
|
import { IDefaultAccount } from '../../../../../base/common/defaultAccount.js';
|
||||||
import { IDefaultAccountService } from '../../../../../platform/defaultAccount/common/defaultAccount.js';
|
import { IDefaultAccountService } from '../../../../../platform/defaultAccount/common/defaultAccount.js';
|
||||||
|
|
||||||
@@ -153,6 +153,11 @@ export class ChatSetupController extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async signIn(options: IChatSetupControllerOptions): Promise<{ defaultAccount: IDefaultAccount | undefined; entitlement: ChatEntitlement | undefined }> {
|
private async signIn(options: IChatSetupControllerOptions): Promise<{ defaultAccount: IDefaultAccount | undefined; entitlement: ChatEntitlement | undefined }> {
|
||||||
|
const authExtensionReEnabled = await maybeEnableAuthExtension(this.extensionsWorkbenchService, this.logService);
|
||||||
|
if (authExtensionReEnabled) {
|
||||||
|
refreshTokens(this.commandService);
|
||||||
|
}
|
||||||
|
|
||||||
let entitlements;
|
let entitlements;
|
||||||
let defaultAccount;
|
let defaultAccount;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -47,13 +47,14 @@ import { ACTION_START as INLINE_CHAT_START } from '../../../inlineChat/common/in
|
|||||||
import { IPosition } from '../../../../../editor/common/core/position.js';
|
import { IPosition } from '../../../../../editor/common/core/position.js';
|
||||||
import { IMarker, IMarkerService, MarkerSeverity } from '../../../../../platform/markers/common/markers.js';
|
import { IMarker, IMarkerService, MarkerSeverity } from '../../../../../platform/markers/common/markers.js';
|
||||||
import { ChatSetupController } from './chatSetupController.js';
|
import { ChatSetupController } from './chatSetupController.js';
|
||||||
import { ChatSetupAnonymous, ChatSetupStep, IChatSetupResult } from './chatSetup.js';
|
import { ChatSetupAnonymous, ChatSetupStep, IChatSetupResult, maybeEnableAuthExtension, refreshTokens } from './chatSetup.js';
|
||||||
import { ChatSetup } from './chatSetupRunner.js';
|
import { ChatSetup } from './chatSetupRunner.js';
|
||||||
import { chatViewsWelcomeRegistry } from '../viewsWelcome/chatViewsWelcome.js';
|
import { chatViewsWelcomeRegistry } from '../viewsWelcome/chatViewsWelcome.js';
|
||||||
import { CommandsRegistry, ICommandService } from '../../../../../platform/commands/common/commands.js';
|
import { CommandsRegistry, ICommandService } from '../../../../../platform/commands/common/commands.js';
|
||||||
import { IDefaultAccountService } from '../../../../../platform/defaultAccount/common/defaultAccount.js';
|
import { IDefaultAccountService } from '../../../../../platform/defaultAccount/common/defaultAccount.js';
|
||||||
import { IHostService } from '../../../../services/host/browser/host.js';
|
import { IHostService } from '../../../../services/host/browser/host.js';
|
||||||
import { IOutputService } from '../../../../services/output/common/output.js';
|
import { IOutputService } from '../../../../services/output/common/output.js';
|
||||||
|
import { IExtensionsWorkbenchService } from '../../../extensions/common/extensions.js';
|
||||||
|
|
||||||
const defaultChat = {
|
const defaultChat = {
|
||||||
extensionId: product.defaultChatAgent?.extensionId ?? '',
|
extensionId: product.defaultChatAgent?.extensionId ?? '',
|
||||||
@@ -197,6 +198,8 @@ export class SetupAgent extends Disposable implements IChatAgentImplementation {
|
|||||||
@IViewsService private readonly viewsService: IViewsService,
|
@IViewsService private readonly viewsService: IViewsService,
|
||||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||||
@IOutputService private readonly outputService: IOutputService,
|
@IOutputService private readonly outputService: IOutputService,
|
||||||
|
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||||
|
@ICommandService private readonly commandService: ICommandService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -315,6 +318,15 @@ export class SetupAgent extends Disposable implements IChatAgentImplementation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async doForwardRequestToChatWhenReady(requestModel: IChatRequestModel, progress: (part: IChatProgress) => void, chatService: IChatService, languageModelsService: ILanguageModelsService, chatAgentService: IChatAgentService, chatWidgetService: IChatWidgetService, languageModelToolsService: ILanguageModelToolsService): Promise<void> {
|
private async doForwardRequestToChatWhenReady(requestModel: IChatRequestModel, progress: (part: IChatProgress) => void, chatService: IChatService, languageModelsService: ILanguageModelsService, chatAgentService: IChatAgentService, chatWidgetService: IChatWidgetService, languageModelToolsService: ILanguageModelToolsService): Promise<void> {
|
||||||
|
|
||||||
|
// Ensure auth extension is enabled before waiting for chat readiness.
|
||||||
|
// This must run before the readiness event listeners are set up because
|
||||||
|
// updateRunningExtensions restarts all extension hosts.
|
||||||
|
const authExtensionReEnabled = await maybeEnableAuthExtension(this.extensionsWorkbenchService, this.logService);
|
||||||
|
if (authExtensionReEnabled) {
|
||||||
|
refreshTokens(this.commandService);
|
||||||
|
}
|
||||||
|
|
||||||
const widget = chatWidgetService.getWidgetBySessionResource(requestModel.session.sessionResource);
|
const widget = chatWidgetService.getWidgetBySessionResource(requestModel.session.sessionResource);
|
||||||
const modeInfo = widget?.input.currentModeInfo;
|
const modeInfo = widget?.input.currentModeInfo;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user