Fix lstk aws streaming output hanging until exit by running the aws CLI in a PTY - #417
Merged
Merged
Conversation
skyrpex
marked this pull request as ready for review
July 30, 2026 08:05
There was a problem hiding this comment.
This runs the wrapped aws CLI on a PTY when both of lstk's streams are terminals, fixing the block-buffered streaming hang (logs tail --follow); the fix is well-scoped and the TTY gating is coherent.
- suggestion(non-blocking): on
internal/awscli/exec.go— now that the child sees a TTY on stdout, aws v2's default pager (less) will engage for long paged output (e.g.lstk aws s3 ls) where the old pipe wiring suppressed it, and rendered through the copied PTY master it can look janky. Consider defaultingAWS_PAGER=""inexecEnv(still user-overridable, same pattern asPYTHONUNBUFFERED) so you keep streaming + colors without an unexpected pager. - thought(non-blocking): on
internal/proc/pty.go— the PTY size is captured once and resizes aren't propagated (documented); fine for streaming today, but aSIGWINCH-drivenSetsizewould be a cheap follow-up if paged/interactive output becomes common. - praise: leaving
cmd.Stdinon the real terminal while only stdout/stderr ride the PTY (no new session) is what keeps Ctrl-C and the process-group semantics intact, and the timing-based unit test plus the real-CLI e2e reproduction make the fix genuinely verifiable. @skyrpex
Automated review on behalf of @gtsiolis.
Generated by Claude Code
…LI in a PTY Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
anisaoshafi
force-pushed
the
claude/lstk-logs-tail-follow-hang-9ff033
branch
from
July 30, 2026 12:27
415053f to
1a6ab38
Compare
anisaoshafi
approved these changes
Jul 30, 2026
Collaborator
There was a problem hiding this comment.
Tested before and after, and looks pretty good. Thanks for the clear manual instructions in the description 👏🏼
Pushed a small commit 1a6ab38 to simplify some long comments
anisaoshafi
enabled auto-merge (squash)
July 30, 2026 12:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
lstk aws logs tail --follow(and any streaming aws command) showed no output until the process exited when run on a terminal.Why
The interactive spinner path in
cmd/aws.gowraps the child's stdout/stderr interminal.StopOnWriteWriter. Since that is a plainio.Writer, os/exec hands the aws CLI a pipe instead of the TTY; the Python-based CLI then block-buffers stdout (8 KB), holding all output until the buffer fills or the process exits. The official frozen aws v2 binary also ignoresPYTHONUNBUFFERED, so an env-var fix alone doesn't work.How
proc.RunInPTY(internal/proc/pty.go): runs the child with stdout+stderr on a PTY slave, copies the master to the given writer (the spinner'sStopOnWriteWriter, so the spinner still stops on first output). No new session is created, so Ctrl-C still reaches the child via the process group; PTY size is inherited once from lstk's terminal. Falls back to the previous pipe wiring when no PTY can be allocated (Windows).awscli.Execgains ausePTYparameter;cmd/aws.goenables it only when both stdout and stderr are terminals — piped output (lstk aws ... | grep) keeps seeing a pipe so pipelines never receive colors/CRLF.PYTHONUNBUFFERED=1is still injected (helps pip-installed, non-frozen CLIs; a user-set value wins).github.com/creack/ptyto the root module (previously test-only).Tests
TestAWSLogsTailFollowStreamsInPTY(test/integration/aws_e2e_test.go): real LocalStack + real aws CLI in a PTY; asserts a pre-existing log event appears whiletail --followis still running. Failed before the fix (output only after Ctrl-C), passes after. Gated on Docker + aws binary +LOCALSTACK_AUTH_TOKEN, like the terraform/cdk/sam e2e suites.proc.RunInPTY(child sees a TTY, output arrives before exit, exit-code propagation, stderr merge) and for the env construction.TestAWSCommand*integration tests pass locally.Manual testing
With a running LocalStack AWS emulator (
lstk start), save this astail-follow-demo.shand runLSTK=./bin/lstk sh tail-follow-demo.shfrom an interactive terminal. It creates a log group, feeds one event per second in the background, and follows the group; stop with Ctrl-C.Before (built from
main) — the spinner runs for the entire session, no events are shown; everything flushes at once only after Ctrl-C:After (this branch) — the spinner stops on the first event, then each line appears live, ~1 s apart:
Notes for reviewers
less) for long output — matching rawawsbehavior, but new forlstk aws.lstk azhas the identical wrapper pattern and needs the same treatment — follow-up ticket DEVX-1028.Review
New user-facing behavior (PTY, colors, possible pager) on a heavily used proxy command plus a new production dependency — human review advisable.
Closes DEVX-1026
Co-Authored-By: Claude noreply@anthropic.com