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