Previously the gitlab output wrapped each command individually, causing
two visible bugs in real GitLab pipelines:
- every section displayed a duration of 00:00, because start and end
markers were emitted microseconds apart for instant commands
- the `task: [NAME] CMD` announcement lines were rendered outside the
sections, because Logger.Errf bypassed the cmd-level wrapper
Fix by wrapping output at the task level via a new optional
[output.TaskWrapper] interface that GitLab implements. Task-scoped
writers are threaded via ctx so nested `task:` invocations produce
properly nested sections (GitLab supports this natively), and deps
running in parallel each get their own buffer with mutex-protected
flushes into the parent's buffer.
- `internal/output/output.go`: add TaskWrapper interface
- `internal/output/gitlab.go`: logic moved from WrapWriter to WrapTask;
WrapWriter becomes passthrough; sync.Mutex around the buffer for
concurrent flushes from parallel sub-task sections
- `task_output.go` (new): ctx plumbing + helpers kept out of task.go
- `task.go`: 7 lines of surgical edits — name the lambda's error
return, wrap before the cmd loop, defer the closer with the final
error, and swap the cmd announcement to `printCmdAnnouncement` which
writes into the task-scoped stderr