diff --git a/modules/command_manager.py b/modules/command_manager.py index 6688973..db3501b 100644 --- a/modules/command_manager.py +++ b/modules/command_manager.py @@ -422,13 +422,22 @@ class CommandManager: return f"Help {command_name}: {help_text}" # If still not found, return unknown command message with helpful suggestion - available_commands = [] - for cmd_name, cmd_instance in self.commands.items(): - available_commands.append(cmd_name) - if hasattr(cmd_instance, 'keywords'): - available_commands.extend(cmd_instance.keywords) + # Use the help command's method to get popular commands (only primary names, no aliases) + available_str = "" + if 'help' in self.commands: + help_command = self.commands['help'] + if hasattr(help_command, 'get_available_commands_list'): + available_str = help_command.get_available_commands_list() + + # Fallback if help command doesn't have the method + if not available_str: + # Only show primary command names, not keywords + primary_names = sorted([ + cmd.name if hasattr(cmd, 'name') else name + for name, cmd in self.commands.items() + ]) + available_str = ', '.join(primary_names) - available_str = ', '.join(sorted(set(available_commands))) if hasattr(self.bot, 'translator'): return self.bot.translator.translate('commands.help.unknown', command=command_name, available=available_str) return f"Unknown: {command_name}. Available: {available_str}. Try 'help' for command list." diff --git a/modules/commands/help_command.py b/modules/commands/help_command.py index 1339e19..98dcfc2 100644 --- a/modules/commands/help_command.py +++ b/modules/commands/help_command.py @@ -4,6 +4,8 @@ Help command for the MeshCore Bot Provides help information for commands and general usage """ +import sqlite3 +from collections import defaultdict from .base_command import BaseCommand from ..models import MeshMessage @@ -68,36 +70,100 @@ class HelpCommand(BaseCommand): return help_text def get_available_commands_list(self) -> str: - """Get a formatted list of available commands""" - commands_list = "" - - # Group commands by category - basic_commands = ['test', 'ping', 'help'] - custom_syntax = ['t_phrase'] # Use the actual command key - special_commands = ['advert'] - - commands_list += "**Basic Commands:**\n" - for cmd in basic_commands: - if cmd in self.bot.command_manager.commands: - help_text = self.bot.command_manager.commands[cmd].get_help_text() - commands_list += f"• `{cmd}` - {help_text}\n" - - commands_list += "\n**Custom Syntax:**\n" - for cmd in custom_syntax: - if cmd in self.bot.command_manager.commands: - help_text = self.bot.command_manager.commands[cmd].get_help_text() - # Add user-friendly aliases - if cmd == 't_phrase': - commands_list += f"• `t phrase` - {help_text}\n" - else: - commands_list += f"• `{cmd}` - {help_text}\n" - - commands_list += "\n**Special Commands:**\n" - for cmd in special_commands: - if cmd in self.bot.command_manager.commands: - help_text = self.bot.command_manager.commands[cmd].get_help_text() - commands_list += f"• `{cmd}` - {help_text}\n" - - return commands_list + """Get a list of most popular commands in descending order, showing only one variant per command""" + try: + # Use the plugin loader's keyword mappings to map keywords/aliases to primary command names + plugin_loader = self.bot.command_manager.plugin_loader + keyword_mappings = plugin_loader.keyword_mappings.copy() if hasattr(plugin_loader, 'keyword_mappings') else {} + + # Build a set of all primary command names and ensure they map to themselves + primary_names = set() + for cmd_name, cmd_instance in self.bot.command_manager.commands.items(): + primary_name = cmd_instance.name if hasattr(cmd_instance, 'name') else cmd_name + primary_names.add(primary_name) + # Ensure primary name maps to itself in keyword_mappings + keyword_mappings[primary_name.lower()] = primary_name + + # Query the database for command usage statistics + command_counts = defaultdict(int) + try: + with sqlite3.connect(self.bot.db_manager.db_path) as conn: + cursor = conn.cursor() + # Check if command_stats table exists + cursor.execute(""" + SELECT name FROM sqlite_master + WHERE type='table' AND name='command_stats' + """) + if cursor.fetchone(): + # Query command usage + cursor.execute(""" + SELECT command_name, COUNT(*) as count + FROM command_stats + GROUP BY command_name + """) + for row in cursor.fetchall(): + command_name = row[0] + count = row[1] + + # Map keyword/alias to primary command name + # First try the plugin_loader's keyword_mappings + primary_name = keyword_mappings.get(command_name.lower()) + + # If not found in mappings, check if it's already a primary name + if primary_name is None: + if command_name in primary_names: + primary_name = command_name + else: + # Try to find which command this belongs to by checking all commands + for cmd_name, cmd_instance in self.bot.command_manager.commands.items(): + # Check if command_name matches the command's name + cmd_primary = cmd_instance.name if hasattr(cmd_instance, 'name') else cmd_name + if cmd_primary == command_name: + primary_name = cmd_primary + break + # Check if it's a keyword of this command + if hasattr(cmd_instance, 'keywords'): + if command_name.lower() in [k.lower() for k in cmd_instance.keywords]: + primary_name = cmd_primary + break + # If still not found, use the command_name as-is + if primary_name is None: + primary_name = command_name + + command_counts[primary_name] += count + except Exception as e: + self.logger.debug(f"Error querying command stats: {e}") + # If stats table doesn't exist or query fails, fall back to all commands + for cmd_name in self.bot.command_manager.commands.keys(): + primary_name = self.bot.command_manager.commands[cmd_name].name if hasattr(self.bot.command_manager.commands[cmd_name], 'name') else cmd_name + command_counts[primary_name] = 0 + + # If we have stats, sort by count descending, otherwise use all commands + if command_counts: + # Sort by count descending, then by name for consistency + sorted_commands = sorted( + command_counts.items(), + key=lambda x: (-x[1], x[0]) + ) + # Extract just the command names (only primary names, no aliases) + command_names = [name for name, _ in sorted_commands] + else: + # Fallback: use all primary command names + command_names = sorted([ + cmd.name if hasattr(cmd, 'name') else name + for name, cmd in self.bot.command_manager.commands.items() + ]) + + # Return comma-separated list + return ', '.join(command_names) + + except Exception as e: + self.logger.error(f"Error getting available commands list: {e}") + # Fallback to simple list of all command names + command_names = sorted([ + cmd.name if hasattr(cmd, 'name') else name + for name, cmd in self.bot.command_manager.commands.items() + ]) + return ', '.join(command_names)