mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
fix: ignore dot files in .roo/rules/ directory to prevent Vim swap file crashes
- Add check to exclude files starting with "." in shouldIncludeRuleFile function - Fixes issue where Vim .swp files (e.g., .filename.swp) crash rules loading - Add comprehensive test case for Vim swap files and other dot files - Resolves #4317
This commit is contained in:
parent
38d8edf05a
commit
6687320f21
2 changed files with 83 additions and 0 deletions
|
|
@ -321,6 +321,84 @@ describe("loadRuleFiles", () => {
|
|||
}
|
||||
})
|
||||
|
||||
it("should filter out Vim swap files and other dot files from .roo/rules/ directory", async () => {
|
||||
// Simulate .roo/rules directory exists
|
||||
statMock.mockResolvedValueOnce({
|
||||
isDirectory: vi.fn().mockReturnValue(true),
|
||||
} as any)
|
||||
|
||||
// Simulate listing files including Vim swap files and other dot files
|
||||
readdirMock.mockResolvedValueOnce([
|
||||
{ name: "rule1.txt", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: ".01-prettier-tree-sitter.md.swp", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: ".vimrc.swp", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: ".hidden-file", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: "rule2.md", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: ".gitignore", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
] as any)
|
||||
|
||||
statMock.mockImplementation((path) => {
|
||||
return Promise.resolve({
|
||||
isFile: vi.fn().mockReturnValue(true),
|
||||
}) as any
|
||||
})
|
||||
|
||||
readFileMock.mockImplementation((filePath: PathLike) => {
|
||||
const pathStr = filePath.toString()
|
||||
const normalizedPath = pathStr.replace(/\\/g, "/")
|
||||
|
||||
// Only rule files should be read - dot files should be skipped
|
||||
if (normalizedPath === "/fake/path/.roo/rules/rule1.txt") {
|
||||
return Promise.resolve("rule 1 content")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/rule2.md") {
|
||||
return Promise.resolve("rule 2 content")
|
||||
}
|
||||
|
||||
// Dot files should not be read due to filtering
|
||||
// If they somehow are read, return recognizable content
|
||||
if (normalizedPath === "/fake/path/.roo/rules/.01-prettier-tree-sitter.md.swp") {
|
||||
return Promise.resolve("b0VIM 8.2")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/.vimrc.swp") {
|
||||
return Promise.resolve("VIM_SWAP_CONTENT")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/.hidden-file") {
|
||||
return Promise.resolve("HIDDEN_FILE_CONTENT")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/.gitignore") {
|
||||
return Promise.resolve("GITIGNORE_CONTENT")
|
||||
}
|
||||
|
||||
return Promise.reject({ code: "ENOENT" })
|
||||
})
|
||||
|
||||
const result = await loadRuleFiles("/fake/path")
|
||||
|
||||
// Should contain rule files
|
||||
expect(result).toContain("rule 1 content")
|
||||
expect(result).toContain("rule 2 content")
|
||||
|
||||
// Should NOT contain dot file content - they should be filtered out
|
||||
expect(result).not.toContain("b0VIM 8.2")
|
||||
expect(result).not.toContain("VIM_SWAP_CONTENT")
|
||||
expect(result).not.toContain("HIDDEN_FILE_CONTENT")
|
||||
expect(result).not.toContain("GITIGNORE_CONTENT")
|
||||
|
||||
// Verify dot files are not read at all
|
||||
const expectedDotFiles = [
|
||||
"/fake/path/.roo/rules/.01-prettier-tree-sitter.md.swp",
|
||||
"/fake/path/.roo/rules/.vimrc.swp",
|
||||
"/fake/path/.roo/rules/.hidden-file",
|
||||
"/fake/path/.roo/rules/.gitignore",
|
||||
]
|
||||
|
||||
for (const dotFile of expectedDotFiles) {
|
||||
const expectedPath = process.platform === "win32" ? dotFile.replace(/\//g, "\\") : dotFile
|
||||
expect(readFileMock).not.toHaveBeenCalledWith(expectedPath, "utf-8")
|
||||
}
|
||||
})
|
||||
|
||||
it("should fall back to .roorules when .roo/rules/ is empty", async () => {
|
||||
// Simulate .roo/rules directory exists
|
||||
statMock.mockResolvedValueOnce({
|
||||
|
|
|
|||
|
|
@ -309,6 +309,11 @@ ${joinedSections}`
|
|||
function shouldIncludeRuleFile(filename: string): boolean {
|
||||
const basename = path.basename(filename)
|
||||
|
||||
// Exclude files that start with . (hidden files, including Vim .swp files)
|
||||
if (basename.startsWith(".")) {
|
||||
return false
|
||||
}
|
||||
|
||||
const cachePatterns = [
|
||||
"*.DS_Store",
|
||||
"*.bak",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue