fix: auto-register all gateway commands as Discord slash commands (#10528)
Discord's _register_slash_commands() had a hardcoded list of ~27 commands while COMMAND_REGISTRY defines 34+ gateway-available commands. Missing commands (debug, branch, rollback, snapshot, profile, yolo, fast, reload, commands) were invisible in Discord's / autocomplete — users couldn't discover them. Add a dynamic catch-all loop after the explicit registrations that iterates COMMAND_REGISTRY, skips already-registered commands, and auto-registers the rest using discord.app_commands.Command(). Commands with args_hint get an optional string parameter; parameterless commands get a simple callback. This ensures any future commands added to COMMAND_REGISTRY automatically appear on Discord without needing a manual entry in discord.py. Telegram and Slack already derive dynamically from COMMAND_REGISTRY via telegram_bot_commands() and slack_subcommand_map() — no changes needed there.
This commit is contained in:
@@ -134,6 +134,57 @@ async def test_registers_native_restart_slash_command(adapter):
|
||||
)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Auto-registration from COMMAND_REGISTRY
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auto_registers_missing_gateway_commands(adapter):
|
||||
"""Commands in COMMAND_REGISTRY that aren't explicitly registered should
|
||||
be auto-registered by the dynamic catch-all block."""
|
||||
adapter._run_simple_slash = AsyncMock()
|
||||
adapter._register_slash_commands()
|
||||
|
||||
tree_names = set(adapter._client.tree.commands.keys())
|
||||
|
||||
# These commands are gateway-available but were not in the original
|
||||
# hardcoded registration list — they should be auto-registered.
|
||||
expected_auto = {"debug", "yolo", "reload", "profile"}
|
||||
for name in expected_auto:
|
||||
assert name in tree_names, f"/{name} should be auto-registered on Discord"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auto_registered_command_dispatches_correctly(adapter):
|
||||
"""Auto-registered commands should dispatch via _run_simple_slash."""
|
||||
adapter._run_simple_slash = AsyncMock()
|
||||
adapter._register_slash_commands()
|
||||
|
||||
# /debug has no args — test parameterless dispatch
|
||||
debug_cmd = adapter._client.tree.commands["debug"]
|
||||
interaction = SimpleNamespace()
|
||||
adapter._run_simple_slash.reset_mock()
|
||||
await debug_cmd.callback(interaction)
|
||||
adapter._run_simple_slash.assert_awaited_once_with(interaction, "/debug")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auto_registered_command_with_args(adapter):
|
||||
"""Auto-registered commands with args_hint should accept an optional args param."""
|
||||
adapter._run_simple_slash = AsyncMock()
|
||||
adapter._register_slash_commands()
|
||||
|
||||
# /branch has args_hint="[name]" — test dispatch with args
|
||||
branch_cmd = adapter._client.tree.commands["branch"]
|
||||
interaction = SimpleNamespace()
|
||||
adapter._run_simple_slash.reset_mock()
|
||||
await branch_cmd.callback(interaction, args="my-branch")
|
||||
adapter._run_simple_slash.assert_awaited_once_with(
|
||||
interaction, "/branch my-branch"
|
||||
)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# _handle_thread_create_slash — success, session dispatch, failure
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user