|
12 | 12 | from ..communicator.utils import create_websocket_config |
13 | 13 |
|
14 | 14 |
|
15 | | - |
16 | 15 | def _filter_shell_output(data: bytes, original_command: str) -> bytes: |
17 | 16 | """Filter shell prompts, command echoes, and ANSI sequences from output.""" |
18 | 17 | import re |
@@ -148,35 +147,37 @@ async def run_command( |
148 | 147 | stderr_buf = bytearray() |
149 | 148 | session_done = asyncio.Event() |
150 | 149 | exit_code = 0 |
151 | | - |
| 150 | + |
152 | 151 | # Line buffers for streaming |
153 | 152 | stdout_line_buf = bytearray() |
154 | 153 | stderr_line_buf = bytearray() |
155 | | - |
| 154 | + |
156 | 155 | def handle_stdout(data: bytes) -> None: |
157 | 156 | """Handle stdout from shell.""" |
158 | 157 | nonlocal stdout_buf, exit_code, stdout_line_buf |
159 | 158 |
|
160 | 159 | # Add to line buffer for streaming |
161 | 160 | stdout_line_buf.extend(data) |
162 | | - |
| 161 | + |
163 | 162 | # Process complete lines for streaming |
164 | | - while b'\n' in stdout_line_buf: |
165 | | - line_end = stdout_line_buf.index(b'\n') |
166 | | - line = stdout_line_buf[:line_end + 1] |
167 | | - stdout_line_buf = stdout_line_buf[line_end + 1:] |
168 | | - |
| 163 | + while b"\n" in stdout_line_buf: |
| 164 | + line_end = stdout_line_buf.index(b"\n") |
| 165 | + line = stdout_line_buf[: line_end + 1] |
| 166 | + stdout_line_buf = stdout_line_buf[line_end + 1 :] |
| 167 | + |
169 | 168 | # Apply existing filter to the line and stream if requested |
170 | 169 | if stream_output: |
171 | 170 | filtered = _filter_shell_output(line, command) |
172 | 171 | if filtered and filtered.strip(): |
173 | 172 | try: |
174 | 173 | import sys |
| 174 | + |
175 | 175 | sys.stdout.buffer.write(filtered) |
176 | 176 | sys.stdout.buffer.flush() |
177 | 177 | except Exception: |
178 | 178 | try: |
179 | 179 | import sys |
| 180 | + |
180 | 181 | sys.stdout.write(filtered.decode("utf-8", errors="replace")) |
181 | 182 | sys.stdout.flush() |
182 | 183 | except Exception: |
@@ -205,32 +206,34 @@ def handle_stdout(data: bytes) -> None: |
205 | 206 | def handle_stderr(data: bytes) -> None: |
206 | 207 | """Handle stderr from shell.""" |
207 | 208 | nonlocal stderr_buf, stderr_line_buf |
208 | | - |
| 209 | + |
209 | 210 | # Add to line buffer for streaming |
210 | 211 | stderr_line_buf.extend(data) |
211 | | - |
| 212 | + |
212 | 213 | # Process complete lines for streaming |
213 | | - while b'\n' in stderr_line_buf: |
214 | | - line_end = stderr_line_buf.index(b'\n') |
215 | | - line = stderr_line_buf[:line_end + 1] |
216 | | - stderr_line_buf = stderr_line_buf[line_end + 1:] |
217 | | - |
| 214 | + while b"\n" in stderr_line_buf: |
| 215 | + line_end = stderr_line_buf.index(b"\n") |
| 216 | + line = stderr_line_buf[: line_end + 1] |
| 217 | + stderr_line_buf = stderr_line_buf[line_end + 1 :] |
| 218 | + |
218 | 219 | # Apply existing filter to stderr line and stream if requested |
219 | 220 | if stream_output: |
220 | 221 | filtered = _filter_shell_output(line, command) |
221 | 222 | if filtered and filtered.strip(): |
222 | 223 | try: |
223 | 224 | import sys |
| 225 | + |
224 | 226 | sys.stderr.buffer.write(filtered) |
225 | 227 | sys.stderr.buffer.flush() |
226 | 228 | except Exception: |
227 | 229 | try: |
228 | 230 | import sys |
| 231 | + |
229 | 232 | sys.stderr.write(filtered.decode("utf-8", errors="replace")) |
230 | 233 | sys.stderr.flush() |
231 | 234 | except Exception: |
232 | 235 | pass |
233 | | - |
| 236 | + |
234 | 237 | stderr_buf.extend(data) |
235 | 238 |
|
236 | 239 | def handle_closed() -> None: |
@@ -281,7 +284,6 @@ def handle_closed() -> None: |
281 | 284 | else: |
282 | 285 | final_stdout = _filter_shell_output(bytes(stdout_buf), command) |
283 | 286 |
|
284 | | - |
285 | 287 | return CommandResult( |
286 | 288 | stdout=final_stdout, |
287 | 289 | stderr=bytes(stderr_buf), # Now using proper stderr separation |
|
0 commit comments