* Fetch untracked file names (no content reading). * Returns file paths only - they'll be displayed with a note to stage them. * * @param maxFiles Maximum number of untracked files to include
( maxFiles: number, )
| 334 | * @param maxFiles Maximum number of untracked files to include |
| 335 | */ |
| 336 | async function fetchUntrackedFiles( |
| 337 | maxFiles: number, |
| 338 | ): Promise<Map<string, PerFileStats> | null> { |
| 339 | // Get list of untracked files (excludes gitignored) |
| 340 | const { stdout, code } = await execFileNoThrow( |
| 341 | gitExe(), |
| 342 | ['--no-optional-locks', 'ls-files', '--others', '--exclude-standard'], |
| 343 | { timeout: GIT_TIMEOUT_MS, preserveOutputOnError: false }, |
| 344 | ) |
| 345 | |
| 346 | if (code !== 0 || !stdout.trim()) return null |
| 347 | |
| 348 | const untrackedPaths = stdout.trim().split('\n').filter(Boolean) |
| 349 | if (untrackedPaths.length === 0) return null |
| 350 | |
| 351 | const perFileStats = new Map<string, PerFileStats>() |
| 352 | |
| 353 | // Just record filenames, no content reading |
| 354 | for (const filePath of untrackedPaths.slice(0, maxFiles)) { |
| 355 | perFileStats.set(filePath, { |
| 356 | added: 0, |
| 357 | removed: 0, |
| 358 | isBinary: false, |
| 359 | isUntracked: true, |
| 360 | }) |
| 361 | } |
| 362 | |
| 363 | return perFileStats |
| 364 | } |
| 365 | |
| 366 | /** |
| 367 | * Parse git diff --shortstat output into stats. |
no test coverage detected