feat(bridge): DingTalk channel plugin + OpenClaw Protocol v3 rewrite
Core changes:
- src/channels/dingtalk.ts: DingTalk Stream SDK channel (no public IP needed)
- TokenManager: auto-refresh with refreshPromise mutex (prevents race condition)
- UserQueue: per-user serial queue, max depth 5
- MsgDedup: O(1) Map<string,timestamp> with 10min TTL + 10k cap
- RateLimiter: sliding window 10 msg/min per user
- ResilientOcClient: 10s heartbeat poll + atomic reconnect guard
- DingTalkStream: exponential backoff reconnect (2s→60s), immediate ACK
- replyToUser: sessionWebhook expiry check + 4800-char chunking
- src/openclaw-client.ts: rewritten for correct Protocol v3 wire format
- Request frame: { type:"req", id, method, params }
- Challenge-response Ed25519 handshake (connect.challenge → connect req)
- Correct rpc() with configurable timeoutMs
- src/index.ts: fixed RPC method names
- agent.run → chat.send with { sessionKey, message, timeoutSeconds }
- metrics.get → gateway.status
- Dockerfile: adds start-dingtalk.sh COPY + chmod
- supervisord.conf: dingtalk-channel program block (autorestart=unexpected)
- start-dingtalk.sh: exits 0 if DINGTALK_CLIENT_ID unset (no restart loop)
- CHANNEL_DEV_GUIDE.md: full dev guide for future channel integrations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>