* Generic function to load markdown files from specified directories * @param dir Directory (eg. "~/.claude/commands") * @returns Array of parsed markdown files with metadata
(dir: string)
| 544 | * @returns Array of parsed markdown files with metadata |
| 545 | */ |
| 546 | async function loadMarkdownFiles(dir: string): Promise< |
| 547 | { |
| 548 | filePath: string |
| 549 | frontmatter: FrontmatterData |
| 550 | content: string |
| 551 | }[] |
| 552 | > { |
| 553 | // File search strategy: |
| 554 | // - Default: ripgrep (faster, battle-tested) |
| 555 | // - Fallback: native Node.js (when CLAUDE_CODE_USE_NATIVE_FILE_SEARCH is set) |
| 556 | // |
| 557 | // Why both? Ripgrep has poor startup performance in native builds. |
| 558 | const useNative = isEnvTruthy(process.env.CLAUDE_CODE_USE_NATIVE_FILE_SEARCH) |
| 559 | const signal = AbortSignal.timeout(3000) |
| 560 | let files: string[] |
| 561 | try { |
| 562 | files = useNative |
| 563 | ? await findMarkdownFilesNative(dir, signal) |
| 564 | : await ripGrep( |
| 565 | ['--files', '--hidden', '--follow', '--no-ignore', '--glob', '*.md'], |
| 566 | dir, |
| 567 | signal, |
| 568 | ) |
| 569 | } catch (e: unknown) { |
| 570 | // Handle missing/inaccessible dir directly instead of pre-checking |
| 571 | // existence (TOCTOU). findMarkdownFilesNative already catches internally; |
| 572 | // ripGrep rejects on inaccessible target paths. |
| 573 | if (isFsInaccessible(e)) return [] |
| 574 | throw e |
| 575 | } |
| 576 | |
| 577 | const results = await Promise.all( |
| 578 | files.map(async filePath => { |
| 579 | try { |
| 580 | const rawContent = await readFile(filePath, { encoding: 'utf-8' }) |
| 581 | const { frontmatter, content } = parseFrontmatter(rawContent, filePath) |
| 582 | |
| 583 | return { |
| 584 | filePath, |
| 585 | frontmatter, |
| 586 | content, |
| 587 | } |
| 588 | } catch (error) { |
| 589 | const errorMessage = |
| 590 | error instanceof Error ? error.message : String(error) |
| 591 | logForDebugging( |
| 592 | `Failed to read/parse markdown file: ${filePath}: ${errorMessage}`, |
| 593 | ) |
| 594 | return null |
| 595 | } |
| 596 | }), |
| 597 | ) |
| 598 | |
| 599 | return results.filter(_ => _ !== null) |
| 600 | } |
no test coverage detected