From 8b21ab8d4aff80ec72cd0e149143e76fbf3dd6d5 Mon Sep 17 00:00:00 2001 From: Mplan Date: Tue, 16 Jun 2026 02:00:53 +0800 Subject: [PATCH] feat(terminal): add dynamic color with NO_COLOR/FORCE_COLOR support - Convert static ANSI constants to functions for dynamic color control - Respect NO_COLOR convention (https://no-color.org/) - Support FORCE_COLOR for CI/CD environments - setColorEnabled() API for --no-color flag integration --- src/terminal.ts | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/terminal.ts b/src/terminal.ts index 769649c..df203b3 100644 --- a/src/terminal.ts +++ b/src/terminal.ts @@ -1,7 +1,35 @@ -export const BOLD = "\x1b[1m"; -export const GREEN = "\x1b[32m"; -export const YELLOW = "\x1b[33m"; -export const CYAN = "\x1b[36m"; -export const RED = "\x1b[31m"; -export const DIM = "\x1b[2m"; -export const RESET = "\x1b[0m"; +// Terminal styling utilities. +// Respects NO_COLOR convention, --no-color flag, and TTY detection. + +import { isStdoutTTY } from "./tty"; + +let _enabled: boolean | null = null; + +export function setColorEnabled(enabled: boolean): void { + _enabled = enabled; +} + +export function isColorEnabled(): boolean { + if (_enabled !== null) return _enabled; + + // Respect NO_COLOR: https://no-color.org/ + if (process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== "") { + return false; + } + if (!isStdoutTTY()) return false; + if (process.env.FORCE_COLOR && process.env.FORCE_COLOR !== "0") return true; + + return true; +} + +function s(code: string): string { + return isColorEnabled() ? code : ""; +} + +export const BOLD = () => s("\x1b[1m"); +export const DIM = () => s("\x1b[2m"); +export const GREEN = () => s("\x1b[32m"); +export const YELLOW = () => s("\x1b[33m"); +export const CYAN = () => s("\x1b[36m"); +export const RED = () => s("\x1b[31m"); +export const RESET = () => s("\x1b[0m");