feat(color): add semantic terminal coloring via color_mode config (#24)#72
Conversation
Add resolve_color(mode, *, is_tty) function to resolve color mode to boolean. Add color: bool = False field to RuntimeContext. Add color: bool = False parameter to emit_envelope signature. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t_envelope - Update render_to_rich_stderr signature to accept color: bool = False - When color=True, use force_terminal=True for ANSI codes - When color=False, use no_color=True and highlight=False to suppress markup - Complete emit_envelope body to pass color to render_to_rich_stderr - Add comprehensive tests for color parameter behavior Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add explicit OutputFormat.TABLE check before applying color in delete responses - Set no_color=False on Console to enable ANSI output to test streams - Fix line-length issue by splitting console instantiation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves the duplicated Console-construction pattern into nsc/output/_console.py and updates table.py, errors.py, explain.py, and handlers.py to use it; also removes the spurious no_color=False default from the delete helpers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Code reviewFound 1 issue:
netbox-super-cli/nsc/output/_console.py Lines 10 to 13 in bc56b2a Fix: add def make_console(stream: TextIO, *, color: bool, soft_wrap: bool = False) -> Console:
if color:
return Console(file=stream, force_terminal=True, highlight=False, soft_wrap=soft_wrap)
return Console(file=stream, no_color=True, highlight=False, soft_wrap=soft_wrap)Verified against the live Rich library: plain 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Advisory findings (below confidence threshold)These issues scored 75/100 — verified real but not certain enough to block. Flagged for awareness:
netbox-super-cli/nsc/cli/globals.py Lines 56 to 60 in bc56b2a
netbox-super-cli/nsc/output/errors.py Lines 103 to 121 in bc56b2a
netbox-super-cli/nsc/output/explain.py Lines 153 to 156 in bc56b2a 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
# Conflicts: # nsc/cli/globals.py # nsc/output/errors.py # uv.lock
…, disable highlighter - make_console(color=True) now sets highlight=False so Rich's auto-highlighter no longer bolds parens / colorizes numbers in plain output. - Escape API/user-sourced text (env.error/endpoint/details, table cells, explain reasoning) before it reaches Rich markup parsing, on every output path — Rich parses markup even in no-color mode. - RuntimeContext gains color_stderr, resolved from sys.stderr.isatty() independently of stdout; emit_envelope calls now use it so `nsc ... 2>file` no longer leaks ANSI into the redirected file. - Add test_console.py, test_explain_color.py, test_globals_color.py, and markup-escape regression tests for table/errors/explain. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Picked up review fixes. Merged latest main (resolved conflicts in globals.py/errors.py/uv.lock), addressed all review feedback: highlight=False on color console, escape API/user text before Rich markup (table/errors/explain, both color modes), and split RuntimeContext.color_stderr from stdout color so |
…test PR #44 added a "Fetch and cache the live schema now?" confirm after `nsc login --new`, but the e2e test fed only the token line — the confirm then hit EOF and aborted (exit 1). e2e has been red on main since #44. Feed `n` to decline the fetch; the test only asserts profile creation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
ColorModeStrEnum (auto|on|off) to config withdefaults.color_mode: autodefaultresolve_color()andcolor: booltoRuntimeContext; resolved once at bootstrap viasys.stdout.isatty()active→green,failed→red,planned→yellow), booleans, and empty cellsdeletedin yellow,already absentdimmed)color_mode: offsuppresses all Rich markup including existing error/explain panelsTest Plan
just test— 656 passed, 1 skippedjust lint— ruff + mypy --strict cleannsc <resource> listin a TTY shows colored status cellsnsc <resource> list | catproduces plain output (auto mode)defaults.color_mode: offin config — no ANSI anywheredefaults.color_mode: on— colors even when pipedCloses #24
🤖 Generated with Claude Code