diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 65e3f9b5b6..609d0fefbf 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -9,6 +9,7 @@ import { codebaseIndexProviderSchema } from "./codebase-index.js" export const providerNames = [ "anthropic", + "claude-code", "glama", "openrouter", "bedrock", @@ -76,6 +77,10 @@ const anthropicSchema = apiModelIdProviderModelSchema.extend({ anthropicUseAuthToken: z.boolean().optional(), }) +const claudeCodeSchema = apiModelIdProviderModelSchema.extend({ + claudeCodePath: z.string().optional(), +}) + const glamaSchema = baseProviderSettingsSchema.extend({ glamaModelId: z.string().optional(), glamaApiKey: z.string().optional(), @@ -208,6 +213,7 @@ const defaultSchema = z.object({ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProvider", [ anthropicSchema.merge(z.object({ apiProvider: z.literal("anthropic") })), + claudeCodeSchema.merge(z.object({ apiProvider: z.literal("claude-code") })), glamaSchema.merge(z.object({ apiProvider: z.literal("glama") })), openRouterSchema.merge(z.object({ apiProvider: z.literal("openrouter") })), bedrockSchema.merge(z.object({ apiProvider: z.literal("bedrock") })), @@ -234,6 +240,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv export const providerSettingsSchema = z.object({ apiProvider: providerNamesSchema.optional(), ...anthropicSchema.shape, + ...claudeCodeSchema.shape, ...glamaSchema.shape, ...openRouterSchema.shape, ...bedrockSchema.shape, diff --git a/packages/types/src/providers/claude-code.ts b/packages/types/src/providers/claude-code.ts new file mode 100644 index 0000000000..ebf053a532 --- /dev/null +++ b/packages/types/src/providers/claude-code.ts @@ -0,0 +1,13 @@ +import type { ModelInfo } from "../model.js" +import { anthropicModels } from "./anthropic.js" + +// Claude Code +export type ClaudeCodeModelId = keyof typeof claudeCodeModels +export const claudeCodeDefaultModelId: ClaudeCodeModelId = "claude-sonnet-4-20250514" +export const claudeCodeModels = { + "claude-sonnet-4-20250514": anthropicModels["claude-sonnet-4-20250514"], + "claude-opus-4-20250514": anthropicModels["claude-opus-4-20250514"], + "claude-3-7-sonnet-20250219": anthropicModels["claude-3-7-sonnet-20250219"], + "claude-3-5-sonnet-20241022": anthropicModels["claude-3-5-sonnet-20241022"], + "claude-3-5-haiku-20241022": anthropicModels["claude-3-5-haiku-20241022"], +} as const satisfies Record diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index 5f1c08041f..4a2b7f1885 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -1,6 +1,7 @@ export * from "./anthropic.js" export * from "./bedrock.js" export * from "./chutes.js" +export * from "./claude-code.js" export * from "./deepseek.js" export * from "./gemini.js" export * from "./glama.js" diff --git a/src/api/index.ts b/src/api/index.ts index 8b09bf4cf9..960209f714 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -27,6 +27,7 @@ import { GroqHandler, ChutesHandler, LiteLLMHandler, + ClaudeCodeHandler, } from "./providers" export interface SingleCompletionHandler { @@ -64,6 +65,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { switch (apiProvider) { case "anthropic": return new AnthropicHandler(options) + case "claude-code": + return new ClaudeCodeHandler(options) case "glama": return new GlamaHandler(options) case "openrouter": diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts new file mode 100644 index 0000000000..f3e66604e4 --- /dev/null +++ b/src/api/providers/claude-code.ts @@ -0,0 +1,171 @@ +import type { Anthropic } from "@anthropic-ai/sdk" +import { claudeCodeDefaultModelId, type ClaudeCodeModelId, claudeCodeModels } from "@roo-code/types" +import { type ApiHandler } from ".." +import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream" +import { runClaudeCode } from "../../integrations/claude-code/run" +import { ClaudeCodeMessage } from "../../integrations/claude-code/types" +import { BaseProvider } from "./base-provider" +import { t } from "../../i18n" +import { ApiHandlerOptions } from "../../shared/api" + +export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { + private options: ApiHandlerOptions + + constructor(options: ApiHandlerOptions) { + super() + this.options = options + } + + override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream { + const claudeProcess = runClaudeCode({ + systemPrompt, + messages, + path: this.options.claudeCodePath, + modelId: this.getModel().id, + }) + + const dataQueue: string[] = [] + let processError = null + let errorOutput = "" + let exitCode: number | null = null + + claudeProcess.stdout.on("data", (data) => { + const output = data.toString() + const lines = output.split("\n").filter((line: string) => line.trim() !== "") + + for (const line of lines) { + dataQueue.push(line) + } + }) + + claudeProcess.stderr.on("data", (data) => { + errorOutput += data.toString() + }) + + claudeProcess.on("close", (code) => { + exitCode = code + }) + + claudeProcess.on("error", (error) => { + processError = error + }) + + // Usage is included with assistant messages, + // but cost is included in the result chunk + let usage: ApiStreamUsageChunk = { + type: "usage", + inputTokens: 0, + outputTokens: 0, + cacheReadTokens: 0, + cacheWriteTokens: 0, + } + + while (exitCode !== 0 || dataQueue.length > 0) { + if (dataQueue.length === 0) { + await new Promise((resolve) => setImmediate(resolve)) + } + + if (exitCode !== null && exitCode !== 0) { + if (errorOutput) { + throw new Error( + t("common:errors.claudeCode.processExitedWithError", { + exitCode, + output: errorOutput.trim(), + }), + ) + } + throw new Error(t("common:errors.claudeCode.processExited", { exitCode })) + } + + const data = dataQueue.shift() + if (!data) { + continue + } + + const chunk = this.attemptParseChunk(data) + + if (!chunk) { + yield { + type: "text", + text: data || "", + } + + continue + } + + if (chunk.type === "system" && chunk.subtype === "init") { + continue + } + + if (chunk.type === "assistant" && "message" in chunk) { + const message = chunk.message + + if (message.stop_reason !== null && message.stop_reason !== "tool_use") { + const errorMessage = + message.content[0]?.text || + t("common:errors.claudeCode.stoppedWithReason", { reason: message.stop_reason }) + + if (errorMessage.includes("Invalid model name")) { + throw new Error(errorMessage + `\n\n${t("common:errors.claudeCode.apiKeyModelPlanMismatch")}`) + } + + throw new Error(errorMessage) + } + + for (const content of message.content) { + if (content.type === "text") { + yield { + type: "text", + text: content.text, + } + } else { + console.warn("Unsupported content type:", content.type) + } + } + + usage.inputTokens += message.usage.input_tokens + usage.outputTokens += message.usage.output_tokens + usage.cacheReadTokens = (usage.cacheReadTokens || 0) + (message.usage.cache_read_input_tokens || 0) + usage.cacheWriteTokens = + (usage.cacheWriteTokens || 0) + (message.usage.cache_creation_input_tokens || 0) + + continue + } + + if (chunk.type === "result" && "result" in chunk) { + // Only use the cost from the CLI if provided + // Don't calculate cost as it may be $0 for subscription users + usage.totalCost = chunk.cost_usd ?? 0 + + yield usage + } + + if (processError) { + throw processError + } + } + } + + getModel() { + const modelId = this.options.apiModelId + if (modelId && modelId in claudeCodeModels) { + const id = modelId as ClaudeCodeModelId + return { id, info: claudeCodeModels[id] } + } + + return { + id: claudeCodeDefaultModelId, + info: claudeCodeModels[claudeCodeDefaultModelId], + } + } + + // TODO: Validate instead of parsing + private attemptParseChunk(data: string): ClaudeCodeMessage | null { + try { + return JSON.parse(data) + } catch (error) { + console.error("Error parsing chunk:", error) + return null + } + } +} diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index b305118188..93df5c58ff 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -2,6 +2,7 @@ export { AnthropicVertexHandler } from "./anthropic-vertex" export { AnthropicHandler } from "./anthropic" export { AwsBedrockHandler } from "./bedrock" export { ChutesHandler } from "./chutes" +export { ClaudeCodeHandler } from "./claude-code" export { DeepSeekHandler } from "./deepseek" export { FakeAIHandler } from "./fake-ai" export { GeminiHandler } from "./gemini" diff --git a/src/api/transform/stream.ts b/src/api/transform/stream.ts index caa69a09fe..89655a3f56 100644 --- a/src/api/transform/stream.ts +++ b/src/api/transform/stream.ts @@ -1,6 +1,12 @@ export type ApiStream = AsyncGenerator -export type ApiStreamChunk = ApiStreamTextChunk | ApiStreamUsageChunk | ApiStreamReasoningChunk +export type ApiStreamChunk = ApiStreamTextChunk | ApiStreamUsageChunk | ApiStreamReasoningChunk | ApiStreamError + +export interface ApiStreamError { + type: "error" + error: string + message: string +} export interface ApiStreamTextChunk { type: "text" diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 8fdc1276cf..d372a57ce6 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -66,7 +66,14 @@ "share_no_active_task": "No hi ha cap tasca activa per compartir", "share_auth_required": "Es requereix autenticació. Si us plau, inicia sessió per compartir tasques.", "share_not_enabled": "La compartició de tasques no està habilitada per a aquesta organització.", - "share_task_not_found": "Tasca no trobada o accés denegat." + "share_task_not_found": "Tasca no trobada o accés denegat.", + "claudeCode": { + "processExited": "El procés Claude Code ha sortit amb codi {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "No s'ha seleccionat contingut de terminal", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Clau API de Groq", - "getGroqApiKey": "Obté la clau API de Groq" + "getGroqApiKey": "Obté la clau API de Groq", + "claudeCode": { + "pathLabel": "Ruta de Claude Code", + "description": "Ruta opcional a la teva CLI de Claude Code. Per defecte 'claude' si no s'estableix.", + "placeholder": "Per defecte: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index e52de53868..d34d266e44 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Keine aktive Aufgabe zum Teilen", "share_auth_required": "Authentifizierung erforderlich. Bitte melde dich an, um Aufgaben zu teilen.", "share_not_enabled": "Aufgabenfreigabe ist für diese Organisation nicht aktiviert.", - "share_task_not_found": "Aufgabe nicht gefunden oder Zugriff verweigert." + "share_task_not_found": "Aufgabe nicht gefunden oder Zugriff verweigert.", + "claudeCode": { + "processExited": "Claude Code Prozess wurde mit Code {{exitCode}} beendet.", + "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." + } }, "warnings": { "no_terminal_content": "Kein Terminal-Inhalt ausgewählt", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Groq API-Schlüssel", - "getGroqApiKey": "Groq API-Schlüssel erhalten" + "getGroqApiKey": "Groq API-Schlüssel erhalten", + "claudeCode": { + "pathLabel": "Claude Code Pfad", + "description": "Optionaler Pfad zu deiner Claude Code CLI. Standardmäßig 'claude', falls nicht festgelegt.", + "placeholder": "Standard: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 7d534d8bc3..0de1a25354 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "No active task to share", "share_auth_required": "Authentication required. Please sign in to share tasks.", "share_not_enabled": "Task sharing is not enabled for this organization.", - "share_task_not_found": "Task not found or access denied." + "share_task_not_found": "Task not found or access denied.", + "claudeCode": { + "processExited": "Claude Code process exited with code {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "No terminal content selected", diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 62634f065b..6da86eb225 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "No hay tarea activa para compartir", "share_auth_required": "Se requiere autenticación. Por favor, inicia sesión para compartir tareas.", "share_not_enabled": "La compartición de tareas no está habilitada para esta organización.", - "share_task_not_found": "Tarea no encontrada o acceso denegado." + "share_task_not_found": "Tarea no encontrada o acceso denegado.", + "claudeCode": { + "processExited": "El proceso de Claude Code terminó con código {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "No hay contenido de terminal seleccionado", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Clave API de Groq", - "getGroqApiKey": "Obtener clave API de Groq" + "getGroqApiKey": "Obtener clave API de Groq", + "claudeCode": { + "pathLabel": "Ruta de Claude Code", + "description": "Ruta opcional a tu CLI de Claude Code. Por defecto 'claude' si no se establece.", + "placeholder": "Por defecto: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index 811be35894..1875bb94a7 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Aucune tâche active à partager", "share_auth_required": "Authentification requise. Veuillez vous connecter pour partager des tâches.", "share_not_enabled": "Le partage de tâches n'est pas activé pour cette organisation.", - "share_task_not_found": "Tâche non trouvée ou accès refusé." + "share_task_not_found": "Tâche non trouvée ou accès refusé.", + "claudeCode": { + "processExited": "Le processus Claude Code s'est terminé avec le code {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "Aucun contenu de terminal sélectionné", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Clé API Groq", - "getGroqApiKey": "Obtenir la clé API Groq" + "getGroqApiKey": "Obtenir la clé API Groq", + "claudeCode": { + "pathLabel": "Chemin de Claude Code", + "description": "Chemin optionnel vers votre CLI Claude Code. Par défaut 'claude' si non défini.", + "placeholder": "Par défaut : claude" + } } }, "mdm": { diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index bbc5558afe..b991b167fe 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "साझा करने के लिए कोई सक्रिय कार्य नहीं", "share_auth_required": "प्रमाणीकरण आवश्यक है। कार्य साझा करने के लिए कृपया साइन इन करें।", "share_not_enabled": "इस संगठन के लिए कार्य साझाकरण सक्षम नहीं है।", - "share_task_not_found": "कार्य नहीं मिला या पहुंच अस्वीकृत।" + "share_task_not_found": "कार्य नहीं मिला या पहुंच अस्वीकृत।", + "claudeCode": { + "processExited": "Claude Code प्रक्रिया कोड {{exitCode}} के साथ समाप्त हुई।", + "errorOutput": "त्रुटि आउटपुट: {{output}}", + "processExitedWithError": "Claude Code प्रक्रिया कोड {{exitCode}} के साथ समाप्त हुई। त्रुटि आउटपुट: {{output}}", + "stoppedWithReason": "Claude Code इस कारण से रुका: {{reason}}", + "apiKeyModelPlanMismatch": "API कुंजी और सब्सक्रिप्शन प्लान अलग-अलग मॉडल की अनुमति देते हैं। सुनिश्चित करें कि चयनित मॉडल आपकी योजना में शामिल है।" + } }, "warnings": { "no_terminal_content": "कोई टर्मिनल सामग्री चयनित नहीं", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "ग्रोक एपीआई कुंजी", - "getGroqApiKey": "ग्रोक एपीआई कुंजी प्राप्त करें" + "getGroqApiKey": "ग्रोक एपीआई कुंजी प्राप्त करें", + "claudeCode": { + "pathLabel": "क्लाउड कोड पाथ", + "description": "आपके क्लाउड कोड CLI का वैकल्पिक पाथ। सेट न होने पर डिफ़ॉल्ट रूप से 'claude'。", + "placeholder": "डिफ़ॉल्ट: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index 4c459324b1..f961b88bed 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Tidak ada tugas aktif untuk dibagikan", "share_auth_required": "Autentikasi diperlukan. Silakan masuk untuk berbagi tugas.", "share_not_enabled": "Berbagi tugas tidak diaktifkan untuk organisasi ini.", - "share_task_not_found": "Tugas tidak ditemukan atau akses ditolak." + "share_task_not_found": "Tugas tidak ditemukan atau akses ditolak.", + "claudeCode": { + "processExited": "Proses Claude Code keluar dengan kode {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "Tidak ada konten terminal yang dipilih", @@ -102,6 +109,17 @@ "task_prompt": "Apa yang harus Roo lakukan?", "task_placeholder": "Ketik tugas kamu di sini" }, + "settings": { + "providers": { + "groqApiKey": "Kunci API Groq", + "getGroqApiKey": "Dapatkan Kunci API Groq", + "claudeCode": { + "pathLabel": "Jalur Claude Code", + "description": "Jalur opsional ke CLI Claude Code Anda. Defaultnya 'claude' jika tidak diatur.", + "placeholder": "Default: claude" + } + } + }, "mdm": { "errors": { "cloud_auth_required": "Organisasi kamu memerlukan autentikasi Roo Code Cloud. Silakan masuk untuk melanjutkan.", diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index 55eb562dfe..0cf42e2cbd 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Nessuna attività attiva da condividere", "share_auth_required": "Autenticazione richiesta. Accedi per condividere le attività.", "share_not_enabled": "La condivisione delle attività non è abilitata per questa organizzazione.", - "share_task_not_found": "Attività non trovata o accesso negato." + "share_task_not_found": "Attività non trovata o accesso negato.", + "claudeCode": { + "processExited": "Il processo Claude Code è terminato con codice {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "Nessun contenuto del terminale selezionato", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Chiave API Groq", - "getGroqApiKey": "Ottieni chiave API Groq" + "getGroqApiKey": "Ottieni chiave API Groq", + "claudeCode": { + "pathLabel": "Percorso Claude Code", + "description": "Percorso opzionale alla tua CLI Claude Code. Predefinito 'claude' se non impostato.", + "placeholder": "Predefinito: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index 965ba73bca..9e1107332b 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "共有するアクティブなタスクがありません", "share_auth_required": "認証が必要です。タスクを共有するにはサインインしてください。", "share_not_enabled": "この組織ではタスク共有が有効になっていません。", - "share_task_not_found": "タスクが見つからないか、アクセスが拒否されました。" + "share_task_not_found": "タスクが見つからないか、アクセスが拒否されました。", + "claudeCode": { + "processExited": "Claude Code プロセスがコード {{exitCode}} で終了しました。", + "errorOutput": "エラー出力:{{output}}", + "processExitedWithError": "Claude Code プロセスがコード {{exitCode}} で終了しました。エラー出力:{{output}}", + "stoppedWithReason": "Claude Code が理由により停止しました:{{reason}}", + "apiKeyModelPlanMismatch": "API キーとサブスクリプションプランでは異なるモデルが利用可能です。選択したモデルがプランに含まれていることを確認してください。" + } }, "warnings": { "no_terminal_content": "選択されたターミナルコンテンツがありません", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Groq APIキー", - "getGroqApiKey": "Groq APIキーを取得" + "getGroqApiKey": "Groq APIキーを取得", + "claudeCode": { + "pathLabel": "Claude Code パス", + "description": "Claude Code CLI へのオプションのパス。設定されていない場合は、デフォルトで「claude」になります。", + "placeholder": "デフォルト: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 670326b851..51614261c1 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "공유할 활성 작업이 없습니다", "share_auth_required": "인증이 필요합니다. 작업을 공유하려면 로그인하세요.", "share_not_enabled": "이 조직에서는 작업 공유가 활성화되지 않았습니다.", - "share_task_not_found": "작업을 찾을 수 없거나 액세스가 거부되었습니다." + "share_task_not_found": "작업을 찾을 수 없거나 액세스가 거부되었습니다.", + "claudeCode": { + "processExited": "Claude Code 프로세스가 코드 {{exitCode}}로 종료되었습니다.", + "errorOutput": "오류 출력: {{output}}", + "processExitedWithError": "Claude Code 프로세스가 코드 {{exitCode}}로 종료되었습니다. 오류 출력: {{output}}", + "stoppedWithReason": "Claude Code가 다음 이유로 중지되었습니다: {{reason}}", + "apiKeyModelPlanMismatch": "API 키와 구독 플랜에서 다른 모델을 허용합니다. 선택한 모델이 플랜에 포함되어 있는지 확인하세요." + } }, "warnings": { "no_terminal_content": "선택된 터미널 내용이 없습니다", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Groq API 키", - "getGroqApiKey": "Groq API 키 받기" + "getGroqApiKey": "Groq API 키 받기", + "claudeCode": { + "pathLabel": "Claude Code 경로", + "description": "Claude Code CLI의 선택적 경로입니다. 설정되지 않은 경우 기본값은 'claude'입니다.", + "placeholder": "기본값: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index 7a97a6b1bc..973f7331a8 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Geen actieve taak om te delen", "share_auth_required": "Authenticatie vereist. Log in om taken te delen.", "share_not_enabled": "Taken delen is niet ingeschakeld voor deze organisatie.", - "share_task_not_found": "Taak niet gevonden of toegang geweigerd." + "share_task_not_found": "Taak niet gevonden of toegang geweigerd.", + "claudeCode": { + "processExited": "Claude Code proces beëindigd met code {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "Geen terminalinhoud geselecteerd", @@ -102,6 +109,17 @@ "task_prompt": "Wat moet Roo doen?", "task_placeholder": "Typ hier je taak" }, + "settings": { + "providers": { + "groqApiKey": "Groq API-sleutel", + "getGroqApiKey": "Groq API-sleutel ophalen", + "claudeCode": { + "pathLabel": "Claude Code Pad", + "description": "Optioneel pad naar je Claude Code CLI. Standaard 'claude' indien niet ingesteld.", + "placeholder": "Standaard: claude" + } + } + }, "mdm": { "errors": { "cloud_auth_required": "Je organisatie vereist Roo Code Cloud-authenticatie. Log in om door te gaan.", diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index 87293db303..71a044ba40 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Brak aktywnego zadania do udostępnienia", "share_auth_required": "Wymagana autoryzacja. Zaloguj się, aby udostępniać zadania.", "share_not_enabled": "Udostępnianie zadań nie jest włączone dla tej organizacji.", - "share_task_not_found": "Zadanie nie znalezione lub dostęp odmówiony." + "share_task_not_found": "Zadanie nie znalezione lub dostęp odmówiony.", + "claudeCode": { + "processExited": "Proces Claude Code zakończył się kodem {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "Nie wybrano zawartości terminala", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Klucz API Groq", - "getGroqApiKey": "Uzyskaj klucz API Groq" + "getGroqApiKey": "Uzyskaj klucz API Groq", + "claudeCode": { + "pathLabel": "Ścieżka Claude Code", + "description": "Opcjonalna ścieżka do Twojego CLI Claude Code. Domyślnie 'claude', jeśli nie ustawiono.", + "placeholder": "Domyślnie: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index e2847d590d..f67383024a 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -66,7 +66,14 @@ "share_no_active_task": "Nenhuma tarefa ativa para compartilhar", "share_auth_required": "Autenticação necessária. Faça login para compartilhar tarefas.", "share_not_enabled": "O compartilhamento de tarefas não está habilitado para esta organização.", - "share_task_not_found": "Tarefa não encontrada ou acesso negado." + "share_task_not_found": "Tarefa não encontrada ou acesso negado.", + "claudeCode": { + "processExited": "O processo Claude Code saiu com código {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "Nenhum conteúdo do terminal selecionado", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Chave de API Groq", - "getGroqApiKey": "Obter chave de API Groq" + "getGroqApiKey": "Obter chave de API Groq", + "claudeCode": { + "pathLabel": "Caminho do Claude Code", + "description": "Caminho opcional para sua CLI do Claude Code. Padrão 'claude' se não for definido.", + "placeholder": "Padrão: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 9d5f29a44a..8a3798307c 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Нет активной задачи для совместного использования", "share_auth_required": "Требуется аутентификация. Войдите в систему для совместного доступа к задачам.", "share_not_enabled": "Совместный доступ к задачам не включен для этой организации.", - "share_task_not_found": "Задача не найдена или доступ запрещен." + "share_task_not_found": "Задача не найдена или доступ запрещен.", + "claudeCode": { + "processExited": "Процесс Claude Code завершился с кодом {{exitCode}}.", + "errorOutput": "Вывод ошибки: {{output}}", + "processExitedWithError": "Процесс Claude Code завершился с кодом {{exitCode}}. Вывод ошибки: {{output}}", + "stoppedWithReason": "Claude Code остановился по причине: {{reason}}", + "apiKeyModelPlanMismatch": "API-ключи и планы подписки позволяют использовать разные модели. Убедитесь, что выбранная модель включена в ваш план." + } }, "warnings": { "no_terminal_content": "Не выбрано содержимое терминала", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Ключ API Groq", - "getGroqApiKey": "Получить ключ API Groq" + "getGroqApiKey": "Получить ключ API Groq", + "claudeCode": { + "pathLabel": "Путь к Claude Code", + "description": "Необязательный путь к вашему CLI Claude Code. По умолчанию 'claude', если не установлено.", + "placeholder": "По умолчанию: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index 893117222a..9902896503 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Paylaşılacak aktif görev yok", "share_auth_required": "Kimlik doğrulama gerekli. Görevleri paylaşmak için lütfen giriş yapın.", "share_not_enabled": "Bu kuruluş için görev paylaşımı etkinleştirilmemiş.", - "share_task_not_found": "Görev bulunamadı veya erişim reddedildi." + "share_task_not_found": "Görev bulunamadı veya erişim reddedildi.", + "claudeCode": { + "processExited": "Claude Code işlemi {{exitCode}} koduyla çıktı.", + "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." + } }, "warnings": { "no_terminal_content": "Seçili terminal içeriği yok", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Groq API Anahtarı", - "getGroqApiKey": "Groq API Anahtarı Al" + "getGroqApiKey": "Groq API Anahtarı Al", + "claudeCode": { + "pathLabel": "Claude Code Yolu", + "description": "Claude Code CLI'nizin isteğe bağlı yolu. Ayarlanmazsa varsayılan olarak 'claude' olur.", + "placeholder": "Varsayılan: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index cc8a22f8a2..93fa9b689b 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "Không có nhiệm vụ hoạt động để chia sẻ", "share_auth_required": "Cần xác thực. Vui lòng đăng nhập để chia sẻ nhiệm vụ.", "share_not_enabled": "Chia sẻ nhiệm vụ không được bật cho tổ chức này.", - "share_task_not_found": "Không tìm thấy nhiệm vụ hoặc truy cập bị từ chối." + "share_task_not_found": "Không tìm thấy nhiệm vụ hoặc truy cập bị từ chối.", + "claudeCode": { + "processExited": "Tiến trình Claude Code thoát với mã {{exitCode}}.", + "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." + } }, "warnings": { "no_terminal_content": "Không có nội dung terminal được chọn", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Khóa API Groq", - "getGroqApiKey": "Lấy khóa API Groq" + "getGroqApiKey": "Lấy khóa API Groq", + "claudeCode": { + "pathLabel": "Đường dẫn Claude Code", + "description": "Đường dẫn tùy chọn đến CLI Claude Code của bạn. Mặc định là 'claude' nếu không được đặt.", + "placeholder": "Mặc định: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index b8e2307b85..f2fedd3c1b 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -67,7 +67,14 @@ "share_no_active_task": "没有活跃任务可分享", "share_auth_required": "需要身份验证。请登录以分享任务。", "share_not_enabled": "此组织未启用任务分享功能。", - "share_task_not_found": "未找到任务或访问被拒绝。" + "share_task_not_found": "未找到任务或访问被拒绝。", + "claudeCode": { + "processExited": "Claude Code 进程退出,退出码:{{exitCode}}。", + "errorOutput": "错误输出:{{output}}", + "processExitedWithError": "Claude Code 进程退出,退出码:{{exitCode}}。错误输出:{{output}}", + "stoppedWithReason": "Claude Code 停止,原因:{{reason}}", + "apiKeyModelPlanMismatch": "API 密钥和订阅计划支持不同的模型。请确保所选模型包含在您的计划中。" + } }, "warnings": { "no_terminal_content": "没有选择终端内容", @@ -110,7 +117,12 @@ "settings": { "providers": { "groqApiKey": "Groq API 密钥", - "getGroqApiKey": "获取 Groq API 密钥" + "getGroqApiKey": "获取 Groq API 密钥", + "claudeCode": { + "pathLabel": "Claude Code 路径", + "description": "Claude Code CLI 的可选路径。如果未设置,默认为 'claude'。", + "placeholder": "默认: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 57e065a7f7..43f44a47b3 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -62,7 +62,14 @@ "share_no_active_task": "沒有活躍的工作可分享", "share_auth_required": "需要身份驗證。請登入以分享工作。", "share_not_enabled": "此組織未啟用工作分享功能。", - "share_task_not_found": "未找到工作或存取被拒絕。" + "share_task_not_found": "未找到工作或存取被拒絕。", + "claudeCode": { + "processExited": "Claude Code 程序退出,退出碼:{{exitCode}}。", + "errorOutput": "錯誤輸出:{{output}}", + "processExitedWithError": "Claude Code 程序退出,退出碼:{{exitCode}}。錯誤輸出:{{output}}", + "stoppedWithReason": "Claude Code 停止,原因:{{reason}}", + "apiKeyModelPlanMismatch": "API 金鑰和訂閱方案允許不同的模型。請確保所選模型包含在您的方案中。" + } }, "warnings": { "no_terminal_content": "沒有選擇終端機內容", @@ -105,7 +112,12 @@ "settings": { "providers": { "groqApiKey": "Groq API 金鑰", - "getGroqApiKey": "取得 Groq API 金鑰" + "getGroqApiKey": "取得 Groq API 金鑰", + "claudeCode": { + "pathLabel": "Claude Code 路徑", + "description": "Claude Code CLI 的選用路徑。如果未設定,預設為 'claude'。", + "placeholder": "預設: claude" + } } }, "mdm": { diff --git a/src/integrations/claude-code/run.ts b/src/integrations/claude-code/run.ts new file mode 100644 index 0000000000..8bc12c8740 --- /dev/null +++ b/src/integrations/claude-code/run.ts @@ -0,0 +1,44 @@ +import * as vscode from "vscode" +import Anthropic from "@anthropic-ai/sdk" +import { execa } from "execa" + +export function runClaudeCode({ + systemPrompt, + messages, + path, + modelId, +}: { + systemPrompt: string + messages: Anthropic.Messages.MessageParam[] + path?: string + modelId?: string +}) { + const claudePath = path || "claude" + + // TODO: Is it worth using sessions? Where do we store the session ID? + const args = [ + "-p", + JSON.stringify(messages), + "--system-prompt", + systemPrompt, + "--verbose", + "--output-format", + "stream-json", + // Cline will handle recursive calls + "--max-turns", + "1", + ] + + if (modelId) { + args.push("--model", modelId) + } + + const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) + return execa(claudePath, args, { + stdin: "ignore", + stdout: "pipe", + stderr: "pipe", + env: process.env, + cwd, + }) +} diff --git a/src/integrations/claude-code/types.ts b/src/integrations/claude-code/types.ts new file mode 100644 index 0000000000..abac758182 --- /dev/null +++ b/src/integrations/claude-code/types.ts @@ -0,0 +1,52 @@ +type InitMessage = { + type: "system" + subtype: "init" + session_id: string + tools: string[] + mcp_servers: string[] +} + +type ClaudeCodeContent = { + type: "text" + text: string +} + +type AssistantMessage = { + type: "assistant" + message: { + id: string + type: "message" + role: "assistant" + model: string + content: ClaudeCodeContent[] + stop_reason: string | null + stop_sequence: null + usage: { + input_tokens: number + cache_creation_input_tokens?: number + cache_read_input_tokens?: number + output_tokens: number + service_tier: "standard" + } + } + session_id: string +} + +type ErrorMessage = { + type: "error" +} + +type ResultMessage = { + type: "result" + subtype: "success" + cost_usd: number + is_error: boolean + duration_ms: number + duration_api_ms: number + num_turns: number + result: string + total_cost: number + session_id: string +} + +export type ClaudeCodeMessage = InitMessage | AssistantMessage | ErrorMessage | ResultMessage diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index c55999efbd..aff2be9b26 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -13,6 +13,7 @@ import { litellmDefaultModelId, openAiNativeDefaultModelId, anthropicDefaultModelId, + claudeCodeDefaultModelId, geminiDefaultModelId, deepSeekDefaultModelId, mistralDefaultModelId, @@ -36,6 +37,7 @@ import { Anthropic, Bedrock, Chutes, + ClaudeCode, DeepSeek, Gemini, Glama, @@ -254,6 +256,7 @@ const ApiOptions = ({ requesty: { field: "requestyModelId", default: requestyDefaultModelId }, litellm: { field: "litellmModelId", default: litellmDefaultModelId }, anthropic: { field: "apiModelId", default: anthropicDefaultModelId }, + "claude-code": { field: "apiModelId", default: claudeCodeDefaultModelId }, "openai-native": { field: "apiModelId", default: openAiNativeDefaultModelId }, gemini: { field: "apiModelId", default: geminiDefaultModelId }, deepseek: { field: "apiModelId", default: deepSeekDefaultModelId }, @@ -383,6 +386,10 @@ const ApiOptions = ({ )} + {selectedProvider === "claude-code" && ( + + )} + {selectedProvider === "openai-native" && ( )} diff --git a/webview-ui/src/components/settings/constants.ts b/webview-ui/src/components/settings/constants.ts index 5b808643e5..bbee8f990d 100644 --- a/webview-ui/src/components/settings/constants.ts +++ b/webview-ui/src/components/settings/constants.ts @@ -3,6 +3,7 @@ import { type ModelInfo, anthropicModels, bedrockModels, + claudeCodeModels, deepSeekModels, geminiModels, mistralModels, @@ -15,6 +16,7 @@ import { export const MODELS_BY_PROVIDER: Partial>> = { anthropic: anthropicModels, + "claude-code": claudeCodeModels, bedrock: bedrockModels, deepseek: deepSeekModels, gemini: geminiModels, @@ -29,6 +31,7 @@ export const MODELS_BY_PROVIDER: Partial void +} + +export const ClaudeCode: React.FC = ({ apiConfiguration, setApiConfigurationField }) => { + const { t } = useAppTranslation() + + const handleInputChange = (e: Event | React.FormEvent) => { + const element = e.target as HTMLInputElement + setApiConfigurationField("claudeCodePath", element.value) + } + + return ( +
+ + {t("settings:providers.claudeCode.pathLabel")} + + +

+ {t("settings:providers.claudeCode.description")} +

+
+ ) +} diff --git a/webview-ui/src/components/settings/providers/index.ts b/webview-ui/src/components/settings/providers/index.ts index b244fb515c..b195607430 100644 --- a/webview-ui/src/components/settings/providers/index.ts +++ b/webview-ui/src/components/settings/providers/index.ts @@ -1,6 +1,7 @@ export { Anthropic } from "./Anthropic" export { Bedrock } from "./Bedrock" export { Chutes } from "./Chutes" +export { ClaudeCode } from "./ClaudeCode" export { DeepSeek } from "./DeepSeek" export { Gemini } from "./Gemini" export { Glama } from "./Glama" diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index d72c7455fe..a7cf42633f 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -303,7 +303,12 @@ "medium": "Mitjà", "low": "Baix" }, - "setReasoningLevel": "Activa l'esforç de raonament" + "setReasoningLevel": "Activa l'esforç de raonament", + "claudeCode": { + "pathLabel": "Ruta del Codi Claude", + "description": "Ruta opcional al teu CLI de Claude Code. Per defecte, 'claude' si no s'estableix.", + "placeholder": "Per defecte: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 7aacb054e2..d5ccff3084 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -303,7 +303,12 @@ "medium": "Mittel", "low": "Niedrig" }, - "setReasoningLevel": "Denkaufwand aktivieren" + "setReasoningLevel": "Denkaufwand aktivieren", + "claudeCode": { + "pathLabel": "Claude-Code-Pfad", + "description": "Optionaler Pfad zu Ihrer Claude Code CLI. Standard ist 'claude', wenn nicht festgelegt.", + "placeholder": "Standard: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 690fea5026..85e7487c0c 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -303,7 +303,12 @@ "medium": "Medium", "low": "Low" }, - "setReasoningLevel": "Enable Reasoning Effort" + "setReasoningLevel": "Enable Reasoning Effort", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 9b2e239cf3..035ccf5628 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -303,7 +303,12 @@ "medium": "Medio", "low": "Bajo" }, - "setReasoningLevel": "Habilitar esfuerzo de razonamiento" + "setReasoningLevel": "Habilitar esfuerzo de razonamiento", + "claudeCode": { + "pathLabel": "Ruta de Claude Code", + "description": "Ruta opcional a su CLI de Claude Code. Por defecto, es 'claude' si no se establece.", + "placeholder": "Por defecto: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 2ac2efcc00..fb0b47e0b3 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -303,7 +303,12 @@ "medium": "Moyen", "low": "Faible" }, - "setReasoningLevel": "Activer l'effort de raisonnement" + "setReasoningLevel": "Activer l'effort de raisonnement", + "claudeCode": { + "pathLabel": "Chemin du code Claude", + "description": "Chemin facultatif vers votre CLI Claude Code. La valeur par défaut est 'claude' si non défini.", + "placeholder": "Défaut : claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 87628e5550..883a84e982 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -303,7 +303,12 @@ "medium": "मध्यम", "low": "निम्न" }, - "setReasoningLevel": "तर्क प्रयास सक्षम करें" + "setReasoningLevel": "तर्क प्रयास सक्षम करें", + "claudeCode": { + "pathLabel": "क्लाउड कोड पथ", + "description": "आपके क्लाउड कोड सीएलआई का वैकल्पिक पथ। यदि सेट नहीं है तो डिफ़ॉल्ट 'claude' है।", + "placeholder": "डिफ़ॉल्ट: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 1a4005446c..e95a415c6f 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -307,7 +307,12 @@ "medium": "Sedang", "low": "Rendah" }, - "setReasoningLevel": "Aktifkan Upaya Reasoning" + "setReasoningLevel": "Aktifkan Upaya Reasoning", + "claudeCode": { + "pathLabel": "Jalur Kode Claude", + "description": "Jalur opsional ke Claude Code CLI Anda. Defaultnya adalah 'claude' jika tidak diatur.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 515cbe8ec7..927bca66ee 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -303,7 +303,12 @@ "medium": "Medio", "low": "Basso" }, - "setReasoningLevel": "Abilita sforzo di ragionamento" + "setReasoningLevel": "Abilita sforzo di ragionamento", + "claudeCode": { + "pathLabel": "Percorso Claude Code", + "description": "Percorso facoltativo per la tua CLI Claude Code. Predefinito 'claude' se non impostato.", + "placeholder": "Predefinito: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 3d3e53d6cd..2ca40dd91d 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -303,7 +303,12 @@ "medium": "中", "low": "低" }, - "setReasoningLevel": "推論労力を有効にする" + "setReasoningLevel": "推論労力を有効にする", + "claudeCode": { + "pathLabel": "クロードコードパス", + "description": "Claude Code CLIへのオプションパス。設定されていない場合、デフォルトは「claude」です。", + "placeholder": "デフォルト:claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index eb0417ba76..4cce3ad754 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -303,7 +303,12 @@ "medium": "중간", "low": "낮음" }, - "setReasoningLevel": "추론 노력 활성화" + "setReasoningLevel": "추론 노력 활성화", + "claudeCode": { + "pathLabel": "클로드 코드 경로", + "description": "Claude Code CLI의 선택적 경로입니다. 설정하지 않으면 'claude'가 기본값입니다.", + "placeholder": "기본값: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index d94ad5480e..95bd3ac762 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -303,7 +303,12 @@ "medium": "Middel", "low": "Laag" }, - "setReasoningLevel": "Redeneervermogen inschakelen" + "setReasoningLevel": "Redeneervermogen inschakelen", + "claudeCode": { + "pathLabel": "Claude Code Pad", + "description": "Optioneel pad naar uw Claude Code CLI. Standaard 'claude' als niet ingesteld.", + "placeholder": "Standaard: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 8b900ae0d4..bb245d80ba 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -303,7 +303,12 @@ "medium": "Średni", "low": "Niski" }, - "setReasoningLevel": "Włącz wysiłek rozumowania" + "setReasoningLevel": "Włącz wysiłek rozumowania", + "claudeCode": { + "pathLabel": "Ścieżka Claude Code", + "description": "Opcjonalna ścieżka do Twojego CLI Claude Code. Domyślnie 'claude', jeśli nie ustawiono.", + "placeholder": "Domyślnie: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 9d1884efa9..96e7dac362 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -303,7 +303,12 @@ "medium": "Médio", "low": "Baixo" }, - "setReasoningLevel": "Habilitar esforço de raciocínio" + "setReasoningLevel": "Habilitar esforço de raciocínio", + "claudeCode": { + "pathLabel": "Caminho do Claude Code", + "description": "Caminho opcional para o seu Claude Code CLI. O padrão é 'claude' se não for definido.", + "placeholder": "Padrão: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index c6a9bca2d6..8508fea509 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -303,7 +303,12 @@ "medium": "Средние", "low": "Низкие" }, - "setReasoningLevel": "Включить усилие рассуждения" + "setReasoningLevel": "Включить усилие рассуждения", + "claudeCode": { + "pathLabel": "Путь к Claude Code", + "description": "Необязательный путь к вашему Claude Code CLI. По умолчанию используется 'claude', если не установлено.", + "placeholder": "По умолчанию: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 6f42914336..5e3db268fc 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -303,7 +303,12 @@ "medium": "Orta", "low": "Düşük" }, - "setReasoningLevel": "Akıl Yürütme Çabasını Etkinleştir" + "setReasoningLevel": "Akıl Yürütme Çabasını Etkinleştir", + "claudeCode": { + "pathLabel": "Claude Code Yolu", + "description": "Claude Code CLI'nize isteğe bağlı yol. Ayarlanmazsa varsayılan olarak 'claude' kullanılır.", + "placeholder": "Varsayılan: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index b728ac1766..0960c30a38 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -303,7 +303,12 @@ "medium": "Trung bình", "low": "Thấp" }, - "setReasoningLevel": "Kích hoạt nỗ lực suy luận" + "setReasoningLevel": "Kích hoạt nỗ lực suy luận", + "claudeCode": { + "pathLabel": "Đường dẫn Claude Code", + "description": "Đường dẫn tùy chọn đến Claude Code CLI của bạn. Mặc định là 'claude' nếu không được đặt.", + "placeholder": "Mặc định: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index f02923e14f..8978ff3e9c 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -303,7 +303,12 @@ "medium": "中", "low": "低" }, - "setReasoningLevel": "启用推理工作量" + "setReasoningLevel": "启用推理工作量", + "claudeCode": { + "pathLabel": "Claude Code 路径", + "description": "您的 Claude Code CLI 的可选路径。如果未设置,则默认为 “claude”。", + "placeholder": "默认:claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index e8b0d2d3cf..5e3ec47007 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -303,7 +303,12 @@ "medium": "中", "low": "低" }, - "setReasoningLevel": "啟用推理工作量" + "setReasoningLevel": "啟用推理工作量", + "claudeCode": { + "pathLabel": "Claude Code 路徑", + "description": "可選的 Claude Code CLI 路徑。如果未設定,則預設為 'claude'。", + "placeholder": "預設:claude" + } }, "browser": { "enable": {