Skip to content

Commit 5e55a7a

Browse files
return files if targeted directory is hidden (RooCodeInc#4176)
1 parent 741b1ed commit 5e55a7a

File tree

2 files changed

+61
-30
lines changed

2 files changed

+61
-30
lines changed

.changeset/beige-turtles-jump.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"claude-dev": minor
3+
---
4+
5+
Fix list_files tool to return files if the targeted directory is a hidden directory

src/services/glob/list-files.ts

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,81 @@
11
import { globby, Options } from "globby"
2-
import os from "os"
2+
import * as os from "os"
33
import * as path from "path"
44
import { arePathsEqual } from "@utils/path"
55

6-
export async function listFiles(dirPath: string, recursive: boolean, limit: number): Promise<[string[], boolean]> {
7-
// First resolve the path normally - path.resolve doesn't care about glob special characters
8-
const absolutePath = path.resolve(dirPath)
9-
// Do not allow listing files in root or home directory, which cline tends to want to do when the user's prompt is vague.
6+
// Constants
7+
const DEFAULT_IGNORE_DIRECTORIES = [
8+
"node_modules",
9+
"__pycache__",
10+
"env",
11+
"venv",
12+
"target/dependency",
13+
"build/dependencies",
14+
"dist",
15+
"out",
16+
"bundle",
17+
"vendor",
18+
"tmp",
19+
"temp",
20+
"deps",
21+
"pkg",
22+
"Pods",
23+
]
24+
25+
// Helper functions
26+
function isRestrictedPath(absolutePath: string): boolean {
1027
const root = process.platform === "win32" ? path.parse(absolutePath).root : "/"
1128
const isRoot = arePathsEqual(absolutePath, root)
1229
if (isRoot) {
13-
return [[root], false]
30+
return true
1431
}
32+
1533
const homeDir = os.homedir()
1634
const isHomeDir = arePathsEqual(absolutePath, homeDir)
1735
if (isHomeDir) {
18-
return [[homeDir], false]
36+
return true
37+
}
38+
39+
return false
40+
}
41+
42+
function isTargetingHiddenDirectory(absolutePath: string): boolean {
43+
const dirName = path.basename(absolutePath)
44+
return dirName.startsWith(".")
45+
}
46+
47+
function buildIgnorePatterns(absolutePath: string): string[] {
48+
const isTargetHidden = isTargetingHiddenDirectory(absolutePath)
49+
50+
const patterns = [...DEFAULT_IGNORE_DIRECTORIES]
51+
52+
// Only ignore hidden directories if we're not explicitly targeting a hidden directory
53+
if (!isTargetHidden) {
54+
patterns.push(".*")
1955
}
2056

21-
const dirsToIgnore = [
22-
"node_modules",
23-
"__pycache__",
24-
"env",
25-
"venv",
26-
"target/dependency",
27-
"build/dependencies",
28-
"dist",
29-
"out",
30-
"bundle",
31-
"vendor",
32-
"tmp",
33-
"temp",
34-
"deps",
35-
"pkg",
36-
"Pods",
37-
".*", // '!**/.*' excludes hidden directories, while '!**/.*/**' excludes only their contents. This way we are at least aware of the existence of hidden directories.
38-
].map((dir) => `**/${dir}/**`)
57+
return patterns.map((dir) => `**/${dir}/**`)
58+
}
59+
60+
export async function listFiles(dirPath: string, recursive: boolean, limit: number): Promise<[string[], boolean]> {
61+
const absolutePath = path.resolve(dirPath)
62+
63+
// Do not allow listing files in root or home directory
64+
if (isRestrictedPath(absolutePath)) {
65+
return [[], false]
66+
}
3967

4068
const options: Options = {
4169
cwd: dirPath,
4270
dot: true, // do not ignore hidden files/directories
4371
absolute: true,
44-
markDirectories: true, // Append a / on any directories matched (/ is used on windows as well, so dont use path.sep)
72+
markDirectories: true, // Append a / on any directories matched
4573
gitignore: recursive, // globby ignores any files that are gitignored
46-
ignore: recursive ? dirsToIgnore : undefined, // just in case there is no gitignore, we ignore sensible defaults
47-
onlyFiles: false, // true by default, false means it will list directories on their own too
74+
ignore: recursive ? buildIgnorePatterns(absolutePath) : undefined,
75+
onlyFiles: false, // include directories in results
4876
suppressErrors: true,
4977
}
5078

51-
// * globs all files in one dir, ** globs files in nested directories
52-
// For non-recursive listing, we still use a simple pattern
5379
const filePaths = recursive ? await globbyLevelByLevel(limit, options) : (await globby("*", options)).slice(0, limit)
5480

5581
return [filePaths, filePaths.length >= limit]

0 commit comments

Comments
 (0)