( args: string[], target: string, abortSignal: AbortSignal, )
| 395 | } |
| 396 | |
| 397 | export async function ripGrep( |
| 398 | args: string[], |
| 399 | target: string, |
| 400 | abortSignal: AbortSignal, |
| 401 | ): Promise<string[]> { |
| 402 | await codesignRipgrepIfNecessary() |
| 403 | |
| 404 | // Test ripgrep on first use and cache the result (fire and forget) |
| 405 | void testRipgrepOnFirstUse().catch(error => { |
| 406 | logError(error) |
| 407 | }) |
| 408 | |
| 409 | return new Promise((resolve, reject) => { |
| 410 | const handleResult = ( |
| 411 | error: ExecFileException | null, |
| 412 | stdout: string, |
| 413 | stderr: string, |
| 414 | isRetry: boolean, |
| 415 | ): void => { |
| 416 | // Success case |
| 417 | if (!error) { |
| 418 | resolve( |
| 419 | stdout |
| 420 | .trim() |
| 421 | .split('\n') |
| 422 | .map(line => line.replace(/\r$/, '')) |
| 423 | .filter(Boolean), |
| 424 | ) |
| 425 | return |
| 426 | } |
| 427 | |
| 428 | // Exit code 1 is normal "no matches" |
| 429 | if (error.code === 1) { |
| 430 | resolve([]) |
| 431 | return |
| 432 | } |
| 433 | |
| 434 | // Critical errors that indicate ripgrep is broken, not "no matches" |
| 435 | // These should be surfaced to the user rather than silently returning empty results |
| 436 | const CRITICAL_ERROR_CODES = ['ENOENT', 'EACCES', 'EPERM'] |
| 437 | if (CRITICAL_ERROR_CODES.includes(error.code as string)) { |
| 438 | reject(error) |
| 439 | return |
| 440 | } |
| 441 | |
| 442 | // If we hit EAGAIN and haven't retried yet, retry with single-threaded mode |
| 443 | // Note: We only use -j 1 for this specific retry, not for future calls. |
| 444 | // Persisting single-threaded mode globally caused timeouts on large repos |
| 445 | // where EAGAIN was just a transient startup error. |
| 446 | if (!isRetry && isEagainError(stderr)) { |
| 447 | logForDebugging( |
| 448 | `rg EAGAIN error detected, retrying with single-threaded mode (-j 1)`, |
| 449 | ) |
| 450 | logEvent('tengu_ripgrep_eagain_retry', {}) |
| 451 | ripGrepRaw( |
| 452 | args, |
| 453 | target, |
| 454 | abortSignal, |
no test coverage detected