import { execFile } from "node:child_process"; import { promisify } from "node:util"; import type { AppearanceMode, DetectionResult } from "./types.js"; const execFileAsync = promisify(execFile); function parseMode(value: string | undefined): AppearanceMode | undefined { const normalized = value?.trim().toLowerCase(); if (!normalized) return undefined; if (normalized === "dark" || normalized === "1" || normalized === "true") return "dark"; if (normalized === "light" || normalized === "0" || normalized === "false") return "light"; return undefined; } async function detectMacOs(): Promise { if (process.platform !== "darwin") return undefined; try { const { stdout } = await execFileAsync("osascript", [ "-e", 'tell application "System Events" to tell appearance preferences to return dark mode', ]); const darkMode = stdout.trim(); if (darkMode === "true") return { mode: "dark", source: "macos" }; if (darkMode === "false") return { mode: "light", source: "macos" }; } catch { // Ignore detector failure and continue down the chain. } return undefined; } async function detectWindows(): Promise { if (process.platform !== "win32") return undefined; try { const { stdout } = await execFileAsync("powershell.exe", [ "-NoProfile", "-NonInteractive", "-Command", "$v=(Get-ItemProperty -Path HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize -Name AppsUseLightTheme -ErrorAction Stop).AppsUseLightTheme; if ($v -eq 0) { 'dark' } elseif ($v -eq 1) { 'light' }", ]); const mode = parseMode(stdout); if (mode) return { mode, source: "windows" }; } catch { // Ignore detector failure and continue down the chain. } return undefined; } async function detectTmux(): Promise { if (!process.env.TMUX && process.env.TERM_PROGRAM !== "tmux") return undefined; try { const { stdout } = await execFileAsync("tmux", ["display-message", "-p", "#{client_theme}"]); const mode = parseMode(stdout); if (mode) return { mode, source: "tmux" }; } catch { // Ignore detector failure and continue down the chain. } return undefined; } function detectDarkModeEnv(): DetectionResult | undefined { const mode = parseMode(process.env.DARK_MODE); return mode ? { mode, source: "env:DARK_MODE" } : undefined; } function detectColorFgBg(): DetectionResult | undefined { const colorfgbg = process.env.COLORFGBG || ""; if (!colorfgbg) return undefined; const parts = colorfgbg.split(";"); if (parts.length < 2) return undefined; const bg = Number.parseInt(parts[1] ?? "", 10); if (Number.isNaN(bg)) return undefined; return { mode: bg < 8 ? "dark" : "light", source: "heuristic:COLORFGBG", }; } export async function detectAppearance(defaultMode: AppearanceMode = "dark"): Promise { return ( (await detectMacOs()) ?? (await detectWindows()) ?? (await detectTmux()) ?? detectDarkModeEnv() ?? detectColorFgBg() ?? { mode: defaultMode, source: `fallback:${defaultMode}` } ); }