fix(auth): update terminology to 'sign in' and 'sign out' (#20892)

Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
Mark McLaughlin
2026-03-10 12:10:26 -07:00
committed by GitHub
parent b00d7c88ad
commit b404fc02e7
35 changed files with 95 additions and 78 deletions
+2 -2
View File
@@ -147,7 +147,7 @@ Integrate Gemini CLI directly into your GitHub workflows with
Choose the authentication method that best fits your needs: Choose the authentication method that best fits your needs:
### Option 1: Login with Google (OAuth login using your Google Account) ### Option 1: Sign in with Google (OAuth login using your Google Account)
**✨ Best for:** Individual developers as well as anyone who has a Gemini Code **✨ Best for:** Individual developers as well as anyone who has a Gemini Code
Assist License. (see Assist License. (see
@@ -161,7 +161,7 @@ for details)
- **No API key management** - just sign in with your Google account - **No API key management** - just sign in with your Google account
- **Automatic updates** to latest models - **Automatic updates** to latest models
#### Start Gemini CLI, then choose _Login with Google_ and follow the browser authentication flow when prompted #### Start Gemini CLI, then choose _Sign in with Google_ and follow the browser authentication flow when prompted
```bash ```bash
gemini gemini
+1 -1
View File
@@ -66,7 +66,7 @@ they appear in the UI.
| Show Line Numbers | `ui.showLineNumbers` | Show line numbers in the chat. | `true` | | Show Line Numbers | `ui.showLineNumbers` | Show line numbers in the chat. | `true` |
| Show Citations | `ui.showCitations` | Show citations for generated text in the chat. | `false` | | Show Citations | `ui.showCitations` | Show citations for generated text in the chat. | `false` |
| Show Model Info In Chat | `ui.showModelInfoInChat` | Show the model name in the chat for each model turn. | `false` | | Show Model Info In Chat | `ui.showModelInfoInChat` | Show the model name in the chat for each model turn. | `false` |
| Show User Identity | `ui.showUserIdentity` | Show the logged-in user's identity (e.g. email) in the UI. | `true` | | Show User Identity | `ui.showUserIdentity` | Show the signed-in user's identity (e.g. email) in the UI. | `true` |
| Use Alternate Screen Buffer | `ui.useAlternateBuffer` | Use an alternate screen buffer for the UI, preserving shell history. | `false` | | Use Alternate Screen Buffer | `ui.useAlternateBuffer` | Use an alternate screen buffer for the UI, preserving shell history. | `false` |
| Use Background Color | `ui.useBackgroundColor` | Whether to use background colors in the UI. | `true` | | Use Background Color | `ui.useBackgroundColor` | Whether to use background colors in the UI. | `true` |
| Incremental Rendering | `ui.incrementalRendering` | Enable incremental rendering for the UI. This option will reduce flickering but may cause rendering artifacts. Only supported when useAlternateBuffer is enabled. | `true` | | Incremental Rendering | `ui.incrementalRendering` | Enable incremental rendering for the UI. This option will reduce flickering but may cause rendering artifacts. Only supported when useAlternateBuffer is enabled. | `true` |
+1 -1
View File
@@ -194,7 +194,7 @@ returns coordinates and element descriptions that the browser agent uses with
the `click_at` tool for precise, coordinate-based interactions. the `click_at` tool for precise, coordinate-based interactions.
> **Note:** The visual agent requires API key or Vertex AI authentication. It is > **Note:** The visual agent requires API key or Vertex AI authentication. It is
> not available when using Google Login. > not available when using "Sign in with Google".
## Creating custom subagents ## Creating custom subagents
+7 -7
View File
@@ -17,8 +17,8 @@ Select the authentication method that matches your situation in the table below:
| User Type / Scenario | Recommended Authentication Method | Google Cloud Project Required | | User Type / Scenario | Recommended Authentication Method | Google Cloud Project Required |
| :--------------------------------------------------------------------- | :--------------------------------------------------------------- | :---------------------------------------------------------- | | :--------------------------------------------------------------------- | :--------------------------------------------------------------- | :---------------------------------------------------------- |
| Individual Google accounts | [Login with Google](#login-google) | No, with exceptions | | Individual Google accounts | [Sign in with Google](#login-google) | No, with exceptions |
| Organization users with a company, school, or Google Workspace account | [Login with Google](#login-google) | [Yes](#set-gcp) | | Organization users with a company, school, or Google Workspace account | [Sign in with Google](#login-google) | [Yes](#set-gcp) |
| AI Studio user with a Gemini API key | [Use Gemini API Key](#gemini-api) | No | | AI Studio user with a Gemini API key | [Use Gemini API Key](#gemini-api) | No |
| Google Cloud Vertex AI user | [Vertex AI](#vertex-ai) | [Yes](#set-gcp) | | Google Cloud Vertex AI user | [Vertex AI](#vertex-ai) | [Yes](#set-gcp) |
| [Headless mode](#headless) | [Use Gemini API Key](#gemini-api) or<br> [Vertex AI](#vertex-ai) | No (for Gemini API Key)<br> [Yes](#set-gcp) (for Vertex AI) | | [Headless mode](#headless) | [Use Gemini API Key](#gemini-api) or<br> [Vertex AI](#vertex-ai) | No (for Gemini API Key)<br> [Yes](#set-gcp) (for Vertex AI) |
@@ -36,7 +36,7 @@ Select the authentication method that matches your situation in the table below:
[Google AI Ultra for Business](https://support.google.com/a/answer/16345165) [Google AI Ultra for Business](https://support.google.com/a/answer/16345165)
subscriptions. subscriptions.
## (Recommended) Login with Google <a id="login-google"></a> ## (Recommended) Sign in with Google <a id="login-google"></a>
If you run Gemini CLI on your local machine, the simplest authentication method If you run Gemini CLI on your local machine, the simplest authentication method
is logging in with your Google account. This method requires a web browser on a is logging in with your Google account. This method requires a web browser on a
@@ -54,9 +54,9 @@ To authenticate and use Gemini CLI:
gemini gemini
``` ```
2. Select **Login with Google**. Gemini CLI opens a login prompt using your web 2. Select **Sign in with Google**. Gemini CLI opens a sign in prompt using your
browser. Follow the on-screen instructions. Your credentials will be cached web browser. Follow the on-screen instructions. Your credentials will be
locally for future sessions. cached locally for future sessions.
### Do I need to set my Google Cloud project? ### Do I need to set my Google Cloud project?
@@ -391,7 +391,7 @@ on this page.
[Headless mode](../cli/headless) will use your existing authentication method, [Headless mode](../cli/headless) will use your existing authentication method,
if an existing authentication credential is cached. if an existing authentication credential is cached.
If you have not already logged in with an authentication credential, you must If you have not already signed in with an authentication credential, you must
configure authentication using environment variables: configure authentication using environment variables:
- [Use Gemini API Key](#gemini-api) - [Use Gemini API Key](#gemini-api)
+1 -1
View File
@@ -38,7 +38,7 @@ cases, you can log in with your existing Google account:
``` ```
2. When asked "How would you like to authenticate for this project?" select **1. 2. When asked "How would you like to authenticate for this project?" select **1.
Login with Google**. Sign in with Google**.
3. Select your Google account. 3. Select your Google account.
+1 -1
View File
@@ -297,7 +297,7 @@ their corresponding top-level category object in your `settings.json` file.
- **Default:** `false` - **Default:** `false`
- **`ui.showUserIdentity`** (boolean): - **`ui.showUserIdentity`** (boolean):
- **Description:** Show the logged-in user's identity (e.g. email) in the UI. - **Description:** Show the signed-in user's identity (e.g. email) in the UI.
- **Default:** `true` - **Default:** `true`
- **`ui.useAlternateBuffer`** (boolean): - **`ui.useAlternateBuffer`** (boolean):
+2 -2
View File
@@ -79,8 +79,8 @@ manually run through this checklist.
- [ ] Verify version: `gemini --version` - [ ] Verify version: `gemini --version`
- **Authentication:** - **Authentication:**
- [ ] In interactive mode run `/auth` and verify all login flows work: - [ ] In interactive mode run `/auth` and verify all sign in flows work:
- [ ] Login With Google - [ ] Sign in with Google
- [ ] API Key - [ ] API Key
- [ ] Vertex AI - [ ] Vertex AI
+3 -3
View File
@@ -46,7 +46,7 @@ for further information.
| Gemini Developer API Key | Gemini API - Paid Services | [Gemini API Terms of Service - Paid Services](https://ai.google.dev/gemini-api/terms#paid-services) | [Google Privacy Policy](https://policies.google.com/privacy) | | Gemini Developer API Key | Gemini API - Paid Services | [Gemini API Terms of Service - Paid Services](https://ai.google.dev/gemini-api/terms#paid-services) | [Google Privacy Policy](https://policies.google.com/privacy) |
| Vertex AI GenAI API Key | Vertex AI GenAI API | [Google Cloud Platform Terms of Service](https://cloud.google.com/terms/service-terms/) | [Google Cloud Privacy Notice](https://cloud.google.com/terms/cloud-privacy-notice) | | Vertex AI GenAI API Key | Vertex AI GenAI API | [Google Cloud Platform Terms of Service](https://cloud.google.com/terms/service-terms/) | [Google Cloud Privacy Notice](https://cloud.google.com/terms/cloud-privacy-notice) |
## 1. If you have logged in with your Google account to Gemini Code Assist ## 1. If you have signed in with your Google account to Gemini Code Assist
For users who use their Google account to access For users who use their Google account to access
[Gemini Code Assist](https://codeassist.google), these Terms of Service and [Gemini Code Assist](https://codeassist.google), these Terms of Service and
@@ -68,7 +68,7 @@ Code Assist Standard or Enterprise edition, the terms and privacy policy of
Gemini Code Assist Standard or Enterprise edition will apply to all your use of Gemini Code Assist Standard or Enterprise edition will apply to all your use of
Gemini Code Assist._ Gemini Code Assist._
## 2. If you have logged in with a Gemini API key to the Gemini Developer API ## 2. If you have signed in with a Gemini API key to the Gemini Developer API
If you are using a Gemini API key for authentication with the If you are using a Gemini API key for authentication with the
[Gemini Developer API](https://ai.google.dev/gemini-api/docs), these Terms of [Gemini Developer API](https://ai.google.dev/gemini-api/docs), these Terms of
@@ -84,7 +84,7 @@ Service and Privacy Notice documents apply:
- Privacy Notice: The collection and use of your data is described in the - Privacy Notice: The collection and use of your data is described in the
[Google Privacy Policy](https://policies.google.com/privacy). [Google Privacy Policy](https://policies.google.com/privacy).
## 3. If you have logged in with a Gemini API key to the Vertex AI GenAI API ## 3. If you have signed in with a Gemini API key to the Vertex AI GenAI API
If you are using a Gemini API key for authentication with a If you are using a Gemini API key for authentication with a
[Vertex AI GenAI API](https://cloud.google.com/vertex-ai/generative-ai/docs/reference/rest) [Vertex AI GenAI API](https://cloud.google.com/vertex-ai/generative-ai/docs/reference/rest)
+2 -2
View File
@@ -29,13 +29,13 @@ topics on:
added to your organization's Gemini Code Assist subscription. added to your organization's Gemini Code Assist subscription.
- **Error: - **Error:
`Failed to login. Message: Your current account is not eligible... because it is not currently available in your location.`** `Failed to sign in. Message: Your current account is not eligible... because it is not currently available in your location.`**
- **Cause:** Gemini CLI does not currently support your location. For a full - **Cause:** Gemini CLI does not currently support your location. For a full
list of supported locations, see the following pages: list of supported locations, see the following pages:
- Gemini Code Assist for individuals: - Gemini Code Assist for individuals:
[Available locations](https://developers.google.com/gemini-code-assist/resources/available-locations#americas) [Available locations](https://developers.google.com/gemini-code-assist/resources/available-locations#americas)
- **Error: `Failed to login. Message: Request contains an invalid argument`** - **Error: `Failed to sign in. Message: Request contains an invalid argument`**
- **Cause:** Users with Google Workspace accounts or Google Cloud accounts - **Cause:** Users with Google Workspace accounts or Google Cloud accounts
associated with their Gmail accounts may not be able to activate the free associated with their Gmail accounts may not be able to activate the free
tier of the Google Code Assist plan. tier of the Google Code Assist plan.
+1 -1
View File
@@ -676,7 +676,7 @@ const SETTINGS_SCHEMA = {
requiresRestart: false, requiresRestart: false,
default: true, default: true,
description: description:
"Show the logged-in user's identity (e.g. email) in the UI.", "Show the signed-in user's identity (e.g. email) in the UI.",
showInDialog: true, showInDialog: true,
}, },
useAlternateBuffer: { useAlternateBuffer: {
+2 -2
View File
@@ -48,14 +48,14 @@ describe('auth', () => {
}); });
it('should return error message on failed auth', async () => { it('should return error message on failed auth', async () => {
const error = new Error('Auth failed'); const error = new Error('Authentication failed');
vi.mocked(mockConfig.refreshAuth).mockRejectedValue(error); vi.mocked(mockConfig.refreshAuth).mockRejectedValue(error);
const result = await performInitialAuth( const result = await performInitialAuth(
mockConfig, mockConfig,
AuthType.LOGIN_WITH_GOOGLE, AuthType.LOGIN_WITH_GOOGLE,
); );
expect(result).toEqual({ expect(result).toEqual({
authError: 'Failed to login. Message: Auth failed', authError: 'Failed to sign in. Message: Authentication failed',
accountSuspensionInfo: null, accountSuspensionInfo: null,
}); });
expect(mockConfig.refreshAuth).toHaveBeenCalledWith( expect(mockConfig.refreshAuth).toHaveBeenCalledWith(
+1 -1
View File
@@ -64,7 +64,7 @@ export async function performInitialAuth(
}; };
} }
return { return {
authError: `Failed to login. Message: ${getErrorMessage(e)}`, authError: `Failed to sign in. Message: ${getErrorMessage(e)}`,
accountSuspensionInfo: null, accountSuspensionInfo: null,
}; };
} }
+2 -2
View File
@@ -209,7 +209,7 @@ describe('AuthDialog', () => {
{ {
setup: () => {}, setup: () => {},
expected: AuthType.LOGIN_WITH_GOOGLE, expected: AuthType.LOGIN_WITH_GOOGLE,
desc: 'defaults to Login with Google', desc: 'defaults to Sign in with Google',
}, },
])('selects initial auth type $desc', async ({ setup, expected }) => { ])('selects initial auth type $desc', async ({ setup, expected }) => {
setup(); setup();
@@ -351,7 +351,7 @@ describe('AuthDialog', () => {
unmount(); unmount();
}); });
it('exits process for Login with Google when browser is suppressed', async () => { it('exits process for Sign in with Google when browser is suppressed', async () => {
vi.useFakeTimers(); vi.useFakeTimers();
const exitSpy = vi const exitSpy = vi
.spyOn(process, 'exit') .spyOn(process, 'exit')
+1 -1
View File
@@ -44,7 +44,7 @@ export function AuthDialog({
const [exiting, setExiting] = useState(false); const [exiting, setExiting] = useState(false);
let items = [ let items = [
{ {
label: 'Login with Google', label: 'Sign in with Google',
value: AuthType.LOGIN_WITH_GOOGLE, value: AuthType.LOGIN_WITH_GOOGLE,
key: AuthType.LOGIN_WITH_GOOGLE, key: AuthType.LOGIN_WITH_GOOGLE,
}, },
@@ -59,8 +59,8 @@ describe('AuthInProgress', () => {
<AuthInProgress onTimeout={onTimeout} />, <AuthInProgress onTimeout={onTimeout} />,
); );
await waitUntilReady(); await waitUntilReady();
expect(lastFrame()).toContain('[Spinner] Waiting for auth...'); expect(lastFrame()).toContain('[Spinner] Waiting for authentication...');
expect(lastFrame()).toContain('Press ESC or CTRL+C to cancel'); expect(lastFrame()).toContain('Press Esc or Ctrl+C to cancel');
unmount(); unmount();
}); });
+2 -2
View File
@@ -53,8 +53,8 @@ export function AuthInProgress({
) : ( ) : (
<Box> <Box>
<Text> <Text>
<CliSpinner type="dots" /> Waiting for auth... (Press ESC or CTRL+C <CliSpinner type="dots" /> Waiting for authentication... (Press Esc
to cancel) or Ctrl+C to cancel)
</Text> </Text>
</Box> </Box>
)} )}
@@ -45,13 +45,13 @@ export const LoginWithGoogleRestartDialog = ({
); );
const message = const message =
'You have successfully logged in with Google. Gemini CLI needs to be restarted.'; "You've successfully signed in with Google. Gemini CLI needs to be restarted.";
return ( return (
<Box borderStyle="round" borderColor={theme.status.warning} paddingX={1}> <Box borderStyle="round" borderColor={theme.status.warning} paddingX={1}>
<Text color={theme.status.warning}> <Text color={theme.status.warning}>
{message} Press &apos;r&apos; to restart, or &apos;escape&apos; to {message} Press R to restart, or Esc to choose a different
choose a different auth method. authentication method.
</Text> </Text>
</Box> </Box>
); );
@@ -7,7 +7,7 @@ exports[`AuthDialog > Snapshots > renders correctly with auth error 1`] = `
│ │ │ │
│ How would you like to authenticate for this project? │ │ How would you like to authenticate for this project? │
│ │ │ │
│ (selected) Login with Google(not selected) Use Gemini API Key(not selected) Vertex AI │ (selected) Sign in with Google(not selected) Use Gemini API Key(not selected) Vertex AI │
│ │ │ │
│ Something went wrong │ │ Something went wrong │
│ │ │ │
@@ -28,7 +28,7 @@ exports[`AuthDialog > Snapshots > renders correctly with default props 1`] = `
│ │ │ │
│ How would you like to authenticate for this project? │ │ How would you like to authenticate for this project? │
│ │ │ │
│ (selected) Login with Google(not selected) Use Gemini API Key(not selected) Vertex AI │ (selected) Sign in with Google(not selected) Use Gemini API Key(not selected) Vertex AI │
│ │ │ │
│ (Use Enter to select) │ │ (Use Enter to select) │
│ │ │ │
@@ -2,8 +2,8 @@
exports[`LoginWithGoogleRestartDialog > renders correctly 1`] = ` exports[`LoginWithGoogleRestartDialog > renders correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ You have successfully logged in with Google. Gemini CLI needs to be restarted. Press 'r' to │ You've successfully signed in with Google. Gemini CLI needs to be restarted. Press R to restart,
restart, or 'escape' to choose a different auth method. │ or Esc to choose a different authentication method.
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
" "
`; `;
+1 -1
View File
@@ -288,7 +288,7 @@ describe('useAuth', () => {
); );
await waitFor(() => { await waitFor(() => {
expect(result.current.authError).toContain('Failed to login'); expect(result.current.authError).toContain('Failed to sign in');
expect(result.current.authState).toBe(AuthState.Updating); expect(result.current.authState).toBe(AuthState.Updating);
}); });
}); });
+1 -1
View File
@@ -149,7 +149,7 @@ export const useAuthCommand = (
// Show the error message directly without "Failed to login" prefix // Show the error message directly without "Failed to login" prefix
onAuthError(getErrorMessage(e)); onAuthError(getErrorMessage(e));
} else { } else {
onAuthError(`Failed to login. Message: ${getErrorMessage(e)}`); onAuthError(`Failed to sign in. Message: ${getErrorMessage(e)}`);
} }
} }
})(); })();
@@ -34,11 +34,13 @@ describe('authCommand', () => {
vi.clearAllMocks(); vi.clearAllMocks();
}); });
it('should have subcommands: login and logout', () => { it('should have subcommands: signin and signout', () => {
expect(authCommand.subCommands).toBeDefined(); expect(authCommand.subCommands).toBeDefined();
expect(authCommand.subCommands).toHaveLength(2); expect(authCommand.subCommands).toHaveLength(2);
expect(authCommand.subCommands?.[0]?.name).toBe('login'); expect(authCommand.subCommands?.[0]?.name).toBe('signin');
expect(authCommand.subCommands?.[1]?.name).toBe('logout'); expect(authCommand.subCommands?.[0]?.altNames).toContain('login');
expect(authCommand.subCommands?.[1]?.name).toBe('signout');
expect(authCommand.subCommands?.[1]?.altNames).toContain('logout');
}); });
it('should return a dialog action to open the auth dialog when called with no args', () => { it('should return a dialog action to open the auth dialog when called with no args', () => {
@@ -59,19 +61,19 @@ describe('authCommand', () => {
expect(authCommand.description).toBe('Manage authentication'); expect(authCommand.description).toBe('Manage authentication');
}); });
describe('auth login subcommand', () => { describe('auth signin subcommand', () => {
it('should return auth dialog action', () => { it('should return auth dialog action', () => {
const loginCommand = authCommand.subCommands?.[0]; const loginCommand = authCommand.subCommands?.[0];
expect(loginCommand?.name).toBe('login'); expect(loginCommand?.name).toBe('signin');
const result = loginCommand!.action!(mockContext, ''); const result = loginCommand!.action!(mockContext, '');
expect(result).toEqual({ type: 'dialog', dialog: 'auth' }); expect(result).toEqual({ type: 'dialog', dialog: 'auth' });
}); });
}); });
describe('auth logout subcommand', () => { describe('auth signout subcommand', () => {
it('should clear cached credentials', async () => { it('should clear cached credentials', async () => {
const logoutCommand = authCommand.subCommands?.[1]; const logoutCommand = authCommand.subCommands?.[1];
expect(logoutCommand?.name).toBe('logout'); expect(logoutCommand?.name).toBe('signout');
const { clearCachedCredentialFile } = await import( const { clearCachedCredentialFile } = await import(
'@google/gemini-cli-core' '@google/gemini-cli-core'
+6 -4
View File
@@ -14,8 +14,9 @@ import { clearCachedCredentialFile } from '@google/gemini-cli-core';
import { SettingScope } from '../../config/settings.js'; import { SettingScope } from '../../config/settings.js';
const authLoginCommand: SlashCommand = { const authLoginCommand: SlashCommand = {
name: 'login', name: 'signin',
description: 'Login or change the auth method', altNames: ['login'],
description: 'Sign in or change the authentication method',
kind: CommandKind.BUILT_IN, kind: CommandKind.BUILT_IN,
autoExecute: true, autoExecute: true,
action: (_context, _args): OpenDialogActionReturn => ({ action: (_context, _args): OpenDialogActionReturn => ({
@@ -25,8 +26,9 @@ const authLoginCommand: SlashCommand = {
}; };
const authLogoutCommand: SlashCommand = { const authLogoutCommand: SlashCommand = {
name: 'logout', name: 'signout',
description: 'Log out and clear all cached credentials', altNames: ['logout'],
description: 'Sign out and clear all cached credentials',
kind: CommandKind.BUILT_IN, kind: CommandKind.BUILT_IN,
action: async (context, _args): Promise<LogoutActionReturn> => { action: async (context, _args): Promise<LogoutActionReturn> => {
await clearCachedCredentialFile(); await clearCachedCredentialFile();
@@ -36,7 +36,7 @@ describe('AboutBox', () => {
expect(output).toContain('gemini-pro'); expect(output).toContain('gemini-pro');
expect(output).toContain('default'); expect(output).toContain('default');
expect(output).toContain('macOS'); expect(output).toContain('macOS');
expect(output).toContain('Logged in with Google'); expect(output).toContain('Signed in with Google');
unmount(); unmount();
}); });
@@ -63,7 +63,7 @@ describe('AboutBox', () => {
); );
await waitUntilReady(); await waitUntilReady();
const output = lastFrame(); const output = lastFrame();
expect(output).toContain('Logged in with Google (test@example.com)'); expect(output).toContain('Signed in with Google (test@example.com)');
unmount(); unmount();
}); });
+2 -2
View File
@@ -116,8 +116,8 @@ export const AboutBox: React.FC<AboutBoxProps> = ({
<Text color={theme.text.primary}> <Text color={theme.text.primary}>
{selectedAuthType.startsWith('oauth') {selectedAuthType.startsWith('oauth')
? userEmail ? userEmail
? `Logged in with Google (${userEmail})` ? `Signed in with Google (${userEmail})`
: 'Logged in with Google' : 'Signed in with Google'
: selectedAuthType} : selectedAuthType}
</Text> </Text>
</Box> </Box>
@@ -28,9 +28,9 @@ describe('LogoutConfirmationDialog', () => {
); );
await waitUntilReady(); await waitUntilReady();
expect(lastFrame()).toContain('You are now logged out.'); expect(lastFrame()).toContain('You are now signed out');
expect(lastFrame()).toContain( expect(lastFrame()).toContain(
'Login again to continue using Gemini CLI, or exit the application.', 'Sign in again to continue using Gemini CLI, or exit the application.',
); );
expect(lastFrame()).toContain('(Use Enter to select, Esc to close)'); expect(lastFrame()).toContain('(Use Enter to select, Esc to close)');
unmount(); unmount();
@@ -45,7 +45,7 @@ describe('LogoutConfirmationDialog', () => {
expect(RadioButtonSelect).toHaveBeenCalled(); expect(RadioButtonSelect).toHaveBeenCalled();
const mockCall = vi.mocked(RadioButtonSelect).mock.calls[0][0]; const mockCall = vi.mocked(RadioButtonSelect).mock.calls[0][0];
expect(mockCall.items).toEqual([ expect(mockCall.items).toEqual([
{ label: 'Login', value: LogoutChoice.LOGIN, key: 'login' }, { label: 'Sign in', value: LogoutChoice.LOGIN, key: 'login' },
{ label: 'Exit', value: LogoutChoice.EXIT, key: 'exit' }, { label: 'Exit', value: LogoutChoice.EXIT, key: 'exit' },
]); ]);
expect(mockCall.isFocused).toBe(true); expect(mockCall.isFocused).toBe(true);
@@ -37,7 +37,7 @@ export const LogoutConfirmationDialog: React.FC<
const options: Array<RadioSelectItem<LogoutChoice>> = [ const options: Array<RadioSelectItem<LogoutChoice>> = [
{ {
label: 'Login', label: 'Sign in',
value: LogoutChoice.LOGIN, value: LogoutChoice.LOGIN,
key: 'login', key: 'login',
}, },
@@ -61,10 +61,10 @@ export const LogoutConfirmationDialog: React.FC<
> >
<Box flexDirection="column" marginBottom={1}> <Box flexDirection="column" marginBottom={1}>
<Text bold color={theme.text.primary}> <Text bold color={theme.text.primary}>
You are now logged out. You are now signed out
</Text> </Text>
<Text color={theme.text.secondary}> <Text color={theme.text.secondary}>
Login again to continue using Gemini CLI, or exit the application. Sign in again to continue using Gemini CLI, or exit the application.
</Text> </Text>
</Box> </Box>
@@ -539,7 +539,7 @@ describe('<ModelStatsDisplay />', () => {
const output = lastFrame(); const output = lastFrame();
expect(output).toContain('Auth Method:'); expect(output).toContain('Auth Method:');
expect(output).toContain('Logged in with Google'); expect(output).toContain('Signed in with Google');
expect(output).toContain('(test@example.com)'); expect(output).toContain('(test@example.com)');
expect(output).toContain('Tier:'); expect(output).toContain('Tier:');
expect(output).toContain('Pro'); expect(output).toContain('Pro');
@@ -340,8 +340,8 @@ export const ModelStatsDisplay: React.FC<ModelStatsDisplayProps> = ({
<Text color={theme.text.primary}> <Text color={theme.text.primary}>
{selectedAuthType.startsWith('oauth') {selectedAuthType.startsWith('oauth')
? userEmail ? userEmail
? `Logged in with Google (${userEmail})` ? `Signed in with Google (${userEmail})`
: 'Logged in with Google' : 'Signed in with Google'
: selectedAuthType} : selectedAuthType}
</Text> </Text>
</Box> </Box>
@@ -616,7 +616,7 @@ describe('<StatsDisplay />', () => {
const output = lastFrame(); const output = lastFrame();
expect(output).toContain('Auth Method:'); expect(output).toContain('Auth Method:');
expect(output).toContain('Logged in with Google (test@example.com)'); expect(output).toContain('Signed in with Google (test@example.com)');
expect(output).toContain('Tier:'); expect(output).toContain('Tier:');
expect(output).toContain('Pro'); expect(output).toContain('Pro');
}); });
@@ -589,8 +589,8 @@ export const StatsDisplay: React.FC<StatsDisplayProps> = ({
<Text color={theme.text.primary}> <Text color={theme.text.primary}>
{selectedAuthType.startsWith('oauth') {selectedAuthType.startsWith('oauth')
? userEmail ? userEmail
? `Logged in with Google (${userEmail})` ? `Signed in with Google (${userEmail})`
: 'Logged in with Google' : 'Signed in with Google'
: selectedAuthType} : selectedAuthType}
</Text> </Text>
</StatRow> </StatRow>
@@ -1,6 +1,6 @@
/** /**
* @license * @license
* Copyright 2025 Google LLC * Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -45,7 +45,7 @@ describe('<UserIdentity />', () => {
await waitUntilReady(); await waitUntilReady();
const output = lastFrame(); const output = lastFrame();
expect(output).toContain('test@example.com'); expect(output).toContain('Signed in with Google: test@example.com');
expect(output).toContain('/auth'); expect(output).toContain('/auth');
expect(output).not.toContain('/upgrade'); expect(output).not.toContain('/upgrade');
unmount(); unmount();
@@ -91,7 +91,8 @@ describe('<UserIdentity />', () => {
await waitUntilReady(); await waitUntilReady();
const output = lastFrame(); const output = lastFrame();
expect(output).toContain('Logged in with Google'); expect(output).toContain('Signed in with Google');
expect(output).not.toContain('Signed in with Google:');
expect(output).toContain('/auth'); expect(output).toContain('/auth');
expect(output).not.toContain('/upgrade'); expect(output).not.toContain('/upgrade');
unmount(); unmount();
@@ -111,11 +112,20 @@ describe('<UserIdentity />', () => {
await waitUntilReady(); await waitUntilReady();
const output = lastFrame(); const output = lastFrame();
expect(output).toContain('test@example.com'); expect(output).toContain('Signed in with Google: test@example.com');
expect(output).toContain('/auth'); expect(output).toContain('/auth');
expect(output).toContain('Premium Plan'); expect(output).toContain('Plan: Premium Plan');
expect(output).toContain('/upgrade'); expect(output).toContain('/upgrade');
// Check for two lines (or more if wrapped, but here it should be separate)
const lines = output?.split('\n').filter((line) => line.trim().length > 0);
expect(lines?.some((line) => line.includes('Signed in with Google'))).toBe(
true,
);
expect(lines?.some((line) => line.includes('Plan: Premium Plan'))).toBe(
true,
);
unmount(); unmount();
}); });
@@ -168,7 +178,7 @@ describe('<UserIdentity />', () => {
await waitUntilReady(); await waitUntilReady();
const output = lastFrame(); const output = lastFrame();
expect(output).toContain('Enterprise Tier'); expect(output).toContain('Plan: Enterprise Tier');
expect(output).toContain('/upgrade'); expect(output).toContain('/upgrade');
unmount(); unmount();
}); });
@@ -43,7 +43,10 @@ export const UserIdentity: React.FC<UserIdentityProps> = ({ config }) => {
<Box> <Box>
<Text color={theme.text.primary} wrap="truncate-end"> <Text color={theme.text.primary} wrap="truncate-end">
{authType === AuthType.LOGIN_WITH_GOOGLE ? ( {authType === AuthType.LOGIN_WITH_GOOGLE ? (
<Text>{email ?? 'Logged in with Google'}</Text> <Text>
<Text bold>Signed in with Google{email ? ':' : ''}</Text>
{email ? ` ${email}` : ''}
</Text>
) : ( ) : (
`Authenticated with ${authType}` `Authenticated with ${authType}`
)} )}
@@ -55,7 +58,7 @@ export const UserIdentity: React.FC<UserIdentityProps> = ({ config }) => {
{tierName && ( {tierName && (
<Box> <Box>
<Text color={theme.text.primary} wrap="truncate-end"> <Text color={theme.text.primary} wrap="truncate-end">
{tierName} <Text bold>Plan:</Text> {tierName}
</Text> </Text>
<Text color={theme.text.secondary}> /upgrade</Text> <Text color={theme.text.secondary}> /upgrade</Text>
</Box> </Box>
@@ -136,7 +136,7 @@ export function ValidationDialog({
<CliSpinner /> <CliSpinner />
<Text> <Text>
{' '} {' '}
Waiting for verification... (Press ESC or CTRL+C to cancel) Waiting for verification... (Press Esc or Ctrl+C to cancel)
</Text> </Text>
</Box> </Box>
{errorMessage && ( {errorMessage && (
+2 -2
View File
@@ -405,8 +405,8 @@
}, },
"showUserIdentity": { "showUserIdentity": {
"title": "Show User Identity", "title": "Show User Identity",
"description": "Show the logged-in user's identity (e.g. email) in the UI.", "description": "Show the signed-in user's identity (e.g. email) in the UI.",
"markdownDescription": "Show the logged-in user's identity (e.g. email) in the UI.\n\n- Category: `UI`\n- Requires restart: `no`\n- Default: `true`", "markdownDescription": "Show the signed-in user's identity (e.g. email) in the UI.\n\n- Category: `UI`\n- Requires restart: `no`\n- Default: `true`",
"default": true, "default": true,
"type": "boolean" "type": "boolean"
}, },