feat(api): expand Coding-Agent detection list

Description

Expands DetectCodingAgent (internal/api/coding_agent.go) so the Coding-Agent/<name> token in glab's User-Agent attributes traffic from three additional sources.

What changed

Signal Env condition Returned name
Roo Code CLI ROO_CLI_RUNTIME == "1" roo-code
GitLab Duo Agent Platform AGENT_PLATFORM_GITLAB_VERSION != "" duo-agent-platform
Cursor terminal (fallback) TERM_PROGRAM == "cursor" cursor-terminal
Windsurf terminal (fallback) TERM_PROGRAM == "windsurf" (case-insensitive) windsurf-terminal
Zed terminal (fallback) TERM_PROGRAM == "zed" zed-terminal

Naming convention: the -terminal suffix

Explicit "agent invoked glab" signals (e.g. CLAUDECODE=1, CURSOR_AGENT=1) keep their plain names. TERM_PROGRAM-based signals get the -terminal suffix because they can fire for human-typed commands inside those IDE terminals as well as agent-driven invocations — analytics can then split true agent calls from "ran in an IDE terminal" context.

Precedence preserved

DetectCodingAgent still returns the first match. AI_AGENT wins, then the explicit per-agent env vars (alphabetical, existing behaviour), then the TERM_PROGRAM fallback. So CURSOR_AGENT=1 plus TERM_PROGRAM=cursor still resolves to cursor, not cursor-terminal.

Resolves #8318 (closed)

How has this been tested?

  • go test ./internal/api/ -run TestDetectCodingAgent -v — all 20 cases pass (8 new).
  • go test ./internal/api/... — passes (no regression).
  • gofmt -d and go vet ./internal/api/... — clean.
  • golangci-lint run ./internal/api/...0 issues.
  • Local end-to-end build, then GLAB_DEBUG_HTTP=1 glab auth status with each env var set; the User-Agent emits the expected token for each:
    • ROO_CLI_RUNTIME=1Coding-Agent/roo-code
    • AGENT_PLATFORM_GITLAB_VERSION=18.0.0Coding-Agent/duo-agent-platform
    • TERM_PROGRAM=WindsurfCoding-Agent/windsurf-terminal
    • CURSOR_AGENT=1 + TERM_PROGRAM=cursorCoding-Agent/cursor (precedence sanity)

Coordination

  • A separate branch add_gemini_cli_detection is in flight, adding Gemini CLI (GEMINI_CLI=1gemini). It doesn't overlap functionally; whichever lands first wins, and the other rebases. Any conflict is adjacent-line and trivial.
  • For duo-agent-platform, AGENT_PLATFORM_GITLAB_VERSION is documented as Duo Agent Platform-specific in the execution-variables docs. Happy to swap to a more explicit flag (e.g. a dedicated DUO_AGENT=1) if the Duo team prefers.

Non-goals

  • No agent version capture — keeping the existing name-only format.
  • No separate HTTP header — staying with the existing Coding-Agent/<name> UA token.
  • No Snowplow / product-analytics instrumentation — only the UA header is changed.

Merge request reports

Loading