When no OpenClaw gateway is detected, Mission Control now automatically
switches to Local Mode — showing a clear info banner, greying out
gateway-dependent panels, and surfacing Claude Code session stats,
GitHub profile data, and subscription-aware cost display.
Changes:
- Add capabilities endpoint to detect gateway, Claude home, subscription
- Add dashboardMode/gatewayAvailable/subscription state to Zustand store
- Add dismissible LocalModeBanner component
- Grey out Agents/Spawn/Config nav items when no gateway
- Show blue "Local Mode" indicator instead of red "Disconnected"
- Dashboard shows local metric cards (sessions, projects, tokens, cost)
- Claude Code Stats panel with session/token/cost breakdown
- GitHub panel with repo stats, languages, star/fork counts
- Subscription detection from ~/.claude/.credentials.json
- Show "Included (Max plan)" instead of dollar cost for subscribers
- Fix token cost estimation (cache reads at 10%, not 100%)
- Sessions API falls back to local Claude session scanner
- Live feed injects session items in local mode
- Memory browser auto-creates data dir with fallback path
Cherry-picks three valuable fixes from @doanbactam's WebSocket refactor PR:
1. Feed item ID collision fix — prefix log IDs with 'log-' to avoid
React key collisions with activity IDs in the combined feed
2. Jittered reconnect backoff — add random jitter (0-50% of base) to
WebSocket exponential backoff to prevent thundering-herd reconnects
when multiple tabs reconnect after a server restart
3. Cron job deduplication + async I/O — deduplicate jobs.json entries
by name (keeps latest), prevent duplicates on add, and convert
sync file reads/writes to async to avoid blocking the event loop
Co-authored-by: Doan Bac Tam <24356000+doanbactam@users.noreply.github.com>
Security hardening:
- Fix timing-safe comparison bugs in webhooks.ts and auth.ts (was comparing buffer with itself)
- Harden rate limiter IP extraction — use rightmost untrusted IP from XFF chain with MC_TRUSTED_PROXIES support
- Add 12-char minimum password validation in Zod schema and runtime check
- Add Zod validation on PUT /api/tasks bulk status update
Webhook retry system (completing in-progress feature):
- Exponential backoff with circuit breaker in webhooks.ts
- POST /api/webhooks/retry endpoint for manual retry
- GET /api/webhooks/verify-docs endpoint for signature verification docs
- Scheduler integration for automatic retry processing
- Unit tests for signature verification and backoff logic
Local Claude Code session tracking:
- New claude-sessions.ts scanner parses JSONL transcripts from ~/.claude/projects/
- Extracts model, tokens, messages, cost estimates, active status per session
- Migration 020 adds claude_sessions table
- GET/POST /api/claude/sessions endpoint with filtering and aggregate stats
- Scheduler runs scan every 60s with MC_CLAUDE_HOME config
Quality improvements:
- Replace all console.error/warn with structured logger across 31 API routes
- Add Docker HEALTHCHECK directive
- Add vitest coverage config with v8 provider (60% threshold)
- Update README with new features, API docs, env vars, and roadmap items
- Fix E2E tests for password length and rate limiter IP changes
- Add openapi.json spec covering all 59 API routes (~95 operations)
- Serve spec at GET /api/docs (no auth required, cached)
- Add interactive Scalar API reference UI at /docs
- Allow unauthenticated access to /api/docs and /docs in middleware
- Add @scalar/api-reference-react dependency
- Add 3 E2E tests for spec validation and auth bypass
- Add `agents` field to tokens action=stats response (groups by agent
extracted from sessionId split on ':')
- Add new action=agent-costs returning per-agent stats, model breakdown,
session list, and daily cost/token timeline
- New AgentCostPanel with summary cards, pie chart, trend lines,
efficiency bars, and expandable ranking table
- Add nav-rail entry in OBSERVE group after Tokens
- Add ContentRouter case for agent-costs tab
- Add 5 E2E tests for the new API endpoints
- Sanitize session ID in control route to prevent command injection
via unsanitized URL params interpolated into shell commands
- Add mutationLimiter and structured logging to session control endpoint
- Install python3/make/g++ in Dockerfile deps stage for better-sqlite3
native addon compilation
- Handle missing public/ directory in Docker COPY with glob pattern
- Guard pino-pretty transport against missing devDependency at runtime