spb/khaelor Public
KHAELOR — a terminal-native autonomous engineering agent powered by Anthropic.
TypeScript 82.9%
HTML 14.9%
CSS 1.1%
JavaScript 0.7%
1/**2 * KHAELOR3 * File: src/tui/renderer/terminal.ts4 * Description: Terminal session guard — raw mode + bracketed paste on mount, guaranteed restore on exit and on crash.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import {11 BRACKETED_PASTE_OFF,12 BRACKETED_PASTE_ON,13 SHOW_CURSOR,14 SYNC_OFF,15} from "./ansi.js";1617export interface TerminalSession {18 /** Restore the terminal to its pre-mount state. Idempotent. */19 restore(): void;20}2122/**23 * Enter KHAELOR's terminal state: raw mode, bracketed paste. Installs24 * process-level handlers so the terminal is restored on normal exit, on25 * SIGTERM/SIGHUP, and on crash (uncaughtException / unhandledRejection) —26 * a dead KHAELOR must never leave the user's shell in raw mode with a27 * hidden cursor (CLAUDE.md §14).28 */29export function enterTerminal(30 stdin: NodeJS.ReadStream,31 stdout: NodeJS.WriteStream,32): TerminalSession {33 const wasRaw = stdin.isTTY ? stdin.isRaw : false;34 if (stdin.isTTY) stdin.setRawMode(true);35 stdin.resume();36 stdout.write(BRACKETED_PASTE_ON);3738 let restored = false;39 const restore = (): void => {40 if (restored) return;41 restored = true;42 // Undo everything a paint could have left half-done.43 stdout.write(SYNC_OFF + SHOW_CURSOR + BRACKETED_PASTE_OFF);44 if (stdin.isTTY) stdin.setRawMode(wasRaw);45 stdin.pause();46 process.off("exit", onExit);47 process.off("SIGTERM", onSignal);48 process.off("SIGHUP", onSignal);49 process.off("uncaughtException", onFatal);50 process.off("unhandledRejection", onFatal);51 };5253 const onExit = (): void => {54 restore();55 };56 const onSignal = (): void => {57 restore();58 process.exit(1);59 };60 const onFatal = (error: unknown): void => {61 restore();62 const message = error instanceof Error ? (error.stack ?? error.message) : String(error);63 process.stderr.write(`\nkhaelor: fatal error\n${message}\n`);64 process.exit(1);65 };6667 process.on("exit", onExit);68 process.on("SIGTERM", onSignal);69 process.on("SIGHUP", onSignal);70 process.on("uncaughtException", onFatal);71 process.on("unhandledRejection", onFatal);7273 return { restore };74}75