Skip to content

Commit 821812f

Browse files
committed
fix: slash commands stored in correct workspace folder in multi-root workspaces
- Added findWorkspaceWithRoo() utility to locate the workspace containing .roo directory - Updated webviewMessageHandler to use the new utility instead of hardcoded first workspace - This ensures slash commands are created in the correct .roo/commands directory Fixes #6700
1 parent d90bab7 commit 821812f

File tree

3 files changed

+70
-16
lines changed

3 files changed

+70
-16
lines changed

src/core/webview/webviewMessageHandler.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { getOpenAiModels } from "../../api/providers/openai"
4343
import { getVsCodeLmModels } from "../../api/providers/vscode-lm"
4444
import { openMention } from "../mentions"
4545
import { TelemetrySetting } from "../../shared/TelemetrySetting"
46-
import { getWorkspacePath } from "../../utils/path"
46+
import { getWorkspacePath, findWorkspaceWithRoo } from "../../utils/path"
4747
import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
4848
import { Mode, defaultModeSlug } from "../../shared/modes"
4949
import { getModels, flushModels } from "../../api/providers/fetchers/modelCache"
@@ -2477,13 +2477,13 @@ export const webviewMessageHandler = async (
24772477
const globalConfigDir = path.join(os.homedir(), ".roo")
24782478
commandsDir = path.join(globalConfigDir, "commands")
24792479
} else {
2480-
// Project commands
2481-
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath
2482-
if (!workspaceRoot) {
2480+
// Project commands - find the workspace with .roo directory
2481+
const workspaceWithRoo = await findWorkspaceWithRoo()
2482+
if (!workspaceWithRoo) {
24832483
vscode.window.showErrorMessage(t("common:errors.no_workspace_for_project_command"))
24842484
break
24852485
}
2486-
commandsDir = path.join(workspaceRoot, ".roo", "commands")
2486+
commandsDir = path.join(workspaceWithRoo.uri.fsPath, ".roo", "commands")
24872487
}
24882488

24892489
// Ensure the commands directory exists

src/utils/__tests__/path.spec.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,18 @@
33
import os from "os"
44
import * as path from "path"
55

6-
import { arePathsEqual, getReadablePath, getWorkspacePath } from "../path"
6+
// Use vi.hoisted to ensure mocks are available during module loading
7+
const { mockWorkspaceFolders, mockGetWorkspaceFolder, mockFileExistsAtPath } = vi.hoisted(() => {
8+
const mockWorkspaceFolders = vi.fn()
9+
const mockGetWorkspaceFolder = vi.fn()
10+
const mockFileExistsAtPath = vi.fn()
11+
return { mockWorkspaceFolders, mockGetWorkspaceFolder, mockFileExistsAtPath }
12+
})
713

8-
// Mock modules
14+
// Mock modules before imports
15+
vi.mock("../fs", () => ({
16+
fileExistsAtPath: mockFileExistsAtPath,
17+
}))
918

1019
vi.mock("vscode", () => ({
1120
window: {
@@ -16,23 +25,37 @@ vi.mock("vscode", () => ({
1625
},
1726
},
1827
workspace: {
19-
workspaceFolders: [
28+
get workspaceFolders() {
29+
return mockWorkspaceFolders()
30+
},
31+
getWorkspaceFolder: mockGetWorkspaceFolder,
32+
},
33+
}))
34+
35+
import { arePathsEqual, getReadablePath, getWorkspacePath, findWorkspaceWithRoo } from "../path"
36+
import { fileExistsAtPath } from "../fs"
37+
38+
describe("Path Utilities", () => {
39+
const originalPlatform = process.platform
40+
// Helper to mock VS Code configuration
41+
42+
beforeEach(() => {
43+
// Reset mocks before each test
44+
vi.clearAllMocks()
45+
// Set default workspace folders
46+
mockWorkspaceFolders.mockReturnValue([
2047
{
2148
uri: { fsPath: "/test/workspace" },
2249
name: "test",
2350
index: 0,
2451
},
25-
],
26-
getWorkspaceFolder: vi.fn().mockReturnValue({
52+
])
53+
mockGetWorkspaceFolder.mockReturnValue({
2754
uri: {
2855
fsPath: "/test/workspaceFolder",
2956
},
30-
}),
31-
},
32-
}))
33-
describe("Path Utilities", () => {
34-
const originalPlatform = process.platform
35-
// Helper to mock VS Code configuration
57+
})
58+
})
3659

3760
afterEach(() => {
3861
Object.defineProperty(process, "platform", {

src/utils/path.ts

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

56
/*
67
The Node.js 'path' module resolves and normalizes paths differently depending on the platform:
@@ -130,3 +131,33 @@ export const getWorkspacePathForContext = (contextPath?: string): string => {
130131
// Fall back to current behavior
131132
return getWorkspacePath()
132133
}
134+
135+
/**
136+
* Finds the workspace folder that contains a .roo directory.
137+
* In multi-root workspaces, this ensures we find the correct workspace
138+
* rather than just using the first one.
139+
*
140+
* @returns The workspace folder containing .roo, or undefined if none found
141+
*/
142+
export async function findWorkspaceWithRoo(): Promise<vscode.WorkspaceFolder | undefined> {
143+
const workspaceFolders = vscode.workspace.workspaceFolders
144+
if (!workspaceFolders || workspaceFolders.length === 0) {
145+
return undefined
146+
}
147+
148+
// If there's only one workspace folder, return it
149+
if (workspaceFolders.length === 1) {
150+
return workspaceFolders[0]
151+
}
152+
153+
// Check each workspace folder for a .roo directory
154+
for (const folder of workspaceFolders) {
155+
const rooPath = path.join(folder.uri.fsPath, ".roo")
156+
if (await fileExistsAtPath(rooPath)) {
157+
return folder
158+
}
159+
}
160+
161+
// If no .roo directory found in any workspace, return the first one as fallback
162+
return workspaceFolders[0]
163+
}

0 commit comments

Comments
 (0)