feat(cli): improve auth dialog UX with clearer three-option layout

- Replace nested API-KEY submenu with flat three-option layout
- Add descriptive labels for each authentication method:
  - Qwen OAuth: Free, up to 1,000 requests/day
  - Alibaba Cloud Coding Plan: Paid, multiple model providers
  - API Key: Bring your own API key
- Simplify region selection for Coding Plan (China vs Global)
- Use DescriptiveRadioButtonSelect for better visual hierarchy
- Add itemGap prop to BaseSelectionList for spacing
- Update i18n strings in en.js, zh.js, and ru.js
- Simplify custom API key configuration info view
- Clean up unused region-specific strings

Closes #2016

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
tanzhenxin 2026-03-01 15:22:35 +08:00
parent 1f46ed28d9
commit d3cdad5100
20 changed files with 442 additions and 619 deletions

View file

@ -251,15 +251,9 @@ export function getCodingPlanConfig(region: CodingPlanRegion) {
region === CodingPlanRegion.CHINA
? 'https://coding.dashscope.aliyuncs.com/v1'
: 'https://coding-intl.dashscope.aliyuncs.com/v1';
const regionName =
region === CodingPlanRegion.CHINA
? 'Coding Plan (Bailian, China)'
: 'Coding Plan (Bailian, Global/Intl)';
return {
template,
baseUrl,
regionName,
version: computeCodingPlanVersion(template),
};
}

View file

@ -157,6 +157,7 @@ export default {
'Enter to confirm, Esc to cancel': 'Enter zum Bestätigen, Esc zum Abbrechen',
'Enter to select, ↑↓ to navigate, Esc to go back':
'Enter zum Auswählen, ↑↓ zum Navigieren, Esc zum Zurückgehen',
'Enter to submit, Esc to go back': 'Enter zum Absenden, Esc zum Zurückgehen',
'Invalid step: {{step}}': 'Ungültiger Schritt: {{step}}',
'No subagents found.': 'Keine Unteragenten gefunden.',
"Use '/agents create' to create your first subagent.":
@ -944,18 +945,22 @@ export default {
// Dialogs - Auth
// ============================================================================
'Get started': 'Loslegen',
'How would you like to authenticate for this project?':
'Wie möchten Sie sich für dieses Projekt authentifizieren?',
'Select Authentication Method': 'Authentifizierungsmethode auswählen',
'OpenAI API key is required to use OpenAI authentication.':
'OpenAI API-Schlüssel ist für die OpenAI-Authentifizierung erforderlich.',
'You must select an auth method to proceed. Press Ctrl+C again to exit.':
'Sie müssen eine Authentifizierungsmethode wählen, um fortzufahren. Drücken Sie erneut Strg+C zum Beenden.',
'(Use Enter to Set Auth)': '(Enter zum Festlegen der Authentifizierung)',
'Terms of Services and Privacy Notice for Qwen Code':
'Nutzungsbedingungen und Datenschutzhinweis für Qwen Code',
'Terms of Services and Privacy Notice':
'Nutzungsbedingungen und Datenschutzhinweis',
'Qwen OAuth': 'Qwen OAuth',
'Free \u00B7 Up to 1,000 requests/day \u00B7 Qwen latest models':
'Kostenlos \u00B7 Bis zu 1.000 Anfragen/Tag \u00B7 Qwen neueste Modelle',
'Login with QwenChat account to use daily free quota.':
'Melden Sie sich mit Ihrem QwenChat-Konto an, um das tägliche kostenlose Kontingent zu nutzen.',
'Paid \u00B7 Up to 6,000 requests/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax and more':
'Kostenpflichtig \u00B7 Bis zu 6.000 Anfragen/5 Std. \u00B7 Qwen, GLM, Kimi, Minimax und mehr',
'Alibaba Cloud Coding Plan': 'Alibaba Cloud Coding Plan',
'Bring your own API key': 'Eigenen API-Schlüssel verwenden',
'API-KEY': 'API-KEY',
'Use coding plan credentials or your own api-keys/providers.':
'Verwenden Sie Coding Plan-Anmeldedaten oder Ihre eigenen API-Schlüssel/Anbieter.',
@ -985,6 +990,8 @@ export default {
'Warten auf Qwen OAuth-Authentifizierung...',
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.':
'Hinweis: Ihr bestehender API-Schlüssel in settings.json wird bei Verwendung von Qwen OAuth nicht gelöscht. Sie können später bei Bedarf zur OpenAI-Authentifizierung zurückwechseln.',
'Note: Your existing API key will not be cleared when using Qwen OAuth.':
'Hinweis: Ihr bestehender API-Schlüssel wird bei Verwendung von Qwen OAuth nicht gelöscht.',
'Authentication timed out. Please try again.':
'Authentifizierung abgelaufen. Bitte versuchen Sie es erneut.',
'Waiting for auth... (Press ESC or CTRL+C to cancel)':
@ -1402,32 +1409,21 @@ export default {
'Probieren Sie /insight, um personalisierte Erkenntnisse aus Ihrem Chatverlauf zu erstellen.',
// ============================================================================
// Custom API-KEY Configuration
// Custom API Key Configuration
// ============================================================================
'For advanced users who want to configure models manually.':
'Für fortgeschrittene Benutzer, die Modelle manuell konfigurieren möchten.',
'Please configure your models in settings.json:':
'Bitte konfigurieren Sie Ihre Modelle in settings.json:',
'Set API key via environment variable (e.g., OPENAI_API_KEY)':
'API-Schlüssel über Umgebungsvariable setzen (z.B. OPENAI_API_KEY)',
"Add model configuration to modelProviders['openai'] (or other auth types)":
"Modellkonfiguration zu modelProviders['openai'] (oder anderen Authentifizierungstypen) hinzufügen",
'Each provider needs: id, envKey (required), plus optional baseUrl, generationConfig':
'Jeder Anbieter benötigt: id, envKey (erforderlich), plus optionale baseUrl, generationConfig',
'Use /model command to select your preferred model from the configured list':
'Verwenden Sie den /model-Befehl, um Ihr bevorzugtes Modell aus der konfigurierten Liste auszuwählen',
'Supported auth types: openai, anthropic, gemini, vertex-ai, etc.':
'Unterstützte Authentifizierungstypen: openai, anthropic, gemini, vertex-ai, usw.',
'You can configure your API key and models in settings.json':
'Sie können Ihren API-Schlüssel und Modelle in settings.json konfigurieren',
'Refer to the documentation for setup instructions':
'Einrichtungsanweisungen finden Sie in der Dokumentation',
// ============================================================================
// Coding Plan Authentication
// ============================================================================
'Please enter your API key:': 'Bitte geben Sie Ihren API-Schlüssel ein:',
'API key cannot be empty.': 'API-Schlüssel darf nicht leer sein.',
'You can get your exclusive Coding Plan API-KEY here:':
'Hier können Sie Ihren exklusiven Coding Plan API-KEY erhalten:',
'New model configurations are available for Bailian Coding Plan. Update now?':
'Neue Modellkonfigurationen sind für Bailian Coding Plan verfügbar. Jetzt aktualisieren?',
'You can get your Coding Plan API key here':
'Sie können Ihren Coding-Plan-API-Schlüssel hier erhalten',
'New model configurations are available for Alibaba Cloud Coding Plan. Update now?':
'Neue Modellkonfigurationen sind für Alibaba Cloud Coding Plan verfügbar. Jetzt aktualisieren?',
'Coding Plan configuration updated successfully. New models are now available.':
'Coding Plan-Konfiguration erfolgreich aktualisiert. Neue Modelle sind jetzt verfügbar.',
'Coding Plan API key not found. Please re-authenticate with Coding Plan.':
@ -1438,32 +1434,16 @@ export default {
// ============================================================================
// Auth Dialog - View Titles and Labels
// ============================================================================
'Coding Plan': 'Coding Plan',
'Coding Plan (Bailian, China)': 'Coding Plan (Bailian, China)',
'Coding Plan (Bailian, Global/Intl)': 'Coding Plan (Bailian, Global/Intl)',
"Paste your api key of Bailian Coding Plan and you're all set!":
'Fügen Sie Ihren Bailian Coding Plan API-Schlüssel ein und Sie sind bereit!',
"Paste your api key of Coding Plan (Bailian, Global/Intl) and you're all set!":
'Fügen Sie Ihren Coding Plan (Bailian, Global/Intl) API-Schlüssel ein und Sie sind bereit!',
Custom: 'Benutzerdefiniert',
'More instructions about configuring `modelProviders` manually.':
'Weitere Anweisungen zur manuellen Konfiguration von `modelProviders`.',
'Select API-KEY configuration mode:':
'API-KEY-Konfigurationsmodus auswählen:',
'(Press Escape to go back)': '(Escape drücken zum Zurückgehen)',
'(Press Enter to submit, Escape to cancel)':
'(Enter zum Absenden, Escape zum Abbrechen)',
'More instructions please check:': 'Weitere Anweisungen finden Sie unter:',
'Select Region for Coding Plan': 'Region für Coding Plan auswählen',
'Choose based on where your account is registered':
'Wählen Sie basierend auf dem Registrierungsort Ihres Kontos',
'Enter Coding Plan API Key': 'Coding-Plan-API-Schlüssel eingeben',
// ============================================================================
// Coding Plan International Updates
// ============================================================================
'New model configurations are available for {{region}}. Update now?':
'Neue Modellkonfigurationen sind für {{region}} verfügbar. Jetzt aktualisieren?',
'New model configurations are available for Bailian Coding Plan (China). Update now?':
'Neue Modellkonfigurationen sind für Bailian Coding Plan (China) verfügbar. Jetzt aktualisieren?',
'New model configurations are available for Coding Plan (Bailian, Global/Intl). Update now?':
'Neue Modellkonfigurationen sind für Coding Plan (Bailian, Global/Intl) verfügbar. Jetzt aktualisieren?',
'{{region}} configuration updated successfully. Model switched to "{{model}}".':
'{{region}}-Konfiguration erfolgreich aktualisiert. Modell auf "{{model}}" umgeschaltet.',
'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).':

View file

@ -178,6 +178,7 @@ export default {
'Enter to confirm, Esc to cancel': 'Enter to confirm, Esc to cancel',
'Enter to select, ↑↓ to navigate, Esc to go back':
'Enter to select, ↑↓ to navigate, Esc to go back',
'Enter to submit, Esc to go back': 'Enter to submit, Esc to go back',
'Invalid step: {{step}}': 'Invalid step: {{step}}',
'No subagents found.': 'No subagents found.',
"Use '/agents create' to create your first subagent.":
@ -935,18 +936,22 @@ export default {
// Dialogs - Auth
// ============================================================================
'Get started': 'Get started',
'How would you like to authenticate for this project?':
'How would you like to authenticate for this project?',
'Select Authentication Method': 'Select Authentication Method',
'OpenAI API key is required to use OpenAI authentication.':
'OpenAI API key is required to use OpenAI authentication.',
'You must select an auth method to proceed. Press Ctrl+C again to exit.':
'You must select an auth method to proceed. Press Ctrl+C again to exit.',
'(Use Enter to Set Auth)': '(Use Enter to Set Auth)',
'Terms of Services and Privacy Notice for Qwen Code':
'Terms of Services and Privacy Notice for Qwen Code',
'Terms of Services and Privacy Notice':
'Terms of Services and Privacy Notice',
'Qwen OAuth': 'Qwen OAuth',
'Free \u00B7 Up to 1,000 requests/day \u00B7 Qwen latest models':
'Free \u00B7 Up to 1,000 requests/day \u00B7 Qwen latest models',
'Login with QwenChat account to use daily free quota.':
'Login with QwenChat account to use daily free quota.',
'Paid \u00B7 Up to 6,000 requests/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax and more':
'Paid \u00B7 Up to 6,000 requests/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax and more',
'Alibaba Cloud Coding Plan': 'Alibaba Cloud Coding Plan',
'Bring your own API key': 'Bring your own API key',
'API-KEY': 'API-KEY',
'Use coding plan credentials or your own api-keys/providers.':
'Use coding plan credentials or your own api-keys/providers.',
@ -974,6 +979,8 @@ export default {
'Waiting for Qwen OAuth authentication...',
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.':
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.',
'Note: Your existing API key will not be cleared when using Qwen OAuth.':
'Note: Your existing API key will not be cleared when using Qwen OAuth.',
'Authentication timed out. Please try again.':
'Authentication timed out. Please try again.',
'Waiting for auth... (Press ESC or CTRL+C to cancel)':
@ -1388,14 +1395,13 @@ export default {
// ============================================================================
// Coding Plan Authentication
// ============================================================================
'Please enter your API key:': 'Please enter your API key:',
'API key cannot be empty.': 'API key cannot be empty.',
'You can get your exclusive Coding Plan API-KEY here:':
'You can get your exclusive Coding Plan API-KEY here:',
'You can get your Coding Plan API key here':
'You can get your Coding Plan API key here',
'API key is stored in settings.env. You can migrate it to a .env file for better security.':
'API key is stored in settings.env. You can migrate it to a .env file for better security.',
'New model configurations are available for Bailian Coding Plan. Update now?':
'New model configurations are available for Bailian Coding Plan. Update now?',
'New model configurations are available for Alibaba Cloud Coding Plan. Update now?':
'New model configurations are available for Alibaba Cloud Coding Plan. Update now?',
'Coding Plan configuration updated successfully. New models are now available.':
'Coding Plan configuration updated successfully. New models are now available.',
'Coding Plan API key not found. Please re-authenticate with Coding Plan.':
@ -1404,51 +1410,26 @@ export default {
'Failed to update Coding Plan configuration: {{message}}',
// ============================================================================
// Custom API-KEY Configuration
// Custom API Key Configuration
// ============================================================================
'For advanced users who want to configure models manually.':
'For advanced users who want to configure models manually.',
'Please configure your models in settings.json:':
'Please configure your models in settings.json:',
'Set API key via environment variable (e.g., OPENAI_API_KEY)':
'Set API key via environment variable (e.g., OPENAI_API_KEY)',
"Add model configuration to modelProviders['openai'] (or other auth types)":
"Add model configuration to modelProviders['openai'] (or other auth types)",
'Each provider needs: id, envKey (required), plus optional baseUrl, generationConfig':
'Each provider needs: id, envKey (required), plus optional baseUrl, generationConfig',
'Use /model command to select your preferred model from the configured list':
'Use /model command to select your preferred model from the configured list',
'Supported auth types: openai, anthropic, gemini, vertex-ai, etc.':
'Supported auth types: openai, anthropic, gemini, vertex-ai, etc.',
'More instructions please check:': 'More instructions please check:',
'You can configure your API key and models in settings.json':
'You can configure your API key and models in settings.json',
'Refer to the documentation for setup instructions':
'Refer to the documentation for setup instructions',
// ============================================================================
// Auth Dialog - View Titles and Labels
// ============================================================================
'Coding Plan': 'Coding Plan',
'Coding Plan (Bailian, China)': 'Coding Plan (Bailian, China)',
'Coding Plan (Bailian, Global/Intl)': 'Coding Plan (Bailian, Global/Intl)',
"Paste your api key of Bailian Coding Plan and you're all set!":
"Paste your api key of Bailian Coding Plan and you're all set!",
"Paste your api key of Coding Plan (Bailian, Global/Intl) and you're all set!":
"Paste your api key of Coding Plan (Bailian, Global/Intl) and you're all set!",
Custom: 'Custom',
'More instructions about configuring `modelProviders` manually.':
'More instructions about configuring `modelProviders` manually.',
'Select API-KEY configuration mode:': 'Select API-KEY configuration mode:',
'(Press Escape to go back)': '(Press Escape to go back)',
'(Press Enter to submit, Escape to cancel)':
'(Press Enter to submit, Escape to cancel)',
'Select Region for Coding Plan': 'Select Region for Coding Plan',
'Choose based on where your account is registered':
'Choose based on where your account is registered',
'Enter Coding Plan API Key': 'Enter Coding Plan API Key',
// ============================================================================
// Coding Plan International Updates
// ============================================================================
'New model configurations are available for {{region}}. Update now?':
'New model configurations are available for {{region}}. Update now?',
'New model configurations are available for Bailian Coding Plan (China). Update now?':
'New model configurations are available for Bailian Coding Plan (China). Update now?',
'New model configurations are available for Coding Plan (Bailian, Global/Intl). Update now?':
'New model configurations are available for Coding Plan (Bailian, Global/Intl). Update now?',
'{{region}} configuration updated successfully. Model switched to "{{model}}".':
'{{region}} configuration updated successfully. Model switched to "{{model}}".',
'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).':

View file

@ -142,6 +142,7 @@ export default {
'Enter to confirm, Esc to cancel': 'Enter で確定、Esc でキャンセル',
'Enter to select, ↑↓ to navigate, Esc to go back':
'Enter で選択、↑↓ で移動、Esc で戻る',
'Enter to submit, Esc to go back': 'Enter で送信、Esc で戻る',
'Invalid step: {{step}}': '無効なステップ: {{step}}',
'No subagents found.': 'サブエージェントが見つかりません',
"Use '/agents create' to create your first subagent.":
@ -671,18 +672,21 @@ export default {
'🎯 Overall Goal:': '🎯 全体目標:',
// Dialogs - Auth
'Get started': '始める',
'How would you like to authenticate for this project?':
'このプロジェクトの認証方法を選択してください:',
'Select Authentication Method': '認証方法を選択',
'OpenAI API key is required to use OpenAI authentication.':
'OpenAI認証を使用するには OpenAI APIキーが必要です',
'You must select an auth method to proceed. Press Ctrl+C again to exit.':
'続行するには認証方法を選択してください。Ctrl+C をもう一度押すと終了します',
'(Use Enter to Set Auth)': '(Enter で認証を設定)',
'Terms of Services and Privacy Notice for Qwen Code':
'Qwen Code の利用規約とプライバシー通知',
'Terms of Services and Privacy Notice': '利用規約とプライバシー通知',
'Qwen OAuth': 'Qwen OAuth',
'Free \u00B7 Up to 1,000 requests/day \u00B7 Qwen latest models':
'無料 \u00B7 1日最大1,000リクエスト \u00B7 Qwen最新モデル',
'Login with QwenChat account to use daily free quota.':
'QwenChatアカウントでログインして、毎日の無料クォータをご利用ください。',
'Paid \u00B7 Up to 6,000 requests/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax and more':
'有料 \u00B7 5時間最大6,000リクエスト \u00B7 Qwen, GLM, Kimi, Minimaxなど',
'Alibaba Cloud Coding Plan': 'Alibaba Cloud Coding Plan',
'Bring your own API key': '自分のAPIキーを使用',
'API-KEY': 'API-KEY',
'Use coding plan credentials or your own api-keys/providers.':
'Coding Planの認証情報またはご自身のAPIキー/プロバイダーをご利用ください。',
@ -710,6 +714,8 @@ export default {
'Waiting for Qwen OAuth authentication...': 'Qwen OAuth認証を待っています...',
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.':
'注: Qwen OAuthを使用しても、settings.json内の既存のAPIキーはクリアされません。必要に応じて後でOpenAI認証に切り替えることができます',
'Note: Your existing API key will not be cleared when using Qwen OAuth.':
'注: Qwen OAuthを使用しても、既存のAPIキーはクリアされません。',
'Authentication timed out. Please try again.':
'認証がタイムアウトしました。再度お試しください',
'Waiting for auth... (Press ESC or CTRL+C to cancel)':
@ -912,32 +918,19 @@ export default {
],
// ============================================================================
// Custom API-KEY Configuration
// Custom API Key Configuration
// ============================================================================
'For advanced users who want to configure models manually.':
'モデルを手動で設定したい上級ユーザー向け。',
'Please configure your models in settings.json:':
'settings.json でモデルを設定してください:',
'Set API key via environment variable (e.g., OPENAI_API_KEY)':
'環境変数を使用して API キーを設定してくださいOPENAI_API_KEY',
"Add model configuration to modelProviders['openai'] (or other auth types)":
"modelProviders['openai'](または他の認証タイプ)にモデル設定を追加してください",
'Each provider needs: id, envKey (required), plus optional baseUrl, generationConfig':
'各プロバイダーにはid、envKey必須、およびオプションの baseUrl、generationConfig が必要です',
'Use /model command to select your preferred model from the configured list':
'/model コマンドを使用して、設定済みリストからお好みのモデルを選択してください',
'Supported auth types: openai, anthropic, gemini, vertex-ai, etc.':
'サポートされている認証タイプopenai、anthropic、gemini、vertex-ai など',
'You can configure your API key and models in settings.json':
'settings.json で API キーとモデルを設定できます',
'Refer to the documentation for setup instructions':
'セットアップ手順はドキュメントを参照してください',
// ============================================================================
// Coding Plan Authentication
// ============================================================================
'Please enter your API key:': 'APIキーを入力してください',
'API key cannot be empty.': 'APIキーは空にできません。',
'You can get your exclusive Coding Plan API-KEY here:':
'Coding Plan の API-KEY はこちらで取得できます:',
'New model configurations are available for Bailian Coding Plan. Update now?':
'Bailian Coding Plan の新しいモデル設定が利用可能です。今すぐ更新しますか?',
'You can get your Coding Plan API key here':
'Coding Plan APIキーはこちらで取得できます',
'Coding Plan configuration updated successfully. New models are now available.':
'Coding Plan の設定が正常に更新されました。新しいモデルが利用可能になりました。',
'Coding Plan API key not found. Please re-authenticate with Coding Plan.':
@ -948,32 +941,16 @@ export default {
// ============================================================================
// Auth Dialog - View Titles and Labels
// ============================================================================
'Coding Plan': 'Coding Plan',
'Coding Plan (Bailian, China)': 'Coding Plan (Bailian, 中国)',
'Coding Plan (Bailian, Global/Intl)':
'Coding Plan (Bailian, グローバル/国際)',
"Paste your api key of Bailian Coding Plan and you're all set!":
'Bailian Coding PlanのAPIキーを貼り付けるだけで準備完了です',
"Paste your api key of Coding Plan (Bailian, Global/Intl) and you're all set!":
'Coding Plan (Bailian, グローバル/国際) のAPIキーを貼り付けるだけで準備完了です',
Custom: 'カスタム',
'More instructions about configuring `modelProviders` manually.':
'`modelProviders`を手動で設定する方法の詳細はこちら。',
'Select API-KEY configuration mode:': 'API-KEY設定モードを選択してください',
'(Press Escape to go back)': '(Escapeキーで戻る)',
'(Press Enter to submit, Escape to cancel)':
'(Enterで送信、Escapeでキャンセル)',
'More instructions please check:': '詳細な手順はこちらをご確認ください:',
'Select Region for Coding Plan': 'Coding Planのリージョンを選択',
'Choose based on where your account is registered':
'アカウントの登録先に応じて選択してください',
'Enter Coding Plan API Key': 'Coding Plan APIキーを入力',
// ============================================================================
// Coding Plan International Updates
// ============================================================================
'New model configurations are available for {{region}}. Update now?':
'{{region}} の新しいモデル設定が利用可能です。今すぐ更新しますか?',
'New model configurations are available for Bailian Coding Plan (China). Update now?':
'Bailian Coding Plan (中国) の新しいモデル設定が利用可能です。今すぐ更新しますか?',
'New model configurations are available for Coding Plan (Bailian, Global/Intl). Update now?':
'Coding Plan (Bailian, グローバル/国際) の新しいモデル設定が利用可能です。今すぐ更新しますか?',
'{{region}} configuration updated successfully. Model switched to "{{model}}".':
'{{region}} の設定が正常に更新されました。モデルが "{{model}}" に切り替わりました。',
'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).':

View file

@ -173,6 +173,7 @@ export default {
'Enter to confirm, Esc to cancel': 'Enter para confirmar, Esc para cancelar',
'Enter to select, ↑↓ to navigate, Esc to go back':
'Enter para selecionar, ↑↓ para navegar, Esc para voltar',
'Enter to submit, Esc to go back': 'Enter para enviar, Esc para voltar',
'Invalid step: {{step}}': 'Etapa inválida: {{step}}',
'No subagents found.': 'Nenhum subagente encontrado.',
"Use '/agents create' to create your first subagent.":
@ -950,18 +951,22 @@ export default {
// Dialogs - Auth
// ============================================================================
'Get started': 'Começar',
'How would you like to authenticate for this project?':
'Como você gostaria de se autenticar para este projeto?',
'Select Authentication Method': 'Selecionar Método de Autenticação',
'OpenAI API key is required to use OpenAI authentication.':
'A chave da API do OpenAI é necessária para usar a autenticação do OpenAI.',
'You must select an auth method to proceed. Press Ctrl+C again to exit.':
'Você deve selecionar um método de autenticação para prosseguir. Pressione Ctrl+C novamente para sair.',
'(Use Enter to Set Auth)': '(Use Enter para Definir Autenticação)',
'Terms of Services and Privacy Notice for Qwen Code':
'Termos de Serviço e Aviso de Privacidade do Qwen Code',
'Terms of Services and Privacy Notice':
'Termos de Serviço e Aviso de Privacidade',
'Qwen OAuth': 'Qwen OAuth',
'Free \u00B7 Up to 1,000 requests/day \u00B7 Qwen latest models':
'Gratuito \u00B7 Até 1.000 solicitações/dia \u00B7 Modelos Qwen mais recentes',
'Login with QwenChat account to use daily free quota.':
'Faça login com sua conta QwenChat para usar a cota gratuita diária.',
'Paid \u00B7 Up to 6,000 requests/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax and more':
'Pago \u00B7 Até 6.000 solicitações/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax e mais',
'Alibaba Cloud Coding Plan': 'Alibaba Cloud Coding Plan',
'Bring your own API key': 'Traga sua própria chave API',
'API-KEY': 'API-KEY',
'Use coding plan credentials or your own api-keys/providers.':
'Use credenciais do Coding Plan ou suas próprias chaves API/provedores.',
@ -989,6 +994,8 @@ export default {
'Aguardando autenticação Qwen OAuth...',
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.':
'Nota: Sua chave de API existente no settings.json não será limpa ao usar o Qwen OAuth. Você pode voltar para a autenticação do OpenAI mais tarde, se necessário.',
'Note: Your existing API key will not be cleared when using Qwen OAuth.':
'Nota: Sua chave de API existente não será limpa ao usar o Qwen OAuth.',
'Authentication timed out. Please try again.':
'A autenticação expirou. Tente novamente.',
'Waiting for auth... (Press ESC or CTRL+C to cancel)':
@ -1396,32 +1403,21 @@ export default {
'Falha ao abrir o navegador. Confira a galeria de extensões em {{url}}',
// ============================================================================
// Custom API-KEY Configuration
// Custom API Key Configuration
// ============================================================================
'For advanced users who want to configure models manually.':
'Para usuários avançados que desejam configurar modelos manualmente.',
'Please configure your models in settings.json:':
'Por favor, configure seus modelos em settings.json:',
'Set API key via environment variable (e.g., OPENAI_API_KEY)':
'Defina a chave de API via variável de ambiente (ex: OPENAI_API_KEY)',
"Add model configuration to modelProviders['openai'] (or other auth types)":
"Adicione a configuração do modelo a modelProviders['openai'] (ou outros tipos de autenticação)",
'Each provider needs: id, envKey (required), plus optional baseUrl, generationConfig':
'Cada provedor precisa de: id, envKey (obrigatório), além de baseUrl e generationConfig opcionais',
'Use /model command to select your preferred model from the configured list':
'Use o comando /model para selecionar seu modelo preferido da lista configurada',
'Supported auth types: openai, anthropic, gemini, vertex-ai, etc.':
'Tipos de autenticação suportados: openai, anthropic, gemini, vertex-ai, etc.',
'You can configure your API key and models in settings.json':
'Você pode configurar sua chave de API e modelos em settings.json',
'Refer to the documentation for setup instructions':
'Consulte a documentação para instruções de configuração',
// ============================================================================
// Coding Plan Authentication
// ============================================================================
'Please enter your API key:': 'Por favor, digite sua chave de API:',
'API key cannot be empty.': 'A chave de API não pode estar vazia.',
'You can get your exclusive Coding Plan API-KEY here:':
'Você pode obter sua chave de API exclusiva do Coding Plan aqui:',
'New model configurations are available for Bailian Coding Plan. Update now?':
'Novas configurações de modelo estão disponíveis para o Bailian Coding Plan. Atualizar agora?',
'You can get your Coding Plan API key here':
'Você pode obter sua chave de API do Coding Plan aqui',
'New model configurations are available for Alibaba Cloud Coding Plan. Update now?':
'Novas configurações de modelo estão disponíveis para o Alibaba Cloud Coding Plan. Atualizar agora?',
'Coding Plan configuration updated successfully. New models are now available.':
'Configuração do Coding Plan atualizada com sucesso. Novos modelos agora estão disponíveis.',
'Coding Plan API key not found. Please re-authenticate with Coding Plan.':
@ -1432,32 +1428,16 @@ export default {
// ============================================================================
// Auth Dialog - View Titles and Labels
// ============================================================================
'Coding Plan': 'Coding Plan',
'Coding Plan (Bailian, China)': 'Coding Plan (Bailian, China)',
'Coding Plan (Bailian, Global/Intl)': 'Coding Plan (Bailian, Global/Intl)',
"Paste your api key of Bailian Coding Plan and you're all set!":
'Cole sua chave de API do Bailian Coding Plan e pronto!',
"Paste your api key of Coding Plan (Bailian, Global/Intl) and you're all set!":
'Cole sua chave de API do Coding Plan (Bailian, Global/Intl) e pronto!',
Custom: 'Personalizado',
'More instructions about configuring `modelProviders` manually.':
'Mais instruções sobre como configurar `modelProviders` manualmente.',
'Select API-KEY configuration mode:':
'Selecione o modo de configuração da API-KEY:',
'(Press Escape to go back)': '(Pressione Escape para voltar)',
'(Press Enter to submit, Escape to cancel)':
'(Pressione Enter para enviar, Escape para cancelar)',
'More instructions please check:': 'Mais instruções, consulte:',
'Select Region for Coding Plan': 'Selecionar região do Coding Plan',
'Choose based on where your account is registered':
'Escolha com base em onde sua conta está registrada',
'Enter Coding Plan API Key': 'Inserir chave de API do Coding Plan',
// ============================================================================
// Coding Plan International Updates
// ============================================================================
'New model configurations are available for {{region}}. Update now?':
'Novas configurações de modelo estão disponíveis para o {{region}}. Atualizar agora?',
'New model configurations are available for Bailian Coding Plan (China). Update now?':
'Novas configurações de modelo estão disponíveis para o Bailian Coding Plan (China). Atualizar agora?',
'New model configurations are available for Coding Plan (Bailian, Global/Intl). Update now?':
'Novas configurações de modelo estão disponíveis para o Coding Plan (Bailian, Global/Intl). Atualizar agora?',
'{{region}} configuration updated successfully. Model switched to "{{model}}".':
'Configuração do {{region}} atualizada com sucesso. Modelo alterado para "{{model}}".',
'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).':

View file

@ -181,6 +181,7 @@ export default {
'Enter to confirm, Esc to cancel': 'Enter для подтверждения, Esc для отмены',
'Enter to select, ↑↓ to navigate, Esc to go back':
'Enter для выбора, ↑↓ для навигации, Esc для возврата',
'Enter to submit, Esc to go back': 'Enter для отправки, Esc для возврата',
'Invalid step: {{step}}': 'Неверный шаг: {{step}}',
'No subagents found.': 'Подагенты не найдены.',
"Use '/agents create' to create your first subagent.":
@ -950,18 +951,22 @@ export default {
// Диалоги - Авторизация
// ============================================================================
'Get started': 'Начать',
'How would you like to authenticate for this project?':
'Как вы хотите авторизоваться для этого проекта?',
'Select Authentication Method': 'Выберите метод авторизации',
'OpenAI API key is required to use OpenAI authentication.':
'Для использования авторизации OpenAI требуется ключ API OpenAI.',
'You must select an auth method to proceed. Press Ctrl+C again to exit.':
'Вы должны выбрать метод авторизации для продолжения. Нажмите Ctrl+C снова для выхода.',
'(Use Enter to Set Auth)': '(Enter для установки авторизации)',
'Terms of Services and Privacy Notice for Qwen Code':
'Условия обслуживания и уведомление о конфиденциальности для Qwen Code',
'Terms of Services and Privacy Notice':
'Условия обслуживания и уведомление о конфиденциальности',
'Qwen OAuth': 'Qwen OAuth',
'Free \u00B7 Up to 1,000 requests/day \u00B7 Qwen latest models':
'Бесплатно \u00B7 До 1 000 запросов/день \u00B7 Новейшие модели Qwen',
'Login with QwenChat account to use daily free quota.':
'Войдите с помощью аккаунта QwenChat, чтобы использовать ежедневную бесплатную квоту.',
'Paid \u00B7 Up to 6,000 requests/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax and more':
'Платно \u00B7 До 6 000 запросов/5 часов \u00B7 Qwen, GLM, Kimi, Minimax и другие',
'Alibaba Cloud Coding Plan': 'Alibaba Cloud Coding Plan',
'Bring your own API key': 'Используйте свой API-ключ',
'API-KEY': 'API-KEY',
'Use coding plan credentials or your own api-keys/providers.':
'Используйте учетные данные Coding Plan или свои собственные API-ключи/провайдеры.',
@ -989,6 +994,8 @@ export default {
'Ожидание авторизации Qwen OAuth...',
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.':
'Примечание: Ваш существующий ключ API в settings.json не будет удален при использовании Qwen OAuth. Вы можете переключиться обратно на авторизацию OpenAI позже при необходимости.',
'Note: Your existing API key will not be cleared when using Qwen OAuth.':
'Примечание: Ваш существующий ключ API не будет удален при использовании Qwen OAuth.',
'Authentication timed out. Please try again.':
'Время ожидания авторизации истекло. Пожалуйста, попробуйте снова.',
'Waiting for auth... (Press ESC or CTRL+C to cancel)':
@ -1406,32 +1413,21 @@ export default {
'Попробуйте /insight, чтобы получить персонализированные выводы из истории чатов.',
// ============================================================================
// Custom API-KEY Configuration
// Custom API Key Configuration
// ============================================================================
'For advanced users who want to configure models manually.':
'Для продвинутых пользователей, которые хотят настраивать модели вручную.',
'Please configure your models in settings.json:':
'Пожалуйста, настройте ваши модели в settings.json:',
'Set API key via environment variable (e.g., OPENAI_API_KEY)':
'Установите ключ API через переменную окружения (например, OPENAI_API_KEY)',
"Add model configuration to modelProviders['openai'] (or other auth types)":
"Добавьте конфигурацию модели в modelProviders['openai'] (или другие типы аутентификации)",
'Each provider needs: id, envKey (required), plus optional baseUrl, generationConfig':
'Каждому провайдеру нужны: id, envKey (обязательно), а также опциональные baseUrl, generationConfig',
'Use /model command to select your preferred model from the configured list':
'Используйте команду /model, чтобы выбрать предпочитаемую модель из настроенного списка',
'Supported auth types: openai, anthropic, gemini, vertex-ai, etc.':
'Поддерживаемые типы аутентификации: openai, anthropic, gemini, vertex-ai и др.',
'You can configure your API key and models in settings.json':
'Вы можете настроить API-ключ и модели в settings.json',
'Refer to the documentation for setup instructions':
'Инструкции по настройке см. в документации',
// ============================================================================
// Coding Plan Authentication
// ============================================================================
'Please enter your API key:': 'Пожалуйста, введите ваш API-ключ:',
'API key cannot be empty.': 'API-ключ не может быть пустым.',
'You can get your exclusive Coding Plan API-KEY here:':
'Получите свой эксклюзивный API-KEY Coding Plan здесь:',
'New model configurations are available for Bailian Coding Plan. Update now?':
'Доступны новые конфигурации моделей для Bailian Coding Plan. Обновить сейчас?',
'You can get your Coding Plan API key here':
'Вы можете получить API-ключ Coding Plan здесь',
'New model configurations are available for Alibaba Cloud Coding Plan. Update now?':
'Доступны новые конфигурации моделей для Alibaba Cloud Coding Plan. Обновить сейчас?',
'Coding Plan configuration updated successfully. New models are now available.':
'Конфигурация Coding Plan успешно обновлена. Новые модели теперь доступны.',
'Coding Plan API key not found. Please re-authenticate with Coding Plan.':
@ -1442,32 +1438,16 @@ export default {
// ============================================================================
// Auth Dialog - View Titles and Labels
// ============================================================================
'Coding Plan': 'Coding Plan',
'Coding Plan (Bailian, China)': 'Coding Plan (Bailian, Китай)',
'Coding Plan (Bailian, Global/Intl)':
'Coding Plan (Bailian, Глобальный/Международный)',
"Paste your api key of Bailian Coding Plan and you're all set!":
'Вставьте ваш API-ключ Bailian Coding Plan и всё готово!',
"Paste your api key of Coding Plan (Bailian, Global/Intl) and you're all set!":
'Вставьте ваш API-ключ Coding Plan (Bailian, Глобальный/Международный) и всё готово!',
Custom: 'Пользовательский',
'More instructions about configuring `modelProviders` manually.':
'Дополнительные инструкции по ручной настройке `modelProviders`.',
'Select API-KEY configuration mode:': 'Выберите режим конфигурации API-KEY:',
'(Press Escape to go back)': '(Нажмите Escape для возврата)',
'(Press Enter to submit, Escape to cancel)':
'(Нажмите Enter для отправки, Escape для отмены)',
'More instructions please check:': 'Дополнительные инструкции см.:',
'Select Region for Coding Plan': 'Выберите регион Coding Plan',
'Choose based on where your account is registered':
'Выберите в зависимости от места регистрации вашего аккаунта',
'Enter Coding Plan API Key': 'Введите API-ключ Coding Plan',
// ============================================================================
// Coding Plan International Updates
// ============================================================================
'New model configurations are available for {{region}}. Update now?':
'Доступны новые конфигурации моделей для {{region}}. Обновить сейчас?',
'New model configurations are available for Bailian Coding Plan (China). Update now?':
'Доступны новые конфигурации моделей для Bailian Coding Plan (Китай). Обновить сейчас?',
'New model configurations are available for Coding Plan (Bailian, Global/Intl). Update now?':
'Доступны новые конфигурации моделей для Coding Plan (Bailian, Глобальный/Международный). Обновить сейчас?',
'{{region}} configuration updated successfully. Model switched to "{{model}}".':
'Конфигурация {{region}} успешно обновлена. Модель переключена на "{{model}}".',
'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).':

View file

@ -173,6 +173,7 @@ export default {
'Enter to confirm, Esc to cancel': 'Enter 确认Esc 取消',
'Enter to select, ↑↓ to navigate, Esc to go back':
'Enter 选择,↑↓ 导航Esc 返回',
'Enter to submit, Esc to go back': 'Enter 提交Esc 返回',
'Invalid step: {{step}}': '无效步骤: {{step}}',
'No subagents found.': '未找到子智能体。',
"Use '/agents create' to create your first subagent.":
@ -882,18 +883,21 @@ export default {
// Dialogs - Auth
// ============================================================================
'Get started': '开始使用',
'How would you like to authenticate for this project?':
'您希望如何为此项目进行身份验证?',
'Select Authentication Method': '选择认证方式',
'OpenAI API key is required to use OpenAI authentication.':
'使用 OpenAI 认证需要 OpenAI API 密钥',
'You must select an auth method to proceed. Press Ctrl+C again to exit.':
'您必须选择认证方法才能继续。再次按 Ctrl+C 退出',
'(Use Enter to Set Auth)': '(使用 Enter 设置认证)',
'Terms of Services and Privacy Notice for Qwen Code':
'Qwen Code 的服务条款和隐私声明',
'Terms of Services and Privacy Notice': '服务条款和隐私声明',
'Qwen OAuth': 'Qwen OAuth (免费)',
'Free \u00B7 Up to 1,000 requests/day \u00B7 Qwen latest models':
'免费 \u00B7 每天最多 1,000 次请求 \u00B7 Qwen 最新模型',
'Login with QwenChat account to use daily free quota.':
'使用 QwenChat 账号登录,享受每日免费额度。',
'Paid \u00B7 Up to 6,000 requests/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax and more':
'付费 \u00B7 每 5 小时最多 6,000 次请求 \u00B7 Qwen、GLM、Kimi、Minimax 等',
'Alibaba Cloud Coding Plan': '阿里云百炼 Coding Plan',
'Bring your own API key': '使用自己的 API 密钥',
'Use coding plan credentials or your own api-keys/providers.':
'使用 Coding Plan 凭证或您自己的 API 密钥/提供商。',
OpenAI: 'OpenAI',
@ -917,6 +921,8 @@ export default {
'Waiting for Qwen OAuth authentication...': '正在等待 Qwen OAuth 认证...',
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.':
'注意:使用 Qwen OAuth 时settings.json 中现有的 API 密钥不会被清除。如果需要,您可以稍后切换回 OpenAI 认证。',
'Note: Your existing API key will not be cleared when using Qwen OAuth.':
'注意:使用 Qwen OAuth 时,现有的 API 密钥不会被清除。',
'Authentication timed out. Please try again.': '认证超时。请重试。',
'Waiting for auth... (Press ESC or CTRL+C to cancel)':
'正在等待认证...(按 ESC 或 CTRL+C 取消)',
@ -1221,14 +1227,13 @@ export default {
// ============================================================================
// Coding Plan Authentication
// ============================================================================
'Please enter your API key:': '请输入您的 API Key',
'API key cannot be empty.': 'API Key 不能为空。',
'You can get your exclusive Coding Plan API-KEY here:':
'您可以在这里获取专属的 Coding Plan API-KEY',
'You can get your Coding Plan API key here':
'您可以在这里获取 Coding Plan API Key',
'API key is stored in settings.env. You can migrate it to a .env file for better security.':
'API Key 已存储在 settings.env 中。您可以将其迁移到 .env 文件以获得更好的安全性。',
'New model configurations are available for Bailian Coding Plan. Update now?':
'百炼 Coding Plan 有新模型配置可用。是否立即更新?',
'New model configurations are available for Alibaba Cloud Coding Plan. Update now?':
'阿里云百炼 Coding Plan 有新模型配置可用。是否立即更新?',
'Coding Plan configuration updated successfully. New models are now available.':
'Coding Plan 配置更新成功。新模型现已可用。',
'Coding Plan API key not found. Please re-authenticate with Coding Plan.':
@ -1237,51 +1242,25 @@ export default {
'更新 Coding Plan 配置失败:{{message}}',
// ============================================================================
// Custom API-KEY Configuration
// Custom API Key Configuration
// ============================================================================
'For advanced users who want to configure models manually.':
'适合需要手动配置模型的高级用户。',
'Please configure your models in settings.json:':
'请在 settings.json 中配置您的模型:',
'Set API key via environment variable (e.g., OPENAI_API_KEY)':
'通过环境变量设置 API Key例如OPENAI_API_KEY',
"Add model configuration to modelProviders['openai'] (or other auth types)":
"将模型配置添加到 modelProviders['openai'](或其他认证类型)",
'Each provider needs: id, envKey (required), plus optional baseUrl, generationConfig':
'每个提供商需要id、envKey必需以及可选的 baseUrl、generationConfig',
'Use /model command to select your preferred model from the configured list':
'使用 /model 命令从配置列表中选择您偏好的模型',
'Supported auth types: openai, anthropic, gemini, vertex-ai, etc.':
'支持的认证类型openai、anthropic、gemini、vertex-ai 等',
'More instructions please check:': '更多说明请查看:',
'You can configure your API key and models in settings.json':
'您可以在 settings.json 中配置 API Key 和模型',
'Refer to the documentation for setup instructions': '请参考文档了解配置说明',
// ============================================================================
// Auth Dialog - View Titles and Labels
// ============================================================================
'API-KEY': 'API-KEY',
'Coding Plan': 'Coding Plan',
'Coding Plan (Bailian, China)': 'Coding Plan (百炼, 中国)',
'Coding Plan (Bailian, Global/Intl)': 'Coding Plan (百炼, 全球/国际)',
"Paste your api key of Bailian Coding Plan and you're all set!":
'粘贴您的百炼 Coding Plan API Key即可完成设置',
"Paste your api key of Coding Plan (Bailian, Global/Intl) and you're all set!":
'粘贴您的 Coding Plan (百炼, 全球/国际) API Key即可完成设置',
Custom: '自定义',
'More instructions about configuring `modelProviders` manually.':
'关于手动配置 `modelProviders` 的更多说明。',
'Select API-KEY configuration mode:': '选择 API-KEY 配置模式:',
'(Press Escape to go back)': '(按 Escape 键返回)',
'(Press Enter to submit, Escape to cancel)': '(按 Enter 提交Escape 取消)',
'Select Region for Coding Plan': '选择 Coding Plan 区域',
'Choose based on where your account is registered':
'请根据您的账号注册地区选择',
'Enter Coding Plan API Key': '输入 Coding Plan API Key',
// ============================================================================
// Coding Plan International Updates
// ============================================================================
'New model configurations are available for {{region}}. Update now?':
'{{region}} 有新的模型配置可用。是否立即更新?',
'New model configurations are available for Bailian Coding Plan (China). Update now?':
'百炼 Coding Plan (中国) 有新的模型配置可用。是否立即更新?',
'New model configurations are available for Coding Plan (Bailian, Global/Intl). Update now?':
'Coding Plan (百炼, 全球/国际) 有新的模型配置可用。是否立即更新?',
'{{region}} configuration updated successfully. Model switched to "{{model}}".':
'{{region}} 配置更新成功。模型已切换至 "{{model}}"。',
'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).':

View file

@ -169,9 +169,9 @@ describe('AuthDialog', () => {
const { lastFrame } = renderAuthDialog(settings);
// Since the auth dialog shows API-KEY option now,
// Since the auth dialog shows API Key option now,
// it won't show GEMINI_API_KEY messages
expect(lastFrame()).toContain('API-KEY');
expect(lastFrame()).toContain('API Key');
});
it('should not show the GEMINI_API_KEY message if QWEN_DEFAULT_AUTH_TYPE is set to something else', () => {
@ -257,9 +257,9 @@ describe('AuthDialog', () => {
const { lastFrame } = renderAuthDialog(settings);
// Since the auth dialog shows API-KEY option now,
// Since the auth dialog shows API Key option now,
// it won't show GEMINI_API_KEY messages
expect(lastFrame()).toContain('API-KEY');
expect(lastFrame()).toContain('API Key');
});
});
@ -305,7 +305,7 @@ describe('AuthDialog', () => {
const { lastFrame } = renderAuthDialog(settings);
// QWEN_OAUTH is the first option, so it should be selected
expect(lastFrame()).toContain('● 1. Qwen OAuth');
expect(lastFrame()).toContain('Qwen OAuth');
});
it('should fall back to default if QWEN_DEFAULT_AUTH_TYPE is not set', () => {
@ -345,7 +345,7 @@ describe('AuthDialog', () => {
const { lastFrame } = renderAuthDialog(settings);
// Default is Qwen OAuth (first option)
expect(lastFrame()).toContain('● 1. Qwen OAuth');
expect(lastFrame()).toContain('Qwen OAuth');
});
it('should show an error and fall back to default if QWEN_DEFAULT_AUTH_TYPE is invalid', () => {
@ -388,7 +388,7 @@ describe('AuthDialog', () => {
// Since the auth dialog doesn't show QWEN_DEFAULT_AUTH_TYPE errors anymore,
// it will just show the default Qwen OAuth option
expect(lastFrame()).toContain('● 1. Qwen OAuth');
expect(lastFrame()).toContain('Qwen OAuth');
});
});

View file

@ -11,16 +11,19 @@ import { Box, Text } from 'ink';
import Link from 'ink-link';
import { theme } from '../semantic-colors.js';
import { useKeypress } from '../hooks/useKeypress.js';
import { RadioButtonSelect } from '../components/shared/RadioButtonSelect.js';
import { DescriptiveRadioButtonSelect } from '../components/shared/DescriptiveRadioButtonSelect.js';
import { ApiKeyInput } from '../components/ApiKeyInput.js';
import { useUIState } from '../contexts/UIStateContext.js';
import { useUIActions } from '../contexts/UIActionsContext.js';
import { useConfig } from '../contexts/ConfigContext.js';
import { t } from '../../i18n/index.js';
import { CodingPlanRegion } from '../../constants/codingPlan.js';
import {
CodingPlanRegion,
isCodingPlanConfig,
} from '../../constants/codingPlan.js';
const MODEL_PROVIDERS_DOCUMENTATION_URL =
'https://qwenlm.github.io/qwen-code-docs/en/users/configuration/settings/#modelproviders';
'https://qwenlm.github.io/qwen-code-docs/en/users/configuration/model-providers/';
function parseDefaultAuthType(
defaultAuthType: string | undefined,
@ -34,11 +37,11 @@ function parseDefaultAuthType(
return null;
}
// Sub-mode types for API-KEY authentication
type ApiKeySubMode = 'coding-plan' | 'coding-plan-intl' | 'custom';
// Main menu option type
type MainOption = typeof AuthType.QWEN_OAUTH | 'CODING_PLAN' | 'API_KEY';
// View level for navigation
type ViewLevel = 'main' | 'api-key-sub' | 'api-key-input' | 'custom-info';
type ViewLevel = 'main' | 'region-select' | 'api-key-input' | 'custom-info';
export function AuthDialog(): React.JSX.Element {
const { pendingAuthType, authError } = useUIState();
@ -50,58 +53,101 @@ export function AuthDialog(): React.JSX.Element {
const config = useConfig();
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
const [viewLevel, setViewLevel] = useState<ViewLevel>('main');
const [apiKeySubModeIndex, setApiKeySubModeIndex] = useState<number>(0);
const [regionIndex, setRegionIndex] = useState<number>(0);
const [region, setRegion] = useState<CodingPlanRegion>(
CodingPlanRegion.CHINA,
);
// Main authentication entries
// Main authentication entries (flat three-option layout)
const mainItems = [
{
key: AuthType.QWEN_OAUTH,
title: t('Qwen OAuth'),
label: t('Qwen OAuth'),
value: AuthType.QWEN_OAUTH,
description: t(
'Free \u00B7 Up to 1,000 requests/day \u00B7 Qwen latest models',
),
value: AuthType.QWEN_OAUTH as MainOption,
},
{
key: 'API-KEY',
label: t('API-KEY'),
value: 'API-KEY' as const,
key: 'CODING_PLAN',
title: t('Alibaba Cloud Coding Plan'),
label: t('Alibaba Cloud Coding Plan'),
description: t(
'Paid \u00B7 Up to 6,000 requests/5 hrs \u00B7 Qwen, GLM, Kimi, Minimax and more',
),
value: 'CODING_PLAN' as MainOption,
},
{
key: 'API_KEY',
title: t('API Key'),
label: t('API Key'),
description: t('Bring your own API key'),
value: 'API_KEY' as MainOption,
},
];
// API-KEY sub-mode entries
const apiKeySubItems = [
// Region selection entries (shown after selecting Alibaba Cloud Coding Plan)
const regionItems = [
{
key: 'coding-plan',
label: t('Coding Plan (Bailian, China)'),
value: 'coding-plan' as ApiKeySubMode,
key: 'china',
title: '阿里云百炼 (aliyun.com)',
label: '阿里云百炼 (aliyun.com)',
description: (
<Link url="https://bailian.console.aliyun.com" fallback={false}>
<Text color={theme.text.secondary}>
https://bailian.console.aliyun.com
</Text>
</Link>
),
value: CodingPlanRegion.CHINA,
},
{
key: 'coding-plan-intl',
label: t('Coding Plan (Bailian, Global/Intl)'),
value: 'coding-plan-intl' as ApiKeySubMode,
},
{
key: 'custom',
label: t('Custom'),
value: 'custom' as ApiKeySubMode,
key: 'global',
title: 'Alibaba Cloud (alibabacloud.com)',
label: 'Alibaba Cloud (alibabacloud.com)',
description: (
<Link url="https://bailian.console.alibabacloud.com" fallback={false}>
<Text color={theme.text.secondary}>
https://bailian.console.alibabacloud.com
</Text>
</Link>
),
value: CodingPlanRegion.GLOBAL,
},
];
// Map an AuthType to the corresponding main menu option.
// QWEN_OAUTH maps directly; any other auth type maps to CODING_PLAN only
// if the current config actually uses a Coding Plan baseUrl+envKey,
// otherwise it maps to API_KEY.
const contentGenConfig = config.getContentGeneratorConfig();
const isCurrentlyCodingPlan =
isCodingPlanConfig(
contentGenConfig?.baseUrl,
contentGenConfig?.apiKeyEnvKey,
) !== false;
const authTypeToMainOption = (authType: AuthType): MainOption => {
if (authType === AuthType.QWEN_OAUTH) return AuthType.QWEN_OAUTH;
if (authType === AuthType.USE_OPENAI && isCurrentlyCodingPlan)
return 'CODING_PLAN';
return 'API_KEY';
};
const initialAuthIndex = Math.max(
0,
mainItems.findIndex((item) => {
// Priority 1: pendingAuthType
if (pendingAuthType) {
return item.value === pendingAuthType;
return item.value === authTypeToMainOption(pendingAuthType);
}
// Priority 2: config.getAuthType() - the source of truth
const currentAuthType = config.getAuthType();
if (currentAuthType) {
return item.value === currentAuthType;
return item.value === authTypeToMainOption(currentAuthType);
}
// Priority 3: QWEN_DEFAULT_AUTH_TYPE env var
@ -109,7 +155,7 @@ export function AuthDialog(): React.JSX.Element {
process.env['QWEN_DEFAULT_AUTH_TYPE'],
);
if (defaultAuthType) {
return item.value === defaultAuthType;
return item.value === authTypeToMainOption(defaultAuthType);
}
// Priority 4: default to QWEN_OAUTH
@ -117,21 +163,19 @@ export function AuthDialog(): React.JSX.Element {
}),
);
const hasApiKey = Boolean(config.getContentGeneratorConfig()?.apiKey);
const currentSelectedAuthType =
selectedIndex !== null
? mainItems[selectedIndex]?.value
: mainItems[initialAuthIndex]?.value;
const handleMainSelect = async (
value: (typeof mainItems)[number]['value'],
) => {
const handleMainSelect = async (value: MainOption) => {
setErrorMessage(null);
onAuthError(null);
if (value === 'API-KEY') {
// Navigate to API-KEY sub-mode selection
setViewLevel('api-key-sub');
if (value === 'CODING_PLAN') {
// Navigate to region selection
setViewLevel('region-select');
return;
}
if (value === 'API_KEY') {
// Navigate directly to custom API key info
setViewLevel('custom-info');
return;
}
@ -139,19 +183,11 @@ export function AuthDialog(): React.JSX.Element {
await onAuthSelect(value);
};
const handleApiKeySubSelect = async (subMode: ApiKeySubMode) => {
const handleRegionSelect = async (selectedRegion: CodingPlanRegion) => {
setErrorMessage(null);
onAuthError(null);
if (subMode === 'coding-plan') {
setRegion(CodingPlanRegion.CHINA);
setViewLevel('api-key-input');
} else if (subMode === 'coding-plan-intl') {
setRegion(CodingPlanRegion.GLOBAL);
setViewLevel('api-key-input');
} else {
setViewLevel('custom-info');
}
setRegion(selectedRegion);
setViewLevel('api-key-input');
};
const handleApiKeyInputSubmit = async (apiKey: string) => {
@ -170,12 +206,10 @@ export function AuthDialog(): React.JSX.Element {
setErrorMessage(null);
onAuthError(null);
if (viewLevel === 'api-key-sub') {
if (viewLevel === 'region-select' || viewLevel === 'custom-info') {
setViewLevel('main');
// Reset selectedIndex to ensure UI syncs with initialAuthIndex
setSelectedIndex(null);
} else if (viewLevel === 'api-key-input' || viewLevel === 'custom-info') {
setViewLevel('api-key-sub');
} else if (viewLevel === 'api-key-input') {
setViewLevel('region-select');
}
};
@ -183,7 +217,7 @@ export function AuthDialog(): React.JSX.Element {
(key) => {
if (key.name === 'escape') {
// Handle Escape based on current view level
if (viewLevel === 'api-key-sub') {
if (viewLevel === 'region-select') {
handleGoBack();
return;
}
@ -215,62 +249,39 @@ export function AuthDialog(): React.JSX.Element {
const renderMainView = () => (
<>
<Box marginTop={1}>
<Text>{t('How would you like to authenticate for this project?')}</Text>
</Box>
<Box marginTop={1}>
<RadioButtonSelect
<DescriptiveRadioButtonSelect
items={mainItems}
initialIndex={initialAuthIndex}
onSelect={handleMainSelect}
onHighlight={(value) => {
const index = mainItems.findIndex((item) => item.value === value);
setSelectedIndex(index);
}}
itemGap={1}
/>
</Box>
<Box marginTop={1} paddingLeft={2}>
<Text color={theme.text.secondary}>
{currentSelectedAuthType === AuthType.QWEN_OAUTH
? t('Login with QwenChat account to use daily free quota.')
: t('Use coding plan credentials or your own api-keys/providers.')}
</Text>
</Box>
</>
);
// Render API-KEY sub-mode selection
const renderApiKeySubView = () => (
// Render region selection for Alibaba Cloud Coding Plan
const renderRegionSelectView = () => (
<>
<Box marginTop={1}>
<Text>{t('Select API-KEY configuration mode:')}</Text>
</Box>
<Box marginTop={1}>
<RadioButtonSelect
items={apiKeySubItems}
initialIndex={apiKeySubModeIndex}
onSelect={handleApiKeySubSelect}
onHighlight={(value) => {
const index = apiKeySubItems.findIndex(
(item) => item.value === value,
);
setApiKeySubModeIndex(index);
}}
/>
</Box>
<Box marginTop={1} paddingLeft={2}>
<Text color={theme.text.secondary}>
{apiKeySubItems[apiKeySubModeIndex]?.value === 'custom'
? t(
'More instructions about configuring `modelProviders` manually.',
)
: t(
"Paste your api key of Bailian Coding Plan and you're all set!",
)}
<Text color={theme.text.primary}>
{t('Choose based on where your account is registered')}
</Text>
</Box>
<Box marginTop={1}>
<DescriptiveRadioButtonSelect
items={regionItems}
initialIndex={regionIndex}
onSelect={handleRegionSelect}
onHighlight={(value) => {
const index = regionItems.findIndex((item) => item.value === value);
setRegionIndex(index);
}}
itemGap={1}
/>
</Box>
<Box marginTop={1}>
<Text color={theme?.text?.secondary}>
{t('(Press Escape to go back)')}
{t('Enter to select, ↑↓ to navigate, Esc to go back')}
</Text>
</Box>
</>
@ -291,68 +302,22 @@ export function AuthDialog(): React.JSX.Element {
const renderCustomInfoView = () => (
<>
<Box marginTop={1}>
<Text bold>{t('Custom API-KEY Configuration')}</Text>
</Box>
<Box marginTop={1}>
<Text>
{t('For advanced users who want to configure models manually.')}
<Text color={theme.text.primary}>
{t('You can configure your API key and models in settings.json')}
</Text>
</Box>
<Box marginTop={1}>
<Text>{t('Please configure your models in settings.json:')}</Text>
</Box>
<Box marginTop={1} paddingLeft={2}>
<Text color={theme.status.warning}>
1. {t('Set API key via environment variable (e.g., OPENAI_API_KEY)')}
</Text>
</Box>
<Box marginTop={0} paddingLeft={2}>
<Text color={theme.status.warning}>
2.{' '}
{t(
"Add model configuration to modelProviders['openai'] (or other auth types)",
)}
</Text>
</Box>
<Box marginTop={0} paddingLeft={2}>
<Text color={theme.status.warning}>
3.{' '}
{t(
'Each provider needs: id, envKey (required), plus optional baseUrl, generationConfig',
)}
</Text>
</Box>
<Box marginTop={0} paddingLeft={2}>
<Text color={theme.status.warning}>
4.{' '}
{t(
'Use /model command to select your preferred model from the configured list',
)}
</Text>
</Box>
<Box marginTop={1}>
<Text color={theme?.text?.secondary}>
{t(
'Supported auth types: openai, anthropic, gemini, vertex-ai, etc.',
)}
</Text>
</Box>
<Box marginTop={1}>
<Text color={theme?.text?.secondary} underline>
{t('More instructions please check:')}
</Text>
<Text>{t('Refer to the documentation for setup instructions')}</Text>
</Box>
<Box marginTop={0}>
<Link url={MODEL_PROVIDERS_DOCUMENTATION_URL} fallback={false}>
<Text color={theme.status.success} underline>
<Text color={theme.text.link}>
{MODEL_PROVIDERS_DOCUMENTATION_URL}
</Text>
</Link>
</Box>
<Box marginTop={1}>
<Text color={theme?.text?.secondary}>
{t('(Press Escape to go back)')}
</Text>
<Text color={theme.text.secondary}>{t('Esc to go back')}</Text>
</Box>
</>
);
@ -360,15 +325,15 @@ export function AuthDialog(): React.JSX.Element {
const getViewTitle = () => {
switch (viewLevel) {
case 'main':
return t('Get started');
case 'api-key-sub':
return t('API-KEY Configuration');
return t('Select Authentication Method');
case 'region-select':
return t('Select Region for Coding Plan');
case 'api-key-input':
return t('Coding Plan Setup');
return t('Enter Coding Plan API Key');
case 'custom-info':
return t('Custom Configuration');
default:
return t('Get started');
return t('Select Authentication Method');
}
};
@ -383,7 +348,7 @@ export function AuthDialog(): React.JSX.Element {
<Text bold>{getViewTitle()}</Text>
{viewLevel === 'main' && renderMainView()}
{viewLevel === 'api-key-sub' && renderApiKeySubView()}
{viewLevel === 'region-select' && renderRegionSelectView()}
{viewLevel === 'api-key-input' && renderApiKeyInputView()}
{viewLevel === 'custom-info' && renderCustomInfoView()}
@ -395,31 +360,28 @@ export function AuthDialog(): React.JSX.Element {
{viewLevel === 'main' && (
<>
<Box marginTop={1}>
<Text color={theme.text.accent}>
{t('(Use Enter to Set Auth)')}
{/* <Box marginTop={1}>
<Text color={theme.text.secondary}>
{t('Enter to select, \u2191\u2193 to navigate, Esc to close')}
</Text>
</Box> */}
<Box marginY={1}>
<Text color={theme.border.default}>{'\u2500'.repeat(80)}</Text>
</Box>
<Box>
<Text color={theme.text.primary}>
{t('Terms of Services and Privacy Notice')}:
</Text>
</Box>
{hasApiKey && currentSelectedAuthType === AuthType.QWEN_OAUTH && (
<Box marginTop={1}>
<Text color={theme?.text?.secondary}>
{t(
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.',
)}
<Box>
<Link
url="https://qwenlm.github.io/qwen-code-docs/en/users/support/tos-privacy/"
fallback={false}
>
<Text color={theme.text.secondary} underline>
https://qwenlm.github.io/qwen-code-docs/en/users/support/tos-privacy/
</Text>
</Box>
)}
<Box marginTop={1}>
<Text>
{t('Terms of Services and Privacy Notice for Qwen Code')}
</Text>
</Box>
<Box marginTop={1}>
<Text color={theme.text.link}>
{
'https://qwenlm.github.io/qwen-code-docs/en/users/support/tos-privacy/'
}
</Text>
</Link>
</Box>
</>
)}

View file

@ -300,7 +300,7 @@ export const useAuthCommand = (
setAuthError(null);
// Get configuration based on region
const { template, version, regionName } = getCodingPlanConfig(region);
const { template, version } = getCodingPlanConfig(region);
// Get persist scope
const persistScope = getPersistScopeForModelSelection(settings);
@ -390,7 +390,7 @@ export const useAuthCommand = (
type: MessageType.INFO,
text: t(
'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).',
{ region: regionName },
{ region: t('Alibaba Cloud Coding Plan') },
),
},
Date.now(),

View file

@ -57,9 +57,6 @@ export function ApiKeyInput({
return (
<Box flexDirection="column">
<Box marginBottom={1}>
<Text>{t('Please enter your API key:')}</Text>
</Box>
<TextInput value={apiKey} onChange={setApiKey} placeholder="sk-sp-..." />
{error && (
<Box marginTop={1}>
@ -67,18 +64,18 @@ export function ApiKeyInput({
</Box>
)}
<Box marginTop={1}>
<Text>{t('You can get your exclusive Coding Plan API-KEY here:')}</Text>
<Text>{t('You can get your Coding Plan API key here')}</Text>
</Box>
<Box marginTop={0}>
<Link url={apiKeyUrl} fallback={false}>
<Text color={theme.status.success} underline>
<Text color={theme.text.link} underline>
{apiKeyUrl}
</Text>
</Link>
</Box>
<Box marginTop={1}>
<Text color={theme.text.secondary}>
{t('(Press Enter to submit, Escape to cancel)')}
{t('Enter to submit, Esc to go back')}
</Text>
</Box>
</Box>

View file

@ -30,6 +30,8 @@ export interface BaseSelectionListProps<
showNumbers?: boolean;
showScrollArrows?: boolean;
maxItemsToShow?: number;
/** Gap (in rows) between each item. */
itemGap?: number;
renderItem: (item: TItem, context: RenderItemContext) => React.ReactNode;
}
@ -59,6 +61,7 @@ export function BaseSelectionList<
showNumbers = true,
showScrollArrows = false,
maxItemsToShow = 10,
itemGap = 0,
renderItem,
}: BaseSelectionListProps<T, TItem>): React.JSX.Element {
const { activeIndex } = useSelectionList({
@ -89,7 +92,7 @@ export function BaseSelectionList<
const numberColumnWidth = String(items.length).length;
return (
<Box flexDirection="column">
<Box flexDirection="column" gap={itemGap}>
{/* Use conditional coloring instead of conditional rendering */}
{showScrollArrows && (
<Text

View file

@ -12,7 +12,7 @@ import type { SelectionListItem } from '../../hooks/useSelectionList.js';
export interface DescriptiveRadioSelectItem<T> extends SelectionListItem<T> {
title: React.ReactNode;
description: string;
description: React.ReactNode;
}
export interface DescriptiveRadioButtonSelectProps<T> {
@ -32,6 +32,8 @@ export interface DescriptiveRadioButtonSelectProps<T> {
showScrollArrows?: boolean;
/** The maximum number of items to show at once. */
maxItemsToShow?: number;
/** Gap (in rows) between each item. */
itemGap?: number;
}
/**
@ -48,6 +50,7 @@ export function DescriptiveRadioButtonSelect<T>({
showNumbers = false,
showScrollArrows = false,
maxItemsToShow = 10,
itemGap = 0,
}: DescriptiveRadioButtonSelectProps<T>): React.JSX.Element {
return (
<BaseSelectionList<T, DescriptiveRadioSelectItem<T>>
@ -59,6 +62,7 @@ export function DescriptiveRadioButtonSelect<T>({
showNumbers={showNumbers}
showScrollArrows={showScrollArrows}
maxItemsToShow={maxItemsToShow}
itemGap={itemGap}
renderItem={(item, { titleColor }) => (
<Box flexDirection="column" key={item.key}>
<Text color={titleColor}>{item.title}</Text>

View file

@ -112,7 +112,7 @@ describe('useCodingPlanUpdates', () => {
// Should prompt for China region since it defaults to China
expect(result.current.codingPlanUpdateRequest?.prompt).toContain(
chinaConfig.regionName,
'Alibaba Cloud Coding Plan',
);
});
@ -135,7 +135,7 @@ describe('useCodingPlanUpdates', () => {
});
expect(result.current.codingPlanUpdateRequest?.prompt).toContain(
chinaConfig.regionName,
'Alibaba Cloud Coding Plan',
);
});
@ -158,7 +158,7 @@ describe('useCodingPlanUpdates', () => {
});
expect(result.current.codingPlanUpdateRequest?.prompt).toContain(
globalConfig.regionName,
'Alibaba Cloud Coding Plan',
);
});
});
@ -228,7 +228,7 @@ describe('useCodingPlanUpdates', () => {
expect(mockAddItem).toHaveBeenCalledWith(
expect.objectContaining({
type: 'info',
text: expect.stringContaining(chinaConfig.regionName),
text: expect.stringContaining('Alibaba Cloud Coding Plan'),
}),
expect.any(Number),
);
@ -297,7 +297,7 @@ describe('useCodingPlanUpdates', () => {
expect(mockAddItem).toHaveBeenCalledWith(
expect.objectContaining({
type: 'info',
text: expect.stringContaining(globalConfig.regionName),
text: expect.stringContaining('Alibaba Cloud Coding Plan'),
}),
expect.any(Number),
);

View file

@ -68,7 +68,7 @@ export function useCodingPlanUpdates(
);
// Get the configuration for the current region
const { template, version, regionName } = getCodingPlanConfig(region);
const { template, version } = getCodingPlanConfig(region);
// Generate new configs from template
const newConfigs = template.map((templateConfig) => ({
@ -117,7 +117,7 @@ export function useCodingPlanUpdates(
type: 'info',
text: t(
'{{region}} configuration updated successfully. Model switched to "{{model}}".',
{ region: regionName, model: activeModel },
{ region: t('Alibaba Cloud Coding Plan'), model: activeModel },
),
},
Date.now(),
@ -170,11 +170,10 @@ export function useCodingPlanUpdates(
// Check if version matches
if (savedVersion !== currentVersion) {
const { regionName } = getCodingPlanConfig(region);
setUpdateRequest({
prompt: t(
'New model configurations are available for {{region}}. Update now?',
{ region: regionName },
{ region: t('Alibaba Cloud Coding Plan') },
),
onConfirm: async (confirmed: boolean) => {
setUpdateRequest(undefined);