mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-24 20:14:44 -07:00
fix(auth): update terminology to 'sign in' and 'sign out' (#20892)
Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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` |
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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 'r' to restart, or 'escape' 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. │
|
||||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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 && (
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user