mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 08:47:44 +00:00
Auth First Run (#1207)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com> Co-authored-by: N. Taylor Mullen <ntaylormullen@google.com>
This commit is contained in:
@@ -103,6 +103,7 @@ describe('useSlashCommandProcessor', () => {
|
||||
let mockSetShowHelp: ReturnType<typeof vi.fn>;
|
||||
let mockOnDebugMessage: ReturnType<typeof vi.fn>;
|
||||
let mockOpenThemeDialog: ReturnType<typeof vi.fn>;
|
||||
let mockOpenAuthDialog: ReturnType<typeof vi.fn>;
|
||||
let mockOpenEditorDialog: ReturnType<typeof vi.fn>;
|
||||
let mockPerformMemoryRefresh: ReturnType<typeof vi.fn>;
|
||||
let mockSetQuittingMessages: ReturnType<typeof vi.fn>;
|
||||
@@ -120,6 +121,7 @@ describe('useSlashCommandProcessor', () => {
|
||||
mockSetShowHelp = vi.fn();
|
||||
mockOnDebugMessage = vi.fn();
|
||||
mockOpenThemeDialog = vi.fn();
|
||||
mockOpenAuthDialog = vi.fn();
|
||||
mockOpenEditorDialog = vi.fn();
|
||||
mockPerformMemoryRefresh = vi.fn().mockResolvedValue(undefined);
|
||||
mockSetQuittingMessages = vi.fn();
|
||||
@@ -171,6 +173,7 @@ describe('useSlashCommandProcessor', () => {
|
||||
mockSetShowHelp,
|
||||
mockOnDebugMessage,
|
||||
mockOpenThemeDialog,
|
||||
mockOpenAuthDialog,
|
||||
mockOpenEditorDialog,
|
||||
mockPerformMemoryRefresh,
|
||||
mockCorgiMode,
|
||||
|
||||
@@ -68,6 +68,7 @@ export const useSlashCommandProcessor = (
|
||||
setShowHelp: React.Dispatch<React.SetStateAction<boolean>>,
|
||||
onDebugMessage: (message: string) => void,
|
||||
openThemeDialog: () => void,
|
||||
openAuthDialog: () => void,
|
||||
openEditorDialog: () => void,
|
||||
performMemoryRefresh: () => Promise<void>,
|
||||
toggleCorgiMode: () => void,
|
||||
@@ -197,6 +198,13 @@ export const useSlashCommandProcessor = (
|
||||
openThemeDialog();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'auth',
|
||||
description: 'change the auth method',
|
||||
action: (_mainCommand, _subCommand, _args) => {
|
||||
openAuthDialog();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'editor',
|
||||
description: 'set external editor preference',
|
||||
@@ -907,6 +915,7 @@ Add any other context about the problem here.
|
||||
setShowHelp,
|
||||
refreshStatic,
|
||||
openThemeDialog,
|
||||
openAuthDialog,
|
||||
openEditorDialog,
|
||||
clearItems,
|
||||
performMemoryRefresh,
|
||||
|
||||
57
packages/cli/src/ui/hooks/useAuthCommand.ts
Normal file
57
packages/cli/src/ui/hooks/useAuthCommand.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { LoadedSettings, SettingScope } from '../../config/settings.js';
|
||||
import { AuthType, Config, clearCachedCredentialFile } from '@gemini-cli/core';
|
||||
|
||||
async function performAuthFlow(authMethod: AuthType, config: Config) {
|
||||
await config.refreshAuth(authMethod);
|
||||
console.log(`Authenticated via "${authMethod}".`);
|
||||
}
|
||||
|
||||
export const useAuthCommand = (
|
||||
settings: LoadedSettings,
|
||||
setAuthError: (error: string | null) => void,
|
||||
config: Config,
|
||||
) => {
|
||||
const [isAuthDialogOpen, setIsAuthDialogOpen] = useState(
|
||||
settings.merged.selectedAuthType === undefined,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthDialogOpen) {
|
||||
performAuthFlow(settings.merged.selectedAuthType as AuthType, config);
|
||||
}
|
||||
}, [isAuthDialogOpen, settings, config]);
|
||||
|
||||
const openAuthDialog = useCallback(() => {
|
||||
setIsAuthDialogOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleAuthSelect = useCallback(
|
||||
async (authMethod: string | undefined, scope: SettingScope) => {
|
||||
if (authMethod) {
|
||||
await clearCachedCredentialFile();
|
||||
settings.setValue(scope, 'selectedAuthType', authMethod);
|
||||
}
|
||||
setIsAuthDialogOpen(false);
|
||||
setAuthError(null);
|
||||
},
|
||||
[settings, setAuthError],
|
||||
);
|
||||
|
||||
const handleAuthHighlight = useCallback((_authMethod: string | undefined) => {
|
||||
// For now, we don't do anything on highlight.
|
||||
}, []);
|
||||
|
||||
return {
|
||||
isAuthDialogOpen,
|
||||
openAuthDialog,
|
||||
handleAuthSelect,
|
||||
handleAuthHighlight,
|
||||
};
|
||||
};
|
||||
@@ -359,6 +359,7 @@ describe('useGeminiStream', () => {
|
||||
props.handleSlashCommand,
|
||||
props.shellModeActive,
|
||||
() => 'vscode' as EditorType,
|
||||
() => {},
|
||||
),
|
||||
{
|
||||
initialProps: {
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
GitService,
|
||||
EditorType,
|
||||
ThoughtSummary,
|
||||
isAuthError,
|
||||
} from '@gemini-cli/core';
|
||||
import { type Part, type PartListUnion } from '@google/genai';
|
||||
import {
|
||||
@@ -87,6 +88,7 @@ export const useGeminiStream = (
|
||||
>,
|
||||
shellModeActive: boolean,
|
||||
getPreferredEditor: () => EditorType | undefined,
|
||||
onAuthError: () => void,
|
||||
) => {
|
||||
const [initError, setInitError] = useState<string | null>(null);
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
@@ -496,7 +498,9 @@ export const useGeminiStream = (
|
||||
setPendingHistoryItem(null);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (!isNodeError(error) || error.name !== 'AbortError') {
|
||||
if (isAuthError(error)) {
|
||||
onAuthError();
|
||||
} else if (!isNodeError(error) || error.name !== 'AbortError') {
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
@@ -522,6 +526,7 @@ export const useGeminiStream = (
|
||||
setInitError,
|
||||
geminiClient,
|
||||
startNewTurn,
|
||||
onAuthError,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user