source dump of claude code
at main 68 lines 2.3 kB view raw
1function handleEPIPE( 2 stream: NodeJS.WriteStream, 3): (err: NodeJS.ErrnoException) => void { 4 return (err: NodeJS.ErrnoException) => { 5 if (err.code === 'EPIPE') { 6 stream.destroy() 7 } 8 } 9} 10 11// Prevents memory leak when pipe is broken (e.g., `claude -p | head -1`) 12export function registerProcessOutputErrorHandlers(): void { 13 process.stdout.on('error', handleEPIPE(process.stdout)) 14 process.stderr.on('error', handleEPIPE(process.stderr)) 15} 16 17function writeOut(stream: NodeJS.WriteStream, data: string): void { 18 if (stream.destroyed) { 19 return 20 } 21 22 // Note: we don't handle backpressure (write() returning false). 23 // 24 // We should consider handling the callback to ensure we wait for data to flush. 25 stream.write(data /* callback to handle here */) 26} 27 28export function writeToStdout(data: string): void { 29 writeOut(process.stdout, data) 30} 31 32export function writeToStderr(data: string): void { 33 writeOut(process.stderr, data) 34} 35 36// Write error to stderr and exit with code 1. Consolidates the 37// console.error + process.exit(1) pattern used in entrypoint fast-paths. 38export function exitWithError(message: string): never { 39 // biome-ignore lint/suspicious/noConsole:: intentional console output 40 console.error(message) 41 // eslint-disable-next-line custom-rules/no-process-exit 42 process.exit(1) 43} 44 45// Wait for a stdin-like stream to close, but give up after ms if no data ever 46// arrives. First data chunk cancels the timeout — after that, wait for end 47// unconditionally (caller's accumulator needs all chunks, not just the first). 48// Returns true on timeout, false on end. Used by -p mode to distinguish a 49// real pipe producer from an inherited-but-idle parent stdin. 50export function peekForStdinData( 51 stream: NodeJS.EventEmitter, 52 ms: number, 53): Promise<boolean> { 54 return new Promise<boolean>(resolve => { 55 const done = (timedOut: boolean) => { 56 clearTimeout(peek) 57 stream.off('end', onEnd) 58 stream.off('data', onFirstData) 59 void resolve(timedOut) 60 } 61 const onEnd = () => done(false) 62 const onFirstData = () => clearTimeout(peek) 63 // eslint-disable-next-line no-restricted-syntax -- not a sleep: races timeout against stream end/data events 64 const peek = setTimeout(done, ms, true) 65 stream.once('end', onEnd) 66 stream.once('data', onFirstData) 67 }) 68}