import { logger } from '../utils/logger.js'; import { execa } from 'execa'; import path from 'path'; export class GrepTool { constructor() { this.name = 'grep'; this.description = 'Search file contents using regex (ripgrep-backed)'; } async execute(args) { const { pattern, path: searchPath = '.', file_glob, max_results = 20, context: ctx = 0 } = args; try { const cmdArgs = [ '--max-count', String(max_results), '--no-heading', '--line-number', ...(ctx > 0 ? ['-C', String(ctx)] : []), ]; if (file_glob) cmdArgs.push('--glob', file_glob); const targetPath = path.resolve(searchPath); cmdArgs.push('--', pattern, targetPath); const { stdout } = await execa('rg', cmdArgs, { timeout: 30000 }); if (!stdout.trim()) return `🔍 No matches for "${pattern}" in ${searchPath}`; const lineCount = stdout.trim().split('\n').length; const suffix = lineCount >= max_results ? `\n(truncated at ${max_results} matches)` : ''; return `🔍 ${lineCount} matches for "${pattern}" in ${searchPath}:${suffix}\n${stdout}`; } catch (e) { if (e.exitCode === 1) return `🔍 No matches for "${pattern}"`; if (e.exitCode === 2) return `❌ Grep error: ${e.stderr || e.message}`; return `❌ ${e.message}`; } } }