Complete real-time monitoring dashboard for Claude Code Features: - FastAPI backend with REST API and WebSocket - React + TypeScript frontend with dark theme - SQLite database for event storage - 6 hook scripts for Claude Code events - Docker deployment setup - Real-time event tracking and statistics - Event filtering (ALL, TOOLS, AGENTS, PROMPTS, SESSIONS) - Connection status indicator - Reset stats functionality Tech Stack: - Backend: Python 3.11, FastAPI, SQLAlchemy, WebSockets - Frontend: React 18, TypeScript, Vite - Database: SQLite - Deployment: Docker, Docker Compose 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
66 lines
2.1 KiB
Python
66 lines
2.1 KiB
Python
"""WebSocket API endpoint for real-time updates."""
|
|
|
|
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends
|
|
from sqlalchemy.orm import Session
|
|
import logging
|
|
import json
|
|
|
|
from app.websocket import manager
|
|
from app.database import get_db
|
|
from app.crud import get_statistics
|
|
|
|
router = APIRouter(tags=["websocket"])
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@router.websocket("/ws")
|
|
async def websocket_endpoint(websocket: WebSocket):
|
|
"""
|
|
WebSocket endpoint for real-time event updates.
|
|
|
|
Clients connect to this endpoint to receive:
|
|
- New events as they're created
|
|
- Updated statistics
|
|
- Reset notifications
|
|
|
|
Message types:
|
|
- event_created: New event with updated statistics
|
|
- stats_updated: Statistics update
|
|
- stats_reset: All stats have been reset
|
|
- connection_status: Connection status message
|
|
"""
|
|
await manager.connect(websocket)
|
|
|
|
try:
|
|
# Send initial connection message
|
|
await manager.send_personal_message(
|
|
{"type": "connection_status", "message": "Connected to Claude Code Monitor"},
|
|
websocket,
|
|
)
|
|
|
|
# Keep connection alive and handle incoming messages
|
|
while True:
|
|
try:
|
|
# Receive messages from client (for future features like pings)
|
|
data = await websocket.receive_text()
|
|
message = json.loads(data)
|
|
|
|
# Handle ping/pong for connection health
|
|
if message.get("type") == "ping":
|
|
await manager.send_personal_message(
|
|
{"type": "pong", "timestamp": message.get("timestamp")},
|
|
websocket,
|
|
)
|
|
|
|
except WebSocketDisconnect:
|
|
logger.info("Client disconnected")
|
|
break
|
|
except Exception as e:
|
|
logger.error(f"Error handling WebSocket message: {e}")
|
|
# Don't break on error, continue listening
|
|
|
|
except Exception as e:
|
|
logger.error(f"WebSocket error: {e}")
|
|
finally:
|
|
manager.disconnect(websocket)
|