| 19 | * Never throws — returns the content string or exits with error JSON. |
| 20 | */ |
| 21 | export async function readInput(filePath: string): Promise<string> { |
| 22 | if (filePath === '-') { |
| 23 | // Read from stdin |
| 24 | const chunks: Buffer[] = []; |
| 25 | for await (const chunk of process.stdin) { |
| 26 | chunks.push(chunk as Buffer); |
| 27 | } |
| 28 | return Buffer.concat(chunks).toString('utf-8'); |
| 29 | } |
| 30 | |
| 31 | try { |
| 32 | return readFileSync(filePath, 'utf-8'); |
| 33 | } catch (error) { |
| 34 | console.error(JSON.stringify({ |
| 35 | error: 'FILE_READ_ERROR', |
| 36 | message: error instanceof Error ? error.message : String(error), |
| 37 | path: filePath, |
| 38 | })); |
| 39 | process.exitCode = 2; |
| 40 | throw error; // bubbles up, but process will exit with code 2 if uncaught |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | /** |
| 45 | * Format output as JSON or human-readable text. |