From 3c8f91097393dd6d3c201f64fccf91b45ae1b9e3 Mon Sep 17 00:00:00 2001 From: SHL0MS <131039422+SHL0MS@users.noreply.github.com> Date: Mon, 30 Mar 2026 17:07:21 -0700 Subject: [PATCH] feat: respect NO_COLOR env var and TERM=dumb (#4079) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add should_use_color() function to hermes_cli/colors.py that checks NO_COLOR (https://no-color.org/) and TERM=dumb before emitting ANSI escapes. The existing color() helper now uses this function instead of a bare isatty() check. This is the foundation — cli.py and banner.py still have inline ANSI constants that bypass this module (tracked in #4071). Closes #4066 Co-authored-by: SHL0MS --- hermes_cli/colors.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/hermes_cli/colors.py b/hermes_cli/colors.py index d30f99c62..8c85b4c0b 100644 --- a/hermes_cli/colors.py +++ b/hermes_cli/colors.py @@ -1,8 +1,24 @@ """Shared ANSI color utilities for Hermes CLI modules.""" +import os import sys +def should_use_color() -> bool: + """Return True when colored output is appropriate. + + Respects the NO_COLOR environment variable (https://no-color.org/) + and TERM=dumb, in addition to the existing TTY check. + """ + if os.environ.get("NO_COLOR") is not None: + return False + if os.environ.get("TERM") == "dumb": + return False + if not sys.stdout.isatty(): + return False + return True + + class Colors: RESET = "\033[0m" BOLD = "\033[1m" @@ -16,7 +32,7 @@ class Colors: def color(text: str, *codes) -> str: - """Apply color codes to text (only when output is a TTY).""" - if not sys.stdout.isatty(): + """Apply color codes to text (only when color output is appropriate).""" + if not should_use_color(): return text return "".join(codes) + text + Colors.RESET