import { stripVTControlCharacters } from 'node:util'; function removeUnsafeControlCharacters(value: string): string { const safe: string[] = []; for (const character of value) { const codePoint = character.codePointAt(0) ?? 0; const isC0OrC1 = codePoint <= 0x08 || codePoint === 0x0b || codePoint === 0x0c || (codePoint >= 0x0e && codePoint <= 0x1f) || (codePoint >= 0x7f && codePoint <= 0x9f); const isDirectionalControl = codePoint === 0x061c || codePoint === 0x200e || codePoint === 0x200f || (codePoint >= 0x202a && codePoint <= 0x202e) || (codePoint >= 0x2066 && codePoint <= 0x2069); if (!isC0OrC1 && !isDirectionalControl) safe.push(character); } return safe.join(''); } /** * Remove terminal escape sequences and invisible control characters from * untrusted text before rendering it in human-readable CLI output. * * JSON and export paths must keep their raw data and should not use this * function. Newlines can be retained for Article bodies; tabs are always * expanded so remote text cannot move the cursor unpredictably. */ export function sanitizeTerminalText(value: string, options: { preserveNewlines?: boolean } = {}): string { const normalized = stripVTControlCharacters(value).replace(/\r\n?/g, '\n').replace(/\t/g, ' '); const sanitized = removeUnsafeControlCharacters(normalized); return options.preserveNewlines ? sanitized : sanitized.replace(/\n/g, ' '); }