@@ -154,42 +154,41 @@ func (h *CommandWSHandler) CommandStream(c *gin.Context) {
154154 }
155155 resultCh , errCh := h .agentClient .ProcessCommandStream (ctx , cmd )
156156
157- for {
158- select {
159- case result , ok := <- resultCh :
160- if ! ok {
161- _ = wsjson .Write (ctx , conn , wsMessage {Type : "done" })
162- _ = conn .Close (websocket .StatusNormalClosure , "stream complete" )
163- return
164- }
165- output := result .GetResult ()
166- if h .variableUC != nil {
167- if masked , mErr := h .variableUC .MaskSecrets (output ); mErr != nil {
168- _ = catcher .Error ("CommandStream: mask secrets" , mErr , nil )
169- } else {
170- output = masked
171- }
172- }
173- msg := wsMessage {Type : "output" , Data : output }
174- if writeErr := wsjson .Write (ctx , conn , msg ); writeErr != nil {
175- cancel ()
176- return
177- }
178-
179- case grpcErr , ok := <- errCh :
180- if ! ok {
181- return
182- }
183- if grpcErr != nil {
184- _ = catcher .Error ("CommandStream: grpc error" , grpcErr , nil )
185- errMsg , _ := json .Marshal (wsMessage {Type : "error" , Message : grpcErr .Error ()})
186- _ = conn .Write (ctx , websocket .MessageText , errMsg )
187- _ = conn .Close (websocket .StatusInternalError , "grpc error" )
157+ // ponytail: one command → one CommandResult (see agent-manager ProcessCommand).
158+ // Server never closes the stream, so we don't wait for !ok — we finalize on the first result.
159+ select {
160+ case result , ok := <- resultCh :
161+ if ! ok {
162+ _ = conn .Close (websocket .StatusNormalClosure , "stream complete" )
163+ return
164+ }
165+ output := result .GetResult ()
166+ if h .variableUC != nil {
167+ if masked , mErr := h .variableUC .MaskSecrets (output ); mErr != nil {
168+ _ = catcher .Error ("CommandStream: mask secrets" , mErr , nil )
169+ } else {
170+ output = masked
188171 }
172+ }
173+ if writeErr := wsjson .Write (ctx , conn , wsMessage {Type : "output" , Data : output }); writeErr != nil {
174+ _ = catcher .Error ("CommandStream: write output" , writeErr , nil )
175+ cancel ()
189176 return
177+ }
178+ if doneErr := wsjson .Write (ctx , conn , wsMessage {Type : "done" }); doneErr != nil {
179+ _ = catcher .Error ("CommandStream: write done" , doneErr , nil )
180+ }
181+ _ = conn .Close (websocket .StatusNormalClosure , "command complete" )
190182
191- case <- ctx .Done ():
183+ case grpcErr , ok := <- errCh :
184+ if ! ok || grpcErr == nil {
192185 return
193186 }
187+ _ = catcher .Error ("CommandStream: grpc error" , grpcErr , nil )
188+ errMsg , _ := json .Marshal (wsMessage {Type : "error" , Message : grpcErr .Error ()})
189+ _ = conn .Write (ctx , websocket .MessageText , errMsg )
190+ _ = conn .Close (websocket .StatusInternalError , "grpc error" )
191+
192+ case <- ctx .Done ():
194193 }
195194}
0 commit comments