@@ -17,6 +17,12 @@ function parse(color: string): RGBA | null {
1717 return null
1818}
1919
20+ function mode ( background : RGBA | null ) : "dark" | "light" {
21+ if ( ! background ) return "dark"
22+ const luminance = ( 0.299 * background . r + 0.587 * background . g + 0.114 * background . b ) / 255
23+ return luminance > 0.5 ? "light" : "dark"
24+ }
25+
2026/**
2127 * Query terminal colors including background, foreground, and palette (0-15).
2228 * Uses OSC escape sequences to retrieve actual terminal color values.
@@ -94,3 +100,36 @@ export async function colors(): Promise<{
94100 } , 1000 )
95101 } )
96102}
103+
104+ // Keep startup mode detection separate from `colors()`: the TUI boot path only
105+ // needs OSC 11 and should resolve on the first background response instead of
106+ // waiting on the full palette query used by system theme generation.
107+ export async function getTerminalBackgroundColor ( ) : Promise < "dark" | "light" > {
108+ if ( ! process . stdin . isTTY ) return "dark"
109+
110+ return new Promise ( ( resolve ) => {
111+ let timeout : NodeJS . Timeout
112+
113+ const cleanup = ( ) => {
114+ process . stdin . setRawMode ( false )
115+ process . stdin . removeListener ( "data" , handler )
116+ clearTimeout ( timeout )
117+ }
118+
119+ const handler = ( data : Buffer ) => {
120+ const match = data . toString ( ) . match ( / \x1b ] 1 1 ; ( [ ^ \x07 \x1b ] + ) / )
121+ if ( ! match ) return
122+ cleanup ( )
123+ resolve ( mode ( parse ( match [ 1 ] ) ) )
124+ }
125+
126+ process . stdin . setRawMode ( true )
127+ process . stdin . on ( "data" , handler )
128+ process . stdout . write ( "\x1b]11;?\x07" )
129+
130+ timeout = setTimeout ( ( ) => {
131+ cleanup ( )
132+ resolve ( "dark" )
133+ } , 1000 )
134+ } )
135+ }
0 commit comments