refactor(core): stabilize gRPC streaming, plugin invocation, and CLI UX

- Implement threaded plugin execution with Queue-based streaming in PluginService
- Refactor remote logger to preserve ANSI colors and fix TTY line endings (\r\n)
- Intelligent terminal filtering: disable SSM screen-clearing filter after success
- Sanitize SSH-only flags in core.py when using SFTP protocol
- Rewrite completion tree with pre/post-node states and flag deduplication
- Update gRPC unit tests to match new streaming response structure
This commit is contained in:
2026-05-05 18:24:31 -03:00
parent 16868828c6
commit 37db74f47d
6 changed files with 159 additions and 49 deletions
+48 -24
View File
@@ -86,25 +86,37 @@ class NodeStub:
old_tty = termios.tcgetattr(sys.stdin)
try:
import time
tty.setraw(sys.stdin.fileno())
response_iterator = self.stub.interact_node(request_generator())
# First response is connection status
# First phase: Wait for connection status, print early data
try:
first_res = next(response_iterator)
if first_res.success:
# Connection established on server, show success message
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
printer.success(conn_msg)
tty.setraw(sys.stdin.fileno())
else:
# Connection failed on server
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
printer.error(f"Connection failed: {first_res.error_message}")
return
for res in response_iterator:
if res.stdout_data:
data = res.stdout_data
if debug:
data = data.replace(b'\x1b[H\x1b[2J', b'').replace(b'\x1bc', b'').replace(b'\x1b[3J', b'')
os.write(sys.stdout.fileno(), data)
if res.success:
# Connection established on server, show success message
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
printer.success(conn_msg)
tty.setraw(sys.stdin.fileno())
break
if res.error_message:
# Connection failed on server
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
printer.error(f"Connection failed: {res.error_message}")
return
except StopIteration:
return
# Second phase: Stream active session
# Clear screen filter is only applied before success (Phase 1).
# Once the user has a prompt, Ctrl+L must work normally.
for res in response_iterator:
if res.stdout_data:
os.write(sys.stdout.fileno(), res.stdout_data)
@@ -160,25 +172,37 @@ class NodeStub:
old_tty = termios.tcgetattr(sys.stdin)
try:
import time
tty.setraw(sys.stdin.fileno())
response_iterator = self.stub.interact_node(request_generator())
# First response is connection status
# First phase: Wait for connection status, print early data
try:
first_res = next(response_iterator)
if first_res.success:
# Connection established on server, show success message
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
printer.success(conn_msg)
tty.setraw(sys.stdin.fileno())
else:
# Connection failed on server
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
printer.error(f"Connection failed: {first_res.error_message}")
return
for res in response_iterator:
if res.stdout_data:
data = res.stdout_data
if debug:
data = data.replace(b'\x1b[H\x1b[2J', b'').replace(b'\x1bc', b'').replace(b'\x1b[3J', b'')
os.write(sys.stdout.fileno(), data)
if res.success:
# Connection established on server, show success message
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
printer.success(conn_msg)
tty.setraw(sys.stdin.fileno())
break
if res.error_message:
# Connection failed on server
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
printer.error(f"Connection failed: {res.error_message}")
return
except StopIteration:
return
# Second phase: Stream active session
# Clear screen filter is only applied before success (Phase 1).
# Once the user has a prompt, Ctrl+L must work normally.
for res in response_iterator:
if res.stdout_data:
os.write(sys.stdout.fileno(), res.stdout_data)