search_files
Search your notes directory recursively for files and directories matching a pattern, including partial names. Exclude specific items using glob patterns to find notes even when their exact location is unknown.
Instructions
Recursively search for files and directories matching a pattern in your notes directory. The search is case-insensitive and matches partial names. Returns full paths to all matching items. Great for finding notes when you don't know their exact location.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| excludePatterns | No | Glob patterns to exclude from search results | |
| pattern | Yes | The pattern to search for in file and directory names |
Implementation Reference
- src/tools/index.ts:348-349 (registration)Registration and dispatch for the "search_files" tool in the main handleToolCall switch statement, calling the dedicated handleSearchFiles function.case "search_files": return await handleSearchFiles(notesPath, args);
- search-utils.ts:12-77 (helper)Supporting utility that performs recursive file search matching a pattern in filenames, with exclusion patterns. This is the core search logic powering the search_files tool.export async function searchFiles(rootPath: string, pattern: string, excludePatterns: string[] = []): Promise<string[]> { const results: string[] = []; // Normalize the search pattern for better matching const normalizedPattern = pattern.toLowerCase(); // Make sure the root path exists try { const rootStats = await fs.stat(rootPath); if (!rootStats.isDirectory()) { console.error(`Search root is not a directory: ${rootPath}`); return []; } } catch (error) { console.error(`Error accessing search root path ${rootPath}:`, error); return []; } async function search(currentPath: string): Promise<void> { try { // Read directory entries const entries = await fs.readdir(currentPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(currentPath, entry.name); try { // Check if path matches any exclude pattern const relativePath = path.relative(rootPath, fullPath); const shouldExclude = excludePatterns.some(pattern => { const globPattern = pattern.includes('*') ? pattern : `**/${pattern}/**`; return minimatch(relativePath, globPattern, { dot: true }); }); if (shouldExclude) { continue; } // Match the name (case-insensitive) if (entry.name.toLowerCase().includes(normalizedPattern)) { results.push(fullPath); } // Recursively search subdirectories if (entry.isDirectory()) { await search(fullPath); } } catch (error) { // Skip problematic entries console.error(`Error processing ${fullPath}:`, error); continue; } } } catch (error) { console.error(`Error reading directory ${currentPath}:`, error); } } // Start the search await search(rootPath); // Log the number of results found console.error(`Search found ${results.length} results for pattern "${pattern}" in ${rootPath}`); return results; }