Skip to content

Commit 3a56ef9

Browse files
committed
fix: centralize rules folder deletion and add error notifications
- Remove duplicate rules folder deletion logic from SimpleInstaller.ts - Centralize rules management in CustomModesManager.deleteCustomMode() - Add user-visible error notifications for marketplace removal failures - Clean up unused imports from SimpleInstaller.ts Addresses review feedback in PR #6136 for marketplace mode removal cleanup.
1 parent 2cf5c25 commit 3a56ef9

File tree

3 files changed

+59
-39
lines changed

3 files changed

+59
-39
lines changed

src/core/config/CustomModesManager.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as vscode from "vscode"
22
import * as path from "path"
33
import * as fs from "fs/promises"
4+
import * as os from "os"
45

56
import * as yaml from "yaml"
67
import stripBom from "strip-bom"
@@ -517,6 +518,9 @@ export class CustomModesManager {
517518
throw new Error(t("common:customModes.errors.modeNotFound"))
518519
}
519520

521+
// Determine which mode to use for rules folder path calculation
522+
const modeToDelete = projectMode || globalMode
523+
520524
await this.queueWrite(async () => {
521525
// Delete from project first if it exists there
522526
if (projectMode && roomodesPath) {
@@ -528,6 +532,11 @@ export class CustomModesManager {
528532
await this.updateModesInFile(settingsPath, (modes) => modes.filter((m) => m.slug !== slug))
529533
}
530534

535+
// Delete associated rules folder
536+
if (modeToDelete) {
537+
await this.deleteRulesFolder(slug, modeToDelete)
538+
}
539+
531540
// Clear cache when modes are deleted
532541
this.clearCache()
533542
await this.refreshMergedState()
@@ -538,6 +547,49 @@ export class CustomModesManager {
538547
}
539548
}
540549

550+
/**
551+
* Deletes the rules folder for a specific mode
552+
* @param slug - The mode slug
553+
* @param mode - The mode configuration to determine the scope
554+
*/
555+
private async deleteRulesFolder(slug: string, mode: ModeConfig): Promise<void> {
556+
try {
557+
// Determine the scope based on source (project or global)
558+
const scope = mode.source || "global"
559+
560+
// Determine the rules folder path
561+
let rulesFolderPath: string
562+
if (scope === "project") {
563+
const workspacePath = getWorkspacePath()
564+
if (workspacePath) {
565+
rulesFolderPath = path.join(workspacePath, ".roo", `rules-${slug}`)
566+
} else {
567+
return // No workspace, can't delete project rules
568+
}
569+
} else {
570+
// Global scope - use OS home directory
571+
const homeDir = os.homedir()
572+
rulesFolderPath = path.join(homeDir, ".roo", `rules-${slug}`)
573+
}
574+
575+
// Check if the rules folder exists and delete it
576+
const rulesFolderExists = await fileExistsAtPath(rulesFolderPath)
577+
if (rulesFolderExists) {
578+
try {
579+
await fs.rm(rulesFolderPath, { recursive: true, force: true })
580+
logger.info(`Deleted rules folder for mode ${slug}: ${rulesFolderPath}`)
581+
} catch (error) {
582+
logger.error(`Failed to delete rules folder for mode ${slug}: ${error}`)
583+
// Continue even if folder deletion fails
584+
}
585+
}
586+
} catch (error) {
587+
logger.error(`Error deleting rules folder for mode ${slug}`, {
588+
error: error instanceof Error ? error.message : String(error),
589+
})
590+
}
591+
}
592+
541593
public async resetCustomModes(): Promise<void> {
542594
try {
543595
const filePath = await this.getCustomModesFilePath()

src/core/webview/webviewMessageHandler.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2238,6 +2238,12 @@ export const webviewMessageHandler = async (
22382238
})
22392239
} catch (error) {
22402240
console.error(`Error removing marketplace item: ${error}`)
2241+
2242+
// Show error message to user
2243+
vscode.window.showErrorMessage(
2244+
`Failed to remove marketplace item: ${error instanceof Error ? error.message : String(error)}`,
2245+
)
2246+
22412247
// Send error message to webview
22422248
provider.postMessageToWebview({
22432249
type: "marketplaceRemoveResult",

src/services/marketplace/SimpleInstaller.ts

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as vscode from "vscode"
22
import * as path from "path"
33
import * as fs from "fs/promises"
44
import * as yaml from "yaml"
5-
import * as os from "os"
65
import type { MarketplaceItem, MarketplaceItemType, InstallMarketplaceItemOptions, McpParameter } from "@roo-code/types"
76
import { GlobalFileNames } from "../../shared/globalFileNames"
87
import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
@@ -321,45 +320,8 @@ export class SimpleInstaller {
321320
throw new Error("Mode missing slug identifier")
322321
}
323322

324-
// Get the mode details before deletion to determine source and rules folder path
325-
const customModes = await this.customModesManager.getCustomModes()
326-
const modeToDelete = customModes.find((mode) => mode.slug === modeSlug)
327-
328-
// Use CustomModesManager to delete the mode configuration
323+
// Use CustomModesManager to delete the mode configuration and associated rules folder
329324
await this.customModesManager.deleteCustomMode(modeSlug)
330-
331-
// Handle rules folder deletion separately (similar to webviewMessageHandler)
332-
if (modeToDelete) {
333-
// Determine the scope based on source (project or global)
334-
const scope = modeToDelete.source || "global"
335-
336-
// Determine the rules folder path
337-
let rulesFolderPath: string
338-
if (scope === "project") {
339-
const workspaceFolder = vscode.workspace.workspaceFolders?.[0]
340-
if (workspaceFolder) {
341-
rulesFolderPath = path.join(workspaceFolder.uri.fsPath, ".roo", `rules-${modeSlug}`)
342-
} else {
343-
return // No workspace, can't delete project rules
344-
}
345-
} else {
346-
// Global scope - use OS home directory
347-
const homeDir = os.homedir()
348-
rulesFolderPath = path.join(homeDir, ".roo", `rules-${modeSlug}`)
349-
}
350-
351-
// Check if the rules folder exists and delete it
352-
const rulesFolderExists = await fileExistsAtPath(rulesFolderPath)
353-
if (rulesFolderExists) {
354-
try {
355-
await fs.rm(rulesFolderPath, { recursive: true, force: true })
356-
console.log(`Deleted rules folder for mode ${modeSlug}: ${rulesFolderPath}`)
357-
} catch (error) {
358-
console.error(`Failed to delete rules folder for mode ${modeSlug}: ${error}`)
359-
// Continue even if folder deletion fails
360-
}
361-
}
362-
}
363325
}
364326

365327
private async removeMcp(item: MarketplaceItem, target: "project" | "global"): Promise<void> {

0 commit comments

Comments
 (0)