/** * IPC Layer - stdin/stdout JSON-line communication */ import { createInterface } from 'node:readline'; import type { FrontendMessage, BackendMessage } from '@tiny-workshop/ipc-types'; /** * Emit a message to the frontend via stdout * * Uses process.stdout.write directly to bypass stdout protection. * This is the ONLY place that should write to stdout! */ export function emit(msg: BackendMessage): void { process.stdout.write(JSON.stringify(msg) + '\n'); } /** * Start listening for messages from frontend via stdin * * @param handler - Async function to handle each message */ export function startIpcListener( handler: (msg: FrontendMessage) => void | Promise ): void { const rl = createInterface({ input: process.stdin, crlfDelay: Infinity, }); rl.on('line', async (line) => { // Skip empty lines if (!line.trim()) return; try { const msg = JSON.parse(line) as FrontendMessage; await handler(msg); } catch (error) { emit({ type: 'error', code: 'PARSE_ERROR', message: `Failed to parse message: ${error}`, recoverable: true, }); } }); rl.on('close', () => { // Frontend closed stdin, exit gracefully process.exit(0); }); }