- Add !cancel command (anyone cancels own blackjack; PL50+ clears all room games)
- Add !wordlestats top-level command (wraps wordle stats function)
- Add !cleanwelcome admin command to purge stale welcome DM records
- !help now hides management section from sub-PL50 users, hides !health from non-admins
- !announce uses nio room cache for join_rule instead of an API call per room
- Fix _INVITEALL_BLOCKED comment (Commands is knock-gated, not restricted)
- welcome.py: skip duplicate DM if a pending welcome already exists for the user
- welcome.py: add clean_stale_dm_messages() helper
- welcome.py: replace no-op post_welcome_message with log_ready()
- bot.py: update import/call to match welcome.py rename
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
nio has a dedicated ReactionEvent type with .reacts_to and .key attributes.
The callback was registered for UnknownEvent so reaction events were silently
dropped. Register for ReactionEvent and use its native attributes; keep the
UnknownEvent fallback for edge cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove unused imports: logging from bot.py and config.py, RoomMessageText/
UnknownEvent from callbacks.py, functools.partial and MAX_INPUT_LENGTH from
commands.py. Rename unused local variables to _ (resp in cmd_ping, symbols in
render_keyboard_plain, guesses_left in two wordle functions). Move wordle import
to top of commands.py to fix E402.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All bot source files from LXC 151 (/opt/matrixbot) are now tracked here.
Secrets (.env, credentials.json), venv dirs, and runtime state files
(nio_store, welcome_state.json, wordle_stats.json) are excluded via .gitignore.
Includes deploy.sh to sync files to /opt/matrixbot and restart the service.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>