/** * Minimal terminal interface for TUI */ export interface Terminal { // Start the terminal with input and resize handlers start(onInput: (data: string) => void, onResize: () => void): void; // Stop the terminal and restore state stop(): void; // Write output to terminal write(data: string): void; // Get terminal dimensions get columns(): number; get rows(): number; } /** * Real terminal using process.stdin/stdout */ export class ProcessTerminal implements Terminal { private wasRaw = false; private inputHandler?: (data: string) => void; private resizeHandler?: () => void; start(onInput: (data: string) => void, onResize: () => void): void { this.inputHandler = onInput; this.resizeHandler = onResize; // Save previous state and enable raw mode this.wasRaw = process.stdin.isRaw || false; if (process.stdin.setRawMode) { process.stdin.setRawMode(true); } process.stdin.setEncoding("utf8"); process.stdin.resume(); // Set up event handlers process.stdin.on("data", this.inputHandler); process.stdout.on("resize", this.resizeHandler); } stop(): void { // Remove event handlers if (this.inputHandler) { process.stdin.removeListener("data", this.inputHandler); this.inputHandler = undefined; } if (this.resizeHandler) { process.stdout.removeListener("resize", this.resizeHandler); this.resizeHandler = undefined; } // Restore raw mode state if (process.stdin.setRawMode) { process.stdin.setRawMode(this.wasRaw); } } write(data: string): void { process.stdout.write(data); } get columns(): number { return process.stdout.columns || 80; } get rows(): number { return process.stdout.rows || 24; } }