40a940304b
- Create enhanced health endpoints with /health and /health/db - Add comprehensive docstrings to all API endpoints - Add Pydantic response models with Field descriptions - Create apps/api/README.md with setup guide - Create ADR-001 for session auth decision - Create ADR-002 for async SQLAlchemy decision - Quality gates: Python syntax OK, TypeScript OK
166 lines
3.6 KiB
Markdown
166 lines
3.6 KiB
Markdown
# Tool Terminal Specification
|
|
|
|
## Requirements
|
|
|
|
### Functional Requirements
|
|
|
|
1. **WebSocket Terminal**: Provide terminal sessions via WebSocket at `/ws/tool-instances/{instance_id}/terminal`
|
|
2. **Terminal I/O**: Stream stdin/stdout/stderr bidirectionally in real-time
|
|
3. **Terminal Resize**: Support dynamic resize with COLS/ROWS updates
|
|
4. **Session Management**: Multiple independent sessions per instance, cleanup on disconnect
|
|
5. **Access Control**: Only instance owners can access, reject unauthorized with 403
|
|
6. **Shell Spawn**: Spawn `/bin/bash` or `/bin/sh` inside container via `docker exec`
|
|
|
|
### Non-Functional Requirements
|
|
|
|
1. **Latency**: Character input to display < 50ms
|
|
2. **Concurrent Sessions**: Support 10+ simultaneous terminal sessions
|
|
3. **Browser Support**: Chrome, Firefox, Safari, Edge
|
|
4. **Container Lifecycle**: Terminal closes when container stops
|
|
|
|
## API Specification
|
|
|
|
### WebSocket Endpoint
|
|
|
|
**URL:** `wss://{api_host}/ws/tool-instances/{instance_id}/terminal`
|
|
|
|
**Protocol:**
|
|
- Connection requires valid session cookie
|
|
- Binary frame: terminal output (stdout/stderr)
|
|
- Text frame: control messages (JSON)
|
|
|
|
**Control Messages:**
|
|
|
|
Request (Client → Server):
|
|
```json
|
|
{
|
|
"type": "resize",
|
|
"cols": 80,
|
|
"rows": 24
|
|
}
|
|
```
|
|
|
|
Response (Server → Client):
|
|
```json
|
|
{
|
|
"type": "status",
|
|
"status": "connected"
|
|
}
|
|
```
|
|
|
|
### REST Endpoint
|
|
|
|
**GET /tool-instances/{instance_id}/terminal** (HTML page)
|
|
- Returns terminal page for the instance
|
|
- Verifies ownership
|
|
- Returns 404 if instance not found
|
|
- Returns 403 if unauthorized
|
|
|
|
## Frontend Specification
|
|
|
|
### TerminalComponent
|
|
|
|
**Props:**
|
|
```typescript
|
|
interface TerminalProps {
|
|
instanceId: string;
|
|
instanceName: string;
|
|
onClose?: () => void;
|
|
}
|
|
```
|
|
|
|
**Features:**
|
|
- xterm.js terminal with custom theme
|
|
- WebSocket connection management
|
|
- Auto-fit to parent container
|
|
- Connection status indicator
|
|
- Reconnect on disconnect (3 retries)
|
|
|
|
### TerminalPage
|
|
|
|
**Route:** `/instances/:instanceId/terminal`
|
|
- Full-page terminal view
|
|
- Shows instance name in header
|
|
- Back button to instance list
|
|
- Connection status badge
|
|
|
|
## Backend Specification
|
|
|
|
### TerminalManager
|
|
|
|
**Methods:**
|
|
```python
|
|
class TerminalManager:
|
|
async def create_session(
|
|
self,
|
|
instance_id: uuid.UUID,
|
|
user_id: uuid.UUID,
|
|
websocket: WebSocket
|
|
) -> TerminalSession
|
|
|
|
async def handle_resize(
|
|
self,
|
|
session_id: str,
|
|
cols: int,
|
|
rows: int
|
|
) -> None
|
|
|
|
async def close_session(self, session_id: str) -> None
|
|
```
|
|
|
|
### TerminalSession
|
|
|
|
**Responsibilities:**
|
|
- Manage docker exec subprocess
|
|
- Stream I/O between WebSocket and PTY
|
|
- Handle resize signals
|
|
- Cleanup on disconnect
|
|
|
|
**Docker Command:**
|
|
```python
|
|
async def spawn_shell(container_id: str) -> subprocess.Process:
|
|
proc = await asyncio.create_subprocess_exec(
|
|
"docker", "exec", "-i", container_id, "/bin/bash",
|
|
stdin=asyncio.subprocess.PIPE,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.STDOUT,
|
|
)
|
|
return proc
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
**Backend:**
|
|
- FastAPI WebSocket support
|
|
- asyncio subprocess
|
|
- docker CLI
|
|
|
|
**Frontend:**
|
|
- `xterm` (v5.x)
|
|
- `xterm-addon-fit`
|
|
- `xterm-addon-web-links`
|
|
|
|
## Migration Plan
|
|
|
|
1. Install xterm.js dependencies
|
|
2. Create backend WebSocket endpoint
|
|
3. Create TerminalManager and TerminalSession
|
|
4. Create frontend TerminalComponent
|
|
5. Add terminal route and navigation
|
|
6. Test with running instances
|
|
|
|
## Testing
|
|
|
|
- Unit: TerminalSession I/O streaming
|
|
- Integration: WebSocket connection lifecycle
|
|
- Manual: Terminal functionality with real containers
|
|
|
|
## Quality Gates
|
|
|
|
- pytest
|
|
- mypy
|
|
- ruff
|
|
- npm run typecheck
|
|
- npm run lint
|
|
- npm run build
|