From d2dac021599faa0242edf7cd7d61753a3ac4c83b Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 30 Sep 2025 18:08:20 +0000 Subject: [PATCH] feat: Add Hard Reset button to clear Electron caches - Implements a new hardResetElectronCache method in ClineProvider - Adds 'Hard Reset' button to the About settings section - Clears platform-specific Electron and VS Code cache directories - Handles macOS, Windows, and Linux cache locations - Includes comprehensive user confirmation and feedback - Adds JSDoc documentation for the new functionality - Includes all necessary translations Fixes #8419 --- .review/pr-8274 | 1 + src/core/webview/ClineProvider.ts | 158 +++++++++++++++++++ src/core/webview/webviewMessageHandler.ts | 3 + src/i18n/locales/en/common.json | 8 +- src/shared/WebviewMessage.ts | 1 + tmp/pr-8287-Roo-Code | 1 + tmp/pr-8412 | 1 + webview-ui/src/components/settings/About.tsx | 7 + webview-ui/src/i18n/locales/en/settings.json | 3 +- 9 files changed, 181 insertions(+), 2 deletions(-) create mode 160000 .review/pr-8274 create mode 160000 tmp/pr-8287-Roo-Code create mode 160000 tmp/pr-8412 diff --git a/.review/pr-8274 b/.review/pr-8274 new file mode 160000 index 0000000000..e46929b8d8 --- /dev/null +++ b/.review/pr-8274 @@ -0,0 +1 @@ +Subproject commit e46929b8d8add0cd3c412d69f8ac882c405a4ba9 diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 2c20d0939c..02dfacdb2a 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2275,6 +2275,164 @@ export class ClineProvider await this.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) } + /** + * Performs a hard reset of Electron and VS Code caches to fix corrupted runtime files. + * This method clears all Electron cache directories, IndexedDB, Local Storage, Session Storage, + * and other cached data that may become corrupted and persist even after normal resets. + * + * The operation targets platform-specific cache locations: + * - macOS: ~/Library/Caches/com.microsoft.VSCode*, ~/Library/Application Support/Code/* + * - Windows: %APPDATA%/Code/*, %LOCALAPPDATA%/Microsoft/vscode-cpptools + * - Linux: ~/.cache/Code*, ~/.config/Code/* + * + * After clearing caches, it also performs a regular state reset and offers to restart VS Code. + * + * @returns {Promise} Resolves when the cache clearing operation is complete + */ + async hardResetElectronCache() { + const answer = await vscode.window.showInformationMessage( + t("common:confirmation.hard_reset_electron_cache"), + { modal: true, detail: t("common:confirmation.hard_reset_electron_cache_detail") }, + t("common:answers.yes"), + ) + + if (answer !== t("common:answers.yes")) { + return + } + + const platform = process.platform + const homeDir = os.homedir() + const pathsToDelete: string[] = [] + + // Platform-specific cache paths + if (platform === "darwin") { + // macOS paths - includes all VS Code and Electron cache locations + pathsToDelete.push( + // VS Code caches + path.join(homeDir, "Library", "Caches", "com.microsoft.VSCode"), + path.join(homeDir, "Library", "Caches", "com.microsoft.VSCode.ShipIt"), + path.join(homeDir, "Library", "Caches", "com.microsoft.VSCodeInsiders"), + // Electron caches + path.join(homeDir, "Library", "Caches", "Electron"), + // Application Support (VS Code specific) + path.join(homeDir, "Library", "Application Support", "Code", "Cache"), + path.join(homeDir, "Library", "Application Support", "Code", "CachedData"), + path.join(homeDir, "Library", "Application Support", "Code", "Code Cache"), + path.join(homeDir, "Library", "Application Support", "Code", "GPUCache"), + path.join(homeDir, "Library", "Application Support", "Code", "Local Storage"), + path.join(homeDir, "Library", "Application Support", "Code", "Session Storage"), + path.join(homeDir, "Library", "Application Support", "Code", "IndexedDB"), + // VS Code Insiders + path.join(homeDir, "Library", "Application Support", "Code - Insiders", "Cache"), + path.join(homeDir, "Library", "Application Support", "Code - Insiders", "CachedData"), + path.join(homeDir, "Library", "Application Support", "Code - Insiders", "Code Cache"), + path.join(homeDir, "Library", "Application Support", "Code - Insiders", "GPUCache"), + path.join(homeDir, "Library", "Application Support", "Code - Insiders", "Local Storage"), + path.join(homeDir, "Library", "Application Support", "Code - Insiders", "Session Storage"), + path.join(homeDir, "Library", "Application Support", "Code - Insiders", "IndexedDB"), + ) + } else if (platform === "win32") { + // Windows paths + const appData = process.env.APPDATA || path.join(homeDir, "AppData", "Roaming") + const localAppData = process.env.LOCALAPPDATA || path.join(homeDir, "AppData", "Local") + + pathsToDelete.push( + // VS Code caches + path.join(localAppData, "Microsoft", "vscode-cpptools"), + path.join(appData, "Code", "Cache"), + path.join(appData, "Code", "CachedData"), + path.join(appData, "Code", "Code Cache"), + path.join(appData, "Code", "GPUCache"), + path.join(appData, "Code", "Local Storage"), + path.join(appData, "Code", "Session Storage"), + path.join(appData, "Code", "IndexedDB"), + // VS Code Insiders + path.join(appData, "Code - Insiders", "Cache"), + path.join(appData, "Code - Insiders", "CachedData"), + path.join(appData, "Code - Insiders", "Code Cache"), + path.join(appData, "Code - Insiders", "GPUCache"), + path.join(appData, "Code - Insiders", "Local Storage"), + path.join(appData, "Code - Insiders", "Session Storage"), + path.join(appData, "Code - Insiders", "IndexedDB"), + ) + } else { + // Linux paths + const configDir = process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config") + const cacheDir = process.env.XDG_CACHE_HOME || path.join(homeDir, ".cache") + + pathsToDelete.push( + // VS Code caches + path.join(cacheDir, "Code"), + path.join(cacheDir, "Code - Insiders"), + path.join(configDir, "Code", "Cache"), + path.join(configDir, "Code", "CachedData"), + path.join(configDir, "Code", "Code Cache"), + path.join(configDir, "Code", "GPUCache"), + path.join(configDir, "Code", "Local Storage"), + path.join(configDir, "Code", "Session Storage"), + path.join(configDir, "Code", "IndexedDB"), + // VS Code Insiders + path.join(configDir, "Code - Insiders", "Cache"), + path.join(configDir, "Code - Insiders", "CachedData"), + path.join(configDir, "Code - Insiders", "Code Cache"), + path.join(configDir, "Code - Insiders", "GPUCache"), + path.join(configDir, "Code - Insiders", "Local Storage"), + path.join(configDir, "Code - Insiders", "Session Storage"), + path.join(configDir, "Code - Insiders", "IndexedDB"), + ) + } + + // Delete the cache directories + let deletedPaths: string[] = [] + let failedPaths: string[] = [] + + for (const cachePath of pathsToDelete) { + try { + // Check if path exists before trying to delete + await fs.access(cachePath) + await fs.rm(cachePath, { recursive: true, force: true }) + deletedPaths.push(cachePath) + this.log(`Deleted cache: ${cachePath}`) + } catch (error) { + // Path doesn't exist or couldn't be deleted + if (error.code !== "ENOENT") { + failedPaths.push(cachePath) + this.log(`Failed to delete cache: ${cachePath} - ${error.message}`) + } + } + } + + // Also perform the regular reset + await this.contextProxy.resetAllState() + await this.providerSettingsManager.resetAllConfigs() + await this.customModesManager.resetCustomModes() + await this.removeClineFromStack() + await this.postStateToWebview() + + // Show result message + if (deletedPaths.length > 0) { + const message = t("common:confirmation.hard_reset_complete", { + count: deletedPaths.length, + failed: + failedPaths.length > 0 + ? t("common:confirmation.hard_reset_some_failed", { count: failedPaths.length }) + : "", + }) + + vscode.window + .showInformationMessage(message, { modal: false }, t("common:answers.restart_vscode")) + .then((selection) => { + if (selection === t("common:answers.restart_vscode")) { + vscode.commands.executeCommand("workbench.action.reloadWindow") + } + }) + } else { + vscode.window.showWarningMessage(t("common:confirmation.hard_reset_no_caches_found")) + } + + await this.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) + } + // logging public log(message: string) { diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index af5f9925c3..6ccbb4d0e4 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -749,6 +749,9 @@ export const webviewMessageHandler = async ( case "resetState": await provider.resetState() break + case "hardResetElectronCache": + await provider.hardResetElectronCache() + break case "flushRouterModels": const routerNameFlush: RouterName = toRouterName(message.text) await flushModels(routerNameFlush) diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 3a613cc1c2..78431884b5 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -16,6 +16,11 @@ }, "confirmation": { "reset_state": "Are you sure you want to reset all state and secret storage in the extension? This cannot be undone.", + "hard_reset_electron_cache": "Are you sure you want to perform a hard reset? This will clear all Electron caches and VS Code data.", + "hard_reset_electron_cache_detail": "This action will:\n• Clear all VS Code caches\n• Clear all Electron caches\n• Clear IndexedDB, Local Storage, and Session Storage\n• Reset all extension settings\n\nYou will need to restart VS Code after this operation.", + "hard_reset_complete": "Hard reset completed. {{count}} cache directories were cleared.{{failed}}", + "hard_reset_some_failed": " ({{count}} directories could not be deleted)", + "hard_reset_no_caches_found": "No cache directories were found to clear.", "delete_config_profile": "Are you sure you want to delete this configuration profile?", "delete_custom_mode_with_rules": "Are you sure you want to delete this {scope} mode?\n\nThis will also delete the associated rules folder at:\n{rulesFolderPath}" }, @@ -148,7 +153,8 @@ "yes": "Yes", "no": "No", "remove": "Remove", - "keep": "Keep" + "keep": "Keep", + "restart_vscode": "Restart VS Code" }, "buttons": { "save": "Save", diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index d43a2fce04..6a73242491 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -64,6 +64,7 @@ export interface WebviewMessage { | "importSettings" | "exportSettings" | "resetState" + | "hardResetElectronCache" | "flushRouterModels" | "requestRouterModels" | "requestOpenAiModels" diff --git a/tmp/pr-8287-Roo-Code b/tmp/pr-8287-Roo-Code new file mode 160000 index 0000000000..88a473b017 --- /dev/null +++ b/tmp/pr-8287-Roo-Code @@ -0,0 +1 @@ +Subproject commit 88a473b017af37091c85ce3056e444e856f80d6e diff --git a/tmp/pr-8412 b/tmp/pr-8412 new file mode 160000 index 0000000000..1339c7cc8b --- /dev/null +++ b/tmp/pr-8412 @@ -0,0 +1 @@ +Subproject commit 1339c7cc8bad17f95532117f36049d84a9ee8266 diff --git a/webview-ui/src/components/settings/About.tsx b/webview-ui/src/components/settings/About.tsx index 9afee12d72..bdc42b456d 100644 --- a/webview-ui/src/components/settings/About.tsx +++ b/webview-ui/src/components/settings/About.tsx @@ -84,6 +84,13 @@ export const About = ({ telemetrySetting, setTelemetrySetting, className, ...pro {t("settings:footer.settings.reset")} + diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index aa3199e8e8..b3e2eb9601 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -810,7 +810,8 @@ "settings": { "import": "Import", "export": "Export", - "reset": "Reset" + "reset": "Reset", + "hardReset": "Hard Reset" } }, "thinkingBudget": {