@@ -156,7 +156,7 @@ func (s *ShellItem) HandleMouseClick(btn ansi.MouseButton, x, y int) bool {
156156func (s *ShellItem) HandleKeyEvent(key tea.KeyMsg) (bool, tea.Cmd) {
157157 switch k := key.String(); k {
158158 case "c", "y":
159− text := "$ " + s.command + "\n" + s.output
159+ text := "$ " + s.command + "\n" + ansi.Strip(s.output)
160160 return true, common.CopyToClipboard(text, "Shell output copied to clipboard")
161161 case "shift+left", "H":
162162 if s.xOffset > 0 {
@@ -223,7 +223,20 @@ func (s *ShellItem) RawRender(width int) string {
223223 // Remap raw ANSI 16-color codes onto legible Charmtone colors so
224224 // dark terminal defaults don't render illegibly on Crush's
225225 // background.
226− output := remapANSI16(strings.TrimRight(s.output, "\n"), s.sty.ANSI)
226+ // Strip trailing whitespace and bare ANSI resets before remapping.
227+ // Programs like `task` emit "\x1b[0m\n" after their last line of
228+ // output; trimming only "\n" misses these because the reset bytes
229+ // sit between the content and the newline.
230+ raw := s.output
231+ for {
232+ trimmed := strings.TrimRight(raw, " \t\r\n")
233+ trimmed = strings.TrimSuffix(trimmed, "\x1b[0m")
234+ if trimmed == raw {
235+ break
236+ }
237+ raw = trimmed
238+ }
239+ output := remapANSI16(raw, s.sty.ANSI)
227240 lines := strings.Split(output, "\n")
228241
229242 // While streaming, show the tail of the output so the most recent