This commit is contained in:
Slipstream 2025-05-13 08:46:29 -06:00
parent e077a1fbba
commit 4336e4174b
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD
6 changed files with 132 additions and 69 deletions

View File

@ -41,15 +41,24 @@ def set_command_context(
"""
# Set guild_only and dm_permission based on the context
if context == AppCommandContext.GUILD or context == AppCommandContext.GUILD_INSTALL:
# Guild-only commands
command.guild_only = True
# dm_permission is automatically set to False when guild_only is True
elif context == AppCommandContext.PRIVATE:
# Private-only commands (DMs and private channels)
command.guild_only = False
# We need to override the extras to set dm_permission to True and guild_permission to False
# Set dm_permission to True
if not hasattr(command, "extras"):
command.extras = {}
command.extras["dm_permission"] = True
command.extras["default_member_permissions"] = "0" # No permissions in guild
# Disable in guilds by setting default_member_permissions to "0"
command.extras["default_member_permissions"] = "0"
elif context == AppCommandContext.ALL:
# Commands that work everywhere
command.guild_only = False
# Set dm_permission to True
if not hasattr(command, "extras"):
command.extras = {}
command.extras["dm_permission"] = True
# Allow default permissions in guilds

View File

@ -203,17 +203,26 @@ async def register_guild_commands(bot, guild: discord.Guild) -> List[app_command
return await syncer.sync_guild_commands(guild)
async def register_all_guild_commands(bot) -> Dict[int, List[app_commands.Command]]:
async def register_all_guild_commands(bot, global_command_names=None) -> Dict[int, List[app_commands.Command]]:
"""
Register commands for all guilds with customizations.
Returns a dictionary mapping guild IDs to lists of registered commands.
Args:
bot: The bot instance
global_command_names: Optional list of command names that are already registered globally
(not used in this implementation, kept for compatibility)
"""
syncer = GuildCommandSyncer(bot)
results = {}
for guild in bot.guilds:
try:
# Sync all commands to this guild
log.info(f"Syncing commands for guild {guild.id}")
results[guild.id] = await syncer.sync_guild_commands(guild)
log.info(f"Synced {len(results[guild.id])} commands for guild {guild.id}")
except Exception as e:
log.error(f"Failed to sync commands for guild {guild.id}: {e}")
results[guild.id] = []

View File

@ -21,19 +21,21 @@ log = logging.getLogger(__name__)
async def sync_global_and_guild_commands(
bot: commands.Bot,
global_only: bool = False,
guild_only: bool = False
guild_only: bool = False,
private_command_names: List[str] = None
) -> Dict[str, Any]:
"""
Sync both global and guild-specific commands with Discord.
Sync commands with Discord, first to guilds and then globally.
This function allows for more control over command syncing, enabling
both global commands (that work in DMs) and guild-specific commands
with customizations.
This function implements the following strategy:
1. First, sync guild-specific commands to every guild (as before)
2. Then, sync global commands with dm_permission=True and guild_only=False
Args:
bot: The bot instance
global_only: If True, only sync global commands
guild_only: If True, only sync guild-specific commands
private_command_names: List of command names that should work in private contexts
Returns:
A dictionary containing the results of the sync operations
@ -44,26 +46,60 @@ async def sync_global_and_guild_commands(
}
try:
# Sync global commands if requested
if not guild_only:
log.info("Syncing global commands...")
global_synced = await bot.tree.sync()
results["global"] = global_synced
log.info(f"Synced {len(global_synced)} global command(s)")
# Get all commands from the command tree
all_commands = bot.tree.get_commands()
command_names = [cmd.name for cmd in all_commands]
log.info(f"Found {len(all_commands)} commands in tree: {', '.join(command_names)}")
# List the synced commands
global_commands = [cmd.name for cmd in global_synced]
log.info(f"Global commands: {', '.join(global_commands)}")
# If private_command_names is not provided, use an empty list
if private_command_names is None:
private_command_names = []
# Sync guild-specific commands if requested
# First, sync guild-specific commands if requested
if not global_only:
log.info("Syncing guild-specific command customizations...")
log.info("Syncing guild-specific commands to all guilds...")
# Use the command_customization module to handle guild-specific commands
guild_syncs = await command_customization.register_all_guild_commands(bot)
results["guild"] = guild_syncs
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
log.info(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} customized commands")
# Now, prepare global commands with appropriate context settings
if not guild_only and private_command_names:
log.info("Preparing global commands for private contexts...")
# Clear the command tree for global commands
bot.tree.clear_commands()
# Add back only the commands that should work in private contexts
from command_context import AppCommandContext, set_command_context
for cmd_name in private_command_names:
# Find the command in the original list
cmd = next((c for c in all_commands if c.name == cmd_name), None)
if cmd:
log.info(f"Setting command {cmd_name} to work in private contexts")
# Set the command to work in private contexts
set_command_context(cmd, AppCommandContext.ALL)
# Add the command back to the tree
bot.tree.add_command(cmd)
else:
log.warning(f"Command {cmd_name} not found in command tree")
# Sync the global commands
log.info("Syncing global commands for private contexts...")
global_synced = await bot.tree.sync()
results["global"] = global_synced
# List the synced commands
global_command_names = [cmd.name for cmd in global_synced]
log.info(f"Synced {len(global_synced)} global command(s) for private contexts: {', '.join(global_command_names)}")
# Restore the original command tree
bot.tree.clear_commands()
for cmd in all_commands:
bot.tree.add_command(cmd)
except Exception as e:
log.error(f"Failed to sync commands: {e}")
import traceback

View File

@ -32,32 +32,31 @@ async def on_ready():
# Import our command sync utilities
try:
import command_sync_utils
from command_context import AppCommandContext
# Sync both global and guild-specific commands
print("Syncing both global and guild-specific commands...")
sync_results = await command_sync_utils.sync_global_and_guild_commands(bot)
# Report results
global_syncs = sync_results["global"]
guild_syncs = sync_results["guild"]
print(f"Synced {len(global_syncs)} global command(s)")
if guild_syncs:
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} customized commands")
# Set context for specific commands to allow them in private channels and DMs
# Define commands that should work in private channels and DMs
private_commands = [
# Add command names that should work in private contexts here
"gurtmood", # Allow mood command in DMs
]
# Create a dictionary mapping command names to contexts
command_contexts = {name: AppCommandContext.ALL for name in private_commands}
# First sync guild-specific commands to all guilds, then sync global commands for private contexts
print("First syncing commands to all guilds, then syncing global commands for private contexts...")
sync_results = await command_sync_utils.sync_global_and_guild_commands(
bot,
private_command_names=private_commands
)
# Apply the contexts to the commands
command_sync_utils.set_command_contexts(bot, command_contexts)
# Report results
global_syncs = sync_results["global"]
guild_syncs = sync_results["guild"]
# Report guild syncs
if guild_syncs:
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} commands")
# Report global syncs
print(f"Synced {len(global_syncs)} global command(s) for private contexts")
except ImportError:
# Fall back to regular sync if the utility modules aren't available

35
main.py
View File

@ -232,25 +232,31 @@ async def on_ready():
# Import our new command sync utilities
import command_sync_utils
from command_context import AppCommandContext
# Sync both global and guild-specific commands
print("Syncing both global and guild-specific commands...")
sync_results = await command_sync_utils.sync_global_and_guild_commands(bot)
# First sync guild-specific commands to all guilds, then sync global commands for private contexts
print("First syncing commands to all guilds, then syncing global commands for private contexts...")
sync_results = await command_sync_utils.sync_global_and_guild_commands(
bot,
private_command_names=private_commands
)
# Report results
global_syncs = sync_results["global"]
guild_syncs = sync_results["guild"]
print(f"Synced {len(global_syncs)} global command(s)")
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} customized commands")
# Report guild syncs
if guild_syncs:
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} commands")
# Report global syncs
print(f"Synced {len(global_syncs)} global command(s) for private contexts")
# List commands after sync
commands_after = [cmd.name for cmd in bot.tree.get_commands()]
print(f"Commands registered in command tree: {', '.join(commands_after)}")
# Set context for specific commands to allow them in private channels and DMs
# Define commands that should work in private channels and DMs
private_commands = [
# Add command names that should work in private contexts here
"dmhelp",
@ -265,11 +271,16 @@ async def on_ready():
except Exception as e:
print(f"Failed to load example_global_commands cog: {e}")
# Create a dictionary mapping command names to contexts
command_contexts = {name: AppCommandContext.ALL for name in private_commands}
# Sync both global and guild-specific commands, avoiding duplicates
print("Re-syncing commands with private context settings...")
sync_results = await command_sync_utils.sync_global_and_guild_commands(
bot,
private_command_names=private_commands
)
# Apply the contexts to the commands
command_sync_utils.set_command_contexts(bot, command_contexts)
# Report results
global_syncs = sync_results["global"]
print(f"Re-synced {len(global_syncs)} global command(s) with private context settings")
except Exception as e:
print(f"Failed to sync commands: {e}")

View File

@ -32,32 +32,31 @@ async def on_ready():
# Import our command sync utilities
try:
import command_sync_utils
from command_context import AppCommandContext
# Sync both global and guild-specific commands
print("Syncing both global and guild-specific commands...")
sync_results = await command_sync_utils.sync_global_and_guild_commands(bot)
# Report results
global_syncs = sync_results["global"]
guild_syncs = sync_results["guild"]
print(f"Synced {len(global_syncs)} global command(s)")
if guild_syncs:
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} customized commands")
# Set context for specific commands to allow them in private channels and DMs
# Define commands that should work in private channels and DMs
private_commands = [
# Add command names that should work in private contexts here
"wheatleymemory", # Allow memory command in DMs
]
# Create a dictionary mapping command names to contexts
command_contexts = {name: AppCommandContext.ALL for name in private_commands}
# First sync guild-specific commands to all guilds, then sync global commands for private contexts
print("First syncing commands to all guilds, then syncing global commands for private contexts...")
sync_results = await command_sync_utils.sync_global_and_guild_commands(
bot,
private_command_names=private_commands
)
# Apply the contexts to the commands
command_sync_utils.set_command_contexts(bot, command_contexts)
# Report results
global_syncs = sync_results["global"]
guild_syncs = sync_results["guild"]
# Report guild syncs
if guild_syncs:
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} commands")
# Report global syncs
print(f"Synced {len(global_syncs)} global command(s) for private contexts")
except ImportError:
# Fall back to regular sync if the utility modules aren't available