jim-bo's picture
fix: address CodeRabbit review findings
2b086b8
import importlib
import pkgutil
import inspect
from abc import ABC, abstractmethod
from typing import List, Dict, Type
class SlashCommand(ABC):
"""Base class for all slash commands."""
@property
@abstractmethod
def name(self) -> str:
"""The command string, e.g., '/help'."""
pass
@property
@abstractmethod
def description(self) -> str:
"""Brief summary of what the command does."""
pass
@property
def requires_permission(self) -> bool:
"""True if this command needs explicit user approval before running."""
return False
@abstractmethod
async def execute(self, app, args: List[str]):
"""The logic to run when the command is invoked."""
pass
class CommandManager:
"""Registry and executor for slash commands."""
def __init__(self):
self.commands: Dict[str, SlashCommand] = {}
def register_command(self, cmd: SlashCommand):
"""Manually register a command instance."""
self.commands[cmd.name.lower()] = cmd
def auto_discover(self, package_path: str):
"""
Dynamically discover and register SlashCommand classes in a package.
e.g., auto_discover('cli_textual.plugins.commands')
"""
try:
package = importlib.import_module(package_path)
for _, name, is_pkg in pkgutil.iter_modules(package.__path__):
full_module_name = f"{package_path}.{name}"
module = importlib.import_module(full_module_name)
for _, obj in inspect.getmembers(module):
if (inspect.isclass(obj) and
issubclass(obj, SlashCommand) and
obj is not SlashCommand):
# Instantiate and register
instance = obj()
self.register_command(instance)
except Exception as e:
print(f"Error during command discovery: {e}")
def get_command(self, name: str) -> SlashCommand | None:
return self.commands.get(name.lower())
def get_all_help(self) -> str:
help_text = "### Commands\n"
for name in sorted(self.commands.keys()):
cmd = self.commands[name]
help_text += f"- {name.ljust(15)} {cmd.description}\n"
return help_text