Skip to content

Commit 1cbe722

Browse files
committed
Create .roomodes file if needed
1 parent 9df50b4 commit 1cbe722

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

.changeset/twelve-ways-peel.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
Create .roomodes file if needed

src/core/config/CustomModesManager.ts

+21-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { CustomModesSettingsSchema } from "./CustomModesSchema"
55
import { ModeConfig } from "../../shared/modes"
66
import { fileExistsAtPath } from "../../utils/fs"
77
import { arePathsEqual } from "../../utils/path"
8+
import { logger } from "../../utils/logging"
89

910
const ROOMODES_FILENAME = ".roomodes"
1011

@@ -214,14 +215,26 @@ export class CustomModesManager {
214215
await this.context.globalState.update("customModes", mergedModes)
215216
return mergedModes
216217
}
217-
218218
async updateCustomMode(slug: string, config: ModeConfig): Promise<void> {
219219
try {
220220
const isProjectMode = config.source === "project"
221-
const targetPath = isProjectMode ? await this.getWorkspaceRoomodes() : await this.getCustomModesFilePath()
221+
let targetPath: string
222222

223-
if (isProjectMode && !targetPath) {
224-
throw new Error("No workspace folder found for project-specific mode")
223+
if (isProjectMode) {
224+
const workspaceFolders = vscode.workspace.workspaceFolders
225+
if (!workspaceFolders || workspaceFolders.length === 0) {
226+
logger.error("Failed to update project mode: No workspace folder found", { slug })
227+
throw new Error("No workspace folder found for project-specific mode")
228+
}
229+
const workspaceRoot = workspaceFolders[0].uri.fsPath
230+
targetPath = path.join(workspaceRoot, ROOMODES_FILENAME)
231+
const exists = await fileExistsAtPath(targetPath)
232+
logger.info(`${exists ? "Updating" : "Creating"} project mode in ${ROOMODES_FILENAME}`, {
233+
slug,
234+
workspace: workspaceRoot,
235+
})
236+
} else {
237+
targetPath = await this.getCustomModesFilePath()
225238
}
226239

227240
await this.queueWrite(async () => {
@@ -231,7 +244,7 @@ export class CustomModesManager {
231244
source: isProjectMode ? ("project" as const) : ("global" as const),
232245
}
233246

234-
await this.updateModesInFile(targetPath!, (modes) => {
247+
await this.updateModesInFile(targetPath, (modes) => {
235248
const updatedModes = modes.filter((m) => m.slug !== slug)
236249
updatedModes.push(modeWithSource)
237250
return updatedModes
@@ -240,9 +253,9 @@ export class CustomModesManager {
240253
await this.refreshMergedState()
241254
})
242255
} catch (error) {
243-
vscode.window.showErrorMessage(
244-
`Failed to update custom mode: ${error instanceof Error ? error.message : String(error)}`,
245-
)
256+
const errorMessage = error instanceof Error ? error.message : String(error)
257+
logger.error("Failed to update custom mode", { slug, error: errorMessage })
258+
vscode.window.showErrorMessage(`Failed to update custom mode: ${errorMessage}`)
246259
}
247260
}
248261
private async updateModesInFile(filePath: string, operation: (modes: ModeConfig[]) => ModeConfig[]): Promise<void> {

src/core/config/__tests__/CustomModesManager.test.ts

+51
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,57 @@ describe("CustomModesManager", () => {
207207
expect(mockOnUpdate).toHaveBeenCalled()
208208
})
209209

210+
it("creates .roomodes file when adding project-specific mode", async () => {
211+
const projectMode: ModeConfig = {
212+
slug: "project-mode",
213+
name: "Project Mode",
214+
roleDefinition: "Project Role",
215+
groups: ["read"],
216+
source: "project",
217+
}
218+
219+
// Mock .roomodes to not exist initially
220+
let roomodesContent: any = null
221+
;(fileExistsAtPath as jest.Mock).mockImplementation(async (path: string) => {
222+
return path === mockSettingsPath
223+
})
224+
;(fs.readFile as jest.Mock).mockImplementation(async (path: string) => {
225+
if (path === mockSettingsPath) {
226+
return JSON.stringify({ customModes: [] })
227+
}
228+
if (path === mockRoomodes) {
229+
if (!roomodesContent) {
230+
throw new Error("File not found")
231+
}
232+
return JSON.stringify(roomodesContent)
233+
}
234+
throw new Error("File not found")
235+
})
236+
;(fs.writeFile as jest.Mock).mockImplementation(async (path: string, content: string) => {
237+
if (path === mockRoomodes) {
238+
roomodesContent = JSON.parse(content)
239+
}
240+
return Promise.resolve()
241+
})
242+
243+
await manager.updateCustomMode("project-mode", projectMode)
244+
245+
// Verify .roomodes was created with the project mode
246+
expect(fs.writeFile).toHaveBeenCalledWith(mockRoomodes, expect.stringContaining("project-mode"), "utf-8")
247+
248+
// Verify the content written to .roomodes
249+
expect(roomodesContent).toEqual({
250+
customModes: [
251+
expect.objectContaining({
252+
slug: "project-mode",
253+
name: "Project Mode",
254+
roleDefinition: "Project Role",
255+
source: "project",
256+
}),
257+
],
258+
})
259+
})
260+
210261
it("queues write operations", async () => {
211262
const mode1: ModeConfig = {
212263
slug: "mode1",

0 commit comments

Comments
 (0)