diff --git a/src/dashboard/app.py b/src/dashboard/app.py index d10489f..28360d2 100644 --- a/src/dashboard/app.py +++ b/src/dashboard/app.py @@ -500,6 +500,42 @@ async def ws_redirect(websocket: WebSocket): await websocket.send({"type": "websocket.close", "code": 1008}) +@app.websocket("/swarm/live") +async def swarm_live(websocket: WebSocket): + """Swarm live event stream via WebSocket.""" + from infrastructure.ws_manager.handler import ws_manager as ws_mgr + + await ws_mgr.connect(websocket) + try: + while True: + # Keep connection alive; events are pushed via ws_mgr.broadcast() + await websocket.receive_text() + except Exception: + ws_mgr.disconnect(websocket) + + +@app.get("/swarm/agents/sidebar", response_class=HTMLResponse) +async def swarm_agents_sidebar(): + """HTMX partial: list active swarm agents for the dashboard sidebar.""" + try: + from config import settings + + agents_yaml = settings.agents_config + agents = agents_yaml.get("agents", {}) + lines = [] + for name, cfg in agents.items(): + model = cfg.get("model", "default") + lines.append( + f'
' + f'{name}' + f'{model}' + f"
" + ) + return "\n".join(lines) if lines else '
No agents configured
' + except Exception: + return '
Agents unavailable
' + + @app.get("/", response_class=HTMLResponse) async def root(request: Request): """Serve the main dashboard page.""" diff --git a/src/dashboard/middleware/csrf.py b/src/dashboard/middleware/csrf.py index e5b5189..e3a8320 100644 --- a/src/dashboard/middleware/csrf.py +++ b/src/dashboard/middleware/csrf.py @@ -134,6 +134,10 @@ class CSRFMiddleware(BaseHTTPMiddleware): if settings.timmy_disable_csrf: return await call_next(request) + # WebSocket upgrades don't carry CSRF tokens — skip them entirely + if request.headers.get("upgrade", "").lower() == "websocket": + return await call_next(request) + # Get existing CSRF token from cookie csrf_cookie = request.cookies.get(self.cookie_name)