Skip to content

cli: render OpTracker as plain lines on non-interactive stderr#2421

Closed
dstotijn wants to merge 2 commits into
encoredev:mainfrom
dstotijn:optracker-non-interactive
Closed

cli: render OpTracker as plain lines on non-interactive stderr#2421
dstotijn wants to merge 2 commits into
encoredev:mainfrom
dstotijn:optracker-non-interactive

Conversation

@dstotijn
Copy link
Copy Markdown

@dstotijn dstotijn commented Apr 30, 2026

Summary

Encore's build-progress UI is rendered by internal/optracker.OpTracker, which uses ANSI cursor save/restore for in-place spinner updates. That works on a TTY, but when stderr is piped — mise run, log aggregators, CI, tee, Docker logs — every 100ms refresh becomes a new line and floods the output.

#2423 added a lineMode rendering path to OpTracker (via NewLineMode(w)) and uses it for the new encore check command. This PR extends that same rendering to the existing encore run and encore exec flows when stderr isn't a terminal.

Fix

  • New proto field non_interactive on RunRequest, ExecScriptRequest, ExecSpecRequest. Defaults to false → existing behavior, fully backwards compatible.
  • The CLI auto-sets it from !term.IsTerminal(int(os.Stderr.Fd())).
  • The daemon constructs the tracker via optracker.NewLineMode(stderr) instead of optracker.New(stderr, stream) when the request is non_interactive.

Example non-interactive output:

encore: Building Encore application graph...
encore: Analyzing service topology...
encore: Building Encore application graph done (1.2s)
encore: Analyzing service topology done (0.4s)
...

Alternatives considered

  • --quiet flag / ENCORE_QUIET env var — rejected. The flooding is an output-format bug, not a verbosity preference; surfacing it as user config asks people to opt out of broken behavior.
  • Total suppression when non-TTY — rejected. Users still want to see what's happening; they only want to stop the spinner spam.

Test plan

  • Interactive: encore run from a TTY shows the spinner UI as before.
  • Non-interactive: encore run 2>&1 | cat produces line-mode output, no spinner / cursor escapes.
  • Same for encore exec (Go and TS apps).

The build progress UI uses ANSI cursor save/restore for in-place spinner
updates, which only works on a TTY. When stderr is piped into mise, a
log aggregator, or CI, every 100ms refresh becomes a new line and floods
the output.

Detect the CLI's stderr TTY state and pass it through to the daemon as a
new non_interactive bool on RunRequest, ExecScriptRequest, and
ExecSpecRequest. The OpTracker now renders one plain line per state
transition (start / done / failed) instead of the spinner when
interactive is false.
…active

# Conflicts:
#	internal/optracker/optracker.go
#	proto/encore/daemon/daemon.pb.go
@eandre
Copy link
Copy Markdown
Member

eandre commented May 7, 2026

Created #2428 which is this PR but with the protobuf generated using the correct versions. Thanks!

@dstotijn
Copy link
Copy Markdown
Author

Closing, change is handled in #2428.

@dstotijn dstotijn closed this May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants