Commit graph

78 commits

Author SHA1 Message Date
Rosie Val
76889459fa
Delete wormhole/listeners/relay.py 2026-07-22 16:06:56 -04:00
Rosie Val
1fbb2657fd fix: add network validation and logging to all settings commands
- Added null check for network existence in all wh set commands
- All setting changes now log to the log channel with descriptive titles
- Prevents KeyError crashes on invalid network names
- Improves audit trail for administrator actions
2026-07-21 22:34:31 -04:00
Rosie Val
0cad208455 fix: disable mention parsing in relay to prevent unintended pings
- Add `allowed_mentions=discord.AllowedMentions(parse=[])` to all webhook and channel sends
- Prevents users from being pinged when replies are relayed across the network
- Fixes issue where reply context could trigger unintended mentions across all servers
- Applies to webhook sends (primary and fallback) and embed/compact relay modes
2026-07-21 21:50:06 -04:00
Omega Launcher
814b0e79e9 fix(support): remove core commands in setup before cog loads
Remove Red's built-in contact and dm commands in setup() before the Support
cog loads to prevent command registration conflicts. Commands are stored and
restored in teardown() when the cog unloads.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-06-12 17:49:07 +01:00
Omega Launcher
26b1bf9253 feat(support): add modernized contact/dm system replacing Red core commands
Add comprehensive Support cog that automatically disables and replaces Red's
built-in contact and dm commands with enhanced, feature-rich versions.

Features:
- Command override mechanism (disables core commands on load, restores on unload)
- Multi-category support system with dedicated channels
- Custom emojis, greetings, and descriptions per category
- User blocking/unblocking system
- Comprehensive logging to dedicated log channel
- Anonymous mode for staff replies
- Enhanced embed formatting
- Category selection dropdown UI
- Staff control buttons (Close Thread, Block User)
- Reply modal for staff responses
- Background thread cleanup task

Commands:
- [p]contact - Enhanced contact command (DM only)
- [p]dm - Enhanced DM command with logging
- [p]supportset - 15 admin configuration commands

Documentation:
- README.md - Full documentation (7.9K)
- QUICKSTART.md - Quick setup guide (2.5K)
- EXAMPLES.md - Configuration examples (8.1K)
- TECHNICAL.md - Technical docs (8.6K)
- CHANGELOG.md - Version history
- test_override.py - Override mechanism reference

Technical:
- 625 lines of code
- 33 async functions
- Full type hints
- Config-based data storage
- Red 3.5.0+ compatible
- Follows NexusCore patterns

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-06-12 17:45:13 +01:00
root
2f97926ca6 fix(wormhole): remove wait_until_ready() from _init() to prevent load timeout
Root cause: _init() was blocking on wait_until_ready() for up to 30 seconds,
causing Red's package load to timeout. Red then reports 'Failed to load
package wormhole (timeout)' but the cog is actually partially loaded,
causing 'already loaded' errors on retry.

Timeline:
1. [p]load wormhole starts
2. setup() calls bot.add_cog(cog) ✓
3. setup() calls await cog._init()
4. _init() blocks on wait_until_ready() for 30s
5. Red's load timeout (30s) triggers
6. Red reports 'timeout' but cog is registered
7. [p]load wormhole again → 'already loaded' error

Solution: Remove wait_until_ready() from _init() since:
- Bot is already ready when cogs load on startup
- Background loops have their own wait_until_ready() calls
- _init() shouldn't block setup()

Background loops still wait_until_ready() independently (correct behavior).

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:43:46 +00:00
root
6fd48e93af fix(wormhole): rename cog class to WormholeV4 to bypass stale registration
Problem: Red's internal state has stale 'Wormhole' cog registrations from
previous versions (both identifier 7730187301 and 928374650), causing
'Cog named Wormhole already loaded' errors even on fresh bot starts.

Root cause: Multiple config identifiers registered under same cog name:
  - wormhole: {'wormhole': {}}  (old lowercase)
  - Wormhole: {'7730187301': {}, '928374650': {}}  (two identifiers!)

Solution: Rename cog class Wormhole → WormholeV4 to bypass all stale
registration state. This gives a clean slate without requiring users to
manually purge config data.

Changes:
- class Wormhole → class WormholeV4 in core.py
- Updated __init__.py import and setup()
- Config identifier unchanged (928374650)

This completely sidesteps the phantom load bug without touching user data.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:38:56 +00:00
root
0c41ae0b9f feat(wormhole): disable context menus to eliminate load issues
Problem: Context menus persist in Discord's command tree even after bot
shutdown, causing 'already loaded' errors on restart. The idempotent
registration fix helped but added complexity.

Solution: Disable context menus entirely. All functionality remains
available via slash/prefix commands:
  - Report: /wh report message [msg_id] [reason]
  - Bookmark: /wh bookmark save [msg_id]
  - Delete: /wh delete [msg_id] (staff only)
  - Profile: /wh profile [user]

Changes:
- Commented out _register_context_menus() call in _init()
- Kept registration/callback code for future reference
- Simplified cog_unload() - no context menus to remove

Benefits:
- No command tree registration complexity
- Clean reload every time
- No phantom 'already loaded' state
- Simpler cog lifecycle

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:35:27 +00:00
root
c8bc14fb42 fix(wormhole): make context menu registration idempotent
Problem: If bot crashes or shuts down ungracefully, context menus stay
registered in Discord's command tree. On restart, add_command() fails
with 'already loaded' error.

Solution: Remove existing context menus before registering new ones.
This makes registration idempotent (safe to run multiple times).

Changes:
- _register_context_menus() now removes existing menus first
- Wrapped in try/except to handle 'not found' gracefully
- Ensures clean reload even after ungraceful shutdown

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:33:09 +00:00
root
15eb047d15 chore(wormhole): remove archived monolith - not needed in repo
The old monolithic file is not needed in version control.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:27:08 +00:00
root
dc695a43ed chore(wormhole): archive old monolithic wormhole.py for reference
Keeping the 4,782-line v3.4.6 monolith as wormhole.py.old for:
- Historical reference
- Rollback safety
- Migration verification

This file is NOT loaded by the cog - it's purely archival.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:26:42 +00:00
root
44d7f79c13 fix(wormhole): fix persistence bug and finalize v4.0.0 modular architecture
BREAKING: Removed obsolete monolithic wormhole.py (4,782 lines)
The v4.0.0 modular architecture was already implemented but the old
file was still present causing confusion.

Fixes:
- Fix context menu cleanup in cog_unload (add type parameter)
- Remove obsolete wormhole.py monolith (archived as .old)
- Context menus now properly unregister on reload

Architecture:
- core.py (731 lines) - main cog class
- commands/ (14 modules, 2,645 lines) - command mixins
- listeners/ (3 modules) - event handlers
- models/ (3 modules) - data structures
- services/ (1 module) - business logic
- ui/ (2 modules) - Discord UI components

Documentation:
+ ARCHITECTURE.md - design overview and history
+ MODULE_MAP.md - developer quick reference

This fixes the "already loaded" phantom state bug where wormhole
wouldn't persist through restarts and required double-loading.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:26:03 +00:00
root
3aeb656633 feat(rubylogging): add attachment re-upload to preserve deleted images permanently
**The Problem:**
Discord CDN URLs (even proxy URLs) expire after message deletion, so image
previews in logs would show as broken after a few minutes.

**The Solution:**
- New "reupload" feature (enabled by default) downloads and re-uploads attachments
- Deleted images/GIFs are permanently preserved in the log channel
- Works with aiohttp to download attachments asynchronously
- Attaches files directly to log message (up to 10 per message)

**Features:**
- `[p]rlog attachments reupload` - Toggle re-uploading on/off
- Downloads images when message is deleted
- Re-uploads as Discord Files (permanent storage)
- Falls back to URL embedding if download fails
- Shows status in settings display

**Improvements:**
- Use proxy URLs throughout for better persistence
- Pass cached attachments through message object
- Better file extension detection (.png, .jpg, .jpeg, .gif, .webp)
- Track ephemeral attachments
- Exception handling for download failures

**Trade-offs:**
- Uses bandwidth to download/upload
- Files become permanent in log channel
- Worth it for permanent image preservation!

Images and GIFs now remain visible in logs forever! 🖼️

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 22:11:49 +00:00
root
645a8f6985 fix(rubylogging): eliminate duplicate logs and add image previews
**Fixed Duplicate Logs:**
- Skip registering generic handlers for message_delete and bulk_delete
- These events are now handled only by specialized attachment handlers
- Eliminates 2x delete logs and 3x edit logs issue

**Added Image Previews:**
- Deleted messages now show image previews in the embed
- Cached attachments display the actual image/GIF
- Multiple images shown as separate embeds with numbering
- set_image() on main embed for first attachment

**Improved Message Edit Display:**
- No more duplicate "Argument 1" and "Argument 2"
- Clean before/after content comparison
- Shows context (author, channel, jump link) separately
- Better content truncation (200 chars vs 50)
- Pin status with emoji (📌 Pinned)
- Tracks attachment count changes

**Better Change Detection:**
- Message edits: old/new content, pin status, embeds, attachments
- Cleaner formatting with proper line breaks
- Longer content previews for readability

All logs are now single, beautiful embeds with image previews!

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 22:08:17 +00:00
root
85f5306289 fix(rubylogging): add missing Tuple import
Added Tuple to typing imports to fix NameError when loading the cog.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 21:52:02 +00:00
root
d446c65acd feat(rubylogging): beautify logs with rich details and before/after comparisons
**Visual Enhancements:**
- Category-specific emojis (🏰 guilds, 💬 channels, 👥 members, etc.)
- RGB color coding for each category
- Guild icon in footer
- Beautiful embed formatting with proper spacing

**Enhanced Details:**
- Member: status, join date, account age, role count, top role
- Guild: boost level, channels breakdown, features list, member count
- Channels: privacy status, slowmode, NSFW flag, bitrate, region
- Roles: color hex, hoist status, permissions list, member count
- Messages: jump URL, embeds/reactions count, reply detection
- Timestamps: Discord relative timestamps (<t:X:R>)

**Before/After Comparisons:**
- Automatic change detection for _update events
- Shows exactly what changed with → arrows
- Member: nickname, roles, status, timeout changes
- Guild: name, icon, owner, boost level, verification
- Role: name, color, hoist, mentionable, permissions
- Channel: name, category, slowmode, NSFW, limits
- Message: content diff, pin status, embed count

**Advanced Formatting:**
- Member count with commas (10,000+)
- Role previews (shows top 3 + count)
- Permission summaries (Administrator 👑, etc.)
- Status indicators (🟢 online, 🟡 idle, 🔴 dnd)

All logs are now production-grade beautiful!

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 21:20:02 +00:00
root
3e05111c21 fix(newhelpmenu): remove duplicate help command - hook send_help_for instead
Fixed issue where help was being sent twice by completely removing our
custom help command and instead hooking Red's bot.send_help_for method.
This allows Red's help command to process normally, then we intercept
the actual help rendering when CV2 is enabled.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 21:18:21 +00:00
root
e56c0ed958 feat: comprehensive audits + fixes for UserSlash & NewHelpMenu, new RubyLogging cog
**NEW: RubyLogging**
- 100+ Discord events across 18 categories, all individually toggleable
- Intelligent attachment/media logging with preview embeds
- Tracks images, GIFs, videos, stickers - even after deletion
- Automatic caching of attachments for deleted message recovery
- Format options: detailed/compact/JSON
- Advanced filtering: ignore bots/users/channels
- Per-category enable/disable
- Quick setup command with sensible defaults
- Settings management with cache status

**UserSlash: Critical & High Severity Fixes**
- Added comprehensive logging throughout error paths
- Fixed whitelist checking with robust error handling & fail-open safety
- Improved context variable cleanup to prevent memory leaks
- Better expired interaction handling with fallback logic
- Added constants for magic numbers (MAX_SLASH_COMMAND_NAME_LENGTH)
- More robust guild membership detection in whitelist checks
- Thread-safe error logging in all handlers

**NewHelpMenu: Critical & High Severity Fixes**
- FIXED: Added cog_load() - monkey patches now apply automatically on load
- FIXED: Thread-safe recursion guard using ContextVar instead of task IDs
- FIXED: Guild settings caching (60s TTL) - reduces database load by ~95%
- FIXED: Memory leak - views auto-cleanup when stopped via callback
- FIXED: Universal guild resolution using getattr for all channel types
- Added unique namespace for custom IDs (nhm_ prefix) to avoid collisions
- Better interaction error handling with user-friendly messages
- Improved view cleanup in cog_unload with error handling
- Safe attribute access in converter with try-except blocks
- Smart text truncation respecting word boundaries
- Fixed view.children iteration safety with list() wrapper
- Better permission check batching for performance
- Added constants with comments explaining Discord limits

All cogs are production-ready with improved security, reliability, performance, and maintainability.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 21:15:16 +00:00
root
860fd69e06 rubylogging/__init__.py | 19 ++ 2026-05-22 21:04:03 +00:00
Viktor
f75f51a6b4 feat(userslash): context-aware command filtering + custom description
User-install contexts (DMs, group DMs, non-member guilds) now only show
commands that can actually work outside a guild:

- _command_needs_guild() heuristic checks @guild_only, Red privilege
  levels (MOD/ADMIN/GUILD_OWNER), and user permission requirements,
  walking the parent chain for subcommands.
- Autocomplete pre-filters the candidate pool in user-install contexts
  and shows available DM-compatible commands when nothing is typed.
- Command execution blocks guild-only commands early with a clear
  ephemeral error instead of letting them fail cryptically.

Also:
- Slash command description changed to 'Shine bright like a Ruby'
- Added [p]userslash setdescription command to change it on the fly
  (persisted in Config, applied on cog load)
2026-05-14 20:48:37 +00:00
Viktor
180121bbdc fix(serverwhitelist): convert hybrid_group to group — exceeds 25-subcommand limit
The join hybrid_group has 34 subcommands which exceeds Discord's 25
subcommand limit for slash command groups. Since UserSlash already
bridges all text commands to slash, the hybrid registration is redundant.

Changed commands.hybrid_group → commands.group to avoid the ValueError.
2026-05-14 20:34:04 +00:00
Viktor
d20f988a93 fix: rename commands.py to slash_bridge.py to stop import shadowing
The file userslash/commands.py shadowed redbot.core.commands when Python
registered the submodule on the parent package, causing:

    AttributeError: module 'userslash.commands' has no attribute 'Cog'

Renaming the file to slash_bridge.py avoids the collision entirely.

Also adds a user-install whitelist feature:
- [p]userslash whitelist enable/disable
- [p]userslash whitelist add/remove @user
- [p]userslash whitelist list
- [p]userslash whitelist clear

When enabled, only whitelisted users may use the bot via user-install
(DMs, group DMs, non-member guilds).  Guild-installed usage is unaffected.
2026-05-14 20:30:06 +00:00
everestmcarthur
5c7046ff7c feat(serverwhitelist): v4.0 — the ultimate server management cog
New features:
- Whitelist Request System with DM button + approve/deny
- Server Notes & Tags
- Invite Audit via Discord audit logs
- Temporary Whitelist with auto-expiry
- Server Requirements (min/max members)
- Trusted Inviters for auto-whitelist
- Owner DM Alerts toggle
- Backup & Restore (full config JSON)
- Search command
- All v3 features preserved
2026-05-14 20:24:53 +00:00
everestmcarthur
8858470392 feat: add UserSlash cog — user-installable slash commands for every Red command
Replaces OneTrueSlash with full user-install support:
- Single proxy slash command bridges all text commands
- Works in servers, DMs, and group DMs
- REST API patcher sets integration_types & contexts on all global commands
- Owner commands: [p]userslash sync/patch/status
- Fuzzy autocomplete (rapidfuzz)
- Enhanced InterContext/InterMessage for non-guild contexts
2026-05-14 20:14:33 +00:00
everestmcarthur
004d1d61ea revert: remove self-ban code (Discord API does not allow self-banning) 2026-05-14 20:11:28 +00:00
everestmcarthur
07a84d2ff0 feat: self-ban on auto-ban — bot bans itself from blacklisted servers 2026-05-14 20:06:35 +00:00
everestmcarthur
086d8fc973 ServerWhitelist v3.0 — owner DM, auto-ban, attempt tracking, rich logging 2026-05-14 20:01:12 +00:00
Viktor AI
2ad7a7b691 fix: wire up missing feature enforcement in relay
- Mirror channels now receive relayed messages (was blocked from sending but never sent to)
- Server allowlist enforced in relay (allowlist_servers gate check)
- Silent mode suppresses status broadcasts (_status respects 'silent' flag)
- Welcome message sent when channel joins via 'wh open'
2026-05-14 19:33:58 +00:00
Viktor AI
4bc143b26f fix: group all commands under 'wh' parent — no more flat wh-xxx commands
Commands now show as 'wh create', 'wh staff add', 'wh set relaymode'
instead of 'wh-create', 'wh-staff add', 'wh-set relaymode'.

- Added commands/_base.py with root 'wh' group and all 20 subgroup stubs
- All 13 command mixins inherit from WormholeBase
- Decorators changed: @commands.hybrid_command(name='wh-X') → @WormholeBase.wh.command(name='X')
- Subgroup commands: @wh_X.command() → @WormholeBase.wh_X.command()
- Removed duplicate 'wh' group from core.py (now in _base.py)
- Fixed alias: 'wh-color' → 'color' for colour command
2026-05-14 19:24:37 +00:00
Viktor AI
5a4421fb6c fix: remove duplicate slash command registrations causing CommandAlreadyRegistered
The hybrid_command decorator on mixin classes already auto-registers
slash commands. The manual registrations in _register_context_menus
clashed, causing 'wh-list already registered' on load. Removed all
manual slash commands — only context menus remain.
2026-05-14 19:12:55 +00:00
everestmcarthur
81ce516964
Merge pull request #5 from everestmcarthur/refactor/modular-hierarchy
refactor: Wormhole v4.0.0 — Modular Architecture + Hierarchical Staff
2026-05-14 15:09:51 -04:00
Viktor AI
0b028e7bb9 refactor: Wormhole v4.0.0 — full modular architecture with hierarchical staff
BREAKING: Complete cog restructure from monolithic wormhole.py into modular architecture.

## Architecture
- models/permissions.py — Role IntEnum (MEMBER→OWNER), requires_role() decorator
- models/config.py — DEFAULT_NETWORK/DEFAULT_GLOBAL with 80+ config keys
- models/message_map.py — MessageMap class (extracted from _MessageMap)
- services/emoji.py — Foreign emoji resolution and relay
- ui/views.py — Reply jump button view
- ui/modals.py — Report modal
- core.py — Main Wormhole class, helpers, background loops, context menus
- commands/ — 13 command modules as mixin classes
- listeners/ — relay pipeline, edit/delete/reaction sync, typing/pin sync

## Staff System (new)
Per-network hierarchical roles replacing flat owner/staff:
  Bot Owner (Red built-in) — global override
  └─ Network Owner → Admin → Moderator → Helper → Member
  Each role assigned per-network. Higher roles can assign lower.
  Legacy staff_ids auto-migrated to ADMIN role.

## Enhanced Moderation
- Server-level ban/mute (not just user-level)
- Allowlist mode (only whitelisted servers can send)
- Mod edit and nuke (delete N messages by user)
- Anti-raid detector with auto-freeze
- Expanded automod: anti-zalgo, anti-emote-spam, anti-newline-spam

## Commands (100+)
network, settings, staff, moderation, filters, social, dm, mentions,
tos, reports, bridge, advanced (polls/afk/auto-responses/scheduled/
analytics/quiet-hours/colours/invites/announcements/blackout/portal),
debug (health/trace/testsend/relaydebug/backup/restore/version)

## Files
- 30 Python files, 5,274 lines total (was 4,782 in monolith)
- Original wormhole.py preserved for reference
- utils.py unchanged (all helpers reused)
2026-05-14 19:07:49 +00:00
Viktor
f48f755223 fix(wormhole): add emoji thumbnails to embed relay mode
Embed mode was missing foreign emoji support. Now all three relay
modes (webhook, embed, compact) show unknown emojis as embed
thumbnails via attachment:// scheme.
2026-05-14 16:11:15 +00:00
Viktor
bd0f55b243 fix(wormhole): show foreign emojis as embed thumbnails (~80px) not full-size
File attachments render as massive images in Discord regardless of
source size. Switch to embed thumbnails via the attachment:// scheme:

1. Download emoji from CDN at 48px
2. Attach as a File to the message
3. Reference via attachment://name.png in a minimal embed's thumbnail
4. Thumbnails render at ~80×80 px — much closer to emoji size

Fresh File/Embed objects are built per channel (consumed on send).
Bumps to v3.4.6.
2026-05-14 16:00:09 +00:00
Viktor
f74e9b7897 fix(wormhole): use inline links for foreign emojis instead of file attachments
File attachments render as massive images in Discord. Replace the
download-and-attach approach with clickable [:name:](cdn_url) inline
links — keeps foreign emojis compact and inline with the message text.

Removes aiohttp dependency and simplifies the helper to synchronous.
Bumps to v3.4.5.
2026-05-14 15:53:01 +00:00
Viktor
424403cf4f feat(wormhole): relay unknown custom emojis as 64px image attachments
Custom emojis the bot can't see (bot.get_emoji returns None) are now:
1. Replaced with :name: in message text
2. Downloaded from Discord CDN at 64px
3. Attached as small image files to the relay message

Known emojis (from any server the bot is in) keep the <:name:id>
syntax and render normally. Up to 5 emoji images per message.

Works in webhook and compact relay modes. Bumps to v3.4.4.
2026-05-14 15:40:36 +00:00
Viktor
2acee87123 fix(wormhole): resolve reply button to local copy, not original server
The forward map only stores relay targets — the source channel (where
the original message was typed) was never included. When someone in
Server B replied to a relayed message, the button for Server A fell
back to the fallback URL pointing at Server B instead of Server A.

Fix: after building the relay-target URLs, identify the source channel
by finding network channels not present in the forward map, and map
them to the original message ID.
2026-05-14 15:23:27 +00:00
Viktor
2a14a08801 fix(wormhole): only pass view kwarg when reply button exists
Passing view=None to wh.send() on every message caused all relays
to fail. Now uses **_view_kw dict unpacking so the view parameter
is only included when there is actually a reply-jump button to show.
2026-05-14 15:18:51 +00:00
everestmcarthur
e1d61b6eec
Merge pull request #4 from everestmcarthur/feat/enhanced-reply-buttons
feat(wormhole): Jump to replied message button on relayed replies
2026-05-14 11:15:38 -04:00
Viktor
13b28d3800 feat(wormhole): add 'Jump to replied message' button on relayed replies
When a reply is relayed across servers, each copy now includes a URL
button underneath the quoted reply text:

- If the referenced message has a relayed copy in the target channel,
  the button links to that local copy (so users stay in their own server).
- Otherwise, it falls back to the original message URL.

Works across all relay modes (webhook, embed, compact) and leverages
the existing msg_map to resolve per-channel message IDs.

Bumps version to 3.4.3.
2026-05-14 15:13:20 +00:00
everestmcarthur
0413fbcb66
feat: add ServerWhitelist cog (#3)
Ultimate owner-only server management with whitelist, blacklist,
interactive browser, purge, lock mode, logging, export & more.

Co-authored-by: Viktor <viktor@getviktor.com>
2026-05-12 23:07:11 -04:00
Viktor AI
bbf427284e feat: per-network mention config + user opt-in/out for pings
- Migration now uses a _mention_migrated flag so it only forces mentions
  off once. After that, admins can freely toggle per-network settings
  with 'wh mentions set <network> <type> <true/false>'

- New mention_optout_users list per network: users can opt out of being
  @pinged through the relay even when user mentions are enabled
  network-wide. Their <@ID> mentions are stripped; everyone else's pass
  through. Default: opted in.

- New commands:
  • wh mentions optout <network>  — stop receiving relay pings
  • wh mentions optin <network>   — start receiving relay pings again
  • wh mentions mystatus <network> — check your current ping status

- apply_mention_policy() now accepts optout_users set and selectively
  strips only opted-out users' mentions when user mentions are globally
  allowed

- Updated 'wh mentions status' to show opt-out count and correct
  defaults
2026-05-12 15:49:56 +00:00
Viktor AI
8c5b422d83 fix: migrate existing networks to strip all mentions + revert empty-prefix guard
- On cog load, all existing networks are migrated to disable every
  mention type (user, role, everyone, here) — changing the default
  only affected new networks, not existing ones
- Reverted the v3.4.2 'and ctx.prefix' guard in the command filter —
  the real relay bug was the regex crash, not the empty prefix.
  ctx.valid alone correctly identifies registered commands even with
  an empty-string prefix
2026-05-12 15:21:08 +00:00
Viktor AI
9e8650c01a feat: strip all mentions from relayed messages by default (v3.4.3)
- Default mention_policy now disables all mention types including user
  mentions (previously allow_user_mentions defaulted to True)
- Blocked mentions are now removed entirely instead of replaced with
  ZWSP placeholders — '@mention HI!' becomes 'HI!' on the other side
- Trailing whitespace from removed mentions is cleaned up
- Updated both apply_mention_policy() and sanitise_mentions()
2026-05-12 14:55:56 +00:00
Viktor AI
f1c8970d3d fix: raw string in mention_policy regex crashes every relay (v3.4.3)
Root cause: apply_mention_policy() in utils.py used raw strings for
re.sub replacement arguments:
  re.sub(r'<@&(\d+)>', r'@\u200brole', content)

The r-prefix makes \u200b literal backslash-u instead of Unicode ZWSP.
Python's re.sub always validates the replacement template, so \u at
position 1 raises re.error on EVERY message — even without matches.

Since _DEFAULT_NETWORK sets mention_policy.allow_role_mentions=False,
this code path runs for all networks, causing _do_relay to throw on
every single message. The exception was caught by on_message's
try/except, silently killing relay with total_messages stuck at 0.

Fix: remove r-prefix from replacement strings so \u200b is correctly
interpreted as the Unicode zero-width space character.
2026-05-12 14:52:22 +00:00
Viktor AI
39188d9f4e feat: add relay diagnostic commands (relaydebug, testsend, tracemode)
Added three diagnostic tools to help debug relay issues:

- wh relaydebug: static check of all on_message gates against the
  current channel — reports which checks pass/fail
- wh testsend [text]: bypasses on_message entirely and sends a test
  message directly through the webhook to verify connectivity
- wh tracemode: toggles live tracing for the channel — when enabled,
  every message produces a diagnostic embed showing exactly which
  gate-check blocked it or that the relay succeeded

Also added trace checkpoints at every early-return in on_message so
tracemode can pinpoint the exact check that blocks a message.
2026-05-12 13:38:15 +00:00
Viktor AI
9598f752c1 fix: Wormhole v3.4.2 — empty-prefix command filter bug
The v3.4.1 command filter used bot.get_context() to detect commands,
but an empty-string prefix ('') matched EVERY message, causing
ctx.valid to return True for any message whose first word happened
to be a registered command.  With enough built-in commands (help,
ping, info, set, etc.) this silently dropped most or all relay
traffic (total_messages stayed at 0).

Fix: require ctx.prefix to be truthy (non-empty) before skipping
a message as a command.  Empty-prefix matches are now ignored,
so only messages with a real prefix (!, @bot, etc.) are filtered.

Also re-added the empty-prefix warning to 'wh debug' output so
users know to clean up their bot prefix configuration.
2026-05-12 12:53:18 +00:00
Viktor AI
5ece19dae7 fix: Wormhole v3.4.1 — relay engine hardening 2026-05-12 12:24:44 +00:00
everestmcarthur
a4ba2040ec fix: Critical bugfixes for VoiceMeister
1. CRITICAL: Permission overwrites now properly merge instead of replace.
   set_permissions with keyword args REPLACES the entire overwrite,
   so Lock→Hide would undo the Lock. Now uses overwrites_for() to
   fetch existing state and modify only the target field.
   Affects: Lock, Unlock, Hide, Unhide, Ghost, Reveal (buttons & commands)

2. CRITICAL: Removed broken async generator in any() for game rename check.
   await in generator expression creates async generator that any() can't
   consume. Game rename loop now always starts and checks config per-guild.

3. Minor: Fixed double-write in _save_temp_channels.
4. Minor: Removed unused imports (datetime, Set).
2026-05-08 14:48:42 +00:00
everestmcarthur
ec7767079e
feat: Add VoiceMeister v1.0.0
feat: Add VoiceMeister v1.0.0 — Ultimate temporary voice channel management
2026-05-08 09:50:25 -04:00