|
| 1 | +import * as assert from "assert" |
| 2 | +import * as fs from "fs/promises" |
| 3 | +import * as path from "path" |
| 4 | +import * as vscode from "vscode" |
| 5 | + |
| 6 | +import { RooCodeEventName, type ClineMessage } from "@roo-code/types" |
| 7 | + |
| 8 | +import { setDefaultSuiteTimeout } from "./test-utils" |
| 9 | +import { waitFor } from "./utils" |
| 10 | + |
| 11 | +suite("Multi-root readFileContent repro", function () { |
| 12 | + setDefaultSuiteTimeout(this) |
| 13 | + |
| 14 | + test("should read a file that exists only in the secondary workspace root", async () => { |
| 15 | + await waitFor(() => (vscode.workspace.workspaceFolders?.length ?? 0) >= 2, { |
| 16 | + timeout: 60_000, |
| 17 | + interval: 250, |
| 18 | + }) |
| 19 | + |
| 20 | + const primaryWorkspace = vscode.workspace.workspaceFolders?.[0] |
| 21 | + assert.ok(primaryWorkspace, "Expected a primary workspace folder") |
| 22 | + const secondaryWorkspace = vscode.workspace.workspaceFolders?.[1] |
| 23 | + assert.ok(secondaryWorkspace, "Expected a secondary workspace folder") |
| 24 | + |
| 25 | + const primaryRoot = primaryWorkspace.uri.fsPath |
| 26 | + const secondaryRoot = secondaryWorkspace.uri.fsPath |
| 27 | + const secondaryFileName = "secondary-root-read-file.txt" |
| 28 | + const expectedContent = "SECONDARY_ROOT_MARKER_204\n" |
| 29 | + const secondaryFilePath = path.join(secondaryRoot, secondaryFileName) |
| 30 | + |
| 31 | + await fs.writeFile(secondaryFilePath, expectedContent, "utf8") |
| 32 | + |
| 33 | + const api = globalThis.api |
| 34 | + const messages: ClineMessage[] = [] |
| 35 | + const messageHandler = ({ message }: { message: ClineMessage }) => { |
| 36 | + if (message.partial !== true) { |
| 37 | + messages.push(message) |
| 38 | + } |
| 39 | + } |
| 40 | + api.on(RooCodeEventName.Message, messageHandler) |
| 41 | + |
| 42 | + let taskCompleted = false |
| 43 | + let taskId = "" |
| 44 | + const taskCompletedHandler = (id: string) => { |
| 45 | + if (id === taskId) { |
| 46 | + taskCompleted = true |
| 47 | + } |
| 48 | + } |
| 49 | + api.on(RooCodeEventName.TaskCompleted, taskCompletedHandler) |
| 50 | + |
| 51 | + try { |
| 52 | + taskId = await api.startNewTask({ |
| 53 | + configuration: { |
| 54 | + mode: "code", |
| 55 | + autoApprovalEnabled: true, |
| 56 | + alwaysAllowReadOnly: true, |
| 57 | + alwaysAllowReadOnlyOutsideWorkspace: true, |
| 58 | + }, |
| 59 | + text: |
| 60 | + `READ_FILE_MULTI_ROOT_REPRO: Use only the read_file tool to read "${secondaryFileName}". ` + |
| 61 | + `The file exists in the current VS Code workspace, but only inside the secondary workspace root. ` + |
| 62 | + `After the read attempt, explain exactly what happened.`, |
| 63 | + }) |
| 64 | + |
| 65 | + await waitFor(() => taskCompleted, { timeout: 60_000, interval: 250 }) |
| 66 | + |
| 67 | + assert.ok( |
| 68 | + vscode.workspace.workspaceFolders?.some((folder) => folder.uri.fsPath === secondaryRoot), |
| 69 | + `Expected secondary root ${secondaryRoot} to remain part of the workspace during the repro`, |
| 70 | + ) |
| 71 | + |
| 72 | + const completionMessage = messages.find( |
| 73 | + (message) => |
| 74 | + message.type === "say" && |
| 75 | + (message.say === "completion_result" || message.say === "text") && |
| 76 | + message.text?.includes("SECONDARY_ROOT_MARKER_204"), |
| 77 | + ) |
| 78 | + |
| 79 | + assert.ok( |
| 80 | + completionMessage, |
| 81 | + `Expected the task to read the secondary-root file. Primary root was ${primaryRoot}, secondary root was ${secondaryRoot}, secondary file was ${secondaryFilePath}, and messages were ${JSON.stringify(messages, null, 2)}.`, |
| 82 | + ) |
| 83 | + } finally { |
| 84 | + api.off(RooCodeEventName.Message, messageHandler) |
| 85 | + api.off(RooCodeEventName.TaskCompleted, taskCompletedHandler) |
| 86 | + |
| 87 | + try { |
| 88 | + await api.cancelCurrentTask() |
| 89 | + } catch { |
| 90 | + // Ignore cleanup races if the task already ended. |
| 91 | + } |
| 92 | + |
| 93 | + await fs.rm(secondaryFilePath, { force: true }) |
| 94 | + } |
| 95 | + }) |
| 96 | +}) |
0 commit comments