feat(cliproxy): allow optional provider nicknames

- stop requiring manual unique nicknames for no-email providers by default

- preserve explicit nickname validation and same-account reauth semantics

- persist optional nicknames through dashboard manual callback flows
This commit is contained in:
Tam Nhu Tran
2026-03-23 11:02:08 -04:00
parent 185f7f469e
commit bdb7ac2937
15 changed files with 398 additions and 220 deletions
@@ -41,7 +41,6 @@ import {
DEFAULT_KIRO_AUTH_METHOD,
getKiroAuthMethodOption,
isDeviceCodeProvider,
isNicknameRequiredProvider,
KIRO_AUTH_METHOD_OPTIONS,
} from '@/lib/provider-config';
import type { KiroAuthMethod } from '@/lib/provider-config';
@@ -89,7 +88,6 @@ export function AddAccountDialog({
const isAgyRiskChecklistComplete = isAntigravityRiskChecklistComplete(agyRiskChecklist);
const isGeminiRiskAcknowledged = normalizeRiskPhrase(riskAcknowledgementText) === RISK_ACK_PHRASE;
const defaultDeviceCode = isDeviceCodeProvider(provider);
const requiresNickname = isNicknameRequiredProvider(provider);
const kiroMethodOption = getKiroAuthMethodOption(kiroAuthMethod);
const isDeviceCode = isKiro ? kiroMethodOption.flowType === 'device_code' : defaultDeviceCode;
const isPending = authFlow.isAuthenticating || kiroImportMutation.isPending;
@@ -266,10 +264,6 @@ export function AddAccountDialog({
);
return;
}
if (requiresNickname && !nicknameTrimmed) {
setLocalError(`Nickname is required for ${displayName} accounts.`);
return;
}
setLocalError(null);
wasAuthenticatingRef.current = true;
authFlow.startAuth(provider, {
@@ -394,11 +388,7 @@ export function AddAccountDialog({
{/* Nickname input - only show before auth starts */}
{!showAuthUI && (
<div className="space-y-2">
<Label htmlFor="nickname">
{requiresNickname
? t('addAccountDialog.nicknameRequired')
: t('addAccountDialog.nicknameOptional')}
</Label>
<Label htmlFor="nickname">{t('addAccountDialog.nicknameOptional')}</Label>
<div className="flex items-center gap-2">
<User className="w-4 h-4 text-muted-foreground" />
<Input
@@ -414,9 +404,7 @@ export function AddAccountDialog({
/>
</div>
<p className="text-xs text-muted-foreground">
{requiresNickname
? t('addAccountDialog.nicknameRequiredHint')
: t('addAccountDialog.nicknameOptionalHint')}
{t('addAccountDialog.nicknameOptionalHint')}
</p>
</div>
)}
@@ -554,7 +542,6 @@ export function AddAccountDialog({
disabled={
isPending ||
isAgyBypassStatePending ||
(requiresNickname && !nicknameTrimmed) ||
(requiresAgyResponsibilityFlow && !isAgyRiskChecklistComplete) ||
(requiresSafetyAcknowledgement && !isGeminiRiskAcknowledged)
}
+4 -4
View File
@@ -473,7 +473,7 @@ const resources = {
nicknameRequiredHint:
'Required for this provider. Use a unique friendly name (e.g., work, personal).',
nicknameOptionalHint:
'A friendly name to identify this account. Auto-generated from email if left empty.',
'A friendly name to identify this account. Leave blank to use a safe generated identifier.',
waitingForAuth: 'Waiting for authentication...',
deviceCodeHint:
'A verification code dialog will appear shortly. Enter the code on the provider website.',
@@ -1632,7 +1632,7 @@ const resources = {
nicknameOptional: '昵称(选填)',
nicknamePlaceholder: '例如:工作、个人',
nicknameRequiredHint: '该提供商必填。请使用唯一易记名称(如工作、个人)。',
nicknameOptionalHint: '用于区分账号的友好名称。留空将根据邮箱自动生成。',
nicknameOptionalHint: '用于区分账号的友好名称。留空将自动生成安全标识。',
waitingForAuth: '等待认证中...',
deviceCodeHint: '验证码对话框即将出现,请在提供商网站输入验证码。',
browserHint: '在浏览器中完成认证后,本对话框将自动关闭。',
@@ -2804,7 +2804,7 @@ const resources = {
nicknameRequiredHint:
'Bắt buộc với nhà cung cấp này. Dùng tên thân thiện duy nhất (ví dụ: work, personal).',
nicknameOptionalHint:
'Một cái tên thân thiện để xác định tài khoản này. Tự động tạo từ email nếu để trống.',
'Tên thân thiện để nhận biết tài khoản này. Để trống để dùng mã nhận dạng an toàn do hệ thống tạo.',
waitingForAuth: 'Đang chờ xác thực...',
deviceCodeHint:
'Hộp thoại mã xác minh sẽ sớm xuất hiện. Nhập mã trên trang web của nhà cung cấp.',
@@ -4004,7 +4004,7 @@ const resources = {
nicknameRequiredHint:
'このプロバイダーでは必須です。重複しないわかりやすい名前を付けてください(例: work, personal)。',
nicknameOptionalHint:
'このアカウントを識別しやすい名前です。空欄ならメールアドレスから自動生成されます。',
'このアカウントを識別しやすい名前です。空欄の場合は安全な識別子を自動生成ます。',
waitingForAuth: '認証を待機中...',
deviceCodeHint:
'確認コードのダイアログがまもなく表示されます。プロバイダーのサイトでコードを入力してください。',
-9
View File
@@ -233,15 +233,6 @@ export function getDeviceCodeProviderInstruction(provider: unknown): string {
return 'Complete the authorization in your browser.';
}
/** Providers that require nickname because token payload may not include email. */
export const NICKNAME_REQUIRED_PROVIDERS: CLIProxyProvider[] = ['ghcp', 'kiro'];
/** Check if provider requires user-supplied nickname in auth flow */
export function isNicknameRequiredProvider(provider: unknown): boolean {
const normalized = normalizeProviderInput(provider);
return isValidProvider(normalized) && NICKNAME_REQUIRED_PROVIDERS.includes(normalized);
}
/** Kiro auth methods exposed in CCS UI (aligned with CLIProxyAPIPlus support). */
export const KIRO_AUTH_METHODS = ['aws', 'aws-authcode', 'google', 'github'] as const;
export type KiroAuthMethod = (typeof KIRO_AUTH_METHODS)[number];