fix(cli): SSE streaming can no longer hang or silently truncate (PR C — hardening)#21
Merged
Conversation
Closes the two residual hardening holes from the AI-chat hang validation — the CLI relied entirely on the server never going silent. - Idle deadline: client.Request gains IdleTimeout; when set, Send wraps the response body so the request context is cancelled if no bytes arrive for the window (reset on every byte, so it's an idle timeout, not a total cap). DefaultStreamIdleTimeout = 45s (3× the server's 15s heartbeat). Applied to every streaming caller: chat (postChat + approve/reject), invoke --stream, and the shared streamSSE (logs/activity/deploy/deployments-logs follow), which is now routed through client.Send instead of a bespoke timeout-free http.Client — one hardened streaming path. - Premature-EOF as error (per-caller, not in consumeSSE so follow-mode and raw --stream still end cleanly on EOF): chat.drive errors when the stream ends without a terminal frame (done/awaiting_approval/error) instead of accepting a truncated turn as success; followDeploymentLogs gets the same terminal guard watchBuild already had. Guarded on err==nil so it never masks a Ctrl-C or a real transport error. Tests: TestDrivePrematureEOF (EOF w/o terminal frame -> error), TestClientIdleTimeout (silent stream cancelled within the window); existing TestDriveSSE (heartbeat + clean done) stays green.
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.
PR C — SSE / chat hardening
Third of four back-to-back CLI gap-closure PRs. Closes the two residual holes found during the AI-chat hang validation: the CLI relied entirely on the server never going silent, and accepted a mid-stream connection drop as a successful (truncated) turn.
Changes
client.RequestgainsIdleTimeout; when set,Sendwraps the response body in anidleReadCloserthat cancels the request context if no bytes arrive for the window (reset on every byte → a true idle timeout, never a total-duration cap).DefaultStreamIdleTimeout = 45s(3× the server's 15s heartbeat). Applied to every streaming caller: chat (postChat+ approve/reject),invoke --stream, and the sharedstreamSSE(logs/activity/deploy/deployments-logs follow) — which is now routed throughclient.Sendinstead of a bespoke timeout-freehttp.Client, collapsing to one hardened streaming path.consumeSSE— follow-mode and raw--streamstill end cleanly on EOF):chat.driveerrors when the stream ends without a terminal frame (done/awaiting_approval/error) instead of accepting a truncated turn as success;followDeploymentLogsgets the same terminal guardwatchBuildalready had. Guarded onerr==nilso it never masks a Ctrl-C (context.Canceled) or a real transport error.Tests
TestDrivePrematureEOF(EOF without a terminal frame → error),TestClientIdleTimeout(silent stream cancelled within the idle window); existingTestDriveSSE(heartbeat + cleandone) stays green.go vet ./...+go test ./...green.Live-verified on the dev instance (:3000)
Happy-path chat still streams (
pong, exit 0);deployments logs --followon an already-completed deployment replays the terminal frame and exits 0 (no false-positive from the new guard);activity --follow+logs --followstream through the rewrittenstreamSSEwithout a spurious EOF error.