feat(dashboard): React Vite real-time monitoring dashboard#93
Open
renakaagusta wants to merge 1 commit intoPleasePrompto:mainfrom
Open
feat(dashboard): React Vite real-time monitoring dashboard#93renakaagusta wants to merge 1 commit intoPleasePrompto:mainfrom
renakaagusta wants to merge 1 commit intoPleasePrompto:mainfrom
Conversation
Adds a dashboard/ subfolder with a React + Vite + TypeScript + Tailwind
web UI for monitoring Claude Code activity in real time.
Backend changes (ductor_bot/api/server.py):
- Add GET /dashboard/status — provider, model, uptime, connection counts
- Add GET /dashboard/sessions — sessions list from sessions.json
- Add GET /dashboard/tasks — task list from TaskHub
- Add GET /dashboard/logs — list log files
- Add GET /dashboard/logs/{filename} — serve log file content
- Add WS /dashboard/stream — real-time event broadcast (no NaCl)
- Add broadcast_dashboard() method wired into _StreamCallbacks
- Wire set_sessions_path / set_logs_dir / set_task_hub_getter in lifecycle.py
Dashboard (React Vite app):
- Status page — auto-refreshes every 5s
- Live Stream page — WebSocket terminal with DOM-direct append (no re-render per chunk)
- Sessions & Tasks page — auto-refreshes every 3s
- Logs page — browse and read ~/.ductor/logs/ files
- Auto-reconnecting WebSocket hook with exponential backoff
- Bearer token auth (HTTP) / query-param token (WebSocket)
- Vite dev proxy: /dashboard/api and /dashboard/ws → localhost:8741
Usage: cd dashboard && npm install && npm run dev
Requires: api.enabled: true and api.token set in ~/.ductor/config/config.json
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
dashboard/React + Vite + TypeScript + Tailwind web app for monitoring Claude Code activity in real time/dashboard/*aiohttp endpoints toApiServer(no NaCl encryption, Bearer/query-param token auth)orchestrator/lifecycle.pyvia existing setter patternWhat's in the dashboard
sessions.jsonand task list from TaskHub — refreshes every 3s~/.ductor/logs/filesNew Python endpoints
GET/dashboard/statusGET/dashboard/sessionsGET/dashboard/tasksGET/dashboard/logsGET/dashboard/logs/{filename}WS/dashboard/stream?token=query paramAll dashboard endpoints reuse the existing
config.api.tokenfor auth. The WebSocket uses query-param token because browsers cannot set custom headers on WebSocket upgrade requests.Usage
Architecture decisions
/wsuses NaCl Box E2E encryption — impractical to implement in a browser. Dedicated/dashboard/*endpoints with simple Bearer token auth are appropriate for local use.<pre>ref, bypassing React reconciler. Only the latest chunk is React state — preventing one re-render per streamed character.useWebSockethook uses exponential backoff (1s → 30s cap) with unmount-safe cleanup.aiohttp(already a core dependency).Post-Deploy Monitoring & Validation
ductor logs— watch forDashboard WebSocket connected/disconnectedmessagesGET /dashboard/statusreturns 200 with"status": "ok"; WS/dashboard/streamconnects and receives{"type": "ping"}immediatelyapi.enabled: false; WS disconnect loop = checkapi.tokenis setapi.enabled: true, localhost-only by default