Files
multi-agent-mux/docs/MAM_WEB_PTY_BRIDGE_PLAN.md
T

4.4 KiB

📑 MAM Web PTY WebSocket Bridge 개발 계획서

이 문서는 브라우저 환경에서 POSIX 가상 터미널(PTY) FFI에 직접 액세스할 수 없는 샌드박스 제약을 극복하고, apps/mam_web 클라이언트를 통해 세션 attach 및 제어 기능을 온전히 구동하기 위한 WebSocket PTY 브릿지 아키텍처 및 구현 계획을 정의합니다.


1. 아키텍처 개요 (Architecture Overview)

브라우저 단독으로는 로컬 리눅스의 시스템 호출(fork(), execvp(), fcntl(), waitpid())을 호출할 수 없으므로, 로컬 데몬으로 동작하는 초경량 WebSocket 프록시 브릿지 서버를 경유하여 양방향 터미널 스트림을 중계합니다.

graph TD
    Client[\"MAM Web Client (Browser)\" - apps/mam_web]
    Bridge[\"Shelf WebSocket Bridge (Daemon)\" - packages/mam_bridge]
    PTY[\"POSIX PtySession (FFI)\" - packages/mam_pty]
    Tmux[\"tmux -L multi-agent-mux attach\" - Local process]

    Client -- \"1. ws://localhost:8080/attach?session=demo\" --> Bridge
    Bridge -- \"2. spawn PTY (fork-safe FFI)\" --> PTY
    PTY -- \"3. dup2 redirect\" --> Tmux
    Client -- \"4. Send inputs (keystrokes)\" --> Bridge
    Bridge -- \"5. pty.writeString()\" --> PTY
    PTY -- \"6. Stream stdout bytes\" --> Bridge
    Bridge -- \"7. WebSocket Frame (text/binary)" --> Client

2. 상세 구현 사양 (Implementation Details)

2.1 PTY WebSocket Bridge 데몬 (packages/mam_bridge)

  • 역할: shelfshelf_web_socket을 사용하여 로컬 루프백(127.0.0.1) 또는 지정 바인딩 포트에서 대기하는 HTTP/WebSocket 중계 서버 구현.
  • 접속 엔드포인트: /ws/attach?session=<name>&server=<server_name>
  • 동작 시퀀스:
    1. WebSocket 핸드셰이크 요청이 도달하면 쿼리 파라미터(session, server)를 검증합니다.
    2. packages/mam_ptyPtySession.start('tmux', ['-L', server, 'attach', '-t', session])을 안전하게 비동기 스폰합니다.
    3. PtySession.stdout 바이트 스트림을 수신하는 즉시 WebSocket binary/text 프레임으로 래핑해 웹 브라우저로 전송합니다.
    4. 웹 브라우저가 WebSocket 채널로 보낸 키보드/마우스 입력 데이터는 PtySession.writeString()으로 포워딩합니다.
    5. WebSocket 연결이 끊어지거나 브라우저 탭이 닫히면 PtySession.close()를 즉시 호출하여 자식 tmux 프로세스를 waitpid()로 소거(reap)하고 PTY FFI 핸들을 원자적으로 닫습니다.

2.2 MAM Web 클라이언트 UI (apps/mam_web)

  • 역할: 대시보드 그리드 및 WebSocket 기반 터미널 위젯 이식.
  • 상태 관리: 기존 M1/M2의 StatusRepository 및 Riverpod 폴링 스트림을 웹 클라이언트 사양으로 동일하게 공유하여 대시보드 그리드를 유지합니다.
  • TerminalPane 웹 전용 컴포넌트:
    • PTY FFI 라이브러리를 임포트하지 않고 package:web_socket_channel/web_socket_channel.dart를 사용하여 백엔드 브릿지 서버에 소켓을 연결합니다.
    • 소켓 스트림(channel.stream)을 xterm v4.0.0 Terminal로 바인딩합니다.
    • Terminal.onOutput 콜백을 통해 발생하는 사용자 타이핑 데이터는 channel.sink.add()를 통해 WebSocket 프레임으로 쏩니다.
    • 터미널 리사이즈(Terminal.onResize) 이벤트가 발생하면 {"action": "resize", "cols": cols, "rows": rows} 형태의 JSON 제어 프레임을 소켓으로 전송하여 백엔드 PTY FFI 단에서 ioctl(TIOCSWINSZ)이 기동되도록 연동합니다.

3. 안정성 및 보안 요구사항 (DoD Requirements)

  • 자원 누수 방지 (Anti-Leak): 웹 브라우저가 갑자기 종료되거나 네트워크 끊김 현상이 발생할 때, 백엔드 데몬이 하트비트 (Ping-Pong) 또는 소켓 에러 이벤트를 즉각 감지해 waitpid()를 호출함으로써 좀비 defunct 프로세스가 시스템에 잔존하지 않도록 확실히 보증합니다.
  • 비블로킹 보장 (Non-blocking): 데몬 서버 단에서도 fcntl O_NONBLOCK 및 non-blocking read loop가 동일하게 가동되어 다중 브라우저가 접속하더라도 백엔드 이벤트 루프가 정지되지 않도록 차단합니다.
  • 접속 권한 제어: 브릿지 서버는 기본적으로 로컬호스트(127.0.0.1) 바인딩으로 기동하여 외부 원격지로부터의 악성 터미널 탈취 공격을 원천 봉쇄합니다.