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
This commit is contained in:
Roo Code 2025-08-05 08:24:03 +00:00
parent d90bab71ff
commit 821812f740
3 changed files with 70 additions and 16 deletions

View file

@ -43,7 +43,7 @@ import { getOpenAiModels } from "../../api/providers/openai"
import { getVsCodeLmModels } from "../../api/providers/vscode-lm"
import { openMention } from "../mentions"
import { TelemetrySetting } from "../../shared/TelemetrySetting"
import { getWorkspacePath } from "../../utils/path"
import { getWorkspacePath, findWorkspaceWithRoo } from "../../utils/path"
import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
import { Mode, defaultModeSlug } from "../../shared/modes"
import { getModels, flushModels } from "../../api/providers/fetchers/modelCache"
@ -2477,13 +2477,13 @@ export const webviewMessageHandler = async (
const globalConfigDir = path.join(os.homedir(), ".roo")
commandsDir = path.join(globalConfigDir, "commands")
} else {
// Project commands
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath
if (!workspaceRoot) {
// Project commands - find the workspace with .roo directory
const workspaceWithRoo = await findWorkspaceWithRoo()
if (!workspaceWithRoo) {
vscode.window.showErrorMessage(t("common:errors.no_workspace_for_project_command"))
break
}
commandsDir = path.join(workspaceRoot, ".roo", "commands")
commandsDir = path.join(workspaceWithRoo.uri.fsPath, ".roo", "commands")
}
// Ensure the commands directory exists

View file

@ -3,9 +3,18 @@
import os from "os"
import * as path from "path"
import { arePathsEqual, getReadablePath, getWorkspacePath } from "../path"
// Use vi.hoisted to ensure mocks are available during module loading
const { mockWorkspaceFolders, mockGetWorkspaceFolder, mockFileExistsAtPath } = vi.hoisted(() => {
const mockWorkspaceFolders = vi.fn()
const mockGetWorkspaceFolder = vi.fn()
const mockFileExistsAtPath = vi.fn()
return { mockWorkspaceFolders, mockGetWorkspaceFolder, mockFileExistsAtPath }
})
// Mock modules
// Mock modules before imports
vi.mock("../fs", () => ({
fileExistsAtPath: mockFileExistsAtPath,
}))
vi.mock("vscode", () => ({
window: {
@ -16,23 +25,37 @@ vi.mock("vscode", () => ({
},
},
workspace: {
workspaceFolders: [
get workspaceFolders() {
return mockWorkspaceFolders()
},
getWorkspaceFolder: mockGetWorkspaceFolder,
},
}))
import { arePathsEqual, getReadablePath, getWorkspacePath, findWorkspaceWithRoo } from "../path"
import { fileExistsAtPath } from "../fs"
describe("Path Utilities", () => {
const originalPlatform = process.platform
// Helper to mock VS Code configuration
beforeEach(() => {
// Reset mocks before each test
vi.clearAllMocks()
// Set default workspace folders
mockWorkspaceFolders.mockReturnValue([
{
uri: { fsPath: "/test/workspace" },
name: "test",
index: 0,
},
],
getWorkspaceFolder: vi.fn().mockReturnValue({
])
mockGetWorkspaceFolder.mockReturnValue({
uri: {
fsPath: "/test/workspaceFolder",
},
}),
},
}))
describe("Path Utilities", () => {
const originalPlatform = process.platform
// Helper to mock VS Code configuration
})
})
afterEach(() => {
Object.defineProperty(process, "platform", {

View file

@ -1,6 +1,7 @@
import * as path from "path"
import os from "os"
import * as vscode from "vscode"
import { fileExistsAtPath } from "./fs"
/*
The Node.js 'path' module resolves and normalizes paths differently depending on the platform:
@ -130,3 +131,33 @@ export const getWorkspacePathForContext = (contextPath?: string): string => {
// Fall back to current behavior
return getWorkspacePath()
}
/**
* Finds the workspace folder that contains a .roo directory.
* In multi-root workspaces, this ensures we find the correct workspace
* rather than just using the first one.
*
* @returns The workspace folder containing .roo, or undefined if none found
*/
export async function findWorkspaceWithRoo(): Promise<vscode.WorkspaceFolder | undefined> {
const workspaceFolders = vscode.workspace.workspaceFolders
if (!workspaceFolders || workspaceFolders.length === 0) {
return undefined
}
// If there's only one workspace folder, return it
if (workspaceFolders.length === 1) {
return workspaceFolders[0]
}
// Check each workspace folder for a .roo directory
for (const folder of workspaceFolders) {
const rooPath = path.join(folder.uri.fsPath, ".roo")
if (await fileExistsAtPath(rooPath)) {
return folder
}
}
// If no .roo directory found in any workspace, return the first one as fallback
return workspaceFolders[0]
}