github.com/mgutz/ansi is not maintained

Problem to solve

github.com/mgutz/ansi is not maintained.

Proposal

github.com/mgutz/ansi could be replaced by github.com/muesli/termenv that is already used in the project.

Implementation plan

Note: This plan was drafted during an AI-assisted triage of the backlog and has not been validated by a maintainer. Treat it as a starting point: file paths, line numbers, and the approach may need adjusting.

The dependency has one call site left, so the swap is small. The catch is that the previous attempt (!3141 (closed)) rebuilt the whole palette on a termenv.Output derived from s.StdOut, and termenv re-runs its own TTY probe on that writer. When a command starts the pager, s.StdOut becomes an *io.PipeWriter (internal/iostreams/iostreams.go:263), termenv sees a non-*os.File, resolves the profile to termenv.Ascii, and every style call becomes a no-op. That is why a maintainer saw no color at all on a fully truecolor-capable terminal. glab already decides for itself whether color is allowed (s.ColorEnabled() && s.IsaTTY), so the fix must not hand that decision back to termenv's writer probe.

  1. In internal/iostreams/color.go, replace the single ansi.ColorFunc(ansiName) call at the end of makeColorFunc (line 106) with a local lookup that emits the escape sequences directly, in the same style as the truecolor and 256-color gray branches that already sit above it in the same function. Add an unexported map[string]string from the eight names used in colorPalette to their SGR parameters: magenta to 0;35, cyan to 0;36, red to 0;31, yellow to 0;33, blue to 0;34, green to 0;32, black+h to 0;90, default+b to 0;1;39. Return func(t string) string { return "\x1b[" + params + "m" + t + "\x1b[0m" }, and return the identity function for an unknown name.
  2. Keep makeColorFunc's signature, the isColorfulOutput gate, and isTrueColorSupported/is256ColorSupported as they are. Do not move profile detection onto s.StdOut. If a reviewer prefers going through termenv instead of writing the sequences by hand, build the output once with an explicit profile (termenv.WithProfile(...) or termenv.WithTTY(true)) driven by glab's own isTrueColorSupported/is256ColorSupported, never by letting termenv.NewOutput probe the writer.
  3. Remove the github.com/mgutz/ansi import from internal/iostreams/color.go:12, run go mod tidy, and confirm grep -rn mgutz --include='*.go' . returns nothing outside vendor/.
  4. Verify against the existing assertions in internal/iostreams/color_test.go: Test_makeColorFunc (line 104) already pins the exact bytes for black+h and green on the basic-ANSI path, so it must pass unchanged. Add cases to that same table for the remaining names (magenta, cyan, red, yellow, blue, default+b) with term: "xterm-16color" so all eight are covered.
  5. Add one regression test in internal/iostreams/color_test.go that builds a palette for a paged stream: set IsaTTY true, point StdOut at an io.Pipe writer, and assert Color().Green("text") still contains an escape sequence. This is the case that sank !3141 (closed) and nothing in the suite catches it today.
  6. No help text or flags change, so make gen-docs is not needed. Run go test ./internal/iostreams/... and make lint.
Edited by Kai Armstrong