# 📑 MAM Web PTY WebSocket Bridge 개발 계획서

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

---

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

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

```mermaid
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`)
* **역할**: `shelf` 및 `shelf_web_socket`을 사용하여 로컬 루프백(`127.0.0.1`) 또는 지정 바인딩 포트에서 대기하는 HTTP/WebSocket 중계 서버 구현.
* **접속 엔드포인트**: `/ws/attach?session=<name>&server=<server_name>`
* **동작 시퀀스**:
  1. WebSocket 핸드셰이크 요청이 도달하면 쿼리 파라미터(`session`, `server`)를 검증합니다.
  2. `packages/mam_pty`의 `PtySession.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`) 바인딩으로 기동하여 외부 원격지로부터의 악성 터미널 탈취 공격을 원천 봉쇄합니다.
