Files
headquarter/openspec/changes/archive/2026-05-19-tool-terminal/specs/spec.md
T
Fusion 40a940304b docs: comprehensive API documentation
- 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
2026-05-19 21:31:20 +02:00

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