Store watcher dispatcher fallback (#33) — when another process (e.g. MCP server) holds the poll lock, on_message handlers and run_background() now automatically fall back to watching the SQLite message store for new messages instead of failing; enables running SDK callback hooks alongside an MCP server without any code changes
Additional media metadata — ImageInfo.mid_size / thumb_size, VideoInfo.thumb_media / video_size / thumb_size parsed from iLink responses
Dispatcher queue overflow protection (#7) — bounded internal queue (default 1,000) drops oldest message on overflow with a warning log; configurable via WeiLink(queue_maxsize=N)
Admin panel auto-refresh — message drawer polls for new messages while open; idle sessions hidden from the session list
Fix prune leaving implicit write transaction — MessageStore.prune() now always commits, preventing SQLite lock contention when multiple connections open the same database
AI coding assistant integration — new weilink setup command installs hooks, MCP config, and slash commands for Claude Code, Codex, and OpenCode with a single command; weilink setup claude-code symlinks a full plugin (auto-polling hook + MCP + /weilink skill), weilink setup codex installs hooks and command, weilink setup opencode merges MCP config into opencode.json
Hook poll engine — new weilink hook-poll reads the local SQLite message store and outputs new messages as JSON; used by UserPromptSubmit hooks in Claude Code and Codex to auto-inject incoming WeChat messages into conversation context
Cross-platform file locking (#8) — replace internal _filelock.py (no-op on Windows) with zerodepfilelock module; Windows now uses msvcrt.locking for real cross-process locking instead of silently skipping
Rename server tools to match SDK (#6) — recv_messages → recv, send_message → send, download_media → download, get_message_history → history, list_sessions → sessions; tool names now mirror the SDK method names for consistency across all three API layers
Merge login + check_login into single login tool — the login tool is now stateful: first call starts a QR flow, subsequent calls poll with a configurable timeout (default 30s) until status changes; check_login has been removed
Default session subdirectory layout — the default session now stores files in base_path/default/ instead of flat in base_path/; existing flat layouts are auto-migrated on first load; this unifies the directory structure for all sessions
SQLite message persistence — new MessageStore (_store.py) backed by SQLite WAL mode stores all received and sent messages to messages.db; enables message history queries, prevents message loss across restarts, and provides a download fallback after server restart; opt-in via WeiLink(message_store=True), enabled by default in MCP/OpenAPI server mode
history server tool — query past messages by user, bot, type, direction, time range, or text content; supports pagination with limit/offset
logout server tool — log out a session and remove persisted credentials
rename_session server tool — rename a session
set_default server tool — set a session as the default
Cooperative polling fallback — when message_store is enabled and the poll lock is held by another process, recv() reads recent messages from SQLite instead of returning an empty list; enables multi-client access without a central server
CLI bot commands — new subcommands login, logout, status, recv, send, download, history, and sessions (with rename/default sub-subcommands); all commands support --json for machine-readable output and -d, --base-path for custom data directories
Atomic file writes — token.json, contexts.json, and .default_session are now written via temp-file + os.replace() to prevent corruption on crash
Admin panel message history — slide-out chat drawer showing per-user conversation with WeChat-style bubbles; supports all message types, pagination, type filtering, and text search
Lazy media download in admin panel — download button on media messages fetches from CDN on demand via GET /api/messages/<id>/download
Background auto-polling — admin panel and MCP/OpenAPI server now call run_background() on startup, so users and messages appear automatically without waiting for an explicit recv call
Fix admin panel login not saving user_id — _handle_poll_login now extracts ilink_user_id from the QR confirmation response and stores it in BotInfo, matching the SDK login() behaviour
Consolidate admin panel User ID display — replaced the redundant "Users" column with a unified "User ID" column showing the bot owner's WeChat user ID and active/expired badge; added user_id field to the /api/sessions response
Add debug logging to protocol layer — _protocol.py now logs all HTTP requests/responses, get_updates message counts, cursor changes, and error details at DEBUG/INFO level for easier troubleshooting
Add debug logging to MCP recv — server/app.py logs polling start, message counts, and individual message details
Add Docker entrypoint with PUID/PGID support — new entrypoint.sh fixes /data/weilink ownership at runtime via su-exec, allowing bind-mounted volumes to match host user permissions
Cross-process profile locking (#5) — multiple WeiLink instances sharing the same data directory (~/.weilink/) are now coordinated via fcntl.flock()-based file locks; a non-blocking poll lock (.poll.lock) ensures only one process polls iLink at a time, while a short-lived data lock (.data.lock) serializes read-modify-write cycles on token.json / contexts.json; prevents cursor divergence, send_count corruption, and file corruption across SDK scripts, stdio MCP, and admin panel processes
Fix session rename leaving stale directory — add per-session _io_lock to serialize file I/O operations (rename, save, load, logout) on _Session; rename now uses shutil.rmtree instead of rmdir to force-clean the old directory; prevents race condition where a background thread could recreate the old directory between file move and path update
Rename weilink.mcp module to weilink.server — internal server module moved from weilink.mcp.server to weilink.server.app; use python -m weilink.server instead of python -m weilink.mcp; CLI subcommands (weilink mcp, weilink openapi, weilink admin) and install extras (weilink[mcp], weilink[server]) are unchanged
Credential migration CLI(experimental) — weilink migrate openclaw imports sessions from the OpenClaw weixin plugin (@tencent-weixin/openclaw-weixin) without re-scanning the QR code; supports --dry-run and --source to customize the OpenClaw state directory
Send quota tracking (58de18b) — SDK tracks per-user send count against the 10-message context_token quota; raises QuotaExhaustedError when exhausted; SendResult.remaining shows the countdown
TextTooLongError (58de18b) — send() raises TextTooLongError with actual byte length when text exceeds the 16 KiB UTF-8 limit, instead of silently splitting
BotInfo.user_id (3772776) — login now captures the WeChat user ID that authorized the bot; accessible via Session.user_id
Multi-session support (7dbb23d) — register one bot with multiple WeChat accounts via login(name="..."); recv() polls all sessions concurrently, send() auto-routes to the correct session
CDN pre-upload (20f660e) — upload() pre-uploads media to CDN, returns reusable UploadedMedia reference; send() accepts it to avoid re-uploading
auto_recv on send() (#4, c72099a) — optionally refresh context tokens before sending; returns SendResult (bool-compatible) carrying any messages received during the refresh
Quoted message support (#3, c984f72) — Message.ref_msg exposes the referenced message when a user replies to a previous message
MCP server (837997f) — stdio, sse, and streamable-http transports; --admin-port flag to co-host admin panel
OpenAPI server (e40c126) — expose bot tools as REST API endpoints via weilink openapi
Web admin panel (c65a28a) — browser UI for session management, QR login, and status monitoring
Docker deployment (e1450dd) — container image with MCP SSE + admin panel, docker-compose.yaml included
Unified CLI (9a48774) — single weilink command with admin, mcp, and openapi subcommands