Loading this cog called bot.remove_command("help") with no replacement
command ever defined and no restore on unload — simply loading it broke
[p]help bot-wide, permanently, until process restart. Traced through Red's
own source (redbot/core/commands/help.py) and confirmed the default help
command already routes through bot.send_help_for(), which is exactly what
this cog hooks to render CV2 output — so the fix is to just not remove the
command at all; the CV2 conversion now actually works as intended too,
since its hook point is reachable again.
_active_views leaked one permanent dict entry (holding the whole rendered
page/embed list) per help/menu invocation — every on_timeout and "close"
button already called view.stop(), but nothing was popping the matching
entry except one specific code path. Added a single _track_view() helper
that wraps stop() for automatic eviction and applied it at all 5 insertion
points instead of just the one.
Parallelized the per-command can_run() permission checks in
gather_bot_help_data/gather_cog_help_data (previously one await at a time
for every bot/cog command on every single [p]help call). Also added the
admin_or_permissions check to `cv2 version`, the one subcommand missing it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
- CV2 HelpPaginatorView: Close button in its own ActionRow,
category Select in a separate ActionRow (Discord requires
selects to be alone in their row)
- Cap overview embed to 20 category fields to stay under
Discord's 25-field limit
Major rewrite of help rendering:
- Embed mode (default): Rich embeds with interactive View buttons
(⏮◀️▶️⏭) + category select dropdown + close button
- CV2 mode (when `cv2 toggle` is on): Components V2 containers
with the same navigation
- Shared data-gathering layer: both modes use the same logic to
gather commands, filter permissions, handle categories
- All Red help features: command filtering, permission checks,
aliases, subcommands, cooldowns, format_help_for_context
- Text fallback for DMs
- Help command now always tries CV2 in guilds (that's its purpose)
with text fallback only on error or in DMs
- cv2 group invoke no longer calls ctx.send_help() which relied
on Red's internal formatter — sends usage text directly
- Context.send calls Messageable.send internally, both patched —
use asyncio task ID set to prevent re-entry loop
- Text fallback for help now paginates at 1900 chars to stay
under Discord's 2000-char limit
The classic Red/discord.py pattern: bot.remove_command('help') in
__init__.py's setup() BEFORE bot.add_cog(), so the cog's own
@commands.command(name='help') decorator doesn't clash with Red's
built-in help.
Original help command stored on cog instance and restored in cog_unload.
- Removes Red's built-in help command on cog load, restores on unload
- Our help command fully replaces it (CV2 when enabled, text fallback for DMs)
- Monkey-patches both Context.send AND Messageable.send so ALL bot embeds
everywhere (channels, threads, DMs) get auto-converted to CV2 containers
- Per-cog overrides still respected for Context sends
- Clean restore of everything on cog unload
Replaces embed-based help with full Components V2 system:
- converter.py: Embed → Container conversion engine
- formatter.py: CV2 help page builder + paginator views
- newhelpmenu.py: Main cog with settings, monkey-patching, public API
- 1,747 lines across 4 files, default off