diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index 03cad1bc96d..d53e3cfd65f 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -524,6 +524,7 @@ export interface WebviewMessage { | "openCustomModesSettings" | "checkpointDiff" | "checkpointRestore" + | "restoreToTaskStart" | "deleteMcpServer" | "codebaseIndexEnabled" | "telemetrySetting" diff --git a/src/core/checkpoints/__tests__/checkpoint.test.ts b/src/core/checkpoints/__tests__/checkpoint.test.ts index 299ff823b87..2398dcbf43e 100644 --- a/src/core/checkpoints/__tests__/checkpoint.test.ts +++ b/src/core/checkpoints/__tests__/checkpoint.test.ts @@ -1,7 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach, Mock } from "vitest" import { Task } from "../../task/Task" import { ClineProvider } from "../../webview/ClineProvider" -import { checkpointSave, checkpointRestore, checkpointDiff, getCheckpointService } from "../index" +import { + checkpointSave, + checkpointRestore, + checkpointRestoreToBase, + checkpointDiff, + getCheckpointService, +} from "../index" import { MessageManager } from "../../message-manager" import * as vscode from "vscode" @@ -296,6 +302,56 @@ describe("Checkpoint functionality", () => { }) }) + describe("checkpointRestoreToBase", () => { + beforeEach(() => { + mockCheckpointService.baseHash = "initial-commit-hash" + }) + + it("should restore to base hash successfully", async () => { + const result = await checkpointRestoreToBase(mockTask) + + expect(result).toBe(true) + expect(mockCheckpointService.restoreCheckpoint).toHaveBeenCalledWith("initial-commit-hash") + expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({ + type: "currentCheckpointUpdated", + text: "initial-commit-hash", + }) + expect(mockProvider.cancelTask).toHaveBeenCalled() + }) + + it("should return false if no checkpoint service available", async () => { + mockTask.checkpointService = undefined + mockTask.enableCheckpoints = false + + const result = await checkpointRestoreToBase(mockTask) + + expect(result).toBe(false) + expect(mockCheckpointService.restoreCheckpoint).not.toHaveBeenCalled() + }) + + it("should return false if no baseHash available", async () => { + mockCheckpointService.baseHash = undefined + + const result = await checkpointRestoreToBase(mockTask) + + expect(result).toBe(false) + expect(mockCheckpointService.restoreCheckpoint).not.toHaveBeenCalled() + expect(mockProvider.log).toHaveBeenCalledWith("[checkpointRestoreToBase] no baseHash available") + }) + + it("should disable checkpoints on error", async () => { + mockCheckpointService.restoreCheckpoint.mockRejectedValue(new Error("Restore failed")) + + const result = await checkpointRestoreToBase(mockTask) + + expect(result).toBe(false) + expect(mockTask.enableCheckpoints).toBe(false) + expect(mockProvider.log).toHaveBeenCalledWith( + "[checkpointRestoreToBase] disabling checkpoints for this task", + ) + }) + }) + describe("checkpointDiff", () => { beforeEach(() => { mockTask.clineMessages = [ diff --git a/src/core/checkpoints/index.ts b/src/core/checkpoints/index.ts index 26a137b939c..01b6ce21717 100644 --- a/src/core/checkpoints/index.ts +++ b/src/core/checkpoints/index.ts @@ -301,6 +301,46 @@ export async function checkpointRestore( } } +/** + * Restore the workspace to its initial state (baseHash) - the state when the shadow git repo was initialized. + * This is a simpler version of checkpointRestore that doesn't need to rewind messages since we're + * restoring to the very beginning of the task. + * @returns true if restoration was successful, false otherwise + */ +export async function checkpointRestoreToBase(task: Task): Promise { + const service = await getCheckpointService(task) + + if (!service) { + return false + } + + const baseHash = service.baseHash + + if (!baseHash) { + const provider = task.providerRef.deref() + provider?.log("[checkpointRestoreToBase] no baseHash available") + return false + } + + const provider = task.providerRef.deref() + + try { + await service.restoreCheckpoint(baseHash) + TelemetryService.instance.captureCheckpointRestored(task.taskId) + await provider?.postMessageToWebview({ type: "currentCheckpointUpdated", text: baseHash }) + + // Cancel the task to reinitialize with the restored state + // This follows the same pattern as checkpointRestore + provider?.cancelTask() + + return true + } catch (err) { + provider?.log("[checkpointRestoreToBase] disabling checkpoints for this task") + task.enableCheckpoints = false + return false + } +} + export type CheckpointDiffOptions = { ts?: number previousCommitHash?: string diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 4a8b7520078..e22674c2065 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -1212,6 +1212,42 @@ export const webviewMessageHandler = async ( break } + case "restoreToTaskStart": { + const currentTask = provider.getCurrentTask() + + if (!currentTask) { + vscode.window.showErrorMessage(t("common:errors.checkpoint_no_active_task")) + break + } + + if (!currentTask.enableCheckpoints) { + vscode.window.showErrorMessage(t("common:errors.checkpoint_not_enabled")) + break + } + + // Cancel the current task first + await provider.cancelTask() + + try { + await pWaitFor(() => provider.getCurrentTask()?.isInitialized === true, { timeout: 3_000 }) + } catch (error) { + vscode.window.showErrorMessage(t("common:errors.checkpoint_timeout")) + break + } + + try { + const { checkpointRestoreToBase } = await import("../checkpoints") + const success = await checkpointRestoreToBase(provider.getCurrentTask()!) + + if (!success) { + vscode.window.showErrorMessage(t("common:errors.checkpoint_restore_base_failed")) + } + } catch (error) { + vscode.window.showErrorMessage(t("common:errors.checkpoint_failed")) + } + + break + } case "cancelTask": await provider.cancelTask() break diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 321a1aa3a06..235c6b489ae 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -32,6 +32,9 @@ "could_not_open_file_generic": "No s'ha pogut obrir el fitxer!", "checkpoint_timeout": "S'ha esgotat el temps en intentar restaurar el punt de control.", "checkpoint_failed": "Ha fallat la restauració del punt de control.", + "checkpoint_no_active_task": "No hi ha cap tasca activa per restaurar.", + "checkpoint_not_enabled": "Els punts de control no estan activats per a aquesta tasca.", + "checkpoint_restore_base_failed": "Ha fallat la restauració de l'espai de treball a l'estat inicial.", "git_not_installed": "Git és necessari per a la funció de punts de control. Si us plau, instal·la Git per activar els punts de control.", "checkpoint_no_first": "No hi ha un primer punt de control per comparar.", "checkpoint_no_previous": "No hi ha un punt de control anterior per comparar.", diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 0611cf889af..487075c85f5 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Datei konnte nicht geöffnet werden!", "checkpoint_timeout": "Zeitüberschreitung beim Versuch, den Checkpoint wiederherzustellen.", "checkpoint_failed": "Fehler beim Wiederherstellen des Checkpoints.", + "checkpoint_no_active_task": "Keine aktive Aufgabe zum Wiederherstellen.", + "checkpoint_not_enabled": "Checkpoints sind für diese Aufgabe nicht aktiviert.", + "checkpoint_restore_base_failed": "Wiederherstellung des Arbeitsbereichs in den Ausgangszustand fehlgeschlagen.", "git_not_installed": "Git ist für die Checkpoint-Funktion erforderlich. Bitte installiere Git, um Checkpoints zu aktivieren.", "checkpoint_no_first": "Kein erster Checkpoint zum Vergleich vorhanden.", "checkpoint_no_previous": "Kein vorheriger Checkpoint zum Vergleich vorhanden.", diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 90c409feb76..4cc9be68ba7 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Could not open file!", "checkpoint_timeout": "Timed out when attempting to restore checkpoint.", "checkpoint_failed": "Failed to restore checkpoint.", + "checkpoint_no_active_task": "No active task to restore.", + "checkpoint_not_enabled": "Checkpoints are not enabled for this task.", + "checkpoint_restore_base_failed": "Failed to restore workspace to initial state.", "git_not_installed": "Git is required for the checkpoints feature. Please install Git to enable checkpoints.", "checkpoint_no_first": "No first checkpoint to compare.", "checkpoint_no_previous": "No previous checkpoint to compare.", diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index d0a086173e9..23164c9f89e 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "¡No se pudo abrir el archivo!", "checkpoint_timeout": "Se agotó el tiempo al intentar restaurar el punto de control.", "checkpoint_failed": "Error al restaurar el punto de control.", + "checkpoint_no_active_task": "No hay ninguna tarea activa para restaurar.", + "checkpoint_not_enabled": "Los puntos de control no están habilitados para esta tarea.", + "checkpoint_restore_base_failed": "Error al restaurar el espacio de trabajo al estado inicial.", "git_not_installed": "Git es necesario para la función de puntos de control. Por favor, instala Git para activar los puntos de control.", "checkpoint_no_first": "No hay primer punto de control para comparar.", "checkpoint_no_previous": "No hay punto de control anterior para comparar.", diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index 58350ef02ba..698cccd527d 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Impossible d'ouvrir le fichier !", "checkpoint_timeout": "Expiration du délai lors de la tentative de rétablissement du checkpoint.", "checkpoint_failed": "Échec du rétablissement du checkpoint.", + "checkpoint_no_active_task": "Aucune tâche active à restaurer.", + "checkpoint_not_enabled": "Les points de contrôle ne sont pas activés pour cette tâche.", + "checkpoint_restore_base_failed": "Échec de la restauration de l'espace de travail à l'état initial.", "git_not_installed": "Git est requis pour la fonctionnalité des points de contrôle. Veuillez installer Git pour activer les points de contrôle.", "checkpoint_no_first": "Aucun premier point de contrôle à comparer.", "checkpoint_no_previous": "Aucun point de contrôle précédent à comparer.", diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index 33277c71623..89fbc37b985 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "फ़ाइल नहीं खोली जा सकी!", "checkpoint_timeout": "चेकपॉइंट को पुनर्स्थापित करने का प्रयास करते समय टाइमआउट हो गया।", "checkpoint_failed": "चेकपॉइंट पुनर्स्थापित करने में विफल।", + "checkpoint_no_active_task": "पुनर्स्थापित करने के लिए कोई सक्रिय कार्य नहीं।", + "checkpoint_not_enabled": "इस कार्य के लिए चेकपॉइंट सक्षम नहीं हैं।", + "checkpoint_restore_base_failed": "वर्कस्पेस को प्रारंभिक स्थिति में पुनर्स्थापित करने में विफल।", "git_not_installed": "चेकपॉइंट सुविधा के लिए Git आवश्यक है। कृपया चेकपॉइंट सक्षम करने के लिए Git इंस्टॉल करें।", "checkpoint_no_first": "तुलना करने के लिए कोई पहला चेकपॉइंट नहीं है।", "checkpoint_no_previous": "तुलना करने के लिए कोई पिछला चेकपॉइंट नहीं है।", diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index c10532beef9..4115c290710 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Tidak dapat membuka file!", "checkpoint_timeout": "Timeout saat mencoba memulihkan checkpoint.", "checkpoint_failed": "Gagal memulihkan checkpoint.", + "checkpoint_no_active_task": "Tidak ada tugas aktif untuk dipulihkan.", + "checkpoint_not_enabled": "Checkpoint tidak diaktifkan untuk tugas ini.", + "checkpoint_restore_base_failed": "Gagal memulihkan workspace ke keadaan awal.", "git_not_installed": "Git diperlukan untuk fitur checkpoint. Silakan instal Git untuk mengaktifkan checkpoint.", "checkpoint_no_first": "Tidak ada checkpoint pertama untuk dibandingkan.", "checkpoint_no_previous": "Tidak ada checkpoint sebelumnya untuk dibandingkan.", diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index a75dccd3875..291dd43ce5a 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Impossibile aprire il file!", "checkpoint_timeout": "Timeout durante il tentativo di ripristinare il checkpoint.", "checkpoint_failed": "Impossibile ripristinare il checkpoint.", + "checkpoint_no_active_task": "Nessuna attività attiva da ripristinare.", + "checkpoint_not_enabled": "I checkpoint non sono abilitati per questa attività.", + "checkpoint_restore_base_failed": "Impossibile ripristinare lo spazio di lavoro allo stato iniziale.", "git_not_installed": "Git è richiesto per la funzione di checkpoint. Per favore, installa Git per abilitare i checkpoint.", "checkpoint_no_first": "Nessun primo checkpoint da confrontare.", "checkpoint_no_previous": "Nessun checkpoint precedente da confrontare.", diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index b378f00b03f..f32a69804d9 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "ファイルを開けませんでした!", "checkpoint_timeout": "チェックポイントの復元を試みる際にタイムアウトしました。", "checkpoint_failed": "チェックポイントの復元に失敗しました。", + "checkpoint_no_active_task": "復元するアクティブなタスクがありません。", + "checkpoint_not_enabled": "このタスクではチェックポイントが有効になっていません。", + "checkpoint_restore_base_failed": "ワークスペースを初期状態に復元できませんでした。", "git_not_installed": "チェックポイント機能にはGitが必要です。チェックポイントを有効にするにはGitをインストールしてください。", "checkpoint_no_first": "比較する最初のチェックポイントがありません。", "checkpoint_no_previous": "比較する前のチェックポイントがありません。", diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index e7afdceabce..b9ad1c90c40 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "파일을 열 수 없습니다!", "checkpoint_timeout": "체크포인트 복원을 시도하는 중 시간 초과되었습니다.", "checkpoint_failed": "체크포인트 복원에 실패했습니다.", + "checkpoint_no_active_task": "복원할 활성 작업이 없습니다.", + "checkpoint_not_enabled": "이 작업에는 체크포인트가 활성화되어 있지 않습니다.", + "checkpoint_restore_base_failed": "워크스페이스를 초기 상태로 복원하는 데 실패했습니다.", "git_not_installed": "체크포인트 기능을 사용하려면 Git이 필요합니다. 체크포인트를 활성화하려면 Git을 설치하세요.", "checkpoint_no_first": "비교할 첫 번째 체크포인트가 없습니다.", "checkpoint_no_previous": "비교할 이전 체크포인트가 없습니다.", diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index 889cd4b3ab6..ed5e0c99bdf 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Kon bestand niet openen!", "checkpoint_timeout": "Time-out bij het herstellen van checkpoint.", "checkpoint_failed": "Herstellen van checkpoint mislukt.", + "checkpoint_no_active_task": "Geen actieve taak om te herstellen.", + "checkpoint_not_enabled": "Checkpoints zijn niet ingeschakeld voor deze taak.", + "checkpoint_restore_base_failed": "Herstellen van workspace naar begintoestand mislukt.", "git_not_installed": "Git is vereist voor de checkpoint-functie. Installeer Git om checkpoints in te schakelen.", "checkpoint_no_first": "Geen eerste checkpoint om mee te vergelijken.", "checkpoint_no_previous": "Geen vorig checkpoint om mee te vergelijken.", diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index faa4e9ed3a5..af3e5d8fd9d 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Nie można otworzyć pliku!", "checkpoint_timeout": "Upłynął limit czasu podczas próby przywrócenia punktu kontrolnego.", "checkpoint_failed": "Nie udało się przywrócić punktu kontrolnego.", + "checkpoint_no_active_task": "Brak aktywnego zadania do przywrócenia.", + "checkpoint_not_enabled": "Punkty kontrolne nie są włączone dla tego zadania.", + "checkpoint_restore_base_failed": "Nie udało się przywrócić obszaru roboczego do stanu początkowego.", "git_not_installed": "Funkcja punktów kontrolnych wymaga oprogramowania Git. Zainstaluj Git, aby włączyć punkty kontrolne.", "checkpoint_no_first": "Brak pierwszego punktu kontrolnego do porównania.", "checkpoint_no_previous": "Brak poprzedniego punktu kontrolnego do porównania.", diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index f41a379acbc..4d7ff569b87 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -32,6 +32,9 @@ "could_not_open_file_generic": "Não foi possível abrir o arquivo!", "checkpoint_timeout": "Tempo esgotado ao tentar restaurar o ponto de verificação.", "checkpoint_failed": "Falha ao restaurar o ponto de verificação.", + "checkpoint_no_active_task": "Nenhuma tarefa ativa para restaurar.", + "checkpoint_not_enabled": "Os pontos de verificação não estão habilitados para esta tarefa.", + "checkpoint_restore_base_failed": "Falha ao restaurar o espaço de trabalho ao estado inicial.", "git_not_installed": "O Git é necessário para o recurso de checkpoints. Por favor, instale o Git para habilitar os checkpoints.", "checkpoint_no_first": "Nenhum primeiro ponto de verificação para comparar.", "checkpoint_no_previous": "Nenhum ponto de verificação anterior para comparar.", diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 751637f19e0..32bfc6a9344 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Не удалось открыть файл!", "checkpoint_timeout": "Превышено время ожидания при попытке восстановления контрольной точки.", "checkpoint_failed": "Не удалось восстановить контрольную точку.", + "checkpoint_no_active_task": "Нет активной задачи для восстановления.", + "checkpoint_not_enabled": "Контрольные точки не включены для этой задачи.", + "checkpoint_restore_base_failed": "Не удалось восстановить рабочее пространство до исходного состояния.", "git_not_installed": "Для функции контрольных точек требуется Git. Пожалуйста, установите Git, чтобы включить контрольные точки.", "checkpoint_no_first": "Нет первой контрольной точки для сравнения.", "checkpoint_no_previous": "Нет предыдущей контрольной точки для сравнения.", diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index 7b2ac152a9b..e345b6d9e7e 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Dosya açılamadı!", "checkpoint_timeout": "Kontrol noktasını geri yüklemeye çalışırken zaman aşımına uğradı.", "checkpoint_failed": "Kontrol noktası geri yüklenemedi.", + "checkpoint_no_active_task": "Geri yüklenecek aktif görev yok.", + "checkpoint_not_enabled": "Bu görev için kontrol noktaları etkinleştirilmemiş.", + "checkpoint_restore_base_failed": "Çalışma alanı başlangıç durumuna geri yüklenemedi.", "git_not_installed": "Kontrol noktaları özelliği için Git gereklidir. Kontrol noktalarını etkinleştirmek için lütfen Git'i yükleyin.", "checkpoint_no_first": "Karşılaştırılacak ilk kontrol noktası yok.", "checkpoint_no_previous": "Karşılaştırılacak önceki kontrol noktası yok.", diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 0d88ba07808..959df4d189f 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "Không thể mở tệp!", "checkpoint_timeout": "Đã hết thời gian khi cố gắng khôi phục điểm kiểm tra.", "checkpoint_failed": "Không thể khôi phục điểm kiểm tra.", + "checkpoint_no_active_task": "Không có nhiệm vụ đang hoạt động để khôi phục.", + "checkpoint_not_enabled": "Các điểm kiểm tra chưa được bật cho nhiệm vụ này.", + "checkpoint_restore_base_failed": "Không thể khôi phục không gian làm việc về trạng thái ban đầu.", "git_not_installed": "Yêu cầu Git cho tính năng điểm kiểm tra. Vui lòng cài đặt Git để bật điểm kiểm tra.", "checkpoint_no_first": "Không có điểm kiểm tra đầu tiên để so sánh.", "checkpoint_no_previous": "Không có điểm kiểm tra trước đó để so sánh.", diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 133b3de0794..0a26c0e17c7 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -33,6 +33,9 @@ "could_not_open_file_generic": "无法打开文件!", "checkpoint_timeout": "尝试恢复检查点时超时。", "checkpoint_failed": "恢复检查点失败。", + "checkpoint_no_active_task": "没有活动任务可恢复。", + "checkpoint_not_enabled": "此任务未启用检查点。", + "checkpoint_restore_base_failed": "无法将工作区恢复到初始状态。", "git_not_installed": "检查点功能需要 Git。请安装 Git 以启用检查点。", "checkpoint_no_first": "没有第一个存档点可供比较。", "checkpoint_no_previous": "没有上一个存档点可供比较。", diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 8039f203b62..47d665139b7 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -28,6 +28,9 @@ "could_not_open_file_generic": "無法開啟檔案!", "checkpoint_timeout": "嘗試恢復檢查點時超時。", "checkpoint_failed": "恢復檢查點失敗。", + "checkpoint_no_active_task": "沒有活動任務可還原。", + "checkpoint_not_enabled": "此任務未啟用存檔點。", + "checkpoint_restore_base_failed": "無法將工作區還原至初始狀態。", "git_not_installed": "存檔點功能需要 Git。請安裝 Git 以啟用存檔點。", "checkpoint_no_first": "沒有第一個存檔點可供比較。", "checkpoint_no_previous": "沒有上一個存檔點可供比較。", diff --git a/webview-ui/src/components/chat/RestoreTaskDialog.tsx b/webview-ui/src/components/chat/RestoreTaskDialog.tsx new file mode 100644 index 00000000000..77bb7b0a27d --- /dev/null +++ b/webview-ui/src/components/chat/RestoreTaskDialog.tsx @@ -0,0 +1,49 @@ +import { useCallback } from "react" +import { AlertDialogProps } from "@radix-ui/react-alert-dialog" + +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + Button, +} from "@/components/ui" +import { useAppTranslation } from "@/i18n/TranslationContext" + +import { vscode } from "@/utils/vscode" + +export const RestoreTaskDialog = ({ ...props }: AlertDialogProps) => { + const { t } = useAppTranslation() + + const { onOpenChange } = props + + const onRestore = useCallback(() => { + vscode.postMessage({ type: "restoreToTaskStart" }) + onOpenChange?.(false) + }, [onOpenChange]) + + return ( + + onOpenChange?.(false)}> + + {t("chat:task.restoreToStart")} + {t("chat:task.restoreToStartConfirm")} + + + + + + + + + + + + ) +} diff --git a/webview-ui/src/components/chat/TaskActions.tsx b/webview-ui/src/components/chat/TaskActions.tsx index 74575ddc28f..1e8fe27e817 100644 --- a/webview-ui/src/components/chat/TaskActions.tsx +++ b/webview-ui/src/components/chat/TaskActions.tsx @@ -8,9 +8,10 @@ import { useCopyToClipboard } from "@/utils/clipboard" import { useExtensionState } from "@/context/ExtensionStateContext" import { DeleteTaskDialog } from "../history/DeleteTaskDialog" +import { RestoreTaskDialog } from "./RestoreTaskDialog" import { ShareButton } from "./ShareButton" import { CloudTaskButton } from "./CloudTaskButton" -import { CopyIcon, DownloadIcon, Trash2Icon, FileJsonIcon, MessageSquareCodeIcon } from "lucide-react" +import { CopyIcon, DownloadIcon, Trash2Icon, FileJsonIcon, MessageSquareCodeIcon, RotateCcw } from "lucide-react" import { LucideIconButton } from "./LucideIconButton" interface TaskActionsProps { @@ -20,9 +21,10 @@ interface TaskActionsProps { export const TaskActions = ({ item, buttonsDisabled }: TaskActionsProps) => { const [deleteTaskId, setDeleteTaskId] = useState(null) + const [showRestoreDialog, setShowRestoreDialog] = useState(false) const { t } = useTranslation() const { copyWithFeedback } = useCopyToClipboard() - const { debug } = useExtensionState() + const { debug, enableCheckpoints } = useExtensionState() return (
@@ -65,6 +67,17 @@ export const TaskActions = ({ item, buttonsDisabled }: TaskActionsProps) => { )} + {enableCheckpoints && ( + <> + setShowRestoreDialog(true)} + /> + + + )} {debug && item?.id && ( <>