#!/usr/bin/env bun /** * Terminal capability detection diagnostic test. * * Shows what ink-picture detects about the current terminal: * env vars, escape sequence query results, and the final protocol. * * Usage: * bun run src/ink-picture/__tests__/TerminalDetection.test.tsx */ import React, { useEffect, useState } from 'react' import { render, Box, Text, useApp } from 'ink' import Image, { InkPictureProvider, type TerminalInfo, useTerminalInfo, } from '../index.ts' /** * Probe Kitty graphics protocol directly via raw escape sequences. * Uses fs.writeSync to stdout and intercepts stdin responses, * bypassing Ink's input pipeline. */ async function probeKittyDirect(): Promise<{ protocol: string }> { return new Promise(resolve => { const result = { protocol: 'no-response' } if (!process.stdout.isTTY || !process.stdin.isTTY) { resolve(result) return } const origPush = process.stdin.push.bind(process.stdin) let resolved = false const finish = (label: string) => { if (resolved) return resolved = true process.stdin.push = origPush as any result.protocol = label resolve(result) } process.stdin.push = ((chunk: any) => { const str = Buffer.isBuffer(chunk) ? chunk.toString() : String(chunk) // Kitty OK response if (/\x1b_Gi=31;OK\x1b\\/.test(str)) { finish('kitty-ok') return origPush(chunk) } // DA1 sentinel — kitty response should arrive before or with DA1 if (/\x1b\[\?(\d+(?:;\d+)*)c/.test(str)) { // Give kitty response a chance if it arrived in same chunk after DA setTimeout(() => finish('no-kitty'), 200) } return origPush(chunk) }) as any const query = '\x1b[8m' + '\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\' + '\x1b[c' + '\x1b[2K\r' + '\x1b[0m' try { process.stdin.setRawMode?.(true) require('fs').writeSync(process.stdout.fd, query) } catch {} setTimeout(() => finish('timeout'), 2000) }) } function DetectionApp() { const { exit } = useApp() const terminalInfo = useTerminalInfo() const [probeResult, setProbeResult] = useState('probing...') useEffect(() => { probeKittyDirect().then(r => { setProbeResult(JSON.stringify(r)) }) const timer = setTimeout(() => exit(), 5000) return () => clearTimeout(timer) }, [exit]) const env: Record = { TERM_PROGRAM: process.env.TERM_PROGRAM, TERM: process.env.TERM, KITTY_WINDOW_ID: process.env.KITTY_WINDOW_ID, GHOSTTY_RESOURCES_DIR: process.env.GHOSTTY_RESOURCES_DIR, TERM_PROGRAM_VERSION: process.env.TERM_PROGRAM_VERSION, COLORTERM: process.env.COLORTERM, WEZTERM_PANE: process.env.WEZTERM_PANE, KONSOLE_VERSION: process.env.KONSOLE_VERSION, XTERM_VERSION: process.env.XTERM_VERSION, VTE_VERSION: process.env.VTE_VERSION, } return ( Terminal Detection Diagnostic {' '} Environment Variables: {Object.entries(env).map(([k, v]) => ( {' '} {k}: {v ?? '(not set)'} ))} {' '} Direct Kitty Probe (raw escape sequence): {probeResult} {' '} InkPictureProvider TerminalInfo: {' '}supportsKittyGraphics: {String(terminalInfo.supportsKittyGraphics)} {' '}supportsSixelGraphics: {String(terminalInfo.supportsSixelGraphics)} {' '}supportsITerm2Graphics: {String(terminalInfo.supportsITerm2Graphics)} {' '}supportsUnicode: {String(terminalInfo.supportsUnicode)} {' '}supportsColor: {String(terminalInfo.supportsColor)} {' '}cell: {terminalInfo.cellWidth}x{terminalInfo.cellHeight} {' '}terminal: {terminalInfo.terminalWidth}x{terminalInfo.terminalHeight} ) } const { waitUntilExit } = render( , ) await waitUntilExit()