summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/hooks
diff options
context:
space:
mode:
authormatt korwel <[email protected]>2025-06-19 16:52:22 -0700
committerGitHub <[email protected]>2025-06-19 16:52:22 -0700
commit04518b52c0ddcd5ae1192763c55e472add218b3c (patch)
tree2587b0ccc5460e9e94eb8b715956cb713950f7c8 /packages/cli/src/ui/hooks
parentc48fcaa8c3fe8175718b1bbfc7770a958012173c (diff)
Auth First Run (#1207)
Co-authored-by: Tommaso Sciortino <[email protected]> Co-authored-by: N. Taylor Mullen <[email protected]>
Diffstat (limited to 'packages/cli/src/ui/hooks')
-rw-r--r--packages/cli/src/ui/hooks/slashCommandProcessor.test.ts3
-rw-r--r--packages/cli/src/ui/hooks/slashCommandProcessor.ts9
-rw-r--r--packages/cli/src/ui/hooks/useAuthCommand.ts57
-rw-r--r--packages/cli/src/ui/hooks/useGeminiStream.test.tsx1
-rw-r--r--packages/cli/src/ui/hooks/useGeminiStream.ts7
5 files changed, 76 insertions, 1 deletions
diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts
index 7c750af1..04931c7f 100644
--- a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts
+++ b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts
@@ -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,
diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.ts
index 0e622f23..ee7b55cb 100644
--- a/packages/cli/src/ui/hooks/slashCommandProcessor.ts
+++ b/packages/cli/src/ui/hooks/slashCommandProcessor.ts
@@ -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,
@@ -198,6 +199,13 @@ export const useSlashCommandProcessor = (
},
},
{
+ name: 'auth',
+ description: 'change the auth method',
+ action: (_mainCommand, _subCommand, _args) => {
+ openAuthDialog();
+ },
+ },
+ {
name: 'editor',
description: 'set external editor preference',
action: (_mainCommand, _subCommand, _args) => {
@@ -907,6 +915,7 @@ Add any other context about the problem here.
setShowHelp,
refreshStatic,
openThemeDialog,
+ openAuthDialog,
openEditorDialog,
clearItems,
performMemoryRefresh,
diff --git a/packages/cli/src/ui/hooks/useAuthCommand.ts b/packages/cli/src/ui/hooks/useAuthCommand.ts
new file mode 100644
index 00000000..a9b1cb1e
--- /dev/null
+++ b/packages/cli/src/ui/hooks/useAuthCommand.ts
@@ -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,
+ };
+};
diff --git a/packages/cli/src/ui/hooks/useGeminiStream.test.tsx b/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
index 96dd6aef..36f420e4 100644
--- a/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
+++ b/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
@@ -359,6 +359,7 @@ describe('useGeminiStream', () => {
props.handleSlashCommand,
props.shellModeActive,
() => 'vscode' as EditorType,
+ () => {},
),
{
initialProps: {
diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts
index 6d92af0d..4049c884 100644
--- a/packages/cli/src/ui/hooks/useGeminiStream.ts
+++ b/packages/cli/src/ui/hooks/useGeminiStream.ts
@@ -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,
],
);