(
filePattern: string,
cwd: string,
{ limit, offset }: { limit: number; offset: number },
abortSignal: AbortSignal,
toolPermissionContext: ToolPermissionContext,
)
| 64 | } |
| 65 | |
| 66 | export async function glob( |
| 67 | filePattern: string, |
| 68 | cwd: string, |
| 69 | { limit, offset }: { limit: number; offset: number }, |
| 70 | abortSignal: AbortSignal, |
| 71 | toolPermissionContext: ToolPermissionContext, |
| 72 | ): Promise<{ files: string[]; truncated: boolean }> { |
| 73 | let searchDir = cwd |
| 74 | let searchPattern = filePattern |
| 75 | |
| 76 | // Handle absolute paths by extracting the base directory and converting to relative pattern |
| 77 | // ripgrep's --glob flag only works with relative patterns |
| 78 | if (isAbsolute(filePattern)) { |
| 79 | const { baseDir, relativePattern } = extractGlobBaseDirectory(filePattern) |
| 80 | if (baseDir) { |
| 81 | searchDir = baseDir |
| 82 | searchPattern = relativePattern |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | const ignorePatterns = normalizePatternsToPath( |
| 87 | getFileReadIgnorePatterns(toolPermissionContext), |
| 88 | searchDir, |
| 89 | ) |
| 90 | |
| 91 | // Use ripgrep for better memory performance |
| 92 | // --files: list files instead of searching content |
| 93 | // --glob: filter by pattern |
| 94 | // --sort=modified: sort by modification time (oldest first) |
| 95 | // --no-ignore: don't respect .gitignore (default true, set CLAUDE_CODE_GLOB_NO_IGNORE=false to respect .gitignore) |
| 96 | // --hidden: include hidden files (default true, set CLAUDE_CODE_GLOB_HIDDEN=false to exclude) |
| 97 | // Note: use || instead of ?? to treat empty string as unset (defaulting to true) |
| 98 | const noIgnore = isEnvTruthy(process.env.CLAUDE_CODE_GLOB_NO_IGNORE || 'true') |
| 99 | const hidden = isEnvTruthy(process.env.CLAUDE_CODE_GLOB_HIDDEN || 'true') |
| 100 | const args = [ |
| 101 | '--files', |
| 102 | '--glob', |
| 103 | searchPattern, |
| 104 | '--sort=modified', |
| 105 | ...(noIgnore ? ['--no-ignore'] : []), |
| 106 | ...(hidden ? ['--hidden'] : []), |
| 107 | ] |
| 108 | |
| 109 | // Add ignore patterns |
| 110 | for (const pattern of ignorePatterns) { |
| 111 | args.push('--glob', `!${pattern}`) |
| 112 | } |
| 113 | |
| 114 | // Exclude orphaned plugin version directories |
| 115 | for (const exclusion of await getGlobExclusionsForPluginCache(searchDir)) { |
| 116 | args.push('--glob', exclusion) |
| 117 | } |
| 118 | |
| 119 | const allPaths = await ripGrep(args, searchDir, abortSignal) |
| 120 | |
| 121 | // ripgrep returns relative paths, convert to absolute |
| 122 | const absolutePaths = allPaths.map(p => |
| 123 | isAbsolute(p) ? p : join(searchDir, p), |
no test coverage detected