From dbdd2ee635b42c431a220eeb7edd755b04af3a08 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 23:05:05 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Improve=20CLI=20UX=20?= =?UTF-8?q?with=20Progress=20Bar=20and=20NO=5FCOLOR=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 What: Added a dynamic progress bar for rule pushing and implemented NO_COLOR standard support. 🎯 Why: Pushing rules involves many batches which previously spammed the logs. A progress bar provides better feedback and reduces noise. NO_COLOR support improves accessibility. ♿ Accessibility: Respects NO_COLOR environment variable. --- .jules/palette.md | 8 ++++++++ main.py | 28 ++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index fbedb303..7be86fd3 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -14,3 +14,11 @@ ## 2024-03-22 - CLI Interactive Fallbacks **Learning:** CLI tools often fail hard when config is missing, but interactive contexts allow for graceful recovery. Users appreciate being asked for missing info instead of just receiving an error. **Action:** When `sys.stdin.isatty()` is true, prompt for missing configuration instead of exiting with an error code. + +## 2025-05-24 - CLI Accessibility Standards +**Learning:** CLI tools often lack standard accessibility features like `NO_COLOR` support, assuming TTY checks are enough. However, users may want to disable colors even in TTYs for contrast reasons. +**Action:** Always check `os.getenv("NO_COLOR")` in CLI tools alongside TTY checks to respect user preference. + +## 2025-05-24 - Reducing CLI Log Noise +**Learning:** High-volume repetitive logs (like batch processing) drown out important errors and context. +**Action:** Use single-line overwriting updates (`\r`) for repetitive progress in interactive sessions, falling back to standard logging for non-interactive streams. diff --git a/main.py b/main.py index e6aabc57..59c52bde 100644 --- a/main.py +++ b/main.py @@ -35,7 +35,11 @@ load_dotenv() # Determine if we should use colors -USE_COLORS = sys.stderr.isatty() and sys.stdout.isatty() +# Respect NO_COLOR standard (https://no-color.org/) +if os.getenv("NO_COLOR"): + USE_COLORS = False +else: + USE_COLORS = sys.stderr.isatty() and sys.stdout.isatty() class Colors: if USE_COLORS: @@ -504,10 +508,16 @@ def push_rules( try: _api_post_form(client, f"{API_BASE}/{profile_id}/rules", data=data) - log.info( - "Folder %s – batch %d: added %d rules", - sanitize_for_log(folder_name), i, len(batch) - ) + + if USE_COLORS: + sys.stderr.write(f"\r{Colors.CYAN}🚀 Folder {sanitize_for_log(folder_name)}: Pushing batch {i}/{total_batches}...{Colors.ENDC}") + sys.stderr.flush() + else: + log.info( + "Folder %s – batch %d: added %d rules", + sanitize_for_log(folder_name), i, len(batch) + ) + successful_batches += 1 if existing_rules_lock: with existing_rules_lock: @@ -515,12 +525,18 @@ def push_rules( else: existing_rules.update(batch) except httpx.HTTPError as e: + if USE_COLORS: + sys.stderr.write("\n") log.error(f"Failed to push batch {i} for folder {sanitize_for_log(folder_name)}: {sanitize_for_log(e)}") if hasattr(e, 'response') and e.response is not None: log.debug(f"Response content: {e.response.text}") if successful_batches == total_batches: - log.info("Folder %s – finished (%d new rules added)", sanitize_for_log(folder_name), len(filtered_hostnames)) + if USE_COLORS: + sys.stderr.write(f"\r{Colors.GREEN}✅ Folder {sanitize_for_log(folder_name)}: Finished ({len(filtered_hostnames)} rules) {Colors.ENDC}\n") + sys.stderr.flush() + else: + log.info("Folder %s – finished (%d new rules added)", sanitize_for_log(folder_name), len(filtered_hostnames)) return True else: log.error("Folder %s – only %d/%d batches succeeded", sanitize_for_log(folder_name), successful_batches, total_batches)