* Capture untracked files (git diff doesn't include them). * Respects size limits and skips binary files.
()
| 629 | * Respects size limits and skips binary files. |
| 630 | */ |
| 631 | async function captureUntrackedFiles(): Promise< |
| 632 | Array<{ path: string; content: string }> |
| 633 | > { |
| 634 | const { stdout, code } = await execFileNoThrow( |
| 635 | gitExe(), |
| 636 | ['ls-files', '--others', '--exclude-standard'], |
| 637 | { preserveOutputOnError: false }, |
| 638 | ) |
| 639 | |
| 640 | const trimmed = stdout.trim() |
| 641 | if (code !== 0 || !trimmed) { |
| 642 | return [] |
| 643 | } |
| 644 | |
| 645 | const files = trimmed.split('\n').filter(Boolean) |
| 646 | const result: Array<{ path: string; content: string }> = [] |
| 647 | let totalSize = 0 |
| 648 | |
| 649 | for (const filePath of files) { |
| 650 | // Check file count limit |
| 651 | if (result.length >= MAX_FILE_COUNT) { |
| 652 | logForDebugging( |
| 653 | `Untracked file capture: reached max file count (${MAX_FILE_COUNT})`, |
| 654 | ) |
| 655 | break |
| 656 | } |
| 657 | |
| 658 | // Skip binary files by extension - zero I/O |
| 659 | if (hasBinaryExtension(filePath)) { |
| 660 | continue |
| 661 | } |
| 662 | |
| 663 | try { |
| 664 | const stats = await stat(filePath) |
| 665 | const fileSize = stats.size |
| 666 | |
| 667 | // Skip files exceeding per-file limit |
| 668 | if (fileSize > MAX_FILE_SIZE_BYTES) { |
| 669 | logForDebugging( |
| 670 | `Untracked file capture: skipping ${filePath} (exceeds ${MAX_FILE_SIZE_BYTES} bytes)`, |
| 671 | ) |
| 672 | continue |
| 673 | } |
| 674 | |
| 675 | // Check total size limit |
| 676 | if (totalSize + fileSize > MAX_TOTAL_SIZE_BYTES) { |
| 677 | logForDebugging( |
| 678 | `Untracked file capture: reached total size limit (${MAX_TOTAL_SIZE_BYTES} bytes)`, |
| 679 | ) |
| 680 | break |
| 681 | } |
| 682 | |
| 683 | // Empty file - no need to open |
| 684 | if (fileSize === 0) { |
| 685 | result.push({ path: filePath, content: '' }) |
| 686 | continue |
| 687 | } |
| 688 |
no test coverage detected