Repository navigation
[terminal-stylist] Terminal Stylist: console output consistency analysis (pkg/, non-test Go) #76206
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.
Summary
Analyzed 1,696 non-test
.gofiles underpkg/(150 packages;_test.gofiles andtestdata/excluded). The centralpkg/consolepackage is in good shape: TTY-gated helpers, adaptive colors shared by Lipgloss and huh, a color-profile writer, and one themed, accessibility-aware wrapper that every interactive form goes through. The problems sit at the edges. A few styled outputs skip the color-profile writer, the progress bar checks the wrong stream, and status glyphs are doubled or inconsistent. Findings 1 to 5 change what users see in a terminal.Key metrics
fmt.Fprint*(os.Stderr, ...))console.*, 72%)console.*; sampled output is data and reports)fmt.Print*in production codepkg/styles/theme.go)console.New*Formhuh.NewFormoutsidepkg/consolepkg/workflowdirectos.Stderrwritesconsole.*)*Stderr-suffixed console calls vs unsuffixedFormat*/Render*callsPatterns to keep
pkg/console/console.go:applyStderrStyleroutes throughcolorwriter.Degrade, soNO_COLOR,COLORTERM, andTERMapply to helper output.pkg/console/prompt_form.go:NewFormappliesstyles.HuhThemeandWithAccessible(IsAccessibleMode()), andRunrequires stdin and stderr to be TTYs.pkg/clibuilds its fields withhuh.New*and wraps them in these constructors, which is the right layering.pkg/console/spinner.go:143: the TTY gate checks stderr, which is where the spinner draws. Only one spinner can own the terminal at a time.pkg/logger/logger.go:129,142: debug lines go throughlipgloss.Fprintf(stderrWriter(), ...).pkg/cli/engine_secrets.go:798-832: column widths uselipgloss.Width, which is display-width aware.Findings
1. Styled output bypasses the color-profile writer (medium).
console.RenderErrorBoxreturns pre-rendered ANSI when stderr is a TTY (pkg/console/console.go:525). Three callers print those lines with rawfmt.Fprintln(os.Stderr, line):pkg/cli/deps_security.go:96-98,pkg/cli/mcp_inspect_mcp.go:68-70, andpkg/cli/mcp_inspect_mcp.go:80-82. The progress bar has the same problem:pkg/cli/logs_run_download_concurrent.go:102writespb.Update(0)(bubblesViewAsoutput) directly toos.Stderr, soNO_COLORis ignored there too.Fix: add a console helper that writes lines through
stderrWriter(), or send these boxes throughRenderComposedSections.2. Progress bar checks stdout but draws on stderr (medium).
pkg/console/progress.go:69setsttyCheck: isTTY, which istty.IsStdoutTerminal(). The bar is written to stderr. Two results:Fix: default to
tty.IsStderrTerminal(), asNewSpinnerdoes.3.
NO_COLORalso turns on accessibility mode (medium; needs a maintainer decision).IsAccessibleMode()(pkg/console/accessibility.go:15-19) returns true whenNO_COLORis set. That value flows intoWithAccessibleon every huh form (prompt_form.go:34-36) and disables spinners (spinner.go:144-145). A user who setsNO_COLORfor color reasons gets plain-text prompts and no spinner. The NO_COLOR convention only asks for color to be removed.Fix: split into
ColorDisabled()(NO_COLOR, TERM=dumb) andIsAccessibleMode()(ACCESSIBLE, TERM=dumb). This changes behavior, so it should be confirmed first.4. Full-screen Bubble Tea TUIs have no accessibility fallback (medium).
pkg/cli/work_command_tui.go:308checks only that stdin and stdout are terminals.pkg/cli/org_rollout_tui.go:271startstea.NewProgramwith no accessibility check. Spinners and forms honorACCESSIBLEandTERM=dumb; these TUIs do not. The work TUI already tells automation users to usestate --json, and the same guidance could apply when accessible mode is set.5. Status glyphs are doubled at 12 call sites (medium). The helpers already prepend a glyph:
PrintSuccessMessageadds a check mark,PrintInfoMessageandFormatInfoMessageaddi, andFormatWarningMessageadds a warning sign (console.go:209-242). Callers add their own on top:pkg/cli/mcp_inspect_mcp.go:90:PrintSuccessMessagewith a✅prefix in the message shows✓ ✅ Successfully connected...pkg/cli/mcp_inspect_mcp.go:621:PrintInfoMessagewith a💡prefix showsi 💡 To allow blocked tools...pkg/workflow/npm_validation.go:102:FormatInfoMessagewith a✓prefix shows an info marker followed by a success marker.The full list is in the details block below.
6. Glyph vocabulary is inconsistent and partly double-width (low to medium).
✓(console,mcp_list.go:266) versus✅(audit_cross_run_render.go:147,354,mcp_tool_table.go:74).⚠versus⚠️(U+26A0 followed by U+FE0F;deps_report.go:124,152,177,deps_security.go:230).✗versus❌(mcp_inspect_mcp.go:68,80) versus🔴(deps_security.go:96).✅and❌are double-width. Inaudit_cross_run_render.go:354-356, one column alternates between✅and⚠, so text after the icon can shift by a cell depending on the terminal.Fix: define one symbol set in
pkg/console(aSymbolOKconstant holding the check mark, for example) and use it everywhere.7. Report renderers mix raw and helper output (low).
pkg/cli/audit_report_render.go(83 raw calls),pkg/cli/mcp_inspect_mcp.go(64), andpkg/cli/experiments_analyze_statistics.go(46) write plain text toos.Stderr. Plain text is reasonable for grep-friendly reports, but the convention is undocumented, and single commands mix helper lines with raw lines.Fix: document the rule, or add a small report writer that these renderers share.
8. The library layer writes to stderr directly (low).
pkg/workflowhas 169 directos.Stderrwrites. Diagnostics cannot be captured per compiler instance without swapping process-global state. Fix: inject anio.Writerfor diagnostics on the compiler. Theconsole.stderrhook is package-global and exists only for tests.9. Console API surface (low).
pkg/consoleexports 288 symbols. Unsuffixed helpers write to stderr,*Stdoutvariants write to stdout, anddestination_aliases.goadds 9*Stderraliases that forward to the unsuffixed names. Some helpers have only one variant (FormatTableHeaderStderr,FormatErrorTextStderr). Fix: pick one naming scheme and mark the aliases// Deprecated:.10. A doc example teaches the bypass pattern (low).
pkg/styles/theme.go:40-47showsfmt.Println(styles.Error.Render(...)), which skips TTY detection and degradation. Useconsole.FormatErrorMessageorconsole.PrintErrorMessagein the example.Verify, not confirmed as a bug:
IsCancelledis checked in only 3 files that run forms (add_interactive_workflow.go,engine_secrets.go,run_interactive.go). Confirm that Esc or Ctrl-C in other prompts ends as a clean cancellation rather than an error line.Suggested order
NO_COLORsemantics.Scope and method
Static analysis: grep counts, file reads, and Serena
find_referencing_symbolsonRenderErrorBoxandIsAccessibleMode. The code was not built or run, so the terminal behavior described above comes from reading the code, not from observing output.All 12 doubled-glyph call sites
pkg/workflow/pip_validation.go:110FormatInfoMessagepkg/workflow/pip_validation.go:257FormatInfoMessagepkg/workflow/agent_validation.go:449FormatInfoMessageStderrpkg/workflow/npm_validation.go:102FormatInfoMessagepkg/cli/mcp_validation.go:171FormatWarningMessagepkg/cli/compile_stats.go:204FormatInfoMessageStderrpkg/cli/generate_action_metadata_command.go:92FormatInfoMessagepkg/cli/actions_build_command.go:205FormatInfoMessagepkg/cli/mcp_inspect_mcp.go:90PrintSuccessMessagepkg/cli/mcp_inspect_mcp.go:621PrintInfoMessagepkg/cli/mcp_inspect_mcp.go:655PrintInfoMessagepkg/cli/mcp_inspect_mcp.go:673PrintSuccessMessagepkg/cli/compile_stats.go:327(FormatErrorTextStderrwith a cross mark) is excluded: that helper adds no glyph, so the result is not doubled.References: §42587486070
All reactions