diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 88b5408fca..dc3ea072fd 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -46,6 +46,8 @@ export const DEFAULT_AUTO_CLOSE_ZOO_OPENED_NEW_FILES = false */ export const DEFAULT_DIFF_FUZZY_THRESHOLD = 1.0 +export const DEFAULT_DESTRUCTIVE_COMMAND_GUARD_ENABLED = false + /** * Terminal output preview size options for persisted command output. * @@ -136,6 +138,7 @@ export const globalSettingsSchema = z.object({ alwaysAllowModeSwitch: z.boolean().optional(), alwaysAllowSubtasks: z.boolean().optional(), alwaysAllowExecute: z.boolean().optional(), + destructiveCommandGuardEnabled: z.boolean().optional(), alwaysAllowFollowupQuestions: z.boolean().optional(), followupAutoApproveTimeoutMs: z.number().optional(), allowedCommands: z.array(z.string()).optional(), diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index c35a5da538..63d5be87a8 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -274,6 +274,7 @@ export type ExtensionState = Pick< | "alwaysAllowSubtasks" | "alwaysAllowFollowupQuestions" | "alwaysAllowExecute" + | "destructiveCommandGuardEnabled" | "followupAutoApproveTimeoutMs" | "allowedCommands" | "deniedCommands" diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 2ee92edebc..db1f634ec0 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -42,6 +42,7 @@ import { openRouterDefaultModelId, DEFAULT_WRITE_DELAY_MS, DEFAULT_DIFF_FUZZY_THRESHOLD, + DEFAULT_DESTRUCTIVE_COMMAND_GUARD_ENABLED, DEFAULT_AUTO_CLOSE_ZOO_OPENED_FILES, DEFAULT_AUTO_CLOSE_ZOO_OPENED_FILES_AFTER_USER_EDITED, DEFAULT_AUTO_CLOSE_ZOO_OPENED_NEW_FILES, @@ -2310,6 +2311,7 @@ export class ClineProvider alwaysAllowWriteOutsideWorkspace, alwaysAllowWriteProtected, alwaysAllowExecute, + destructiveCommandGuardEnabled, allowedCommands, deniedCommands, alwaysAllowMcp, @@ -2459,6 +2461,7 @@ export class ClineProvider alwaysAllowWriteOutsideWorkspace: alwaysAllowWriteOutsideWorkspace ?? false, alwaysAllowWriteProtected: alwaysAllowWriteProtected ?? false, alwaysAllowExecute: alwaysAllowExecute ?? false, + destructiveCommandGuardEnabled: destructiveCommandGuardEnabled ?? DEFAULT_DESTRUCTIVE_COMMAND_GUARD_ENABLED, alwaysAllowMcp: alwaysAllowMcp ?? false, alwaysAllowModeSwitch: alwaysAllowModeSwitch ?? false, alwaysAllowSubtasks: alwaysAllowSubtasks ?? false, @@ -2691,6 +2694,8 @@ export class ClineProvider alwaysAllowWriteOutsideWorkspace: stateValues.alwaysAllowWriteOutsideWorkspace ?? false, alwaysAllowWriteProtected: stateValues.alwaysAllowWriteProtected ?? false, alwaysAllowExecute: stateValues.alwaysAllowExecute ?? false, + destructiveCommandGuardEnabled: + stateValues.destructiveCommandGuardEnabled ?? DEFAULT_DESTRUCTIVE_COMMAND_GUARD_ENABLED, alwaysAllowMcp: stateValues.alwaysAllowMcp ?? false, alwaysAllowModeSwitch: stateValues.alwaysAllowModeSwitch ?? false, alwaysAllowSubtasks: stateValues.alwaysAllowSubtasks ?? false, diff --git a/src/core/webview/__tests__/ClineProvider.spec.ts b/src/core/webview/__tests__/ClineProvider.spec.ts index b99e502f61..70d9824156 100644 --- a/src/core/webview/__tests__/ClineProvider.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.spec.ts @@ -1011,6 +1011,23 @@ describe("ClineProvider", () => { expect(state).toHaveProperty("writeDelayMs") }) + test("getStateToPostToWebview returns the saved destructive command guard setting", async () => { + await provider.resolveWebviewView(mockWebviewView) + await provider.contextProxy.setValue("destructiveCommandGuardEnabled", true) + + const state = await provider.getStateToPostToWebview() + + expect(state.destructiveCommandGuardEnabled).toBe(true) + }) + + test("getStateToPostToWebview disables destructive command guard by default", async () => { + await provider.resolveWebviewView(mockWebviewView) + + const state = await provider.getStateToPostToWebview() + + expect(state.destructiveCommandGuardEnabled).toBe(false) + }) + test("language is set to VSCode language", async () => { // Mock VSCode language as Spanish ;(vscode.env as any).language = "pt-BR" diff --git a/src/core/webview/__tests__/webviewMessageHandler.spec.ts b/src/core/webview/__tests__/webviewMessageHandler.spec.ts index 64ad6804df..8cf1076992 100644 --- a/src/core/webview/__tests__/webviewMessageHandler.spec.ts +++ b/src/core/webview/__tests__/webviewMessageHandler.spec.ts @@ -26,6 +26,10 @@ vi.mock("../../../services/command/commands", () => ({ getCommands: vi.fn(), })) +vi.mock("../../../services/destructive-command-guard", () => ({ + ensureDcgInstalled: vi.fn(), +})) + vi.mock("@anthropic-ai/vertex-sdk", () => ({ AnthropicVertex: vi.fn(), })) @@ -58,6 +62,7 @@ import type { ClineProvider } from "../ClineProvider" import { flushModels, getModels } from "../../../api/providers/fetchers/modelCache" import { getLMStudioModels } from "../../../api/providers/fetchers/lmstudio" import { getCommands } from "../../../services/command/commands" +import { ensureDcgInstalled } from "../../../services/destructive-command-guard" import { handleCreateRule, handleDeleteRule, @@ -1098,6 +1103,79 @@ describe("webviewMessageHandler - mcpEnabled", () => { }) }) +describe("webviewMessageHandler - destructiveCommandGuardEnabled", () => { + beforeEach(() => { + vi.clearAllMocks() + vi.mocked(ensureDcgInstalled).mockResolvedValue("/mock/global/storage/dcg") + }) + + it("installs and persists destructive command guard when enabled", async () => { + await webviewMessageHandler(mockClineProvider, { + type: "updateSettings", + updatedSettings: { destructiveCommandGuardEnabled: true }, + }) + + expect(ensureDcgInstalled).toHaveBeenCalledWith("/mock/global/storage") + expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", true) + expect(vscode.window.showErrorMessage).not.toHaveBeenCalled() + }) + + it("disables the setting and reports an installation failure", async () => { + vi.mocked(ensureDcgInstalled).mockRejectedValue(new Error("checksum mismatch")) + + await webviewMessageHandler(mockClineProvider, { + type: "updateSettings", + updatedSettings: { destructiveCommandGuardEnabled: true }, + }) + + expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", false) + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith( + "common:errors.destructive_command_guard_enable_failed", + ) + }) + + it("disables the setting when DCG is unavailable for the current platform", async () => { + vi.mocked(ensureDcgInstalled).mockResolvedValue(undefined) + + await webviewMessageHandler(mockClineProvider, { + type: "updateSettings", + updatedSettings: { destructiveCommandGuardEnabled: true }, + }) + + expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", false) + expect(t).toHaveBeenCalledWith("common:errors.destructive_command_guard_enable_failed", { + error: "common:errors.destructiveCommandGuard.unavailable", + }) + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith( + "common:errors.destructive_command_guard_enable_failed", + ) + }) + + it("reports non-Error installation failures", async () => { + vi.mocked(ensureDcgInstalled).mockRejectedValue("download unavailable") + + await webviewMessageHandler(mockClineProvider, { + type: "updateSettings", + updatedSettings: { destructiveCommandGuardEnabled: true }, + }) + + expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", false) + expect(t).toHaveBeenCalledWith("common:errors.destructive_command_guard_enable_failed", { + error: "download unavailable", + }) + }) + + it("persists disabled state without trying to install", async () => { + await webviewMessageHandler(mockClineProvider, { + type: "updateSettings", + updatedSettings: { destructiveCommandGuardEnabled: false }, + }) + + expect(ensureDcgInstalled).not.toHaveBeenCalled() + expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", false) + }) +}) + describe("webviewMessageHandler - terminalProfile", () => { beforeEach(() => { vi.clearAllMocks() diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 7009343573..ea13cf80a6 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -681,6 +681,23 @@ export const webviewMessageHandler = async ( case "updateSettings": if (message.updatedSettings) { + if (message.updatedSettings.destructiveCommandGuardEnabled === true) { + try { + const { ensureDcgInstalled } = await import("../../services/destructive-command-guard") + const binaryPath = await ensureDcgInstalled(provider.context.globalStorageUri.fsPath) + if (!binaryPath) { + throw new Error(t("common:errors.destructiveCommandGuard.unavailable")) + } + } catch (error) { + message.updatedSettings.destructiveCommandGuardEnabled = false + vscode.window.showErrorMessage( + t("common:errors.destructive_command_guard_enable_failed", { + error: error instanceof Error ? error.message : String(error), + }), + ) + } + } + for (const [key, value] of Object.entries(message.updatedSettings)) { let newValue = value diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index f988fa0c37..f0a0039a6d 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -76,6 +76,10 @@ "url_fetch_failed": "Error en obtenir el contingut de la URL: {{error}}", "url_fetch_error_with_url": "Error en obtenir contingut per {{url}}: {{error}}", "command_timeout": "L'execució de la comanda ha superat el temps d'espera de {{seconds}} segons", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard està activat, però no està disponible per a aquesta plataforma" + }, + "destructive_command_guard_enable_failed": "No s'ha pogut activar Destructive Command Guard: {{error}}", "share_task_failed": "Ha fallat compartir la tasca. Si us plau, torna-ho a provar.", "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.", diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 03dc94ca22..f802dd7cb7 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Fehler beim Abrufen des URL-Inhalts: {{error}}", "url_fetch_error_with_url": "Fehler beim Abrufen des Inhalts für {{url}}: {{error}}", "command_timeout": "Zeitüberschreitung bei der Befehlsausführung nach {{seconds}} Sekunden", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard ist aktiviert, aber für diese Plattform nicht verfügbar" + }, + "destructive_command_guard_enable_failed": "Destructive Command Guard konnte nicht aktiviert werden: {{error}}", "share_task_failed": "Teilen der Aufgabe fehlgeschlagen. Bitte versuche es erneut.", "share_no_active_task": "Keine aktive Aufgabe zum Teilen", "share_auth_required": "Authentifizierung erforderlich. Bitte melde dich an, um Aufgaben zu teilen.", diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 190af9180a..05d17e430d 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Failed to fetch URL content: {{error}}", "url_fetch_error_with_url": "Error fetching content for {{url}}: {{error}}", "command_timeout": "Command execution timed out after {{seconds}} seconds", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard is enabled but is not available for this platform" + }, + "destructive_command_guard_enable_failed": "Unable to enable Destructive Command Guard: {{error}}", "share_task_failed": "Failed to share task. Please try again.", "share_no_active_task": "No active task to share", "share_auth_required": "Authentication required. Please sign in to share tasks.", diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 4fcbd82a85..4c8db1797c 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Error al obtener el contenido de la URL: {{error}}", "url_fetch_error_with_url": "Error al obtener contenido para {{url}}: {{error}}", "command_timeout": "La ejecución del comando superó el tiempo de espera de {{seconds}} segundos", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard está activado, pero no está disponible para esta plataforma" + }, + "destructive_command_guard_enable_failed": "No se pudo activar Destructive Command Guard: {{error}}", "share_task_failed": "Error al compartir la tarea. Por favor, inténtalo de nuevo.", "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.", diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index ece55c9b11..5d38125cfa 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Échec de récupération du contenu de l'URL : {{error}}", "url_fetch_error_with_url": "Erreur lors de la récupération du contenu pour {{url}} : {{error}}", "command_timeout": "L'exécution de la commande a expiré après {{seconds}} secondes", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard est activé, mais n'est pas disponible pour cette plateforme" + }, + "destructive_command_guard_enable_failed": "Impossible d'activer Destructive Command Guard : {{error}}", "share_task_failed": "Échec du partage de la tâche. Veuillez réessayer.", "share_no_active_task": "Aucune tâche active à partager", "share_auth_required": "Authentification requise. Veuillez vous connecter pour partager des tâches.", diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index 42e46f0e9e..47aac65cc0 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "URL सामग्री प्राप्त करने में त्रुटि: {{error}}", "url_fetch_error_with_url": "{{url}} के लिए सामग्री प्राप्त करने में त्रुटि: {{error}}", "command_timeout": "कमांड निष्पादन {{seconds}} सेकंड के बाद समय समाप्त हो गया", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard सक्षम है, लेकिन इस प्लेटफ़ॉर्म के लिए उपलब्ध नहीं है" + }, + "destructive_command_guard_enable_failed": "Destructive Command Guard को सक्षम नहीं किया जा सका: {{error}}", "share_task_failed": "कार्य साझा करने में विफल। कृपया पुनः प्रयास करें।", "share_no_active_task": "साझा करने के लिए कोई सक्रिय कार्य नहीं", "share_auth_required": "प्रमाणीकरण आवश्यक है। कार्य साझा करने के लिए कृपया साइन इन करें।", diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index 92dbf24171..dd770878b0 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Gagal mengambil konten URL: {{error}}", "url_fetch_error_with_url": "Error mengambil konten untuk {{url}}: {{error}}", "command_timeout": "Eksekusi perintah waktu habis setelah {{seconds}} detik", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard diaktifkan, tetapi tidak tersedia untuk platform ini" + }, + "destructive_command_guard_enable_failed": "Tidak dapat mengaktifkan Destructive Command Guard: {{error}}", "share_task_failed": "Gagal membagikan tugas. Silakan coba lagi.", "share_no_active_task": "Tidak ada tugas aktif untuk dibagikan", "share_auth_required": "Autentikasi diperlukan. Silakan masuk untuk berbagi tugas.", diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index fd739f7d8d..c1bee82189 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Errore nel recupero del contenuto URL: {{error}}", "url_fetch_error_with_url": "Errore nel recupero del contenuto per {{url}}: {{error}}", "command_timeout": "Esecuzione del comando scaduta dopo {{seconds}} secondi", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard è abilitato, ma non è disponibile per questa piattaforma" + }, + "destructive_command_guard_enable_failed": "Impossibile abilitare Destructive Command Guard: {{error}}", "share_task_failed": "Condivisione dell'attività fallita. Riprova.", "share_no_active_task": "Nessuna attività attiva da condividere", "share_auth_required": "Autenticazione richiesta. Accedi per condividere le attività.", diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index 06c8fd4a05..93a60e293e 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "URLコンテンツの取得に失敗しました:{{error}}", "url_fetch_error_with_url": "{{url}} のコンテンツ取得エラー:{{error}}", "command_timeout": "コマンドの実行が{{seconds}}秒後にタイムアウトしました", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard は有効ですが、このプラットフォームでは利用できません" + }, + "destructive_command_guard_enable_failed": "Destructive Command Guard を有効にできませんでした: {{error}}", "share_task_failed": "タスクの共有に失敗しました", "share_no_active_task": "共有するアクティブなタスクがありません", "share_auth_required": "認証が必要です。タスクを共有するにはサインインしてください。", diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 4b2944cfd9..b20d3c57cb 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "URL 콘텐츠 가져오기 실패: {{error}}", "url_fetch_error_with_url": "{{url}} 콘텐츠 가져오기 오류: {{error}}", "command_timeout": "명령 실행 시간이 {{seconds}}초 후 초과되었습니다", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard가 활성화되어 있지만 이 플랫폼에서는 사용할 수 없습니다" + }, + "destructive_command_guard_enable_failed": "Destructive Command Guard를 활성화할 수 없습니다: {{error}}", "share_task_failed": "작업 공유에 실패했습니다", "share_no_active_task": "공유할 활성 작업이 없습니다", "share_auth_required": "인증이 필요합니다. 작업을 공유하려면 로그인하세요.", diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index 96a921c6c1..ebedc3322f 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Fout bij ophalen van URL-inhoud: {{error}}", "url_fetch_error_with_url": "Fout bij ophalen van inhoud voor {{url}}: {{error}}", "command_timeout": "Time-out bij uitvoeren van commando na {{seconds}} seconden", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard is ingeschakeld, maar is niet beschikbaar voor dit platform" + }, + "destructive_command_guard_enable_failed": "Destructive Command Guard kan niet worden ingeschakeld: {{error}}", "share_task_failed": "Delen van taak mislukt", "share_no_active_task": "Geen actieve taak om te delen", "share_auth_required": "Authenticatie vereist. Log in om taken te delen.", diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index f3e789e842..c1f2974813 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Błąd pobierania zawartości URL: {{error}}", "url_fetch_error_with_url": "Błąd pobierania zawartości dla {{url}}: {{error}}", "command_timeout": "Przekroczono limit czasu wykonania polecenia po {{seconds}} sekundach", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard jest włączony, ale nie jest dostępny dla tej platformy" + }, + "destructive_command_guard_enable_failed": "Nie udało się włączyć Destructive Command Guard: {{error}}", "share_task_failed": "Nie udało się udostępnić zadania", "share_no_active_task": "Brak aktywnego zadania do udostępnienia", "share_auth_required": "Wymagana autoryzacja. Zaloguj się, aby udostępniać zadania.", diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index ac5ec44f6b..44f8081f6e 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -76,6 +76,10 @@ "url_fetch_failed": "Falha ao buscar conteúdo da URL: {{error}}", "url_fetch_error_with_url": "Erro ao buscar conteúdo para {{url}}: {{error}}", "command_timeout": "A execução do comando excedeu o tempo limite após {{seconds}} segundos", + "destructiveCommandGuard": { + "unavailable": "O Destructive Command Guard está ativado, mas não está disponível para esta plataforma" + }, + "destructive_command_guard_enable_failed": "Não foi possível ativar o Destructive Command Guard: {{error}}", "share_task_failed": "Falha ao compartilhar tarefa", "share_no_active_task": "Nenhuma tarefa ativa para compartilhar", "share_auth_required": "Autenticação necessária. Faça login para compartilhar tarefas.", diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 26d4b2032f..3dc402adff 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Ошибка получения содержимого URL: {{error}}", "url_fetch_error_with_url": "Ошибка получения содержимого для {{url}}: {{error}}", "command_timeout": "Время выполнения команды истекло через {{seconds}} секунд", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard включён, но недоступен для этой платформы" + }, + "destructive_command_guard_enable_failed": "Не удалось включить Destructive Command Guard: {{error}}", "share_task_failed": "Не удалось поделиться задачей", "share_no_active_task": "Нет активной задачи для совместного использования", "share_auth_required": "Требуется аутентификация. Войдите в систему для совместного доступа к задачам.", diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index bde000783a..2707945fe8 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "URL içeriği getirme hatası: {{error}}", "url_fetch_error_with_url": "{{url}} için içerik getirme hatası: {{error}}", "command_timeout": "Komut çalıştırma {{seconds}} saniye sonra zaman aşımına uğradı", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard etkin, ancak bu platformda kullanılamıyor" + }, + "destructive_command_guard_enable_failed": "Destructive Command Guard etkinleştirilemedi: {{error}}", "share_task_failed": "Görev paylaşılamadı", "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.", diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 2a9433c506..ab6bd714c2 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "Lỗi lấy nội dung URL: {{error}}", "url_fetch_error_with_url": "Lỗi lấy nội dung cho {{url}}: {{error}}", "command_timeout": "Thực thi lệnh đã hết thời gian chờ sau {{seconds}} giây", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard đã được bật nhưng không khả dụng cho nền tảng này" + }, + "destructive_command_guard_enable_failed": "Không thể bật Destructive Command Guard: {{error}}", "share_task_failed": "Không thể chia sẻ nhiệm vụ", "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ụ.", diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index a1d0b06e89..0af3875a5c 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -77,6 +77,10 @@ "url_fetch_failed": "获取 URL 内容失败:{{error}}", "url_fetch_error_with_url": "获取 {{url}} 内容时出错:{{error}}", "command_timeout": "命令执行超时,{{seconds}} 秒后", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard 已启用,但不适用于此平台" + }, + "destructive_command_guard_enable_failed": "无法启用 Destructive Command Guard:{{error}}", "share_task_failed": "分享任务失败。请重试。", "share_no_active_task": "没有活跃任务可分享", "share_auth_required": "需要身份验证。请登录以分享任务。", diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 92435e42ff..13832974bf 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -72,6 +72,10 @@ "url_fetch_failed": "取得 URL 內容失敗:{{error}}", "url_fetch_error_with_url": "取得 {{url}} 內容時發生錯誤:{{error}}", "command_timeout": "命令執行超時,{{seconds}} 秒後", + "destructiveCommandGuard": { + "unavailable": "Destructive Command Guard 已啟用,但不適用於此平台" + }, + "destructive_command_guard_enable_failed": "無法啟用 Destructive Command Guard:{{error}}", "share_task_failed": "分享工作失敗。請重試。", "share_no_active_task": "沒有活躍的工作可分享", "share_auth_required": "需要身份驗證。請登入以分享工作。", diff --git a/src/services/destructive-command-guard/index.ts b/src/services/destructive-command-guard/index.ts new file mode 100644 index 0000000000..f58e907ac6 --- /dev/null +++ b/src/services/destructive-command-guard/index.ts @@ -0,0 +1,3 @@ +export * from "./constants" +export * from "./manager" +export * from "./runner" diff --git a/webview-ui/src/components/settings/AutoApproveSettings.tsx b/webview-ui/src/components/settings/AutoApproveSettings.tsx index 90b82dc4be..29676f2299 100644 --- a/webview-ui/src/components/settings/AutoApproveSettings.tsx +++ b/webview-ui/src/components/settings/AutoApproveSettings.tsx @@ -28,6 +28,7 @@ type AutoApproveSettingsProps = HTMLAttributes & { alwaysAllowModeSwitch?: boolean alwaysAllowSubtasks?: boolean alwaysAllowExecute?: boolean + destructiveCommandGuardEnabled?: boolean alwaysAllowFollowupQuestions?: boolean followupAutoApproveTimeoutMs?: number allowedCommands?: string[] @@ -44,6 +45,7 @@ type AutoApproveSettingsProps = HTMLAttributes & { | "alwaysAllowModeSwitch" | "alwaysAllowSubtasks" | "alwaysAllowExecute" + | "destructiveCommandGuardEnabled" | "alwaysAllowFollowupQuestions" | "followupAutoApproveTimeoutMs" | "allowedCommands" @@ -63,6 +65,7 @@ export const AutoApproveSettings = ({ alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysAllowExecute, + destructiveCommandGuardEnabled, alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs = 60000, allowedCommands, @@ -219,6 +222,7 @@ export const AutoApproveSettings = ({ {t("settings:autoApprove.write.outsideWorkspace.description")} + - + label={t("settings:autoApprove.execute.destructiveCommandGuard.label")}> + + setCachedStateField("destructiveCommandGuardEnabled", e.target.checked) + } + data-testid="destructive-command-guard-checkbox"> + + {t("settings:autoApprove.execute.destructiveCommandGuard.label")} + +
- {t("settings:autoApprove.execute.allowedCommandsDescription")} + {t("settings:autoApprove.execute.destructiveCommandGuard.description")}
-
- setCommandInput(e.target.value)} - onKeyDown={(e: any) => { - if (e.key === "Enter") { - e.preventDefault() - handleAddCommand() - } - }} - placeholder={t("settings:autoApprove.execute.commandPlaceholder")} - className="grow" - data-testid="command-input" - /> - -
- -
- {(allowedCommands ?? []).map((cmd, index) => ( - - ))} -
+
- {/* Denied Commands Section */} - - -
- {t("settings:autoApprove.execute.deniedCommandsDescription")} -
-
+
+ setCommandInput(e.target.value)} + onKeyDown={(e: any) => { + if (e.key === "Enter") { + e.preventDefault() + handleAddCommand() + } + }} + placeholder={t("settings:autoApprove.execute.commandPlaceholder")} + className="grow" + data-testid="command-input" + /> + +
-
- setDeniedCommandInput(e.target.value)} - onKeyDown={(e: any) => { - if (e.key === "Enter") { - e.preventDefault() - handleAddDeniedCommand() - } - }} - placeholder={t("settings:autoApprove.execute.deniedCommandPlaceholder")} - className="grow" - data-testid="denied-command-input" - /> - -
+
+ {(allowedCommands ?? []).map((cmd, index) => ( + + ))} +
-
- {(deniedCommands ?? []).map((cmd, index) => ( - - ))} -
+ + +
+ setDeniedCommandInput(e.target.value)} + onKeyDown={(e: any) => { + if (e.key === "Enter") { + e.preventDefault() + handleAddDeniedCommand() + } + }} + placeholder={t("settings:autoApprove.execute.deniedCommandPlaceholder")} + className="grow" + data-testid="denied-command-input" + /> + +
+ +
+ {(deniedCommands ?? []).map((cmd, index) => ( + + ))} +
+ + )} )} diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index c45ca38eea..952c5615af 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -162,6 +162,7 @@ const SettingsView = forwardRef(({ onDone, t allowedMaxCost, language, alwaysAllowExecute, + destructiveCommandGuardEnabled, alwaysAllowMcp, alwaysAllowModeSwitch, alwaysAllowSubtasks, @@ -387,6 +388,7 @@ const SettingsView = forwardRef(({ onDone, t alwaysAllowWriteOutsideWorkspace: alwaysAllowWriteOutsideWorkspace ?? undefined, alwaysAllowWriteProtected: alwaysAllowWriteProtected ?? undefined, alwaysAllowExecute: alwaysAllowExecute ?? undefined, + destructiveCommandGuardEnabled: destructiveCommandGuardEnabled ?? false, alwaysAllowMcp, alwaysAllowModeSwitch, allowedCommands: allowedCommands ?? [], @@ -814,6 +816,7 @@ const SettingsView = forwardRef(({ onDone, t alwaysAllowModeSwitch={alwaysAllowModeSwitch} alwaysAllowSubtasks={alwaysAllowSubtasks} alwaysAllowExecute={alwaysAllowExecute} + destructiveCommandGuardEnabled={destructiveCommandGuardEnabled} alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions} followupAutoApproveTimeoutMs={followupAutoApproveTimeoutMs} allowedCommands={allowedCommands} diff --git a/webview-ui/src/components/settings/__tests__/AutoApproveSettings.spec.tsx b/webview-ui/src/components/settings/__tests__/AutoApproveSettings.spec.tsx index 8b736280ee..0808c05531 100644 --- a/webview-ui/src/components/settings/__tests__/AutoApproveSettings.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/AutoApproveSettings.spec.tsx @@ -67,6 +67,16 @@ describe("AutoApproveSettings - Save/Discard contract", () => { expectNoImmediateUpdateSettings() }) + it("buffers an allowed command submitted with Enter", () => { + const { setCachedStateField } = renderSettings() + + const input = screen.getByTestId("command-input") + fireEvent.change(input, { target: { value: "pnpm test" } }) + fireEvent.keyDown(input, { key: "Enter" }) + + expect(setCachedStateField).toHaveBeenCalledWith("allowedCommands", ["pnpm test"]) + }) + // Case 2: allowedCommands remove it("buffers a removed allowed command without persisting before Save", () => { const { setCachedStateField } = renderSettings({ allowedCommands: ["npm test"] }) @@ -88,6 +98,16 @@ describe("AutoApproveSettings - Save/Discard contract", () => { expectNoImmediateUpdateSettings() }) + it("buffers a denied command submitted with Enter", () => { + const { setCachedStateField } = renderSettings() + + const input = screen.getByTestId("denied-command-input") + fireEvent.change(input, { target: { value: "sudo rm" } }) + fireEvent.keyDown(input, { key: "Enter" }) + + expect(setCachedStateField).toHaveBeenCalledWith("deniedCommands", ["sudo rm"]) + }) + // Case 3b: deniedCommands remove it("buffers a removed denied command without persisting before Save", () => { const { setCachedStateField } = renderSettings({ deniedCommands: ["rm -rf"] }) @@ -97,4 +117,41 @@ describe("AutoApproveSettings - Save/Discard contract", () => { expect(setCachedStateField).toHaveBeenCalledWith("deniedCommands", []) expectNoImmediateUpdateSettings() }) + + it("buffers the destructive command guard setting", () => { + const { setCachedStateField } = renderSettings() + + fireEvent.click(screen.getByTestId("destructive-command-guard-checkbox")) + + expect(setCachedStateField).toHaveBeenCalledWith("destructiveCommandGuardEnabled", true) + expectNoImmediateUpdateSettings() + }) + + it("renders destructive command guard disabled by default", () => { + renderSettings() + + expect(screen.getByTestId("destructive-command-guard-checkbox")).not.toBeChecked() + }) + + it("renders destructive command guard enabled from cached settings", () => { + renderSettings({ destructiveCommandGuardEnabled: true }) + + expect(screen.getByTestId("destructive-command-guard-checkbox")).toBeChecked() + }) + + it("buffers disabling destructive command guard", () => { + const { setCachedStateField } = renderSettings({ destructiveCommandGuardEnabled: true }) + + fireEvent.click(screen.getByTestId("destructive-command-guard-checkbox")) + + expect(setCachedStateField).toHaveBeenCalledWith("destructiveCommandGuardEnabled", false) + expectNoImmediateUpdateSettings() + }) + + it("hides Zoo command list editors while destructive command guard is enabled", () => { + renderSettings({ destructiveCommandGuardEnabled: true, deniedCommands: ["rm -rf"] }) + + expect(screen.queryByTestId("allowed-commands-heading")).not.toBeInTheDocument() + expect(screen.queryByTestId("denied-commands-heading")).not.toBeInTheDocument() + }) }) diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index b9644e0d12..ad37a51f8a 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Executar", "description": "Executar automàticament comandes de terminal permeses sense requerir aprovació", + "destructiveCommandGuard": { + "label": "Activa la protecció contra ordres destructives", + "description": "Baixa i utilitza Destructive Command Guard (DCG) per a aquesta plataforma. Les ordres permeses per DCG s'executen automàticament. Les ordres bloquejades per DCG requereixen la teva aprovació. Les llistes d'ordres de Zoo es desactiven mentre aquesta opció està activa. L'executable baixat es conserva si la desactives." + }, "allowedCommands": "Comandes d'auto-execució permeses", "allowedCommandsDescription": "Prefixos de comandes que poden ser executats automàticament quan \"Aprovar sempre operacions d'execució\" està habilitat. Afegeix * per permetre totes les comandes (usar amb precaució).", "deniedCommands": "Comandes denegades", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 46a8bd28e4..3ef6b71952 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Ausführen", "description": "Erlaubte Terminal-Befehle automatisch ohne Genehmigung ausführen", + "destructiveCommandGuard": { + "label": "Schutz vor destruktiven Befehlen aktivieren", + "description": "Lädt Destructive Command Guard (DCG) für diese Plattform herunter und verwendet es. Von DCG erlaubte Befehle werden automatisch ausgeführt. Von DCG blockierte Befehle benötigen deine Zustimmung. Die Befehlslisten von Zoo sind währenddessen deaktiviert. Die heruntergeladene ausführbare Datei bleibt erhalten, wenn du die Option ausschaltest." + }, "allowedCommands": "Erlaubte Auto-Ausführungsbefehle", "allowedCommandsDescription": "Befehlspräfixe, die automatisch ausgeführt werden können, wenn 'Ausführungsoperationen immer genehmigen' aktiviert ist. Fügen Sie * hinzu, um alle Befehle zu erlauben (mit Vorsicht verwenden).", "deniedCommands": "Verweigerte Befehle", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 37d33f8172..bcdbea2543 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -406,6 +406,10 @@ "execute": { "label": "Execute", "description": "Automatically execute allowed terminal commands without requiring approval", + "destructiveCommandGuard": { + "label": "Enable destructive command guard", + "description": "Download and use Destructive Command Guard (DCG) for this platform. Commands allowed by DCG run automatically. Commands blocked by DCG require your approval. Zoo's command lists are disabled while this is enabled. The downloaded executable is retained if you turn this off." + }, "allowedCommands": "Allowed Auto-Execute Commands", "allowedCommandsDescription": "Command prefixes that can be auto-executed when \"Always approve execute operations\" is enabled. Add * to allow all commands (use with caution).", "deniedCommands": "Denied Commands", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index f9c1be76f4..a5f880c998 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Ejecutar", "description": "Ejecutar automáticamente comandos de terminal permitidos sin requerir aprobación", + "destructiveCommandGuard": { + "label": "Activar la protección contra comandos destructivos", + "description": "Descarga y usa Destructive Command Guard (DCG) para esta plataforma. Los comandos permitidos por DCG se ejecutan automáticamente. Los comandos bloqueados por DCG requieren tu aprobación. Las listas de comandos de Zoo se desactivan mientras esta opción está habilitada. El ejecutable descargado se conserva si la desactivas." + }, "allowedCommands": "Comandos de auto-ejecución permitidos", "allowedCommandsDescription": "Prefijos de comandos que pueden ser ejecutados automáticamente cuando \"Aprobar siempre operaciones de ejecución\" está habilitado. Añade * para permitir todos los comandos (usar con precaución).", "deniedCommands": "Comandos denegados", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 6da211144b..93257e89f4 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -329,6 +329,10 @@ "execute": { "label": "Exécuter", "description": "Exécuter automatiquement les commandes de terminal autorisées sans nécessiter d'approbation", + "destructiveCommandGuard": { + "label": "Activer la protection contre les commandes destructrices", + "description": "Télécharge et utilise Destructive Command Guard (DCG) pour cette plateforme. Les commandes autorisées par DCG s'exécutent automatiquement. Les commandes bloquées par DCG nécessitent votre approbation. Les listes de commandes de Zoo sont désactivées tant que cette option est active. L'exécutable téléchargé est conservé si vous la désactivez." + }, "allowedCommands": "Commandes auto-exécutables autorisées", "allowedCommandsDescription": "Préfixes de commandes qui peuvent être auto-exécutés lorsque \"Toujours approuver les opérations d'exécution\" est activé. Ajoutez * pour autoriser toutes les commandes (à utiliser avec précaution).", "deniedCommands": "Commandes refusées", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 522c68a586..8350322d72 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "निष्पादित करें", "description": "अनुमोदन की आवश्यकता के बिना स्वचालित रूप से अनुमत टर्मिनल कमांड निष्पादित करें", + "destructiveCommandGuard": { + "label": "विनाशकारी कमांड सुरक्षा सक्षम करें", + "description": "इस प्लेटफ़ॉर्म के लिए Destructive Command Guard (DCG) डाउनलोड करके उपयोग करें। DCG द्वारा अनुमत कमांड अपने आप चलते हैं। DCG द्वारा रोके गए कमांड चलाने के लिए आपकी मंज़ूरी आवश्यक होगी। इसके सक्षम रहने पर Zoo की कमांड सूचियाँ बंद रहेंगी। इसे बंद करने पर डाउनलोड किया गया executable रखा जाएगा।" + }, "allowedCommands": "अनुमत स्वतः-निष्पादन कमांड", "allowedCommandsDescription": "कमांड प्रीफिक्स जो स्वचालित रूप से निष्पादित किए जा सकते हैं जब \"निष्पादन ऑपरेशन हमेशा अनुमोदित करें\" सक्षम है। सभी कमांड की अनुमति देने के लिए * जोड़ें (सावधानी से उपयोग करें)।", "deniedCommands": "अस्वीकृत कमांड", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index b2943e63bc..f807ef3dfb 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Eksekusi", "description": "Secara otomatis mengeksekusi perintah terminal yang diizinkan tanpa memerlukan persetujuan", + "destructiveCommandGuard": { + "label": "Aktifkan perlindungan perintah destruktif", + "description": "Unduh dan gunakan Destructive Command Guard (DCG) untuk platform ini. Perintah yang diizinkan DCG dijalankan secara otomatis. Perintah yang diblokir DCG memerlukan persetujuanmu. Daftar perintah Zoo dinonaktifkan selama opsi ini aktif. File executable yang diunduh tetap disimpan jika kamu menonaktifkannya." + }, "allowedCommands": "Perintah Auto-Execute yang Diizinkan", "allowedCommandsDescription": "Prefix perintah yang dapat di-auto-execute ketika \"Selalu setujui operasi eksekusi\" diaktifkan. Tambahkan * untuk mengizinkan semua perintah (gunakan dengan hati-hati).", "deniedCommands": "Perintah yang ditolak", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 6bd638c796..4bc19dda6a 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Esegui", "description": "Esegui automaticamente i comandi del terminale consentiti senza richiedere approvazione", + "destructiveCommandGuard": { + "label": "Abilita la protezione dai comandi distruttivi", + "description": "Scarica e usa Destructive Command Guard (DCG) per questa piattaforma. I comandi consentiti da DCG vengono eseguiti automaticamente. I comandi bloccati da DCG richiedono la tua approvazione. Gli elenchi dei comandi di Zoo vengono disabilitati mentre questa opzione è attiva. L'eseguibile scaricato viene conservato se la disattivi." + }, "allowedCommands": "Comandi di auto-esecuzione consentiti", "allowedCommandsDescription": "Prefissi di comando che possono essere auto-eseguiti quando \"Approva sempre operazioni di esecuzione\" è abilitato. Aggiungi * per consentire tutti i comandi (usare con cautela).", "deniedCommands": "Comandi negati", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 96fba3521a..037f53593b 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "実行", "description": "承認なしで自動的に許可されたターミナルコマンドを実行", + "destructiveCommandGuard": { + "label": "破壊的コマンドガードを有効にする", + "description": "このプラットフォーム用の Destructive Command Guard(DCG)をダウンロードして使用します。DCG が許可したコマンドは自動的に実行されます。DCG がブロックしたコマンドの実行には承認が必要です。有効な間は Zoo のコマンドリストが無効になります。無効にしても、ダウンロードした実行ファイルは保持されます。" + }, "allowedCommands": "許可された自動実行コマンド", "allowedCommandsDescription": "「実行操作を常に承認」が有効な場合に自動実行できるコマンドプレフィックス。すべてのコマンドを許可するには * を追加します(注意して使用してください)。", "deniedCommands": "拒否されたコマンド", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 40313a32f5..b51463198b 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "실행", "description": "승인 없이 자동으로 허용된 터미널 명령 실행", + "destructiveCommandGuard": { + "label": "파괴적 명령어 보호 활성화", + "description": "이 플랫폼용 Destructive Command Guard(DCG)를 다운로드하여 사용합니다. DCG가 허용한 명령어는 자동으로 실행됩니다. DCG가 차단한 명령어는 실행 전 승인이 필요합니다. 이 옵션을 사용하는 동안 Zoo의 명령어 목록은 비활성화됩니다. 옵션을 꺼도 다운로드한 실행 파일은 유지됩니다." + }, "allowedCommands": "허용된 자동 실행 명령", "allowedCommandsDescription": "\"실행 작업 항상 승인\"이 활성화되었을 때 자동 실행될 수 있는 명령 접두사. 모든 명령을 허용하려면 * 추가(주의해서 사용)", "deniedCommands": "거부된 명령", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 6664eb3d74..5d4f29e601 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Uitvoeren", "description": "Automatisch toegestane terminalcommando's uitvoeren zonder goedkeuring", + "destructiveCommandGuard": { + "label": "Beveiliging tegen destructieve opdrachten inschakelen", + "description": "Download en gebruik Destructive Command Guard (DCG) voor dit platform. Opdrachten die DCG toestaat, worden automatisch uitgevoerd. Voor opdrachten die DCG blokkeert, is jouw goedkeuring nodig. De opdrachtenlijsten van Zoo zijn uitgeschakeld zolang deze optie actief is. Het gedownloade uitvoerbare bestand blijft bewaard als je de optie uitschakelt." + }, "allowedCommands": "Toegestane automatisch uit te voeren commando's", "allowedCommandsDescription": "Commando-prefixen die automatisch kunnen worden uitgevoerd als 'Altijd goedkeuren voor uitvoeren' is ingeschakeld. Voeg * toe om alle commando's toe te staan (gebruik met voorzichtigheid).", "deniedCommands": "Geweigerde commando's", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 7a7ab3dcb0..eae01f4b9b 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Wykonaj", "description": "Automatycznie wykonuj dozwolone polecenia terminala bez konieczności zatwierdzania", + "destructiveCommandGuard": { + "label": "Włącz ochronę przed destrukcyjnymi poleceniami", + "description": "Pobiera i używa Destructive Command Guard (DCG) dla tej platformy. Polecenia dozwolone przez DCG są wykonywane automatycznie. Polecenia zablokowane przez DCG wymagają twojej zgody. Listy poleceń Zoo są wyłączone, gdy ta opcja jest aktywna. Pobrany plik wykonywalny pozostaje na dysku po wyłączeniu opcji." + }, "allowedCommands": "Dozwolone polecenia auto-wykonania", "allowedCommandsDescription": "Prefiksy poleceń, które mogą być automatycznie wykonywane, gdy \"Zawsze zatwierdzaj operacje wykonania\" jest włączone. Dodaj * aby zezwolić na wszystkie polecenia (używaj z ostrożnością).", "deniedCommands": "Odrzucone polecenia", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index bb44c1bcaa..89a19e493c 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Executar", "description": "Executar automaticamente comandos de terminal permitidos sem exigir aprovação", + "destructiveCommandGuard": { + "label": "Ativar a proteção contra comandos destrutivos", + "description": "Baixa e usa o Destructive Command Guard (DCG) para esta plataforma. Comandos permitidos pelo DCG são executados automaticamente. Comandos bloqueados pelo DCG precisam da sua aprovação. As listas de comandos do Zoo ficam desativadas enquanto esta opção estiver ativa. O executável baixado é mantido se você desativá-la." + }, "allowedCommands": "Comandos de auto-execução permitidos", "allowedCommandsDescription": "Prefixos de comando que podem ser auto-executados quando \"Aprovar sempre operações de execução\" está ativado. Adicione * para permitir todos os comandos (use com cautela).", "deniedCommands": "Comandos negados", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index ee02578534..3f1b1eaee5 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Выполнение", "description": "Автоматически выполнять разрешённые команды терминала без необходимости одобрения", + "destructiveCommandGuard": { + "label": "Включить защиту от разрушительных команд", + "description": "Скачивает и использует Destructive Command Guard (DCG) для этой платформы. Разрешённые DCG команды выполняются автоматически. Команды, заблокированные DCG, требуют твоего подтверждения. Пока эта настройка включена, списки команд Zoo отключены. Скачанный исполняемый файл сохраняется после отключения настройки." + }, "allowedCommands": "Разрешённые авто-выполняемые команды", "allowedCommandsDescription": "Префиксы команд, которые могут быть автоматически выполнены при включённом параметре \"Всегда одобрять выполнение операций\". Добавьте * для разрешения всех команд (используйте с осторожностью).", "deniedCommands": "Запрещенные команды", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index e37c154ead..30ef6005ec 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Yürüt", "description": "Onay gerektirmeden otomatik olarak izin verilen terminal komutlarını yürüt", + "destructiveCommandGuard": { + "label": "Yıkıcı komut korumasını etkinleştir", + "description": "Bu platform için Destructive Command Guard'ı (DCG) indirir ve kullanır. DCG'nin izin verdiği komutlar otomatik olarak çalıştırılır. DCG tarafından engellenen komutlar onayını gerektirir. Bu seçenek etkinken Zoo'nun komut listeleri devre dışı bırakılır. Seçeneği kapatsan da indirilen çalıştırılabilir dosya korunur." + }, "allowedCommands": "İzin Verilen Otomatik Yürütme Komutları", "allowedCommandsDescription": "\"Yürütme işlemlerini her zaman onayla\" etkinleştirildiğinde otomatik olarak yürütülebilen komut önekleri. Tüm komutlara izin vermek için * ekleyin (dikkatli kullanın).", "deniedCommands": "Reddedilen komutlar", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index c3b40a004a..3291d19015 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "Thực thi", "description": "Tự động thực thi các lệnh terminal được phép mà không cần phê duyệt", + "destructiveCommandGuard": { + "label": "Bật bảo vệ khỏi lệnh phá hoại", + "description": "Tải xuống và sử dụng Destructive Command Guard (DCG) cho nền tảng này. Các lệnh được DCG cho phép sẽ tự động chạy. Các lệnh bị DCG chặn cần bạn phê duyệt. Danh sách lệnh của Zoo sẽ bị vô hiệu hóa khi tùy chọn này được bật. Tệp thực thi đã tải xuống vẫn được giữ lại nếu bạn tắt tùy chọn." + }, "allowedCommands": "Các lệnh tự động thực thi được phép", "allowedCommandsDescription": "Tiền tố lệnh có thể được tự động thực thi khi \"Luôn phê duyệt các hoạt động thực thi\" được bật. Thêm * để cho phép tất cả các lệnh (sử dụng cẩn thận).", "deniedCommands": "Lệnh bị từ chối", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 2e8abf435e..c69238ed0d 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -328,6 +328,10 @@ "execute": { "label": "执行", "description": "自动执行白名单中的命令而无需批准", + "destructiveCommandGuard": { + "label": "启用破坏性命令防护", + "description": "下载并使用适用于此平台的 Destructive Command Guard(DCG)。DCG 允许的命令会自动执行。被 DCG 拦截的命令需要你批准后才能执行。启用后,Zoo 的命令列表将被禁用。关闭此选项时,已下载的可执行文件会保留。" + }, "allowedCommands": "命令白名单", "allowedCommandsDescription": "当\"自动批准命令行操作\"启用时可以自动执行的命令前缀。添加 * 以允许所有命令(谨慎使用)。", "deniedCommands": "拒绝的命令", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 481bab5301..2578cf517a 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -353,6 +353,10 @@ "execute": { "label": "執行命令", "description": "無需核准即可自動執行允許的終端機命令", + "destructiveCommandGuard": { + "label": "啟用破壞性命令防護", + "description": "下載並使用適用於此平台的 Destructive Command Guard(DCG)。DCG 允許的命令會自動執行。被 DCG 阻擋的命令需要你核准後才能執行。啟用後,Zoo 的命令清單將停用。關閉此選項時,已下載的執行檔會保留。" + }, "allowedCommands": "允許自動執行的命令", "allowedCommandsDescription": "啟用「始終核准執行」時,可自動執行的命令前綴。新增 * 可允許所有命令(請謹慎使用)。", "deniedCommands": "拒絕的命令",