mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: Exclude cache files from rules compilation (#5283)
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
This commit is contained in:
parent
adb3ee9a11
commit
933f28fe32
2 changed files with 146 additions and 1 deletions
|
|
@ -221,6 +221,106 @@ describe("loadRuleFiles", () => {
|
|||
expect(readFileMock).toHaveBeenCalledWith(expectedFile2Path, "utf-8")
|
||||
})
|
||||
|
||||
it("should filter out cache files from .roo/rules/ directory", async () => {
|
||||
// Simulate .roo/rules directory exists
|
||||
statMock.mockResolvedValueOnce({
|
||||
isDirectory: vi.fn().mockReturnValue(true),
|
||||
} as any)
|
||||
|
||||
// Simulate listing files including cache files
|
||||
readdirMock.mockResolvedValueOnce([
|
||||
{ name: "rule1.txt", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: ".DS_Store", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: "Thumbs.db", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: "rule2.md", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{ name: "cache.log", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{
|
||||
name: "backup.bak",
|
||||
isFile: () => true,
|
||||
isSymbolicLink: () => false,
|
||||
parentPath: "/fake/path/.roo/rules",
|
||||
},
|
||||
{ name: "temp.tmp", isFile: () => true, isSymbolicLink: () => false, parentPath: "/fake/path/.roo/rules" },
|
||||
{
|
||||
name: "script.pyc",
|
||||
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 - cache 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")
|
||||
}
|
||||
|
||||
// Cache files should not be read due to filtering
|
||||
// If they somehow are read, return recognizable content
|
||||
if (normalizedPath === "/fake/path/.roo/rules/.DS_Store") {
|
||||
return Promise.resolve("DS_STORE_BINARY_CONTENT")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/Thumbs.db") {
|
||||
return Promise.resolve("THUMBS_DB_CONTENT")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/backup.bak") {
|
||||
return Promise.resolve("BACKUP_CONTENT")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/cache.log") {
|
||||
return Promise.resolve("LOG_CONTENT")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/temp.tmp") {
|
||||
return Promise.resolve("TEMP_CONTENT")
|
||||
}
|
||||
if (normalizedPath === "/fake/path/.roo/rules/script.pyc") {
|
||||
return Promise.resolve("PYTHON_BYTECODE")
|
||||
}
|
||||
|
||||
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 cache file content - they should be filtered out
|
||||
expect(result).not.toContain("DS_STORE_BINARY_CONTENT")
|
||||
expect(result).not.toContain("THUMBS_DB_CONTENT")
|
||||
expect(result).not.toContain("BACKUP_CONTENT")
|
||||
expect(result).not.toContain("LOG_CONTENT")
|
||||
expect(result).not.toContain("TEMP_CONTENT")
|
||||
expect(result).not.toContain("PYTHON_BYTECODE")
|
||||
|
||||
// Verify cache files are not read at all
|
||||
const expectedCacheFiles = [
|
||||
"/fake/path/.roo/rules/.DS_Store",
|
||||
"/fake/path/.roo/rules/Thumbs.db",
|
||||
"/fake/path/.roo/rules/backup.bak",
|
||||
"/fake/path/.roo/rules/cache.log",
|
||||
"/fake/path/.roo/rules/temp.tmp",
|
||||
"/fake/path/.roo/rules/script.pyc",
|
||||
]
|
||||
|
||||
for (const cacheFile of expectedCacheFiles) {
|
||||
const expectedPath = process.platform === "win32" ? cacheFile.replace(/\//g, "\\") : cacheFile
|
||||
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({
|
||||
|
|
|
|||
|
|
@ -123,6 +123,10 @@ async function readTextFilesFromDirectory(dirPath: string): Promise<Array<{ file
|
|||
// Check if it's a file (not a directory)
|
||||
const stats = await fs.stat(file)
|
||||
if (stats.isFile()) {
|
||||
// Filter out cache files and system files that shouldn't be in rules
|
||||
if (!shouldIncludeRuleFile(file)) {
|
||||
return null
|
||||
}
|
||||
const content = await safeReadFile(file)
|
||||
return { filename: file, content }
|
||||
}
|
||||
|
|
@ -133,7 +137,7 @@ async function readTextFilesFromDirectory(dirPath: string): Promise<Array<{ file
|
|||
}),
|
||||
)
|
||||
|
||||
// Filter out null values (directories or failed reads)
|
||||
// Filter out null values (directories, failed reads, or excluded files)
|
||||
return fileContents.filter((item): item is { filename: string; content: string } => item !== null)
|
||||
} catch (err) {
|
||||
return []
|
||||
|
|
@ -297,3 +301,44 @@ The following additional instructions are provided by the user, and should be fo
|
|||
${joinedSections}`
|
||||
: ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file should be included in rule compilation.
|
||||
* Excludes cache files and system files that shouldn't be processed as rules.
|
||||
*/
|
||||
function shouldIncludeRuleFile(filename: string): boolean {
|
||||
const basename = path.basename(filename)
|
||||
|
||||
const cachePatterns = [
|
||||
"*.DS_Store",
|
||||
"*.bak",
|
||||
"*.cache",
|
||||
"*.crdownload",
|
||||
"*.db",
|
||||
"*.dmp",
|
||||
"*.dump",
|
||||
"*.eslintcache",
|
||||
"*.lock",
|
||||
"*.log",
|
||||
"*.old",
|
||||
"*.part",
|
||||
"*.partial",
|
||||
"*.pyc",
|
||||
"*.pyo",
|
||||
"*.stackdump",
|
||||
"*.swo",
|
||||
"*.swp",
|
||||
"*.temp",
|
||||
"*.tmp",
|
||||
"Thumbs.db",
|
||||
]
|
||||
|
||||
return !cachePatterns.some((pattern) => {
|
||||
if (pattern.startsWith("*.")) {
|
||||
const extension = pattern.slice(1)
|
||||
return basename.endsWith(extension)
|
||||
} else {
|
||||
return basename === pattern
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue