diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 0fba764080..394c08dbd7 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -86,7 +86,8 @@ "errorOutput": "Sortida d'error: {{output}}", "processExitedWithError": "El procés Claude Code ha sortit amb codi {{exitCode}}. Sortida d'error: {{output}}", "stoppedWithReason": "Claude Code s'ha aturat per la raó: {{reason}}", - "apiKeyModelPlanMismatch": "Les claus API i els plans de subscripció permeten models diferents. Assegura't que el model seleccionat estigui inclòs al teu pla." + "apiKeyModelPlanMismatch": "Les claus API i els plans de subscripció permeten models diferents. Assegura't que el model seleccionat estigui inclòs al teu pla.", + "notFound": "No s'ha trobat l'executable Claude Code '{{claudePath}}'.\n\nInstal·la Claude Code CLI:\n1. Visita {{installationUrl}} per descarregar Claude Code\n2. Segueix les instruccions d'instal·lació per al teu sistema operatiu\n3. Assegura't que la comanda 'claude' estigui disponible al teu PATH\n4. Alternativament, configura una ruta personalitzada a la configuració de Roo sota 'Ruta de Claude Code'\n\nError original: {{originalError}}" }, "gemini": { "generate_stream": "Error del flux de context de generació de Gemini: {{error}}", diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 1c60189b2f..0e51a1644d 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -83,7 +83,8 @@ "errorOutput": "Fehlerausgabe: {{output}}", "processExitedWithError": "Claude Code Prozess wurde mit Code {{exitCode}} beendet. Fehlerausgabe: {{output}}", "stoppedWithReason": "Claude Code wurde mit Grund gestoppt: {{reason}}", - "apiKeyModelPlanMismatch": "API-Schlüssel und Abonnement-Pläne erlauben verschiedene Modelle. Stelle sicher, dass das ausgewählte Modell in deinem Plan enthalten ist." + "apiKeyModelPlanMismatch": "API-Schlüssel und Abonnement-Pläne erlauben verschiedene Modelle. Stelle sicher, dass das ausgewählte Modell in deinem Plan enthalten ist.", + "notFound": "Claude Code ausführbare Datei '{{claudePath}}' nicht gefunden.\n\nBitte installiere Claude Code CLI:\n1. Besuche {{installationUrl}} um Claude Code herunterzuladen\n2. Folge den Installationsanweisungen für dein Betriebssystem\n3. Stelle sicher, dass der 'claude' Befehl in deinem PATH verfügbar ist\n4. Alternativ konfiguriere einen benutzerdefinierten Pfad in den Roo-Einstellungen unter 'Claude Code Pfad'\n\nUrsprünglicher Fehler: {{originalError}}" }, "gemini": { "generate_stream": "Fehler beim Generieren des Kontext-Streams von Gemini: {{error}}", diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 114e129f45..57454cbfe6 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -83,7 +83,8 @@ "errorOutput": "Error output: {{output}}", "processExitedWithError": "Claude Code process exited with code {{exitCode}}. Error output: {{output}}", "stoppedWithReason": "Claude Code stopped with reason: {{reason}}", - "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { "generate_stream": "Gemini generate context stream error: {{error}}", diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 62ab4dcb6e..32ae5f284e 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -83,7 +83,8 @@ "errorOutput": "Salida de error: {{output}}", "processExitedWithError": "El proceso de Claude Code terminó con código {{exitCode}}. Salida de error: {{output}}", "stoppedWithReason": "Claude Code se detuvo por la razón: {{reason}}", - "apiKeyModelPlanMismatch": "Las claves API y los planes de suscripción permiten diferentes modelos. Asegúrate de que el modelo seleccionado esté incluido en tu plan." + "apiKeyModelPlanMismatch": "Las claves API y los planes de suscripción permiten diferentes modelos. Asegúrate de que el modelo seleccionado esté incluido en tu plan.", + "notFound": "Ejecutable de Claude Code '{{claudePath}}' no encontrado.\n\nPor favor instala Claude Code CLI:\n1. Visita {{installationUrl}} para descargar Claude Code\n2. Sigue las instrucciones de instalación para tu sistema operativo\n3. Asegúrate de que el comando 'claude' esté disponible en tu PATH\n4. Alternativamente, configura una ruta personalizada en la configuración de Roo bajo 'Ruta de Claude Code'\n\nError original: {{originalError}}" }, "gemini": { "generate_stream": "Error del stream de contexto de generación de Gemini: {{error}}", diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index aae4d5d7b1..3f256a3488 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -83,11 +83,12 @@ "errorOutput": "Sortie d'erreur : {{output}}", "processExitedWithError": "Le processus Claude Code s'est terminé avec le code {{exitCode}}. Sortie d'erreur : {{output}}", "stoppedWithReason": "Claude Code s'est arrêté pour la raison : {{reason}}", - "apiKeyModelPlanMismatch": "Les clés API et les plans d'abonnement permettent différents modèles. Assurez-vous que le modèle sélectionné est inclus dans votre plan." + "apiKeyModelPlanMismatch": "Les clés API et les plans d'abonnement permettent différents modèles. Assurez-vous que le modèle sélectionné est inclus dans votre plan.", + "notFound": "Exécutable Claude Code '{{claudePath}}' introuvable.\n\nVeuillez installer Claude Code CLI :\n1. Visitez {{installationUrl}} pour télécharger Claude Code\n2. Suivez les instructions d'installation pour votre système d'exploitation\n3. Assurez-vous que la commande 'claude' est disponible dans votre PATH\n4. Alternativement, configurez un chemin personnalisé dans les paramètres Roo sous 'Chemin de Claude Code'\n\nErreur originale : {{originalError}}" }, "gemini": { - "generate_stream": "Erreur du flux de contexte de génération Gemini : {{error}}", - "generate_complete_prompt": "Erreur d'achèvement de Gemini : {{error}}", + "generate_stream": "Erreur du flux de contexte de génération Gemini : {{error}}", + "generate_complete_prompt": "Erreur d'achèvement de Gemini : {{error}}", "sources": "Sources :" } }, diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index fae7c42be9..6ffc87a9eb 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -83,12 +83,13 @@ "errorOutput": "त्रुटि आउटपुट: {{output}}", "processExitedWithError": "Claude Code प्रक्रिया कोड {{exitCode}} के साथ समाप्त हुई। त्रुटि आउटपुट: {{output}}", "stoppedWithReason": "Claude Code इस कारण से रुका: {{reason}}", - "apiKeyModelPlanMismatch": "API कुंजी और सब्सक्रिप्शन प्लान अलग-अलग मॉडल की अनुमति देते हैं। सुनिश्चित करें कि चयनित मॉडल आपकी योजना में शामिल है।" + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "जेमिनी जनरेट कॉन्टेक्स्ट स्ट्रीम त्रुटि: {{error}}", - "generate_complete_prompt": "जेमिनी समापन त्रुटि: {{error}}", - "sources": "स्रोत:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index eb2db5ac84..fdd619ec4d 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -83,12 +83,13 @@ "errorOutput": "Output error: {{output}}", "processExitedWithError": "Proses Claude Code keluar dengan kode {{exitCode}}. Output error: {{output}}", "stoppedWithReason": "Claude Code berhenti karena alasan: {{reason}}", - "apiKeyModelPlanMismatch": "Kunci API dan paket berlangganan memungkinkan model yang berbeda. Pastikan model yang dipilih termasuk dalam paket Anda." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Kesalahan aliran konteks pembuatan Gemini: {{error}}", - "generate_complete_prompt": "Kesalahan penyelesaian Gemini: {{error}}", - "sources": "Sumber:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index a7ef4b075a..92cbf64316 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -83,12 +83,13 @@ "errorOutput": "Output di errore: {{output}}", "processExitedWithError": "Il processo Claude Code è terminato con codice {{exitCode}}. Output di errore: {{output}}", "stoppedWithReason": "Claude Code si è fermato per il motivo: {{reason}}", - "apiKeyModelPlanMismatch": "Le chiavi API e i piani di abbonamento consentono modelli diversi. Assicurati che il modello selezionato sia incluso nel tuo piano." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Errore del flusso di contesto di generazione Gemini: {{error}}", - "generate_complete_prompt": "Errore di completamento Gemini: {{error}}", - "sources": "Fonti:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index 6e7e0b8a3e..c82aa6b90d 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -83,12 +83,13 @@ "errorOutput": "エラー出力:{{output}}", "processExitedWithError": "Claude Code プロセスがコード {{exitCode}} で終了しました。エラー出力:{{output}}", "stoppedWithReason": "Claude Code が理由により停止しました:{{reason}}", - "apiKeyModelPlanMismatch": "API キーとサブスクリプションプランでは異なるモデルが利用可能です。選択したモデルがプランに含まれていることを確認してください。" + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Gemini 生成コンテキスト ストリーム エラー: {{error}}", - "generate_complete_prompt": "Gemini 完了エラー: {{error}}", - "sources": "ソース:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 1d0a5f3c4a..d9d178a39c 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -83,12 +83,13 @@ "errorOutput": "오류 출력: {{output}}", "processExitedWithError": "Claude Code 프로세스가 코드 {{exitCode}}로 종료되었습니다. 오류 출력: {{output}}", "stoppedWithReason": "Claude Code가 다음 이유로 중지되었습니다: {{reason}}", - "apiKeyModelPlanMismatch": "API 키와 구독 플랜에서 다른 모델을 허용합니다. 선택한 모델이 플랜에 포함되어 있는지 확인하세요." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Gemini 생성 컨텍스트 스트림 오류: {{error}}", - "generate_complete_prompt": "Gemini 완료 오류: {{error}}", - "sources": "출처:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index bb7d3c0f23..277b1d7445 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -83,12 +83,13 @@ "errorOutput": "Foutuitvoer: {{output}}", "processExitedWithError": "Claude Code proces beëindigd met code {{exitCode}}. Foutuitvoer: {{output}}", "stoppedWithReason": "Claude Code gestopt om reden: {{reason}}", - "apiKeyModelPlanMismatch": "API-sleutels en abonnementsplannen staan verschillende modellen toe. Zorg ervoor dat het geselecteerde model is opgenomen in je plan." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Fout bij het genereren van contextstream door Gemini: {{error}}", - "generate_complete_prompt": "Fout bij het voltooien door Gemini: {{error}}", - "sources": "Bronnen:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index 953f52ea79..ce0597e241 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -83,12 +83,13 @@ "errorOutput": "Wyjście błędu: {{output}}", "processExitedWithError": "Proces Claude Code zakończył się kodem {{exitCode}}. Wyjście błędu: {{output}}", "stoppedWithReason": "Claude Code zatrzymał się z powodu: {{reason}}", - "apiKeyModelPlanMismatch": "Klucze API i plany subskrypcji pozwalają na różne modele. Upewnij się, że wybrany model jest zawarty w twoim planie." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Błąd strumienia kontekstu generowania Gemini: {{error}}", - "generate_complete_prompt": "Błąd uzupełniania Gemini: {{error}}", - "sources": "Źródła:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index 21aca727a1..96912bf9a4 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -87,12 +87,13 @@ "errorOutput": "Saída de erro: {{output}}", "processExitedWithError": "O processo Claude Code saiu com código {{exitCode}}. Saída de erro: {{output}}", "stoppedWithReason": "Claude Code parou pela razão: {{reason}}", - "apiKeyModelPlanMismatch": "Chaves de API e planos de assinatura permitem modelos diferentes. Certifique-se de que o modelo selecionado esteja incluído no seu plano." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Erro de fluxo de contexto de geração do Gemini: {{error}}", - "generate_complete_prompt": "Erro de conclusão do Gemini: {{error}}", - "sources": "Fontes:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 30913e16e9..7f469da787 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -83,12 +83,13 @@ "errorOutput": "Вывод ошибки: {{output}}", "processExitedWithError": "Процесс Claude Code завершился с кодом {{exitCode}}. Вывод ошибки: {{output}}", "stoppedWithReason": "Claude Code остановился по причине: {{reason}}", - "apiKeyModelPlanMismatch": "API-ключи и планы подписки позволяют использовать разные модели. Убедитесь, что выбранная модель включена в ваш план." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Ошибка потока контекста генерации Gemini: {{error}}", - "generate_complete_prompt": "Ошибка завершения Gemini: {{error}}", - "sources": "Источники:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index 6892c7c8f1..c100172e61 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -83,12 +83,13 @@ "errorOutput": "Hata çıktısı: {{output}}", "processExitedWithError": "Claude Code işlemi {{exitCode}} koduyla çıktı. Hata çıktısı: {{output}}", "stoppedWithReason": "Claude Code şu nedenle durdu: {{reason}}", - "apiKeyModelPlanMismatch": "API anahtarları ve abonelik planları farklı modellere izin verir. Seçilen modelin planınıza dahil olduğundan emin olun." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Gemini oluşturma bağlam akışı hatası: {{error}}", - "generate_complete_prompt": "Gemini tamamlama hatası: {{error}}", - "sources": "Kaynaklar:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index f88120098d..9a2fe23c77 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -83,12 +83,13 @@ "errorOutput": "Đầu ra lỗi: {{output}}", "processExitedWithError": "Tiến trình Claude Code thoát với mã {{exitCode}}. Đầu ra lỗi: {{output}}", "stoppedWithReason": "Claude Code dừng lại vì lý do: {{reason}}", - "apiKeyModelPlanMismatch": "Khóa API và gói đăng ký cho phép các mô hình khác nhau. Đảm bảo rằng mô hình đã chọn được bao gồm trong gói của bạn." + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Lỗi luồng ngữ cảnh tạo Gemini: {{error}}", - "generate_complete_prompt": "Lỗi hoàn thành Gemini: {{error}}", - "sources": "Nguồn:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index e81b7d589a..9dba8dada9 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -88,12 +88,13 @@ "errorOutput": "错误输出:{{output}}", "processExitedWithError": "Claude Code 进程退出,退出码:{{exitCode}}。错误输出:{{output}}", "stoppedWithReason": "Claude Code 停止,原因:{{reason}}", - "apiKeyModelPlanMismatch": "API 密钥和订阅计划支持不同的模型。请确保所选模型包含在您的计划中。" + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan.", + "notFound": "Claude Code executable '{{claudePath}}' not found.\n\nPlease install Claude Code CLI:\n1. Visit {{installationUrl}} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: {{originalError}}" }, "gemini": { - "generate_stream": "Gemini 生成上下文流错误:{{error}}", - "generate_complete_prompt": "Gemini 完成错误:{{error}}", - "sources": "来源:" + "generate_stream": "Gemini generate context stream error: {{error}}", + "generate_complete_prompt": "Gemini completion error: {{error}}", + "sources": "Sources:" } }, "warnings": { diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 1c800d4d37..1167e49220 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -82,7 +82,8 @@ "errorOutput": "錯誤輸出:{{output}}", "processExitedWithError": "Claude Code 程序退出,退出碼:{{exitCode}}。錯誤輸出:{{output}}", "stoppedWithReason": "Claude Code 停止,原因:{{reason}}", - "apiKeyModelPlanMismatch": "API 金鑰和訂閱方案允許不同的模型。請確保所選模型包含在您的方案中。" + "apiKeyModelPlanMismatch": "API 金鑰和訂閱方案允許不同的模型。請確保所選模型包含在您的方案中。", + "notFound": "找不到 Claude Code 可執行檔案 '{{claudePath}}'。\n\n請安裝 Claude Code CLI:\n1. 造訪 {{installationUrl}} 下載 Claude Code\n2. 依照作業系統的安裝說明進行操作\n3. 確保 'claude' 指令在 PATH 中可用\n4. 或者在 Roo 設定中的 'Claude Code 路徑' 下設定自訂路徑\n\n原始錯誤:{{originalError}}" }, "gemini": { "generate_stream": "Gemini 產生內容串流錯誤:{{error}}", diff --git a/src/integrations/claude-code/__tests__/run.spec.ts b/src/integrations/claude-code/__tests__/run.spec.ts index 27af274447..fa5aedcd36 100644 --- a/src/integrations/claude-code/__tests__/run.spec.ts +++ b/src/integrations/claude-code/__tests__/run.spec.ts @@ -1,5 +1,21 @@ import { describe, test, expect, vi, beforeEach, afterEach } from "vitest" +// Mock i18n system +vi.mock("../../i18n", () => ({ + t: vi.fn((key: string, options?: Record) => { + // Mock the specific translation key used in the code + if (key === "errors.claudeCode.notFound") { + const claudePath = options?.claudePath || "claude" + const installationUrl = options?.installationUrl || "https://docs.anthropic.com/en/docs/claude-code/setup" + const originalError = options?.originalError || "spawn claude ENOENT" + + return `Claude Code executable '${claudePath}' not found.\n\nPlease install Claude Code CLI:\n1. Visit ${installationUrl} to download Claude Code\n2. Follow the installation instructions for your operating system\n3. Ensure the 'claude' command is available in your PATH\n4. Alternatively, configure a custom path in Roo settings under 'Claude Code Path'\n\nOriginal error: ${originalError}` + } + // Return the key as fallback for other translations + return key + }), +})) + // Mock os module vi.mock("os", () => ({ platform: vi.fn(() => "darwin"), // Default to non-Windows @@ -100,6 +116,8 @@ describe("runClaudeCode", () => { callback() return {} as any }) + // Clear module cache to ensure fresh imports + vi.resetModules() }) afterEach(() => { @@ -289,4 +307,217 @@ describe("runClaudeCode", () => { consoleErrorSpy.mockRestore() await generator.return(undefined) }) + + test("should handle ENOENT errors during process spawn with helpful error message", async () => { + const { runClaudeCode } = await import("../run") + + // Mock execa to throw ENOENT error + const enoentError = new Error("spawn claude ENOENT") + ;(enoentError as any).code = "ENOENT" + mockExeca.mockImplementationOnce(() => { + throw enoentError + }) + + const options = { + systemPrompt: "You are a helpful assistant", + messages: [{ role: "user" as const, content: "Hello" }], + } + + const generator = runClaudeCode(options) + + // Should throw enhanced ENOENT error + await expect(generator.next()).rejects.toThrow(/errors\.claudeCode\.notFound/) + }) + + test("should handle ENOENT errors during process execution with helpful error message", async () => { + const { runClaudeCode } = await import("../run") + + // Create a mock process that emits ENOENT error + const mockProcessWithError = createMockProcess() + const enoentError = new Error("spawn claude ENOENT") + ;(enoentError as any).code = "ENOENT" + + mockProcessWithError.on = vi.fn((event, callback) => { + if (event === "error") { + // Emit ENOENT error immediately + callback(enoentError) + } else if (event === "close") { + // Don't emit close event in this test + } + }) + + // Mock readline to not yield any data when there's an error + const mockReadlineForError = { + [Symbol.asyncIterator]() { + return { + async next() { + // Don't yield anything - simulate error before any output + return { done: true, value: undefined } + }, + } + }, + close: vi.fn(), + } + + const readline = await import("readline") + vi.mocked(readline.default.createInterface).mockReturnValueOnce(mockReadlineForError as any) + + mockExeca.mockReturnValueOnce(mockProcessWithError) + + const options = { + systemPrompt: "You are a helpful assistant", + messages: [{ role: "user" as const, content: "Hello" }], + } + + const generator = runClaudeCode(options) + + // Should throw enhanced ENOENT error + await expect(generator.next()).rejects.toThrow(/errors\.claudeCode\.notFound/) + }) + + test("should handle ENOENT errors with custom claude path", async () => { + const { runClaudeCode } = await import("../run") + + const customPath = "/custom/path/to/claude" + const enoentError = new Error(`spawn ${customPath} ENOENT`) + ;(enoentError as any).code = "ENOENT" + mockExeca.mockImplementationOnce(() => { + throw enoentError + }) + + const options = { + systemPrompt: "You are a helpful assistant", + messages: [{ role: "user" as const, content: "Hello" }], + path: customPath, + } + + const generator = runClaudeCode(options) + + // Should throw enhanced ENOENT error with custom path + await expect(generator.next()).rejects.toThrow(/errors\.claudeCode\.notFound/) + }) + + test("should preserve non-ENOENT errors during process spawn", async () => { + const { runClaudeCode } = await import("../run") + + // Mock execa to throw non-ENOENT error + const otherError = new Error("Permission denied") + mockExeca.mockImplementationOnce(() => { + throw otherError + }) + + const options = { + systemPrompt: "You are a helpful assistant", + messages: [{ role: "user" as const, content: "Hello" }], + } + + const generator = runClaudeCode(options) + + // Should throw original error, not enhanced ENOENT error + await expect(generator.next()).rejects.toThrow("Permission denied") + }) + + test("should preserve non-ENOENT errors during process execution", async () => { + const { runClaudeCode } = await import("../run") + + // Create a mock process that emits non-ENOENT error + const mockProcessWithError = createMockProcess() + const otherError = new Error("Permission denied") + + mockProcessWithError.on = vi.fn((event, callback) => { + if (event === "error") { + // Emit non-ENOENT error immediately + callback(otherError) + } else if (event === "close") { + // Don't emit close event in this test + } + }) + + // Mock readline to not yield any data when there's an error + const mockReadlineForError = { + [Symbol.asyncIterator]() { + return { + async next() { + // Don't yield anything - simulate error before any output + return { done: true, value: undefined } + }, + } + }, + close: vi.fn(), + } + + const readline = await import("readline") + vi.mocked(readline.default.createInterface).mockReturnValueOnce(mockReadlineForError as any) + + mockExeca.mockReturnValueOnce(mockProcessWithError) + + const options = { + systemPrompt: "You are a helpful assistant", + messages: [{ role: "user" as const, content: "Hello" }], + } + + const generator = runClaudeCode(options) + + // Should throw original error, not enhanced ENOENT error + await expect(generator.next()).rejects.toThrow("Permission denied") + }) + + test("should prioritize ClaudeCodeNotFoundError over generic exit code errors", async () => { + const { runClaudeCode } = await import("../run") + + // Create a mock process that emits ENOENT error and then exits with non-zero code + const mockProcessWithError = createMockProcess() + const enoentError = new Error("spawn claude ENOENT") + ;(enoentError as any).code = "ENOENT" + + let resolveProcess: (value: { exitCode: number }) => void + const processPromise = new Promise<{ exitCode: number }>((resolve) => { + resolveProcess = resolve + }) + + mockProcessWithError.on = vi.fn((event, callback) => { + if (event === "error") { + // Emit ENOENT error immediately + callback(enoentError) + } else if (event === "close") { + // Emit non-zero exit code + setTimeout(() => { + callback(1) + resolveProcess({ exitCode: 1 }) + }, 10) + } + }) + + mockProcessWithError.then = processPromise.then.bind(processPromise) + mockProcessWithError.catch = processPromise.catch.bind(processPromise) + mockProcessWithError.finally = processPromise.finally.bind(processPromise) + + // Mock readline to not yield any data when there's an error + const mockReadlineForError = { + [Symbol.asyncIterator]() { + return { + async next() { + // Don't yield anything - simulate error before any output + return { done: true, value: undefined } + }, + } + }, + close: vi.fn(), + } + + const readline = await import("readline") + vi.mocked(readline.default.createInterface).mockReturnValueOnce(mockReadlineForError as any) + + mockExeca.mockReturnValueOnce(mockProcessWithError) + + const options = { + systemPrompt: "You are a helpful assistant", + messages: [{ role: "user" as const, content: "Hello" }], + } + + const generator = runClaudeCode(options) + + // Should throw ClaudeCodeNotFoundError, not generic exit code error + await expect(generator.next()).rejects.toThrow(/errors\.claudeCode\.notFound/) + }) }) diff --git a/src/integrations/claude-code/run.ts b/src/integrations/claude-code/run.ts index 65e32bd96f..3f438df0fc 100644 --- a/src/integrations/claude-code/run.ts +++ b/src/integrations/claude-code/run.ts @@ -5,9 +5,13 @@ import { ClaudeCodeMessage } from "./types" import readline from "readline" import { CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS } from "@roo-code/types" import * as os from "os" +import { t } from "../../i18n" const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) +// Claude Code installation URL - can be easily updated if needed +const CLAUDE_CODE_INSTALLATION_URL = "https://docs.anthropic.com/en/docs/claude-code/setup" + type ClaudeCodeOptions = { systemPrompt: string messages: Anthropic.Messages.MessageParam[] @@ -25,7 +29,18 @@ type ProcessState = { export async function* runClaudeCode( options: ClaudeCodeOptions & { maxOutputTokens?: number }, ): AsyncGenerator { - const process = runProcess(options) + const claudePath = options.path || "claude" + let process + + try { + process = runProcess(options) + } catch (error: any) { + // Handle ENOENT errors immediately when spawning the process + if (error.code === "ENOENT" || error.message?.includes("ENOENT")) { + throw createClaudeCodeNotFoundError(claudePath, error) + } + throw error + } const rl = readline.createInterface({ input: process.stdout, @@ -48,7 +63,14 @@ export async function* runClaudeCode( }) process.on("error", (err) => { - processState.error = err + // Enhance ENOENT errors with helpful installation guidance + if (err.message.includes("ENOENT") || (err as any).code === "ENOENT") { + processState.error = createClaudeCodeNotFoundError(claudePath, err) + } else { + processState.error = err + } + // Close the readline interface to break out of the loop + rl.close() }) for await (const line of rl) { @@ -67,6 +89,11 @@ export async function* runClaudeCode( } } + // Check for errors that occurred during processing + if (processState.error) { + throw processState.error + } + // We rely on the assistant message. If the output was truncated, it's better having a poorly formatted message // from which to extract something, than throwing an error/showing the model didn't return any messages. if (processState.partialData && processState.partialData.startsWith(`{"type":"assistant"`)) { @@ -75,7 +102,12 @@ export async function* runClaudeCode( const { exitCode } = await process if (exitCode !== null && exitCode !== 0) { - const errorOutput = processState.error?.message || processState.stderrLogs?.trim() + // If we have a specific ENOENT error, throw that instead + if (processState.error && (processState.error as any).name === "ClaudeCodeNotFoundError") { + throw processState.error + } + + const errorOutput = (processState.error as any)?.message || processState.stderrLogs?.trim() throw new Error( `Claude Code process exited with code ${exitCode}.${errorOutput ? ` Error output: ${errorOutput}` : ""}`, ) @@ -223,3 +255,18 @@ function attemptParseChunk(data: string): ClaudeCodeMessage | null { return null } } + +/** + * Creates a user-friendly error message for Claude Code ENOENT errors + */ +function createClaudeCodeNotFoundError(claudePath: string, originalError: Error): Error { + const errorMessage = t("errors.claudeCode.notFound", { + claudePath, + installationUrl: CLAUDE_CODE_INSTALLATION_URL, + originalError: originalError.message, + }) + + const error = new Error(errorMessage) + error.name = "ClaudeCodeNotFoundError" + return error +}