Repository navigation
[terminal-stylist] Terminal Stylist audit: stream-aware console output and Charmbracelet usage #67164
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Overview
The terminal UI foundation is strong:
pkg/stylescentralizes an adaptive Lipgloss palette,pkg/consoleprovides semantic formatters and Huh wrappers, tables uselipgloss/table, and animated components generally gate themselves on TTY/accessibility checks.The main consistency defect is stream-aware styling. A large amount of text written to
stderris formatted by helpers that inspectstdout. This can suppress styling in an interactive terminal or emit ANSI into redirectedstderr, depending on which stream is a TTY.Scope: all 1,513 non-test Go files were statically scanned, with detailed review focused on the 1,493 files under
pkg/. Test files and non-Go files were excluded.Key metrics and issues
pkg/pkg/files withfmt.Print*/fmt.Fprint*callspkg/files usingconsole.*callspkg/files importing/using Lipglosspkg/files importing/using Huhstderr/formatter stream mismatches1. High: formatters inspect the wrong stream
There are 1,588 direct writes where an stdout-oriented formatter is passed to
os.Stderr:FormatInfoMessageFormatWarningMessageFormatSuccessMessageFormatVerboseMessageFormatCommandMessageFormatProgressMessageFormatSectionHeaderExample:
FormatInfoMessagecalls the stdout TTY detector. If stdout is piped but stderr is interactive, the status loses styling. If stdout is interactive but stderr is redirected, styled bytes can be written into the redirected stream.Prefer the already available writer-aware path:
or, where composition is necessary:
This pattern appears broadly in
pkg/cli/, includingstatus_command.go,mcp_inspect.go,run_workflow_execution.go,update_workflows.go, and audit/log rendering files.2. High: two styled trees bypass TTY/color-profile handling
pkg/cli/mcp_inspect.go:193-228pkg/cli/status_command.go:436-460Both construct
lipgloss/treeoutput withstyles.TreeEnumeratorandstyles.TreeNode, callString(), then write directly tostderr. Unlikeconsole.RenderTable, these paths do not select styles based on the destination TTY and do not pass throughcolorwriter.Stderr().Add a console-level tree renderer that accepts the destination stream/TTY policy, or conditionally attach tree styles only when
tty.IsStderrTerminal()and write through the color-profile-aware stderr writer.3. Medium: banner styling checks stdout but writes stderr
pkg/console/banner.gocallsFormatBanner(), which uses the stdout-orientedapplyStyle, and then writes the result tostderrWriter(). This is the same split-stream defect in a centralized component. AddFormatBannerStderr, or havePrintBannerrender throughapplyStderrStyledirectly.4. Medium: raw user-facing diagnostics remain inconsistent
There are legitimate raw writes for tables, structured reports, subprocess output, JSON, and shell completion. However, several human-facing failures and warnings bypass semantic console formatting, for example:
pkg/cli/add_interactive_workflow.go:129,246— rawStatus check error/gh workflow list failedpkg/cli/mcp_inspect_mcp.go:574,588— raw schema display errorspkg/workflow/cache_steps.go:23— rawWarning:diagnosticpkg/workflow/compiler_orchestrator_engine.go:289,295— raw uppercase warningspkg/workflow/mcp_renderer.go:111— raw generation errorRoute CLI diagnostics through
console.PrintErrorMessage/PrintWarningMessage. For compiler diagnostics, retain the IDE-parseablefile:line:column: type: messagecontract and centralize rendering rather than adding decorative prefixes indiscriminately.What is working well
Representative files and patterns using the console stack correctly
pkg/console/console.go— semantic styles, stdout/stderr variants, TTY gating, color-profile degradation, andlipgloss/tableintegration.pkg/styles/theme.go— centralized semantic palette with light/dark adaptive colors and reusable borders/styles.pkg/styles/huh_theme.go— one palette shared with Huh vialipgloss.LightDark.pkg/console/prompt_form.go— common Huh theme, accessibility mode, dual stdin/stderr TTY checks, and controlled cleanup.pkg/console/spinner.go— stderr TTY detection, accessibility-aware animation suppression, and single-spinner coordination.pkg/console/progress.go— visual TTY rendering with a plain-text non-TTY fallback.pkg/console/terminal.go— raw ANSI is limited to cursor/screen operations that Lipgloss does not model and is guarded by stderr TTY checks.pkg/tty/tty.goandpkg/colorwriter/colorprofile_writer.go— clear centralized terminal detection andNO_COLOR/terminal-profile handling.pkg/cli/experiments_render.go— correctly suppliesTTYFunc: tty.IsStderrTerminalto tables destined for stderr.pkg/cli/engine_secrets.go,logs_format_compact.go,logs_report.go,logs_work_queue_render.go, andmcp_inspect_mcp.gohave begun adopting the directconsole.Print*helpers (72 calls across these five files).pkg/cli/work_command_tui_view.go— responsive width/height handling, small-terminal fallback, alternate-screen usage, and keyboard help.Lipgloss assessment
pkg/styles.pkg/consolehelpers; inconsistent when callers render Lipgloss objects directly or select an stdout formatter for stderr.console.RenderTableis the correct standard. It already handles borders, zebra rows, totals, and destination-specific TTY checks. Prefer it over new hand-aligned tables where output is intended for humans.terminal.goandprompt_form.goare cursor-control operations, are documented, and are appropriately TTY-gated.Huh assessment
All reviewed CLI Huh forms route through
console.NewForm,NewInputForm,NewSelectForm, orNewConfirmForm, so they inherit the shared theme and accessible mode. Password input usesEchoModePassword, and the shared form runner rejects non-interactive stdin/stderr combinations.Opportunities:
pkg/console/list.gouses package-levelfmt.Scanfin its text fallback, unlikeshowTextConfirm, which accepts anio.Reader. Accept a reader consistently for testability and predictable input ownership.NO_COLORenables Huh accessible mode and disables spinners.NO_COLORnecessarily means no color, but does not always mean the user wants a different interaction model. KeepACCESSIBLEandTERM=dumbas explicit accessibility signals; handle color suppression independently.Recommended next actions
console.Print*; add missing stderr variants or a destination-aware formatter/printer abstraction for composed output.fmt.Fprint*(os.Stderr, console.FormatX(...))whenFormatXis stdout-oriented, and the inverse for stdout.NO_COLORfrom screen-reader-oriented interaction changes.(TTY, pipe),(pipe, TTY),NO_COLOR, andTERM=dumb.Method and limitations
The inventory used a lexical scan of every non-test
.gofile, followed by targeted source review ofpkg/console,pkg/styles,pkg/tty,pkg/colorwriter, direct Lipgloss users, direct Huh users, and representative CLI/compiler output sites. Counts describe source call sites, not runtime execution frequency.Serena project activation succeeded, but its Go language server could not initialize because the Serena service reported that Go was unavailable in its environment. Semantic symbol/reference queries were therefore unavailable; analysis continued with repository-local source scanning and targeted reads.
References: §37907719497
All reactions