| 24 | const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'out', '.next', '.nuxt', 'vendor', '.cache', 'coverage']); |
| 25 | |
| 26 | async function walkFiles(root: string, extensions: Set<string>, maxFiles: number): Promise<{ abs: string; rel: string; content: string }[]> { |
| 27 | const out: { abs: string; rel: string; content: string }[] = []; |
| 28 | const stack = [root]; |
| 29 | while (stack.length > 0 && out.length < maxFiles) { |
| 30 | const dir = stack.pop()!; |
| 31 | let entries; |
| 32 | try { entries = await fs.readdir(dir, { withFileTypes: true }); } catch { continue; } |
| 33 | for (const e of entries) { |
| 34 | if (out.length >= maxFiles) break; |
| 35 | if (e.isDirectory()) { |
| 36 | if (SKIP_DIRS.has(e.name) || e.name.startsWith('.')) continue; |
| 37 | stack.push(path.join(dir, e.name)); |
| 38 | } else if (e.isFile()) { |
| 39 | const ext = path.extname(e.name).toLowerCase(); |
| 40 | if (!extensions.has(ext)) continue; |
| 41 | const abs = path.join(dir, e.name); |
| 42 | try { |
| 43 | const stat = await fs.stat(abs); |
| 44 | if (stat.size > 2_000_000) continue; |
| 45 | const content = await fs.readFile(abs, 'utf-8'); |
| 46 | out.push({ abs, rel: path.relative(root, abs), content }); |
| 47 | } catch { /* skip */ } |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | return out; |
| 52 | } |
| 53 | |
| 54 | // ───────────────────────────────────────────────────────────────────────────── |
| 55 | // analyze_design_system |