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
This commit is contained in:
Roo Code 2025-09-30 18:08:20 +00:00
parent 9f41ee098d
commit d2dac02159
9 changed files with 181 additions and 2 deletions

1
.review/pr-8274 Submodule

@ -0,0 +1 @@
Subproject commit e46929b8d8add0cd3c412d69f8ac882c405a4ba9

View file

@ -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<void>} 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) {

View file

@ -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)

View file

@ -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",

View file

@ -64,6 +64,7 @@ export interface WebviewMessage {
| "importSettings"
| "exportSettings"
| "resetState"
| "hardResetElectronCache"
| "flushRouterModels"
| "requestRouterModels"
| "requestOpenAiModels"

1
tmp/pr-8287-Roo-Code Submodule

@ -0,0 +1 @@
Subproject commit 88a473b017af37091c85ce3056e444e856f80d6e

1
tmp/pr-8412 Submodule

@ -0,0 +1 @@
Subproject commit 1339c7cc8bad17f95532117f36049d84a9ee8266

View file

@ -84,6 +84,13 @@ export const About = ({ telemetrySetting, setTelemetrySetting, className, ...pro
<TriangleAlert className="p-0.5" />
{t("settings:footer.settings.reset")}
</Button>
<Button
variant="destructive"
onClick={() => vscode.postMessage({ type: "hardResetElectronCache" })}
className="w-32">
<TriangleAlert className="p-0.5" />
{t("settings:footer.settings.hardReset")}
</Button>
</div>
</Section>
</div>

View file

@ -810,7 +810,8 @@
"settings": {
"import": "Import",
"export": "Export",
"reset": "Reset"
"reset": "Reset",
"hardReset": "Hard Reset"
}
},
"thinkingBudget": {