Skip to content

feat(dashboard): React Vite real-time monitoring dashboard#93

Open
renakaagusta wants to merge 1 commit intoPleasePrompto:mainfrom
renakaagusta:feat/dashboard
Open

feat(dashboard): React Vite real-time monitoring dashboard#93
renakaagusta wants to merge 1 commit intoPleasePrompto:mainfrom
renakaagusta:feat/dashboard

Conversation

@renakaagusta
Copy link
Copy Markdown

Summary

  • Adds dashboard/ React + Vite + TypeScript + Tailwind web app for monitoring Claude Code activity in real time
  • Adds lightweight /dashboard/* aiohttp endpoints to ApiServer (no NaCl encryption, Bearer/query-param token auth)
  • Wires new endpoints into orchestrator/lifecycle.py via existing setter pattern

What's in the dashboard

Page Description
Status Provider, model, uptime, connection counts — auto-refreshes every 5s
Live Stream Real-time Claude Code output via WebSocket terminal; DOM-direct append avoids React re-renders per chunk
Sessions & Tasks Active sessions from sessions.json and task list from TaskHub — refreshes every 3s
Logs Browse and read ~/.ductor/logs/ files

New Python endpoints

Method Path Auth
GET /dashboard/status Bearer
GET /dashboard/sessions Bearer
GET /dashboard/tasks Bearer
GET /dashboard/logs Bearer
GET /dashboard/logs/{filename} Bearer
WS /dashboard/stream ?token= query param

All dashboard endpoints reuse the existing config.api.token for auth. The WebSocket uses query-param token because browsers cannot set custom headers on WebSocket upgrade requests.

Usage

# 1. Enable API in ~/.ductor/config/config.json
#    "api": { "enabled": true, "token": "your-token", "allow_public": false }

# 2. Restart ductor
ductor restart

# 3. Run dashboard
cd dashboard
npm install
npm run dev
# → http://localhost:5173

# 4. Set token in browser console
localStorage.setItem('ductor_token', 'your-token')

Architecture decisions

  • No NaCl in browser: The existing /ws uses NaCl Box E2E encryption — impractical to implement in a browser. Dedicated /dashboard/* endpoints with simple Bearer token auth are appropriate for local use.
  • DOM-direct streaming: The Terminal component appends text nodes directly to a <pre> ref, bypassing React reconciler. Only the latest chunk is React state — preventing one re-render per streamed character.
  • Auto-reconnect: useWebSocket hook uses exponential backoff (1s → 30s cap) with unmount-safe cleanup.
  • Zero new Python deps: All backend changes use only aiohttp (already a core dependency).

Post-Deploy Monitoring & Validation

  • Logs: ductor logs — watch for Dashboard WebSocket connected / disconnected messages
  • Expected healthy signals: GET /dashboard/status returns 200 with "status": "ok"; WS /dashboard/stream connects and receives {"type": "ping"} immediately
  • Failure signals: 401 = wrong token; 503 = api.enabled: false; WS disconnect loop = check api.token is set
  • No production impact: Dashboard is opt-in via api.enabled: true, localhost-only by default

Compound Engineered 🤖 Generated with Claude Code

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant