* feat: add 'sessions' subcommand with TUI viewer (WIP)
* feat: add 'sessions' subcommand with TUI viewer for browsing session history
Three modes: interactive TUI browser (default), non-interactive list,
and non-interactive show. Reads session JSON files directly from
~/.cc-connect/sessions/ without requiring the daemon to be running.
- TUI: bubbles/table overview + bubbles/viewport detail with lipgloss styling
- `sessions list`: pipe-friendly tabwriter output
- `sessions show <id> [-n N]`: view specific session by composite ID or index
* feat: persist user/group names for sessions viewer
- Add UserMeta (UserName/ChatName) to SessionManager with persistence
- Capture metadata in engine.handleMessage() on every incoming message
- Fix feishu userName bug: was using sender.SenderType ("user"), now
calls resolveUserName() for actual display names
- Populate ChatName with Chat.Title for Telegram group chats
- Display User and Group/Chat columns in sessions list/show/TUI
- Return copy from GetUserMeta() for thread safety
- Use rune-based truncation to avoid corrupting multi-byte UTF-8
* feat: add user/chat name resolution for all platforms
- Slack: resolve UserName via GetUserInfo API, ChatName via channel name
- Discord: resolve ChatName via Channel API with sync.Map cache
- LINE: resolve UserName via GetProfile API with sync.Map cache
- DingTalk: populate ChatName from ConversationTitle (SDK provides it)
- QQ (OneBot): resolve ChatName via get_group_info API with cache
- WeChat Work (HTTP): resolve UserName via user/get API with cache
Platforms with API limitations (left as raw ID):
- QQ Bot: official API does not provide user nicknames
- WeChat Work (WS): no REST API access from WebSocket mode
* fix: consistent fallback to raw ID when name resolution fails
- Slack: resolveChannelNameForMsg returns channelID (not "") on error
- Discord: resolveChannelName returns channelID (not "") on error,
skip caching empty names
- QQ: resolveGroupName returns groupID string (not "") on error
- WeChat Work WS: add comment documenting why raw userID is used
* feat: add chat/group name resolution for feishu and LINE
- Feishu: resolve chat name via Im.Chat.Get API with sync.Map cache,
populate ChatName for all message types
- LINE: resolve group name via GetGroupSummary API with sync.Map cache,
populate ChatName for group messages
* fix: populate UserName/ChatName in all remaining message paths
- Feishu: add UserName + ChatName to onCardAction handler (perm/askq/cmd)
- QQ Bot: add GroupOpenID as ChatName fallback in group messages
- WeChat Work WS: add ChatID as ChatName for group chats